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 // Target bitrate or video encoding. If 0, a standard bitrate is used. |
| 116 const int32_t bits_per_second_; |
| 117 |
110 // Used to shutdown properly on the same thread we were created. | 118 // Used to shutdown properly on the same thread we were created. |
111 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 119 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
112 | 120 |
113 // Task runner where frames to encode and reply callbacks must happen. | 121 // Task runner where frames to encode and reply callbacks must happen. |
114 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; | 122 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; |
115 | 123 |
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 | 124 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables |
120 // below this are used in this thread. | 125 // below this are used in this thread. |
121 scoped_ptr<base::Thread> encoding_thread_; | 126 scoped_ptr<base::Thread> encoding_thread_; |
122 // VP8 internal objects: configuration and encoder. | 127 // VP8 internal objects: configuration and encoder. |
123 vpx_codec_enc_cfg_t codec_config_; | 128 vpx_codec_enc_cfg_t codec_config_; |
124 // |encoder_| is a special scoped pointer to guarantee proper destruction. | 129 // |encoder_| is a special scoped pointer to guarantee proper destruction. |
125 // Again, it should only be accessed on |encoding_thread_|. | 130 // Again, it should only be accessed on |encoding_thread_|. |
126 ScopedVpxCodecCtxPtr encoder_; | 131 ScopedVpxCodecCtxPtr encoder_; |
127 | 132 |
128 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to | 133 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to |
129 // predict the duration of the next frame. | 134 // predict the duration of the next frame. |
130 base::TimeDelta last_frame_timestamp_; | 135 base::TimeDelta last_frame_timestamp_; |
131 | 136 |
132 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); | 137 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); |
133 }; | 138 }; |
134 | 139 |
135 // static | 140 // static |
136 void VideoTrackRecorder::VpxEncoder::ShutdownEncoder( | 141 void VideoTrackRecorder::VpxEncoder::ShutdownEncoder( |
137 scoped_ptr<base::Thread> encoding_thread, | 142 scoped_ptr<base::Thread> encoding_thread, |
138 ScopedVpxCodecCtxPtr encoder) { | 143 ScopedVpxCodecCtxPtr encoder) { |
139 DCHECK(encoding_thread->IsRunning()); | 144 DCHECK(encoding_thread->IsRunning()); |
140 encoding_thread->Stop(); | 145 encoding_thread->Stop(); |
141 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. | 146 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. |
142 } | 147 } |
143 | 148 |
144 VideoTrackRecorder::VpxEncoder::VpxEncoder( | 149 VideoTrackRecorder::VpxEncoder::VpxEncoder( |
145 bool use_vp9, | 150 bool use_vp9, |
146 const OnEncodedVideoCB& on_encoded_video_callback) | 151 const OnEncodedVideoCB& on_encoded_video_callback, |
| 152 int32_t bits_per_second) |
147 : paused_(false), | 153 : paused_(false), |
148 use_vp9_(use_vp9), | 154 use_vp9_(use_vp9), |
| 155 on_encoded_video_callback_(on_encoded_video_callback), |
| 156 bits_per_second_(bits_per_second), |
149 main_task_runner_(base::MessageLoop::current()->task_runner()), | 157 main_task_runner_(base::MessageLoop::current()->task_runner()), |
150 on_encoded_video_callback_(on_encoded_video_callback), | |
151 encoding_thread_(new base::Thread("EncodingThread")) { | 158 encoding_thread_(new base::Thread("EncodingThread")) { |
152 DCHECK(!on_encoded_video_callback_.is_null()); | 159 DCHECK(!on_encoded_video_callback_.is_null()); |
153 | 160 |
154 codec_config_.g_timebase.den = 0; // Not initialized. | 161 codec_config_.g_timebase.den = 0; // Not initialized. |
155 | 162 |
156 DCHECK(!encoding_thread_->IsRunning()); | 163 DCHECK(!encoding_thread_->IsRunning()); |
157 encoding_thread_->Start(); | 164 encoding_thread_->Start(); |
158 } | 165 } |
159 | 166 |
160 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { | 167 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 encoder_.reset(); | 258 encoder_.reset(); |
252 } | 259 } |
253 | 260 |
254 const vpx_codec_iface_t* interface = | 261 const vpx_codec_iface_t* interface = |
255 use_vp9_ ? vpx_codec_vp9_cx() : vpx_codec_vp8_cx(); | 262 use_vp9_ ? vpx_codec_vp9_cx() : vpx_codec_vp8_cx(); |
256 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, | 263 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, |
257 &codec_config_, | 264 &codec_config_, |
258 0 /* reserved */); | 265 0 /* reserved */); |
259 DCHECK_EQ(VPX_CODEC_OK, result); | 266 DCHECK_EQ(VPX_CODEC_OK, result); |
260 | 267 |
261 // Adjust default bit rate to account for the actual size. | |
262 DCHECK_EQ(320u, codec_config_.g_w); | 268 DCHECK_EQ(320u, codec_config_.g_w); |
263 DCHECK_EQ(240u, codec_config_.g_h); | 269 DCHECK_EQ(240u, codec_config_.g_h); |
264 DCHECK_EQ(256u, codec_config_.rc_target_bitrate); | 270 DCHECK_EQ(256u, codec_config_.rc_target_bitrate); |
265 codec_config_.rc_target_bitrate = size.GetArea() * | 271 // Use the selected bitrate or adjust default bit rate to account for the |
266 codec_config_.rc_target_bitrate / | 272 // actual size. |
267 codec_config_.g_w / codec_config_.g_h; | 273 if (bits_per_second_ > 0) { |
| 274 codec_config_.rc_target_bitrate = bits_per_second_; |
| 275 } else { |
| 276 codec_config_.rc_target_bitrate = size.GetArea() * |
| 277 codec_config_.rc_target_bitrate / |
| 278 codec_config_.g_w / codec_config_.g_h; |
| 279 } |
268 // Both VP8/VP9 configuration should be Variable BitRate by default. | 280 // Both VP8/VP9 configuration should be Variable BitRate by default. |
269 DCHECK_EQ(VPX_VBR, codec_config_.rc_end_usage); | 281 DCHECK_EQ(VPX_VBR, codec_config_.rc_end_usage); |
270 if (use_vp9_) { | 282 if (use_vp9_) { |
271 // Number of frames to consume before producing output. | 283 // Number of frames to consume before producing output. |
272 codec_config_.g_lag_in_frames = 0; | 284 codec_config_.g_lag_in_frames = 0; |
273 | 285 |
274 // DCHECK that the profile selected by default is I420 (magic number 0). | 286 // DCHECK that the profile selected by default is I420 (magic number 0). |
275 DCHECK_EQ(0u, codec_config_.g_profile); | 287 DCHECK_EQ(0u, codec_config_.g_profile); |
276 } else { | 288 } else { |
277 // VP8 always produces frames instantaneously. | 289 // 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. | 353 // Make sure |predicted_frame_duration| is in a safe range of values. |
342 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); | 354 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); |
343 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); | 355 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); |
344 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, | 356 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, |
345 kMinFrameDuration)); | 357 kMinFrameDuration)); |
346 } | 358 } |
347 | 359 |
348 VideoTrackRecorder::VideoTrackRecorder( | 360 VideoTrackRecorder::VideoTrackRecorder( |
349 bool use_vp9, | 361 bool use_vp9, |
350 const blink::WebMediaStreamTrack& track, | 362 const blink::WebMediaStreamTrack& track, |
351 const OnEncodedVideoCB& on_encoded_video_callback) | 363 const OnEncodedVideoCB& on_encoded_video_callback, |
| 364 int32_t bits_per_second) |
352 : track_(track), | 365 : track_(track), |
353 encoder_(new VpxEncoder(use_vp9, on_encoded_video_callback)) { | 366 encoder_( |
| 367 new VpxEncoder(use_vp9, on_encoded_video_callback, bits_per_second)) { |
354 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 368 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
355 DCHECK(!track_.isNull()); | 369 DCHECK(!track_.isNull()); |
356 DCHECK(track_.extraData()); | 370 DCHECK(track_.extraData()); |
357 | 371 |
358 // StartFrameEncode() will be called on Render IO thread. | 372 // StartFrameEncode() will be called on Render IO thread. |
359 AddToVideoTrack(this, | 373 AddToVideoTrack(this, |
360 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode, | 374 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode, |
361 encoder_), | 375 encoder_), |
362 track_); | 376 track_); |
363 } | 377 } |
(...skipping 16 matching lines...) Expand all Loading... |
380 encoder_->set_paused(false); | 394 encoder_->set_paused(false); |
381 } | 395 } |
382 | 396 |
383 void VideoTrackRecorder::OnVideoFrameForTesting( | 397 void VideoTrackRecorder::OnVideoFrameForTesting( |
384 const scoped_refptr<media::VideoFrame>& frame, | 398 const scoped_refptr<media::VideoFrame>& frame, |
385 base::TimeTicks timestamp) { | 399 base::TimeTicks timestamp) { |
386 encoder_->StartFrameEncode(frame, timestamp); | 400 encoder_->StartFrameEncode(frame, timestamp); |
387 } | 401 } |
388 | 402 |
389 } // namespace content | 403 } // namespace content |
OLD | NEW |