Chromium Code Reviews| OLD | NEW |
|---|---|
| 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" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 // which is cached on first frame arrival, and is supposed to be the render IO | 71 // which is cached on first frame arrival, and is supposed to be the render IO |
| 72 // thread, but this is not enforced; | 72 // thread, but this is not enforced; |
| 73 // - uses an internal |encoding_thread_| for libvpx interactions, notably for | 73 // - uses an internal |encoding_thread_| for libvpx interactions, notably for |
| 74 // encoding (which might take some time). | 74 // encoding (which might take some time). |
| 75 class VideoTrackRecorder::VpxEncoder final | 75 class VideoTrackRecorder::VpxEncoder final |
| 76 : public base::RefCountedThreadSafe<VpxEncoder> { | 76 : public base::RefCountedThreadSafe<VpxEncoder> { |
| 77 public: | 77 public: |
| 78 static void ShutdownEncoder(scoped_ptr<base::Thread> encoding_thread, | 78 static void ShutdownEncoder(scoped_ptr<base::Thread> encoding_thread, |
| 79 ScopedVpxCodecCtxPtr encoder); | 79 ScopedVpxCodecCtxPtr encoder); |
| 80 | 80 |
| 81 VpxEncoder(bool use_vp9, const OnEncodedVideoCB& on_encoded_video_callback); | 81 VpxEncoder(bool use_vp9, |
| 82 const OnEncodedVideoCB& on_encoded_video_callback, | |
| 83 int32_t bits_per_second); | |
| 82 | 84 |
| 83 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, | 85 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, |
| 84 base::TimeTicks capture_timestamp); | 86 base::TimeTicks capture_timestamp); |
| 85 | 87 |
| 86 void set_paused(bool paused) { paused_ = paused; } | 88 void set_paused(bool paused) { paused_ = paused; } |
| 87 | 89 |
| 88 private: | 90 private: |
| 89 friend class base::RefCountedThreadSafe<VpxEncoder>; | 91 friend class base::RefCountedThreadSafe<VpxEncoder>; |
| 90 ~VpxEncoder(); | 92 ~VpxEncoder(); |
| 91 | 93 |
| 92 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 94 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, |
| 93 base::TimeTicks capture_timestamp); | 95 base::TimeTicks capture_timestamp); |
| 94 | 96 |
| 95 void ConfigureEncoding(const gfx::Size& size); | 97 void ConfigureEncoding(const gfx::Size& size); |
| 96 | 98 |
| 97 // Returns true if |codec_config_| has been filled in at least once. | 99 // Returns true if |codec_config_| has been filled in at least once. |
| 98 bool IsInitialized() const; | 100 bool IsInitialized() const; |
| 99 | 101 |
| 100 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. | 102 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. |
| 101 base::TimeDelta CalculateFrameDuration( | 103 base::TimeDelta CalculateFrameDuration( |
| 102 const scoped_refptr<VideoFrame>& frame); | 104 const scoped_refptr<VideoFrame>& frame); |
| 103 | 105 |
| 104 // While |paused_|, frames are not encoded. | 106 // While |paused_|, frames are not encoded. |
| 105 bool paused_; | 107 bool paused_; |
| 106 | 108 |
| 107 // Force usage of VP9 for encoding, instead of VP8 which is the default. | 109 // Force usage of VP9 for encoding, instead of VP8 which is the default. |
| 108 const bool use_vp9_; | 110 const bool use_vp9_; |
| 109 | 111 |
| 112 // This callback should be exercised on IO thread. | |
| 113 const OnEncodedVideoCB on_encoded_video_callback_; | |
| 114 | |
| 115 const int32_t bits_per_second_; | |
|
Peter Beverloo
2016/01/20 18:35:35
nit: all other members have documentation
mcasas
2016/01/20 21:13:22
Done.
| |
| 116 | |
| 110 // Used to shutdown properly on the same thread we were created. | 117 // Used to shutdown properly on the same thread we were created. |
| 111 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 118 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
| 112 | 119 |
| 113 // Task runner where frames to encode and reply callbacks must happen. | 120 // Task runner where frames to encode and reply callbacks must happen. |
| 114 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; | 121 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; |
| 115 | 122 |
| 116 // This callback should be exercised on IO thread. | |
| 117 const OnEncodedVideoCB on_encoded_video_callback_; | |
| 118 | |
| 119 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables | 123 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables |
| 120 // below this are used in this thread. | 124 // below this are used in this thread. |
| 121 scoped_ptr<base::Thread> encoding_thread_; | 125 scoped_ptr<base::Thread> encoding_thread_; |
| 122 // VP8 internal objects: configuration and encoder. | 126 // VP8 internal objects: configuration and encoder. |
| 123 vpx_codec_enc_cfg_t codec_config_; | 127 vpx_codec_enc_cfg_t codec_config_; |
| 124 // |encoder_| is a special scoped pointer to guarantee proper destruction. | 128 // |encoder_| is a special scoped pointer to guarantee proper destruction. |
| 125 // Again, it should only be accessed on |encoding_thread_|. | 129 // Again, it should only be accessed on |encoding_thread_|. |
| 126 ScopedVpxCodecCtxPtr encoder_; | 130 ScopedVpxCodecCtxPtr encoder_; |
| 127 | 131 |
| 128 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to | 132 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to |
| 129 // predict the duration of the next frame. | 133 // predict the duration of the next frame. |
| 130 base::TimeDelta last_frame_timestamp_; | 134 base::TimeDelta last_frame_timestamp_; |
| 131 | 135 |
| 132 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); | 136 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); |
| 133 }; | 137 }; |
| 134 | 138 |
| 135 // static | 139 // static |
| 136 void VideoTrackRecorder::VpxEncoder::ShutdownEncoder( | 140 void VideoTrackRecorder::VpxEncoder::ShutdownEncoder( |
| 137 scoped_ptr<base::Thread> encoding_thread, | 141 scoped_ptr<base::Thread> encoding_thread, |
| 138 ScopedVpxCodecCtxPtr encoder) { | 142 ScopedVpxCodecCtxPtr encoder) { |
| 139 DCHECK(encoding_thread->IsRunning()); | 143 DCHECK(encoding_thread->IsRunning()); |
| 140 encoding_thread->Stop(); | 144 encoding_thread->Stop(); |
| 141 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. | 145 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. |
| 142 } | 146 } |
| 143 | 147 |
| 144 VideoTrackRecorder::VpxEncoder::VpxEncoder( | 148 VideoTrackRecorder::VpxEncoder::VpxEncoder( |
| 145 bool use_vp9, | 149 bool use_vp9, |
| 146 const OnEncodedVideoCB& on_encoded_video_callback) | 150 const OnEncodedVideoCB& on_encoded_video_callback, |
| 151 int32_t bits_per_second) | |
| 147 : paused_(false), | 152 : paused_(false), |
| 148 use_vp9_(use_vp9), | 153 use_vp9_(use_vp9), |
| 154 on_encoded_video_callback_(on_encoded_video_callback), | |
| 155 bits_per_second_(bits_per_second), | |
| 149 main_task_runner_(base::MessageLoop::current()->task_runner()), | 156 main_task_runner_(base::MessageLoop::current()->task_runner()), |
| 150 on_encoded_video_callback_(on_encoded_video_callback), | |
| 151 encoding_thread_(new base::Thread("EncodingThread")) { | 157 encoding_thread_(new base::Thread("EncodingThread")) { |
| 152 DCHECK(!on_encoded_video_callback_.is_null()); | 158 DCHECK(!on_encoded_video_callback_.is_null()); |
| 153 | 159 |
| 154 codec_config_.g_timebase.den = 0; // Not initialized. | 160 codec_config_.g_timebase.den = 0; // Not initialized. |
| 155 | 161 |
| 156 DCHECK(!encoding_thread_->IsRunning()); | 162 DCHECK(!encoding_thread_->IsRunning()); |
| 157 encoding_thread_->Start(); | 163 encoding_thread_->Start(); |
| 158 } | 164 } |
| 159 | 165 |
| 160 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { | 166 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 encoder_.reset(); | 257 encoder_.reset(); |
| 252 } | 258 } |
| 253 | 259 |
| 254 const vpx_codec_iface_t* interface = | 260 const vpx_codec_iface_t* interface = |
| 255 use_vp9_ ? vpx_codec_vp9_cx() : vpx_codec_vp8_cx(); | 261 use_vp9_ ? vpx_codec_vp9_cx() : vpx_codec_vp8_cx(); |
| 256 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, | 262 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, |
| 257 &codec_config_, | 263 &codec_config_, |
| 258 0 /* reserved */); | 264 0 /* reserved */); |
| 259 DCHECK_EQ(VPX_CODEC_OK, result); | 265 DCHECK_EQ(VPX_CODEC_OK, result); |
| 260 | 266 |
| 261 // Adjust default bit rate to account for the actual size. | |
| 262 DCHECK_EQ(320u, codec_config_.g_w); | 267 DCHECK_EQ(320u, codec_config_.g_w); |
| 263 DCHECK_EQ(240u, codec_config_.g_h); | 268 DCHECK_EQ(240u, codec_config_.g_h); |
| 264 DCHECK_EQ(256u, codec_config_.rc_target_bitrate); | 269 DCHECK_EQ(256u, codec_config_.rc_target_bitrate); |
| 265 codec_config_.rc_target_bitrate = size.GetArea() * | 270 // Use the selected bitrate or adjust default bit rate to account for the |
| 266 codec_config_.rc_target_bitrate / | 271 // actual size. |
| 267 codec_config_.g_w / codec_config_.g_h; | 272 if (bits_per_second_ > 0) { |
| 273 codec_config_.rc_target_bitrate = bits_per_second_; | |
| 274 } else { | |
| 275 codec_config_.rc_target_bitrate = size.GetArea() * | |
| 276 codec_config_.rc_target_bitrate / | |
| 277 codec_config_.g_w / codec_config_.g_h; | |
| 278 } | |
| 268 // Both VP8/VP9 configuration should be Variable BitRate by default. | 279 // Both VP8/VP9 configuration should be Variable BitRate by default. |
| 269 DCHECK_EQ(VPX_VBR, codec_config_.rc_end_usage); | 280 DCHECK_EQ(VPX_VBR, codec_config_.rc_end_usage); |
| 270 if (use_vp9_) { | 281 if (use_vp9_) { |
| 271 // Number of frames to consume before producing output. | 282 // Number of frames to consume before producing output. |
| 272 codec_config_.g_lag_in_frames = 0; | 283 codec_config_.g_lag_in_frames = 0; |
| 273 | 284 |
| 274 // DCHECK that the profile selected by default is I420 (magic number 0). | 285 // DCHECK that the profile selected by default is I420 (magic number 0). |
| 275 DCHECK_EQ(0u, codec_config_.g_profile); | 286 DCHECK_EQ(0u, codec_config_.g_profile); |
| 276 } else { | 287 } else { |
| 277 // VP8 always produces frames instantaneously. | 288 // VP8 always produces frames instantaneously. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 // Make sure |predicted_frame_duration| is in a safe range of values. | 352 // Make sure |predicted_frame_duration| is in a safe range of values. |
| 342 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); | 353 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); |
| 343 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); | 354 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); |
| 344 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, | 355 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, |
| 345 kMinFrameDuration)); | 356 kMinFrameDuration)); |
| 346 } | 357 } |
| 347 | 358 |
| 348 VideoTrackRecorder::VideoTrackRecorder( | 359 VideoTrackRecorder::VideoTrackRecorder( |
| 349 bool use_vp9, | 360 bool use_vp9, |
| 350 const blink::WebMediaStreamTrack& track, | 361 const blink::WebMediaStreamTrack& track, |
| 351 const OnEncodedVideoCB& on_encoded_video_callback) | 362 const OnEncodedVideoCB& on_encoded_video_callback, |
| 363 int32_t bits_per_second) | |
| 352 : track_(track), | 364 : track_(track), |
| 353 encoder_(new VpxEncoder(use_vp9, on_encoded_video_callback)) { | 365 encoder_( |
| 366 new VpxEncoder(use_vp9, on_encoded_video_callback, bits_per_second)) { | |
| 354 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 367 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 355 DCHECK(!track_.isNull()); | 368 DCHECK(!track_.isNull()); |
| 356 DCHECK(track_.extraData()); | 369 DCHECK(track_.extraData()); |
| 357 | 370 |
| 358 // StartFrameEncode() will be called on Render IO thread. | 371 // StartFrameEncode() will be called on Render IO thread. |
| 359 AddToVideoTrack(this, | 372 AddToVideoTrack(this, |
| 360 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode, | 373 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode, |
| 361 encoder_), | 374 encoder_), |
| 362 track_); | 375 track_); |
| 363 } | 376 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 380 encoder_->set_paused(false); | 393 encoder_->set_paused(false); |
| 381 } | 394 } |
| 382 | 395 |
| 383 void VideoTrackRecorder::OnVideoFrameForTesting( | 396 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 384 const scoped_refptr<media::VideoFrame>& frame, | 397 const scoped_refptr<media::VideoFrame>& frame, |
| 385 base::TimeTicks timestamp) { | 398 base::TimeTicks timestamp) { |
| 386 encoder_->StartFrameEncode(frame, timestamp); | 399 encoder_->StartFrameEncode(frame, timestamp); |
| 387 } | 400 } |
| 388 | 401 |
| 389 } // namespace content | 402 } // namespace content |
| OLD | NEW |