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 28 matching lines...) Expand all Loading... | |
| 39 // Base class to describe a generic Encoder, encapsulating all actual encoder | 39 // Base class to describe a generic Encoder, encapsulating all actual encoder |
| 40 // (re)configurations, encoding and delivery of received frames. This class is | 40 // (re)configurations, encoding and delivery of received frames. This class is |
| 41 // ref-counted to allow the MediaStreamVideoTrack to hold a reference to it (via | 41 // ref-counted to allow the MediaStreamVideoTrack to hold a reference to it (via |
| 42 // the callback that MediaStreamVideoSink passes along) and to jump back and | 42 // the callback that MediaStreamVideoSink passes along) and to jump back and |
| 43 // forth to an internal encoder thread. Moreover, this class: | 43 // forth to an internal encoder thread. Moreover, this class: |
| 44 // - is created and destroyed on its parent's thread (usually the main Render | 44 // - is created and destroyed on its parent's thread (usually the main Render |
| 45 // thread), |main_task_runner_|. | 45 // thread), |main_task_runner_|. |
| 46 // - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on | 46 // - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on |
| 47 // that thread as well. This task runner is cached on first frame arrival, and | 47 // that thread as well. This task runner is cached on first frame arrival, and |
| 48 // is supposed to be the render IO thread (but this is not enforced); | 48 // is supposed to be the render IO thread (but this is not enforced); |
| 49 // - uses an internal |encoding_thread_| for actual encoder interactions, namely | 49 // - uses an internal |encoding_task_runner_| for actual encoder interactions, |
| 50 // configuration, encoding (which might take some time) and destruction. | 50 // namely configuration, encoding (which might take some time) and destruction. |
| 51 // This task runner can be passed on the creation. If nothing is passed, a new | |
| 52 // encoding thread is created and used. | |
| 51 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { | 53 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { |
| 52 public: | 54 public: |
| 53 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, | 55 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, |
| 54 int32_t bits_per_second) | 56 int32_t bits_per_second, |
| 57 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = | |
| 58 nullptr) | |
| 55 : main_task_runner_(base::MessageLoop::current()->task_runner()), | 59 : main_task_runner_(base::MessageLoop::current()->task_runner()), |
| 56 encoding_thread_(new base::Thread("EncodingThread")), | 60 encoding_task_runner_(encoding_task_runner), |
| 57 paused_(false), | 61 paused_(false), |
| 58 on_encoded_video_callback_(on_encoded_video_callback), | 62 on_encoded_video_callback_(on_encoded_video_callback), |
| 59 bits_per_second_(bits_per_second) { | 63 bits_per_second_(bits_per_second) { |
| 60 DCHECK(!on_encoded_video_callback_.is_null()); | 64 DCHECK(!on_encoded_video_callback_.is_null()); |
| 65 if (!encoding_thread_) { | |
|
mcasas
2016/05/14 01:31:08
if (encoding_task_runner_)
return;
?
emircan
2016/05/16 19:45:27
Done.
| |
| 66 encoding_thread_.reset(new base::Thread("EncodingThread")); | |
| 67 encoding_thread_->Start(); | |
| 68 encoding_task_runner_ = encoding_thread_->task_runner(); | |
| 69 } | |
| 61 } | 70 } |
| 62 | 71 |
| 63 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This | 72 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This |
| 64 // call will also trigger a ConfigureEncoderOnEncodingThread() upon first | 73 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first |
| 65 // frame arrival or parameter change, and an EncodeOnEncodingThread() to | 74 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to |
| 66 // actually encode the frame. | 75 // actually encode the frame. |
| 67 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, | 76 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, |
| 68 base::TimeTicks capture_timestamp); | 77 base::TimeTicks capture_timestamp); |
| 69 | 78 |
| 70 void SetPaused(bool paused); | 79 void SetPaused(bool paused); |
| 71 | 80 |
| 72 protected: | 81 protected: |
| 73 friend class base::RefCountedThreadSafe<Encoder>; | 82 friend class base::RefCountedThreadSafe<Encoder>; |
| 74 virtual ~Encoder() {} | 83 virtual ~Encoder() {} |
| 75 | 84 |
| 76 virtual void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 85 virtual void EncodeOnEncodingTaskRunner( |
| 77 base::TimeTicks capture_timestamp) = 0; | 86 const scoped_refptr<VideoFrame>& frame, |
| 78 virtual void ConfigureEncoderOnEncodingThread(const gfx::Size& size) = 0; | 87 base::TimeTicks capture_timestamp) = 0; |
| 88 virtual void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) = 0; | |
| 79 | 89 |
| 80 // Used to shutdown properly on the same thread we were created. | 90 // Used to shutdown properly on the same thread we were created. |
| 81 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 91 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
| 82 | 92 |
| 83 // Task runner where frames to encode and reply callbacks must happen. | 93 // Task runner where frames to encode and reply callbacks must happen. |
| 84 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; | 94 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; |
| 85 | 95 |
| 86 // Thread for encoding. Active for the lifetime of VpxEncoder. | 96 // Task runner where encoding interactions happen. |
| 97 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner_; | |
| 98 | |
| 99 // Optional thread for encoding. Active for the lifetime of VpxEncoder. | |
| 87 std::unique_ptr<base::Thread> encoding_thread_; | 100 std::unique_ptr<base::Thread> encoding_thread_; |
| 88 | 101 |
| 89 // While |paused_|, frames are not encoded. Used only from |encoding_thread_|. | 102 // While |paused_|, frames are not encoded. Used only from |encoding_thread_|. |
| 90 bool paused_; | 103 bool paused_; |
| 91 | 104 |
| 92 // This callback should be exercised on IO thread. | 105 // This callback should be exercised on IO thread. |
| 93 const OnEncodedVideoCB on_encoded_video_callback_; | 106 const OnEncodedVideoCB on_encoded_video_callback_; |
| 94 | 107 |
| 95 // Target bitrate for video encoding. If 0, a standard bitrate is used. | 108 // Target bitrate for video encoding. If 0, a standard bitrate is used. |
| 96 const int32_t bits_per_second_; | 109 const int32_t bits_per_second_; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 112 video_frame->format() == media::PIXEL_FORMAT_YV12 || | 125 video_frame->format() == media::PIXEL_FORMAT_YV12 || |
| 113 video_frame->format() == media::PIXEL_FORMAT_YV12A)) { | 126 video_frame->format() == media::PIXEL_FORMAT_YV12A)) { |
| 114 NOTREACHED(); | 127 NOTREACHED(); |
| 115 return; | 128 return; |
| 116 } | 129 } |
| 117 scoped_refptr<media::VideoFrame> frame = video_frame; | 130 scoped_refptr<media::VideoFrame> frame = video_frame; |
| 118 // Drop alpha channel since we do not support it yet. | 131 // Drop alpha channel since we do not support it yet. |
| 119 if (frame->format() == media::PIXEL_FORMAT_YV12A) | 132 if (frame->format() == media::PIXEL_FORMAT_YV12A) |
| 120 frame = media::WrapAsI420VideoFrame(video_frame); | 133 frame = media::WrapAsI420VideoFrame(video_frame); |
| 121 | 134 |
| 122 encoding_thread_->task_runner()->PostTask( | 135 encoding_task_runner_->PostTask( |
| 123 FROM_HERE, base::Bind(&Encoder::EncodeOnEncodingThread, | 136 FROM_HERE, base::Bind(&Encoder::EncodeOnEncodingTaskRunner, this, frame, |
| 124 this, frame, capture_timestamp)); | 137 capture_timestamp)); |
| 125 } | 138 } |
| 126 | 139 |
| 127 void VideoTrackRecorder::Encoder::SetPaused(bool paused) { | 140 void VideoTrackRecorder::Encoder::SetPaused(bool paused) { |
| 128 if (!encoding_thread_->task_runner()->BelongsToCurrentThread()) { | 141 if (!encoding_task_runner_->BelongsToCurrentThread()) { |
| 129 encoding_thread_->task_runner()->PostTask( | 142 encoding_task_runner_->PostTask( |
| 130 FROM_HERE, base::Bind(&Encoder::SetPaused, this, paused)); | 143 FROM_HERE, base::Bind(&Encoder::SetPaused, this, paused)); |
| 131 return; | 144 return; |
| 132 } | 145 } |
| 133 paused_ = paused; | 146 paused_ = paused; |
| 134 } | 147 } |
| 135 | 148 |
| 136 namespace { | 149 namespace { |
| 137 | 150 |
| 138 // Originally from remoting/codec/scoped_vpx_codec.h. | 151 // Originally from remoting/codec/scoped_vpx_codec.h. |
| 139 // TODO(mcasas): Refactor into a common location. | 152 // TODO(mcasas): Refactor into a common location. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 ScopedVpxCodecCtxPtr encoder); | 186 ScopedVpxCodecCtxPtr encoder); |
| 174 | 187 |
| 175 VpxEncoder( | 188 VpxEncoder( |
| 176 bool use_vp9, | 189 bool use_vp9, |
| 177 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 190 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 178 int32_t bits_per_second); | 191 int32_t bits_per_second); |
| 179 | 192 |
| 180 private: | 193 private: |
| 181 // VideoTrackRecorder::Encoder | 194 // VideoTrackRecorder::Encoder |
| 182 ~VpxEncoder() override; | 195 ~VpxEncoder() override; |
| 183 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 196 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, |
| 184 base::TimeTicks capture_timestamp) override; | 197 base::TimeTicks capture_timestamp) override; |
| 185 void ConfigureEncoderOnEncodingThread(const gfx::Size& size) override; | 198 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; |
| 186 | 199 |
| 187 // Returns true if |codec_config_| has been filled in at least once. | 200 // Returns true if |codec_config_| has been filled in at least once. |
| 188 bool IsInitialized() const; | 201 bool IsInitialized() const; |
| 189 | 202 |
| 190 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. | 203 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. |
| 191 base::TimeDelta EstimateFrameDuration(const scoped_refptr<VideoFrame>& frame); | 204 base::TimeDelta EstimateFrameDuration(const scoped_refptr<VideoFrame>& frame); |
| 192 | 205 |
| 193 // Force usage of VP9 for encoding, instead of VP8 which is the default. | 206 // Force usage of VP9 for encoding, instead of VP8 which is the default. |
| 194 const bool use_vp9_; | 207 const bool use_vp9_; |
| 195 | 208 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 225 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, | 238 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, |
| 226 ScopedISVCEncoderPtr encoder); | 239 ScopedISVCEncoderPtr encoder); |
| 227 | 240 |
| 228 H264Encoder( | 241 H264Encoder( |
| 229 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 242 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 230 int32_t bits_per_second); | 243 int32_t bits_per_second); |
| 231 | 244 |
| 232 private: | 245 private: |
| 233 // VideoTrackRecorder::Encoder | 246 // VideoTrackRecorder::Encoder |
| 234 ~H264Encoder() override; | 247 ~H264Encoder() override; |
| 235 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 248 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, |
| 236 base::TimeTicks capture_timestamp) override; | 249 base::TimeTicks capture_timestamp) override; |
| 237 void ConfigureEncoderOnEncodingThread(const gfx::Size& size) override; | 250 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; |
| 238 | 251 |
| 239 // |openh264_encoder_| is a special scoped pointer to guarantee proper | 252 // |openh264_encoder_| is a special scoped pointer to guarantee proper |
| 240 // destruction, also when reconfiguring due to parameters change. Only used on | 253 // destruction, also when reconfiguring due to parameters change. Only used on |
| 241 // |encoding_thread_|. | 254 // |encoding_thread_|. |
| 242 gfx::Size configured_size_; | 255 gfx::Size configured_size_; |
| 243 ScopedISVCEncoderPtr openh264_encoder_; | 256 ScopedISVCEncoderPtr openh264_encoder_; |
| 244 | 257 |
| 245 // The |VideoFrame::timestamp()| of the first received frame. Only used on | 258 // The |VideoFrame::timestamp()| of the first received frame. Only used on |
| 246 // |encoding_thread_|. | 259 // |encoding_thread_|. |
| 247 base::TimeTicks first_frame_timestamp_; | 260 base::TimeTicks first_frame_timestamp_; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 259 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. | 272 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. |
| 260 } | 273 } |
| 261 | 274 |
| 262 VpxEncoder::VpxEncoder( | 275 VpxEncoder::VpxEncoder( |
| 263 bool use_vp9, | 276 bool use_vp9, |
| 264 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 277 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 265 int32_t bits_per_second) | 278 int32_t bits_per_second) |
| 266 : Encoder(on_encoded_video_callback, bits_per_second), | 279 : Encoder(on_encoded_video_callback, bits_per_second), |
| 267 use_vp9_(use_vp9) { | 280 use_vp9_(use_vp9) { |
| 268 codec_config_.g_timebase.den = 0; // Not initialized. | 281 codec_config_.g_timebase.den = 0; // Not initialized. |
| 269 | 282 DCHECK(encoding_thread_->IsRunning()); |
| 270 DCHECK(!encoding_thread_->IsRunning()); | |
| 271 encoding_thread_->Start(); | |
| 272 } | 283 } |
| 273 | 284 |
| 274 VpxEncoder::~VpxEncoder() { | 285 VpxEncoder::~VpxEncoder() { |
| 275 main_task_runner_->PostTask(FROM_HERE, | 286 main_task_runner_->PostTask(FROM_HERE, |
| 276 base::Bind(&VpxEncoder::ShutdownEncoder, | 287 base::Bind(&VpxEncoder::ShutdownEncoder, |
| 277 base::Passed(&encoding_thread_), | 288 base::Passed(&encoding_thread_), |
| 278 base::Passed(&encoder_))); | 289 base::Passed(&encoder_))); |
| 279 } | 290 } |
| 280 | 291 |
| 281 void VpxEncoder::EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 292 void VpxEncoder::EncodeOnEncodingTaskRunner( |
| 282 base::TimeTicks capture_timestamp) { | 293 const scoped_refptr<VideoFrame>& frame, |
| 283 TRACE_EVENT0("video", "VpxEncoder::EncodeOnEncodingThread"); | 294 base::TimeTicks capture_timestamp) { |
| 284 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); | 295 TRACE_EVENT0("video", "VpxEncoder::EncodeOnEncodingTaskRunner"); |
| 296 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 285 | 297 |
| 286 const gfx::Size frame_size = frame->visible_rect().size(); | 298 const gfx::Size frame_size = frame->visible_rect().size(); |
| 287 if (!IsInitialized() || | 299 if (!IsInitialized() || |
| 288 gfx::Size(codec_config_.g_w, codec_config_.g_h) != frame_size) { | 300 gfx::Size(codec_config_.g_w, codec_config_.g_h) != frame_size) { |
| 289 ConfigureEncoderOnEncodingThread(frame_size); | 301 ConfigureEncoderOnEncodingTaskRunner(frame_size); |
| 290 } | 302 } |
| 291 | 303 |
| 292 vpx_image_t vpx_image; | 304 vpx_image_t vpx_image; |
| 293 vpx_image_t* const result = vpx_img_wrap(&vpx_image, | 305 vpx_image_t* const result = vpx_img_wrap(&vpx_image, |
| 294 VPX_IMG_FMT_I420, | 306 VPX_IMG_FMT_I420, |
| 295 frame_size.width(), | 307 frame_size.width(), |
| 296 frame_size.height(), | 308 frame_size.height(), |
| 297 1 /* align */, | 309 1 /* align */, |
| 298 frame->data(VideoFrame::kYPlane)); | 310 frame->data(VideoFrame::kYPlane)); |
| 299 DCHECK_EQ(result, &vpx_image); | 311 DCHECK_EQ(result, &vpx_image); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 331 } | 343 } |
| 332 origin_task_runner_->PostTask(FROM_HERE, | 344 origin_task_runner_->PostTask(FROM_HERE, |
| 333 base::Bind(OnFrameEncodeCompleted, | 345 base::Bind(OnFrameEncodeCompleted, |
| 334 on_encoded_video_callback_, | 346 on_encoded_video_callback_, |
| 335 frame, | 347 frame, |
| 336 base::Passed(&data), | 348 base::Passed(&data), |
| 337 capture_timestamp, | 349 capture_timestamp, |
| 338 keyframe)); | 350 keyframe)); |
| 339 } | 351 } |
| 340 | 352 |
| 341 void VpxEncoder::ConfigureEncoderOnEncodingThread(const gfx::Size& size) { | 353 void VpxEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) { |
| 342 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); | 354 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 343 if (IsInitialized()) { | 355 if (IsInitialized()) { |
| 344 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less- | 356 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less- |
| 345 // than-or-equal than the old size, in terms of area, the existing encoder | 357 // than-or-equal than the old size, in terms of area, the existing encoder |
| 346 // instance could be reused after changing |codec_config_.{g_w,g_h}|. | 358 // instance could be reused after changing |codec_config_.{g_w,g_h}|. |
| 347 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: " | 359 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: " |
| 348 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString() | 360 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString() |
| 349 << " --> " << size.ToString() << (use_vp9_ ? " vp9" : " vp8"); | 361 << " --> " << size.ToString() << (use_vp9_ ? " vp9" : " vp8"); |
| 350 encoder_.reset(); | 362 encoder_.reset(); |
| 351 } | 363 } |
| 352 | 364 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 // target time spent encoding the frame. Go from 8 to 5 (values for real | 433 // target time spent encoding the frame. Go from 8 to 5 (values for real |
| 422 // time encoding) depending on the amount of cores available in the system. | 434 // time encoding) depending on the amount of cores available in the system. |
| 423 const int kCpuUsed = | 435 const int kCpuUsed = |
| 424 std::max(5, 8 - base::SysInfo::NumberOfProcessors() / 2); | 436 std::max(5, 8 - base::SysInfo::NumberOfProcessors() / 2); |
| 425 result = vpx_codec_control(encoder_.get(), VP8E_SET_CPUUSED, kCpuUsed); | 437 result = vpx_codec_control(encoder_.get(), VP8E_SET_CPUUSED, kCpuUsed); |
| 426 DLOG_IF(WARNING, VPX_CODEC_OK != result) << "VP8E_SET_CPUUSED failed"; | 438 DLOG_IF(WARNING, VPX_CODEC_OK != result) << "VP8E_SET_CPUUSED failed"; |
| 427 } | 439 } |
| 428 } | 440 } |
| 429 | 441 |
| 430 bool VpxEncoder::IsInitialized() const { | 442 bool VpxEncoder::IsInitialized() const { |
| 431 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); | 443 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 432 return codec_config_.g_timebase.den != 0; | 444 return codec_config_.g_timebase.den != 0; |
| 433 } | 445 } |
| 434 | 446 |
| 435 base::TimeDelta VpxEncoder::EstimateFrameDuration( | 447 base::TimeDelta VpxEncoder::EstimateFrameDuration( |
| 436 const scoped_refptr<VideoFrame>& frame) { | 448 const scoped_refptr<VideoFrame>& frame) { |
| 437 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); | 449 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 438 | 450 |
| 439 using base::TimeDelta; | 451 using base::TimeDelta; |
| 440 TimeDelta predicted_frame_duration; | 452 TimeDelta predicted_frame_duration; |
| 441 if (!frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION, | 453 if (!frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION, |
| 442 &predicted_frame_duration) || | 454 &predicted_frame_duration) || |
| 443 predicted_frame_duration <= TimeDelta()) { | 455 predicted_frame_duration <= TimeDelta()) { |
| 444 // The source of the video frame did not provide the frame duration. Use | 456 // The source of the video frame did not provide the frame duration. Use |
| 445 // the actual amount of time between the current and previous frame as a | 457 // the actual amount of time between the current and previous frame as a |
| 446 // prediction for the next frame's duration. | 458 // prediction for the next frame's duration. |
| 447 // TODO(mcasas): This duration estimation could lead to artifacts if the | 459 // TODO(mcasas): This duration estimation could lead to artifacts if the |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 464 ScopedISVCEncoderPtr encoder) { | 476 ScopedISVCEncoderPtr encoder) { |
| 465 DCHECK(encoding_thread->IsRunning()); | 477 DCHECK(encoding_thread->IsRunning()); |
| 466 encoding_thread->Stop(); | 478 encoding_thread->Stop(); |
| 467 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. | 479 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. |
| 468 } | 480 } |
| 469 | 481 |
| 470 H264Encoder::H264Encoder( | 482 H264Encoder::H264Encoder( |
| 471 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 483 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 472 int32_t bits_per_second) | 484 int32_t bits_per_second) |
| 473 : Encoder(on_encoded_video_callback, bits_per_second) { | 485 : Encoder(on_encoded_video_callback, bits_per_second) { |
| 474 DCHECK(!encoding_thread_->IsRunning()); | 486 DCHECK(encoding_thread_->IsRunning()); |
| 475 encoding_thread_->Start(); | |
| 476 } | 487 } |
| 477 | 488 |
| 478 H264Encoder::~H264Encoder() { | 489 H264Encoder::~H264Encoder() { |
| 479 main_task_runner_->PostTask(FROM_HERE, | 490 main_task_runner_->PostTask(FROM_HERE, |
| 480 base::Bind(&H264Encoder::ShutdownEncoder, | 491 base::Bind(&H264Encoder::ShutdownEncoder, |
| 481 base::Passed(&encoding_thread_), | 492 base::Passed(&encoding_thread_), |
| 482 base::Passed(&openh264_encoder_))); | 493 base::Passed(&openh264_encoder_))); |
| 483 } | 494 } |
| 484 | 495 |
| 485 void H264Encoder::EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 496 void H264Encoder::EncodeOnEncodingTaskRunner( |
| 486 base::TimeTicks capture_timestamp) { | 497 const scoped_refptr<VideoFrame>& frame, |
| 487 TRACE_EVENT0("video", "H264Encoder::EncodeOnEncodingThread"); | 498 base::TimeTicks capture_timestamp) { |
| 488 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); | 499 TRACE_EVENT0("video", "H264Encoder::EncodeOnEncodingTaskRunner"); |
| 500 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 489 | 501 |
| 490 const gfx::Size frame_size = frame->visible_rect().size(); | 502 const gfx::Size frame_size = frame->visible_rect().size(); |
| 491 if (!openh264_encoder_ || configured_size_ != frame_size) { | 503 if (!openh264_encoder_ || configured_size_ != frame_size) { |
| 492 ConfigureEncoderOnEncodingThread(frame_size); | 504 ConfigureEncoderOnEncodingTaskRunner(frame_size); |
| 493 first_frame_timestamp_ = capture_timestamp; | 505 first_frame_timestamp_ = capture_timestamp; |
| 494 } | 506 } |
| 495 | 507 |
| 496 SSourcePicture picture = {}; | 508 SSourcePicture picture = {}; |
| 497 picture.iPicWidth = frame_size.width(); | 509 picture.iPicWidth = frame_size.width(); |
| 498 picture.iPicHeight = frame_size.height(); | 510 picture.iPicHeight = frame_size.height(); |
| 499 picture.iColorFormat = EVideoFormatType::videoFormatI420; | 511 picture.iColorFormat = EVideoFormatType::videoFormatI420; |
| 500 picture.uiTimeStamp = | 512 picture.uiTimeStamp = |
| 501 (capture_timestamp - first_frame_timestamp_).InMilliseconds(); | 513 (capture_timestamp - first_frame_timestamp_).InMilliseconds(); |
| 502 picture.iStride[0] = frame->stride(VideoFrame::kYPlane); | 514 picture.iStride[0] = frame->stride(VideoFrame::kYPlane); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 532 data->append(reinterpret_cast<char*>(layerInfo.pBsBuf), layer_len); | 544 data->append(reinterpret_cast<char*>(layerInfo.pBsBuf), layer_len); |
| 533 } | 545 } |
| 534 | 546 |
| 535 const bool is_key_frame = info.eFrameType == videoFrameTypeIDR; | 547 const bool is_key_frame = info.eFrameType == videoFrameTypeIDR; |
| 536 origin_task_runner_->PostTask( | 548 origin_task_runner_->PostTask( |
| 537 FROM_HERE, | 549 FROM_HERE, |
| 538 base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_, frame, | 550 base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_, frame, |
| 539 base::Passed(&data), capture_timestamp, is_key_frame)); | 551 base::Passed(&data), capture_timestamp, is_key_frame)); |
| 540 } | 552 } |
| 541 | 553 |
| 542 void H264Encoder::ConfigureEncoderOnEncodingThread(const gfx::Size& size) { | 554 void H264Encoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) { |
| 543 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); | 555 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 544 ISVCEncoder* temp_encoder = nullptr; | 556 ISVCEncoder* temp_encoder = nullptr; |
| 545 if (WelsCreateSVCEncoder(&temp_encoder) != 0) { | 557 if (WelsCreateSVCEncoder(&temp_encoder) != 0) { |
| 546 NOTREACHED() << "Failed to create OpenH264 encoder"; | 558 NOTREACHED() << "Failed to create OpenH264 encoder"; |
| 547 return; | 559 return; |
| 548 } | 560 } |
| 549 openh264_encoder_.reset(temp_encoder); | 561 openh264_encoder_.reset(temp_encoder); |
| 550 configured_size_ = size; | 562 configured_size_ = size; |
| 551 | 563 |
| 552 #if DCHECK_IS_ON() | 564 #if DCHECK_IS_ON() |
| 553 int trace_level = WELS_LOG_INFO; | 565 int trace_level = WELS_LOG_INFO; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 654 encoder_->SetPaused(false); | 666 encoder_->SetPaused(false); |
| 655 } | 667 } |
| 656 | 668 |
| 657 void VideoTrackRecorder::OnVideoFrameForTesting( | 669 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 658 const scoped_refptr<media::VideoFrame>& frame, | 670 const scoped_refptr<media::VideoFrame>& frame, |
| 659 base::TimeTicks timestamp) { | 671 base::TimeTicks timestamp) { |
| 660 encoder_->StartFrameEncode(frame, timestamp); | 672 encoder_->StartFrameEncode(frame, timestamp); |
| 661 } | 673 } |
| 662 | 674 |
| 663 } // namespace content | 675 } // namespace content |
| OLD | NEW |