Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: content/renderer/media/video_track_recorder.cc

Issue 1886123002: [experimental] MR: add support for H264 recording (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/video_track_recorder.h" 5 #include "content/renderer/media/video_track_recorder.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/macros.h" 11 #include "base/macros.h"
12 #include "base/sys_info.h" 12 #include "base/sys_info.h"
13 #include "base/threading/thread.h" 13 #include "base/threading/thread.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "base/trace_event/trace_event.h" 15 #include "base/trace_event/trace_event.h"
16 #include "media/base/video_frame.h" 16 #include "media/base/video_frame.h"
17 #include "media/base/video_util.h" 17 #include "media/base/video_util.h"
18 #include "ui/gfx/geometry/size.h" 18 #include "ui/gfx/geometry/size.h"
19 19
20 extern "C" { 20 extern "C" {
21 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide 21 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide
22 // backwards compatibility for legacy applications using the library. 22 // backwards compatibility for legacy applications using the library.
23 #define VPX_CODEC_DISABLE_COMPAT 1 23 #define VPX_CODEC_DISABLE_COMPAT 1
24 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" 24 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
25 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" 25 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
26 } 26 }
27 27
28 #include "third_party/openh264/src/codec/api/svc/codec_api.h"
29 #include "third_party/openh264/src/codec/api/svc/codec_app_def.h"
30 #include "third_party/openh264/src/codec/api/svc/codec_def.h"
31
28 using media::VideoFrame; 32 using media::VideoFrame;
29 using media::VideoFrameMetadata; 33 using media::VideoFrameMetadata;
30 34
31 namespace content { 35 namespace content {
32 36
33 namespace { 37 namespace {
34 38
35 const vpx_codec_flags_t kNoFlags = 0; 39 const vpx_codec_flags_t kNoFlags = 0;
36 40
37 // Originally from remoting/codec/scoped_vpx_codec.h. 41 // Originally from remoting/codec/scoped_vpx_codec.h.
(...skipping 16 matching lines...) Expand all
54 std::unique_ptr<std::string> data, 58 std::unique_ptr<std::string> data,
55 base::TimeTicks capture_timestamp, 59 base::TimeTicks capture_timestamp,
56 bool keyframe) { 60 bool keyframe) {
57 DVLOG(1) << (keyframe ? "" : "non ") << "keyframe "<< data->length() << "B, " 61 DVLOG(1) << (keyframe ? "" : "non ") << "keyframe "<< data->length() << "B, "
58 << capture_timestamp << " ms"; 62 << capture_timestamp << " ms";
59 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe); 63 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe);
60 } 64 }
61 65
62 } // anonymous namespace 66 } // anonymous namespace
63 67
68 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> {
69 public:
70 virtual void StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
71 base::TimeTicks capture_timestamp) = 0;
72
73 virtual void set_paused(bool paused) = 0;
74
75 protected:
76 friend class base::RefCountedThreadSafe<Encoder>;
77 virtual ~Encoder() {}
78 };
79
80 namespace {
81
64 // Inner class encapsulating all libvpx interactions and the encoding+delivery 82 // Inner class encapsulating all libvpx interactions and the encoding+delivery
65 // of received frames. Limitation: Only VP8 is supported for the time being. 83 // of received frames. Limitation: Only VP8 is supported for the time being.
66 // This class must be ref-counted because the MediaStreamVideoTrack will hold a 84 // This class must be ref-counted because the MediaStreamVideoTrack will hold a
67 // reference to it, via the callback MediaStreamVideoSink passes along, and it's 85 // reference to it, via the callback MediaStreamVideoSink passes along, and it's
68 // unknown when exactly it will release that reference. This class: 86 // unknown when exactly it will release that reference. This class:
69 // - is created and destroyed on its parent's thread (usually the main Render 87 // - is created and destroyed on its parent's thread (usually the main Render
70 // thread); 88 // thread);
71 // - receives VideoFrames and Run()s the callbacks on |origin_task_runner_|, 89 // - receives VideoFrames and Run()s the callbacks on |origin_task_runner_|,
72 // which is cached on first frame arrival, and is supposed to be the render IO 90 // which is cached on first frame arrival, and is supposed to be the render IO
73 // thread, but this is not enforced; 91 // thread, but this is not enforced;
74 // - uses an internal |encoding_thread_| for libvpx interactions, notably for 92 // - uses an internal |encoding_thread_| for libvpx interactions, notably for
75 // encoding (which might take some time). 93 // encoding (which might take some time).
76 class VideoTrackRecorder::VpxEncoder final 94 class VpxEncoder final : public VideoTrackRecorder::Encoder {
77 : public base::RefCountedThreadSafe<VpxEncoder> {
78 public: 95 public:
79 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, 96 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread,
80 ScopedVpxCodecCtxPtr encoder); 97 ScopedVpxCodecCtxPtr encoder);
81 98
82 VpxEncoder(bool use_vp9, 99 VpxEncoder(
83 const OnEncodedVideoCB& on_encoded_video_callback, 100 bool use_vp9,
84 int32_t bits_per_second); 101 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
102 int32_t bits_per_second);
85 103
86 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, 104 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
87 base::TimeTicks capture_timestamp); 105 base::TimeTicks capture_timestamp) override;
88 106
89 void set_paused(bool paused) { paused_ = paused; } 107 void set_paused(bool paused) override { paused_ = paused; }
90 108
91 private: 109 private:
92 friend class base::RefCountedThreadSafe<VpxEncoder>; 110 ~VpxEncoder() override;
93 ~VpxEncoder();
94 111
95 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, 112 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame,
96 base::TimeTicks capture_timestamp); 113 base::TimeTicks capture_timestamp);
97 114
98 void ConfigureEncoding(const gfx::Size& size); 115 void ConfigureEncoding(const gfx::Size& size);
99 116
100 // Returns true if |codec_config_| has been filled in at least once. 117 // Returns true if |codec_config_| has been filled in at least once.
101 bool IsInitialized() const; 118 bool IsInitialized() const;
102 119
103 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. 120 // Estimate the frame duration from |frame| and |last_frame_timestamp_|.
104 base::TimeDelta CalculateFrameDuration( 121 base::TimeDelta CalculateFrameDuration(
105 const scoped_refptr<VideoFrame>& frame); 122 const scoped_refptr<VideoFrame>& frame);
106 123
107 // While |paused_|, frames are not encoded. 124 // While |paused_|, frames are not encoded.
108 bool paused_; 125 bool paused_;
109 126
110 // Force usage of VP9 for encoding, instead of VP8 which is the default. 127 // Force usage of VP9 for encoding, instead of VP8 which is the default.
111 const bool use_vp9_; 128 const bool use_vp9_;
112 129
113 // This callback should be exercised on IO thread. 130 // This callback should be exercised on IO thread.
114 const OnEncodedVideoCB on_encoded_video_callback_; 131 const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_callback_;
115 132
116 // Target bitrate or video encoding. If 0, a standard bitrate is used. 133 // Target bitrate or video encoding. If 0, a standard bitrate is used.
117 const int32_t bits_per_second_; 134 const int32_t bits_per_second_;
118 135
119 // Used to shutdown properly on the same thread we were created. 136 // Used to shutdown properly on the same thread we were created.
120 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; 137 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
121 138
122 // Task runner where frames to encode and reply callbacks must happen. 139 // Task runner where frames to encode and reply callbacks must happen.
123 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; 140 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
124 141
125 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables 142 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables
126 // below this are used in this thread. 143 // below this are used in this thread.
127 std::unique_ptr<base::Thread> encoding_thread_; 144 std::unique_ptr<base::Thread> encoding_thread_;
128 // VP8 internal objects: configuration and encoder. 145 // VP8 internal objects: configuration and encoder.
129 vpx_codec_enc_cfg_t codec_config_; 146 vpx_codec_enc_cfg_t codec_config_;
130 // |encoder_| is a special scoped pointer to guarantee proper destruction. 147 // |encoder_| is a special scoped pointer to guarantee proper destruction.
131 // Again, it should only be accessed on |encoding_thread_|. 148 // Again, it should only be accessed on |encoding_thread_|.
132 ScopedVpxCodecCtxPtr encoder_; 149 ScopedVpxCodecCtxPtr encoder_;
133 150
151
134 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to 152 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to
135 // predict the duration of the next frame. 153 // predict the duration of the next frame.
136 base::TimeDelta last_frame_timestamp_; 154 base::TimeDelta last_frame_timestamp_;
137 155
138 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); 156 DISALLOW_COPY_AND_ASSIGN(VpxEncoder);
139 }; 157 };
140 158
159 class H264Encoder final : public VideoTrackRecorder::Encoder {
160 public:
161 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread,
162 scoped_ptr<ISVCEncoder> encoder);
163
164 H264Encoder(
165 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
166 int32_t bits_per_second);
167
168 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
169 base::TimeTicks capture_timestamp) override;
170
171 void set_paused(bool paused) override { paused_ = paused; }
172
173 private:
174 ~H264Encoder() override;
175
176 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame,
177 base::TimeTicks capture_timestamp);
178
179 void ConfigureEncoding(const gfx::Size& size);
180
181 // While |paused_|, frames are not encoded.
182 bool paused_;
183
184 // This callback should be exercised on IO thread.
185 const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_callback_;
186
187 // Target bitrate or video encoding. If 0, a standard bitrate is used.
188 const int32_t bits_per_second_;
189
190 // Used to shutdown properly on the same thread we were created.
191 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
192
193 // Task runner where frames to encode and reply callbacks must happen.
194 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
195
196 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables
197 // below this are used in this thread.
198 std::unique_ptr<base::Thread> encoding_thread_;
199
200 scoped_ptr<ISVCEncoder> openh264_encoder_;
201 gfx::Size configured_size_;
202
203 // The |VideoFrame::timestamp()| of the first received frame.
204 base::TimeTicks first_frame_timestamp_;
205
206 DISALLOW_COPY_AND_ASSIGN(H264Encoder);
207 };
208
141 // static 209 // static
142 void VideoTrackRecorder::VpxEncoder::ShutdownEncoder( 210 void H264Encoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread,
143 std::unique_ptr<base::Thread> encoding_thread, 211 scoped_ptr<ISVCEncoder> encoder) {
144 ScopedVpxCodecCtxPtr encoder) { 212 DVLOG(1) << __FUNCTION__;
213 DCHECK(encoding_thread->IsRunning());
214 encoding_thread->Stop();
215
216 if (encoder) {
217 const int uninit_ret = encoder->Uninitialize();
218 DLOG_IF(ERROR, uninit_ret != 0) << "OpenH264 Uninitialize()";
219
220 WelsDestroySVCEncoder(encoder.release());
221 }
222 }
223
224 H264Encoder::H264Encoder(
225 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
226 int32_t bits_per_second)
227 : paused_(false),
228 on_encoded_video_callback_(on_encoded_video_callback),
229 bits_per_second_(bits_per_second),
230 main_task_runner_(base::MessageLoop::current()->task_runner()),
231 encoding_thread_(new base::Thread("EncodingThread")) {
232 DCHECK(!on_encoded_video_callback_.is_null());
233
234 DCHECK(!encoding_thread_->IsRunning());
235 encoding_thread_->Start();
236 }
237
238 void H264Encoder::StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
239 base::TimeTicks capture_timestamp) {
240 DVLOG(1) << __FUNCTION__;
241 // Cache the thread sending frames on first frame arrival.
242 if (!origin_task_runner_.get())
243 origin_task_runner_ = base::MessageLoop::current()->task_runner();
244 DCHECK(origin_task_runner_->BelongsToCurrentThread());
245 if (paused_)
246 return;
247 encoding_thread_->task_runner()->PostTask(
248 FROM_HERE, base::Bind(&H264Encoder::EncodeOnEncodingThread,
249 this, frame, capture_timestamp));
250 }
251
252
253 void H264Encoder::EncodeOnEncodingThread(
254 const scoped_refptr<VideoFrame>& video_frame,
255 base::TimeTicks capture_timestamp) {
256 DVLOG(1) << __FUNCTION__;
257 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
258
259 if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
260 video_frame->format() == media::PIXEL_FORMAT_YV12 ||
261 video_frame->format() == media::PIXEL_FORMAT_YV12A)) {
262 NOTREACHED();
263 return;
264 }
265 scoped_refptr<media::VideoFrame> frame = video_frame;
266 // Drop alpha channel since we do not support it yet.
267 if (frame->format() == media::PIXEL_FORMAT_YV12A)
268 frame = media::WrapAsI420VideoFrame(video_frame);
269
270 const gfx::Size frame_size = frame->visible_rect().size();
271 if (!openh264_encoder_ || configured_size_ != frame_size) {
272 ConfigureEncoding(frame_size);
273 first_frame_timestamp_ = capture_timestamp;
274 }
275
276 DCHECK(openh264_encoder_);
277
278 // EncodeFrame input.
279 SSourcePicture picture = {};
280 picture.iPicWidth = frame_size.width();
281 picture.iPicHeight = frame_size.height();
282 picture.iColorFormat = EVideoFormatType::videoFormatI420;
283 picture.uiTimeStamp =
284 (capture_timestamp - first_frame_timestamp_).InMilliseconds();
285 picture.iStride[0] = video_frame->stride(VideoFrame::kYPlane);
286 picture.iStride[1] = video_frame->stride(VideoFrame::kUPlane);
287 picture.iStride[2] = video_frame->stride(VideoFrame::kVPlane);
288 picture.pData[0] = video_frame->data(VideoFrame::kYPlane);
289 picture.pData[1] = video_frame->data(VideoFrame::kUPlane);
290 picture.pData[2] = video_frame->data(VideoFrame::kVPlane);
291
292 // EncodeFrame output.
293 SFrameBSInfo info;
294 memset(&info, 0, sizeof(SFrameBSInfo));
295
296 // Encode!
297 int enc_ret = openh264_encoder_->EncodeFrame(&picture, &info);
298 if (enc_ret != cmResultSuccess) {
299 DLOG(ERROR) << "OpenH264 encoding failed, EncodeFrame says " << enc_ret;
300 NOTREACHED();
301 return;
302 }
303
304 std::unique_ptr<std::string> data(new std::string);
305 const uint8_t kNALStartCode[4] = {0, 0, 0, 1};
306 for (int layer = 0; layer < info.iLayerNum; ++layer) {
307 const SLayerBSInfo& layerInfo = info.sLayerInfo[layer];
308 // Iterate NAL units making up this layer, noting fragments.
309 size_t layer_len = 0;
310 for (int nal = 0; nal < layerInfo.iNalCount; ++nal) {
311
312 DCHECK_GE(layerInfo.pNalLengthInByte[nal], 4);
313 DCHECK_EQ(kNALStartCode[0], layerInfo.pBsBuf[layer_len+0]);
314 DCHECK_EQ(kNALStartCode[1], layerInfo.pBsBuf[layer_len+1]);
315 DCHECK_EQ(kNALStartCode[2], layerInfo.pBsBuf[layer_len+2]);
316 DCHECK_EQ(kNALStartCode[3], layerInfo.pBsBuf[layer_len+3]);
317
318 layer_len += layerInfo.pNalLengthInByte[nal];
319 }
320 // Copy the entire layer's data (including start codes).
321 data->append(reinterpret_cast<char*>(layerInfo.pBsBuf), layer_len);
322 }
323
324 const bool is_key_frame = info.eFrameType == videoFrameTypeIDR;
325
326 origin_task_runner_->PostTask(
327 FROM_HERE,
328 base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_, frame,
329 base::Passed(&data), capture_timestamp, is_key_frame));
330 }
331
332 void H264Encoder::ConfigureEncoding(const gfx::Size& size) {
333 DVLOG(1) << __FUNCTION__;
334 configured_size_ = size;
335
336 ISVCEncoder* temp_encoder = nullptr;
337 int result = WelsCreateSVCEncoder(&temp_encoder);
338 if (result != 0) {
339 DLOG(ERROR) << "Failed to create OpenH264 encoder";
340 NOTREACHED();
341 return;
342 }
343 openh264_encoder_.reset(temp_encoder);
344
345 #if DCHECK_IS_ON()
346 int trace_level = WELS_LOG_DETAIL;
347 openh264_encoder_->SetOption(ENCODER_OPTION_TRACE_LEVEL, &trace_level);
348 #endif
349
350 SEncParamExt init_params;
351 openh264_encoder_->GetDefaultParams(&init_params);
352 init_params.iUsageType = CAMERA_VIDEO_REAL_TIME;
353
354 init_params.iPicWidth = size.width();
355 init_params.iPicHeight = size.height();
356 if (bits_per_second_ > 0) {
357 init_params.iRCMode = RC_BITRATE_MODE;
358 init_params.iTargetBitrate = bits_per_second_;
359 } else {
360 init_params.iRCMode = RC_OFF_MODE;
361 }
362
363 // Do not saturate CPU utilization just for encoding. On a lower-end system
364 // with only 1 or 2 cores, use only one thread for encoding. On systems with
365 // more cores, allow half of the cores to be used for encoding.
366 init_params.iMultipleThreadIdc =
367 std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2);
368
369 // The base spatial layer 0 is the only one we use.
370 DCHECK_EQ(1, init_params.iSpatialLayerNum);
371 init_params.sSpatialLayers[0].iVideoWidth = init_params.iPicWidth;
372 init_params.sSpatialLayers[0].iVideoHeight = init_params.iPicHeight;
373 init_params.sSpatialLayers[0].iSpatialBitrate = init_params.iTargetBitrate;
374
375 result = openh264_encoder_->InitializeExt(&init_params);
376 if (result != cmResultSuccess) {
377 DLOG(ERROR) << "Failed to initialize OpenH264 encoder";
378 NOTREACHED();
379 return;
380 }
381
382 int video_format = EVideoFormatType::videoFormatI420;
383 openh264_encoder_->SetOption(ENCODER_OPTION_DATAFORMAT,
384 &video_format);
385 }
386
387 H264Encoder::~H264Encoder() {
388 main_task_runner_->PostTask(FROM_HERE,
389 base::Bind(&H264Encoder::ShutdownEncoder,
390 base::Passed(&encoding_thread_),
391 base::Passed(&openh264_encoder_)));
392 }
393
394 //
395 //
396 // static
397 void VpxEncoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread,
398 ScopedVpxCodecCtxPtr encoder) {
145 DCHECK(encoding_thread->IsRunning()); 399 DCHECK(encoding_thread->IsRunning());
146 encoding_thread->Stop(); 400 encoding_thread->Stop();
147 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. 401 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope.
148 } 402 }
149 403
150 VideoTrackRecorder::VpxEncoder::VpxEncoder( 404 VpxEncoder::VpxEncoder(
151 bool use_vp9, 405 bool use_vp9,
152 const OnEncodedVideoCB& on_encoded_video_callback, 406 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
153 int32_t bits_per_second) 407 int32_t bits_per_second)
154 : paused_(false), 408 : paused_(false),
155 use_vp9_(use_vp9), 409 use_vp9_(use_vp9),
156 on_encoded_video_callback_(on_encoded_video_callback), 410 on_encoded_video_callback_(on_encoded_video_callback),
157 bits_per_second_(bits_per_second), 411 bits_per_second_(bits_per_second),
158 main_task_runner_(base::MessageLoop::current()->task_runner()), 412 main_task_runner_(base::MessageLoop::current()->task_runner()),
159 encoding_thread_(new base::Thread("EncodingThread")) { 413 encoding_thread_(new base::Thread("EncodingThread")) {
160 DCHECK(!on_encoded_video_callback_.is_null()); 414 DCHECK(!on_encoded_video_callback_.is_null());
161 415
162 codec_config_.g_timebase.den = 0; // Not initialized. 416 codec_config_.g_timebase.den = 0; // Not initialized.
163 417
164 DCHECK(!encoding_thread_->IsRunning()); 418 DCHECK(!encoding_thread_->IsRunning());
165 encoding_thread_->Start(); 419 encoding_thread_->Start();
166 } 420 }
167 421
168 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { 422 VpxEncoder::~VpxEncoder() {
169 main_task_runner_->PostTask(FROM_HERE, 423 main_task_runner_->PostTask(FROM_HERE,
170 base::Bind(&VpxEncoder::ShutdownEncoder, 424 base::Bind(&VpxEncoder::ShutdownEncoder,
171 base::Passed(&encoding_thread_), 425 base::Passed(&encoding_thread_),
172 base::Passed(&encoder_))); 426 base::Passed(&encoder_)));
173 } 427 }
174 428
175 void VideoTrackRecorder::VpxEncoder::StartFrameEncode( 429 void VpxEncoder::StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
176 const scoped_refptr<VideoFrame>& frame, 430 base::TimeTicks capture_timestamp) {
177 base::TimeTicks capture_timestamp) {
178 // Cache the thread sending frames on first frame arrival. 431 // Cache the thread sending frames on first frame arrival.
179 if (!origin_task_runner_.get()) 432 if (!origin_task_runner_.get())
180 origin_task_runner_ = base::MessageLoop::current()->task_runner(); 433 origin_task_runner_ = base::MessageLoop::current()->task_runner();
181 DCHECK(origin_task_runner_->BelongsToCurrentThread()); 434 DCHECK(origin_task_runner_->BelongsToCurrentThread());
182 if (paused_) 435 if (paused_)
183 return; 436 return;
184 encoding_thread_->task_runner()->PostTask( 437 encoding_thread_->task_runner()->PostTask(
185 FROM_HERE, base::Bind(&VpxEncoder::EncodeOnEncodingThread, 438 FROM_HERE, base::Bind(&VpxEncoder::EncodeOnEncodingThread,
186 this, frame, capture_timestamp)); 439 this, frame, capture_timestamp));
187 } 440 }
188 441
189 void VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread( 442 void VpxEncoder::EncodeOnEncodingThread(
190 const scoped_refptr<VideoFrame>& video_frame, 443 const scoped_refptr<VideoFrame>& video_frame,
191 base::TimeTicks capture_timestamp) { 444 base::TimeTicks capture_timestamp) {
192 TRACE_EVENT0("video", 445 TRACE_EVENT0("video",
193 "VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread"); 446 "VpxEncoder::EncodeOnEncodingThread");
194 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); 447 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
195 448
196 if (!(video_frame->format() == media::PIXEL_FORMAT_I420 || 449 if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
197 video_frame->format() == media::PIXEL_FORMAT_YV12 || 450 video_frame->format() == media::PIXEL_FORMAT_YV12 ||
198 video_frame->format() == media::PIXEL_FORMAT_YV12A)) { 451 video_frame->format() == media::PIXEL_FORMAT_YV12A)) {
199 NOTREACHED(); 452 NOTREACHED();
200 return; 453 return;
201 } 454 }
202 scoped_refptr<media::VideoFrame> frame = video_frame; 455 scoped_refptr<media::VideoFrame> frame = video_frame;
203 // Drop alpha channel since we do not support it yet. 456 // Drop alpha channel since we do not support it yet.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 } 505 }
253 origin_task_runner_->PostTask(FROM_HERE, 506 origin_task_runner_->PostTask(FROM_HERE,
254 base::Bind(OnFrameEncodeCompleted, 507 base::Bind(OnFrameEncodeCompleted,
255 on_encoded_video_callback_, 508 on_encoded_video_callback_,
256 frame, 509 frame,
257 base::Passed(&data), 510 base::Passed(&data),
258 capture_timestamp, 511 capture_timestamp,
259 keyframe)); 512 keyframe));
260 } 513 }
261 514
262 void VideoTrackRecorder::VpxEncoder::ConfigureEncoding(const gfx::Size& size) { 515 void VpxEncoder::ConfigureEncoding(const gfx::Size& size) {
263 if (IsInitialized()) { 516 if (IsInitialized()) {
264 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less- 517 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less-
265 // than-or-equal than the old size, in terms of area, the existing encoder 518 // than-or-equal than the old size, in terms of area, the existing encoder
266 // instance could be reused after changing |codec_config_.{g_w,g_h}|. 519 // instance could be reused after changing |codec_config_.{g_w,g_h}|.
267 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: " 520 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: "
268 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString() 521 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString()
269 << " --> " << size.ToString() << (use_vp9_ ? " vp9" : " vp8"); 522 << " --> " << size.ToString() << (use_vp9_ ? " vp9" : " vp8");
270 encoder_.reset(); 523 encoder_.reset();
271 } 524 }
272 525
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 // the expense of quality up to a maximum value of 8 for VP9, by tuning the 597 // the expense of quality up to a maximum value of 8 for VP9, by tuning the
345 // target time spent encoding the frame. Go from 8 to 5 (values for real 598 // target time spent encoding the frame. Go from 8 to 5 (values for real
346 // time encoding) depending on the amount of cores available in the system. 599 // time encoding) depending on the amount of cores available in the system.
347 const int kCpuUsed = 600 const int kCpuUsed =
348 std::max(5, 8 - base::SysInfo::NumberOfProcessors() / 2); 601 std::max(5, 8 - base::SysInfo::NumberOfProcessors() / 2);
349 result = vpx_codec_control(encoder_.get(), VP8E_SET_CPUUSED, kCpuUsed); 602 result = vpx_codec_control(encoder_.get(), VP8E_SET_CPUUSED, kCpuUsed);
350 DLOG_IF(WARNING, VPX_CODEC_OK != result) << "VP8E_SET_CPUUSED failed"; 603 DLOG_IF(WARNING, VPX_CODEC_OK != result) << "VP8E_SET_CPUUSED failed";
351 } 604 }
352 } 605 }
353 606
354 bool VideoTrackRecorder::VpxEncoder::IsInitialized() const { 607 bool VpxEncoder::IsInitialized() const {
355 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); 608 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
356 return codec_config_.g_timebase.den != 0; 609 return codec_config_.g_timebase.den != 0;
357 } 610 }
358 611
359 base::TimeDelta VideoTrackRecorder::VpxEncoder::CalculateFrameDuration( 612 base::TimeDelta VpxEncoder::CalculateFrameDuration(
360 const scoped_refptr<VideoFrame>& frame) { 613 const scoped_refptr<VideoFrame>& frame) {
361 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); 614 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
362 615
363 using base::TimeDelta; 616 using base::TimeDelta;
364 TimeDelta predicted_frame_duration; 617 TimeDelta predicted_frame_duration;
365 if (!frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION, 618 if (!frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION,
366 &predicted_frame_duration) || 619 &predicted_frame_duration) ||
367 predicted_frame_duration <= TimeDelta()) { 620 predicted_frame_duration <= TimeDelta()) {
368 // The source of the video frame did not provide the frame duration. Use 621 // The source of the video frame did not provide the frame duration. Use
369 // the actual amount of time between the current and previous frame as a 622 // the actual amount of time between the current and previous frame as a
370 // prediction for the next frame's duration. 623 // prediction for the next frame's duration.
371 // TODO(mcasas): This duration estimation could lead to artifacts if the 624 // TODO(mcasas): This duration estimation could lead to artifacts if the
372 // cadence of the received stream is compromised (e.g. camera freeze, pause, 625 // cadence of the received stream is compromised (e.g. camera freeze, pause,
373 // remote packet loss). Investigate using GetFrameRate() in this case. 626 // remote packet loss). Investigate using GetFrameRate() in this case.
374 predicted_frame_duration = frame->timestamp() - last_frame_timestamp_; 627 predicted_frame_duration = frame->timestamp() - last_frame_timestamp_;
375 } 628 }
376 last_frame_timestamp_ = frame->timestamp(); 629 last_frame_timestamp_ = frame->timestamp();
377 // Make sure |predicted_frame_duration| is in a safe range of values. 630 // Make sure |predicted_frame_duration| is in a safe range of values.
378 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); 631 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8);
379 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); 632 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1);
380 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, 633 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration,
381 kMinFrameDuration)); 634 kMinFrameDuration));
382 } 635 }
383 636
637 } // anonymous namespace
638
384 VideoTrackRecorder::VideoTrackRecorder( 639 VideoTrackRecorder::VideoTrackRecorder(
385 bool use_vp9, 640 CodecId codec,
386 const blink::WebMediaStreamTrack& track, 641 const blink::WebMediaStreamTrack& track,
387 const OnEncodedVideoCB& on_encoded_video_callback, 642 const OnEncodedVideoCB& on_encoded_video_callback,
388 int32_t bits_per_second) 643 int32_t bits_per_second)
389 : track_(track), 644 : track_(track) {
390 encoder_(
391 new VpxEncoder(use_vp9, on_encoded_video_callback, bits_per_second)) {
392 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 645 DCHECK(main_render_thread_checker_.CalledOnValidThread());
393 DCHECK(!track_.isNull()); 646 DCHECK(!track_.isNull());
394 DCHECK(track_.getExtraData()); 647 DCHECK(track_.getExtraData());
395 648
649 switch (codec) {
650 case CodecId::H264:
651 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second);
652 break;
653 case CodecId::VP8:
654 case CodecId::VP9:
655 encoder_ = new VpxEncoder(codec == CodecId::VP9,
656 on_encoded_video_callback, bits_per_second);
657 break;
658 default:
659 NOTREACHED();
660 }
661
396 // StartFrameEncode() will be called on Render IO thread. 662 // StartFrameEncode() will be called on Render IO thread.
397 MediaStreamVideoSink::ConnectToTrack( 663 MediaStreamVideoSink::ConnectToTrack(
398 track_, 664 track_,
399 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode, encoder_)); 665 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_));
400 } 666 }
401 667
402 VideoTrackRecorder::~VideoTrackRecorder() { 668 VideoTrackRecorder::~VideoTrackRecorder() {
403 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 669 DCHECK(main_render_thread_checker_.CalledOnValidThread());
404 MediaStreamVideoSink::DisconnectFromTrack(); 670 MediaStreamVideoSink::DisconnectFromTrack();
405 track_.reset(); 671 track_.reset();
406 } 672 }
407 673
408 void VideoTrackRecorder::Pause() { 674 void VideoTrackRecorder::Pause() {
409 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 675 DCHECK(main_render_thread_checker_.CalledOnValidThread());
410 DCHECK(encoder_); 676 DCHECK(encoder_);
411 encoder_->set_paused(true); 677 encoder_->set_paused(true);
412 } 678 }
413 679
414 void VideoTrackRecorder::Resume() { 680 void VideoTrackRecorder::Resume() {
415 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 681 DCHECK(main_render_thread_checker_.CalledOnValidThread());
416 DCHECK(encoder_); 682 DCHECK(encoder_);
417 encoder_->set_paused(false); 683 encoder_->set_paused(false);
418 } 684 }
419 685
420 void VideoTrackRecorder::OnVideoFrameForTesting( 686 void VideoTrackRecorder::OnVideoFrameForTesting(
421 const scoped_refptr<media::VideoFrame>& frame, 687 const scoped_refptr<media::VideoFrame>& frame,
422 base::TimeTicks timestamp) { 688 base::TimeTicks timestamp) {
423 encoder_->StartFrameEncode(frame, timestamp); 689 encoder_->StartFrameEncode(frame, timestamp);
424 } 690 }
425 691
426 } // namespace content 692 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/video_track_recorder.h ('k') | content/renderer/media/video_track_recorder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698