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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 64 media::H264PROFILE_MAX}}; | 64 media::H264PROFILE_MAX}}; |
| 65 | 65 |
| 66 // Returns the corresponding codec profile from VEA supported codecs. If no | 66 // Returns the corresponding codec profile from VEA supported codecs. If no |
| 67 // profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN. | 67 // profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN. |
| 68 media::VideoCodecProfile CodecIdToVEAProfile( | 68 media::VideoCodecProfile CodecIdToVEAProfile( |
| 69 content::VideoTrackRecorder::CodecId codec) { | 69 content::VideoTrackRecorder::CodecId codec) { |
| 70 // See https://crbug.com/616659. | 70 // See https://crbug.com/616659. |
| 71 #if defined(OS_CHROMEOS) | 71 #if defined(OS_CHROMEOS) |
| 72 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 72 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 73 #endif // defined(OS_CHROMEOS) | 73 #endif // defined(OS_CHROMEOS) |
| 74 content::RenderThreadImpl* render_thread_impl = | 74 content::RenderThreadImpl* const render_thread_impl = |
| 75 content::RenderThreadImpl::current(); | 75 content::RenderThreadImpl::current(); |
| 76 if (!render_thread_impl) | 76 if (!render_thread_impl) { |
| 77 DVLOG(3) << "Couldn't access the render thread"; | |
| 77 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 78 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 79 } | |
| 78 | 80 |
| 79 media::GpuVideoAcceleratorFactories* gpu_factories = | 81 media::GpuVideoAcceleratorFactories* const gpu_factories = |
| 80 content::RenderThreadImpl::current()->GetGpuFactories(); | 82 render_thread_impl->GetGpuFactories(); |
| 81 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { | 83 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { |
| 82 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; | 84 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; |
| 83 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 85 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 84 } | 86 } |
| 85 | 87 |
| 86 const media::VideoEncodeAccelerator::SupportedProfiles& vea_profiles = | 88 const media::VideoEncodeAccelerator::SupportedProfiles& vea_profiles = |
| 87 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); | 89 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); |
| 88 for (const auto& vea_profile : vea_profiles) { | 90 for (const auto& vea_profile : vea_profiles) { |
| 89 for (const auto& supported_profile : kSupportedVideoCodecIdToProfile) { | 91 for (const auto& supported_profile : kSupportedVideoCodecIdToProfile) { |
| 90 if (codec == supported_profile.codec_id && | 92 if (codec == supported_profile.codec_id && |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 | 245 |
| 244 // Class encapsulating VideoEncodeAccelerator interactions. | 246 // Class encapsulating VideoEncodeAccelerator interactions. |
| 245 // This class is created and destroyed in its owner thread. All other methods | 247 // This class is created and destroyed in its owner thread. All other methods |
| 246 // operate on the task runner pointed by GpuFactories. | 248 // operate on the task runner pointed by GpuFactories. |
| 247 class VEAEncoder final : public VideoTrackRecorder::Encoder, | 249 class VEAEncoder final : public VideoTrackRecorder::Encoder, |
| 248 public media::VideoEncodeAccelerator::Client { | 250 public media::VideoEncodeAccelerator::Client { |
| 249 public: | 251 public: |
| 250 VEAEncoder( | 252 VEAEncoder( |
| 251 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 253 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 252 int32_t bits_per_second, | 254 int32_t bits_per_second, |
| 253 media::VideoCodecProfile codec); | 255 media::VideoCodecProfile codec, |
| 256 const gfx::Size& size); | |
| 254 | 257 |
| 255 // media::VideoEncodeAccelerator::Client implementation. | 258 // media::VideoEncodeAccelerator::Client implementation. |
| 256 void RequireBitstreamBuffers(unsigned int input_count, | 259 void RequireBitstreamBuffers(unsigned int input_count, |
| 257 const gfx::Size& input_coded_size, | 260 const gfx::Size& input_coded_size, |
| 258 size_t output_buffer_size) override; | 261 size_t output_buffer_size) override; |
| 259 void BitstreamBufferReady(int32_t bitstream_buffer_id, | 262 void BitstreamBufferReady(int32_t bitstream_buffer_id, |
| 260 size_t payload_size, | 263 size_t payload_size, |
| 261 bool key_frame, | 264 bool key_frame, |
| 262 base::TimeDelta timestamp) override; | 265 base::TimeDelta timestamp) override; |
| 263 void NotifyError(media::VideoEncodeAccelerator::Error error) override; | 266 void NotifyError(media::VideoEncodeAccelerator::Error error) override; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 284 | 287 |
| 285 // Shared memory buffers for output with the VEA. | 288 // Shared memory buffers for output with the VEA. |
| 286 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; | 289 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; |
| 287 | 290 |
| 288 // Shared memory buffers for output with the VEA as FIFO. | 291 // Shared memory buffers for output with the VEA as FIFO. |
| 289 std::queue<std::unique_ptr<base::SharedMemory>> input_buffers_; | 292 std::queue<std::unique_ptr<base::SharedMemory>> input_buffers_; |
| 290 | 293 |
| 291 // Tracks error status. | 294 // Tracks error status. |
| 292 bool error_notified_; | 295 bool error_notified_; |
| 293 | 296 |
| 294 // Tracks the first frame to encode. | 297 // Tracks the last frame that we delay the encode. |
| 295 std::unique_ptr<VideoFrameAndTimestamp> first_frame_; | 298 std::unique_ptr<VideoFrameAndTimestamp> last_frame_; |
| 296 | 299 |
| 297 // Size used to initialize encoder. | 300 // Size used to initialize encoder. |
| 298 gfx::Size input_size_; | 301 gfx::Size input_size_; |
| 299 | 302 |
| 300 // Coded size that encoder requests as input. | 303 // Coded size that encoder requests as input. |
| 301 gfx::Size vea_requested_input_size_; | 304 gfx::Size vea_requested_input_size_; |
| 302 | 305 |
| 303 // Frames and corresponding timestamps in encode as FIFO. | 306 // Frames and corresponding timestamps in encode as FIFO. |
| 304 std::queue<VideoFrameAndTimestamp> frames_in_encode_; | 307 std::queue<VideoFrameAndTimestamp> frames_in_encode_; |
| 305 }; | 308 }; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 base::TimeTicks first_frame_timestamp_; | 388 base::TimeTicks first_frame_timestamp_; |
| 386 | 389 |
| 387 DISALLOW_COPY_AND_ASSIGN(H264Encoder); | 390 DISALLOW_COPY_AND_ASSIGN(H264Encoder); |
| 388 }; | 391 }; |
| 389 | 392 |
| 390 #endif // #if BUILDFLAG(RTC_USE_H264) | 393 #endif // #if BUILDFLAG(RTC_USE_H264) |
| 391 | 394 |
| 392 VEAEncoder::VEAEncoder( | 395 VEAEncoder::VEAEncoder( |
| 393 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 396 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 394 int32_t bits_per_second, | 397 int32_t bits_per_second, |
| 395 media::VideoCodecProfile codec) | 398 media::VideoCodecProfile codec, |
| 399 const gfx::Size& size) | |
| 396 : Encoder(on_encoded_video_callback, | 400 : Encoder(on_encoded_video_callback, |
| 397 bits_per_second, | 401 bits_per_second, |
| 398 RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()), | 402 RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()), |
| 399 gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()), | 403 gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()), |
| 400 codec_(codec), | 404 codec_(codec), |
| 401 error_notified_(false) { | 405 error_notified_(false) { |
| 402 DCHECK(gpu_factories_); | 406 DCHECK(gpu_factories_); |
| 407 | |
|
mcasas
2016/07/08 22:59:27
DCHECK_GE(size.width(), kVEAEncoderMinResolutionWi
emircan
2016/07/12 01:00:35
Done.
| |
| 408 encoding_task_runner_->PostTask( | |
| 409 FROM_HERE, base::Bind(&VEAEncoder::ConfigureEncoderOnEncodingTaskRunner, | |
| 410 this, size)); | |
| 403 } | 411 } |
| 404 | 412 |
| 405 VEAEncoder::~VEAEncoder() { | 413 VEAEncoder::~VEAEncoder() { |
| 406 encoding_task_runner_->PostTask( | 414 encoding_task_runner_->PostTask( |
| 407 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy, | 415 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy, |
| 408 base::Unretained(video_encoder_.release()))); | 416 base::Unretained(video_encoder_.release()))); |
| 409 } | 417 } |
| 410 | 418 |
| 411 void VEAEncoder::RequireBitstreamBuffers(unsigned int /*input_count*/, | 419 void VEAEncoder::RequireBitstreamBuffers(unsigned int /*input_count*/, |
| 412 const gfx::Size& input_coded_size, | 420 const gfx::Size& input_coded_size, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 const scoped_refptr<VideoFrame>& frame, | 486 const scoped_refptr<VideoFrame>& frame, |
| 479 base::TimeTicks capture_timestamp) { | 487 base::TimeTicks capture_timestamp) { |
| 480 DVLOG(3) << __FUNCTION__; | 488 DVLOG(3) << __FUNCTION__; |
| 481 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | 489 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 482 | 490 |
| 483 if (input_size_ != frame->visible_rect().size() && video_encoder_) { | 491 if (input_size_ != frame->visible_rect().size() && video_encoder_) { |
| 484 video_encoder_->Destroy(); | 492 video_encoder_->Destroy(); |
| 485 video_encoder_.reset(); | 493 video_encoder_.reset(); |
| 486 } | 494 } |
| 487 | 495 |
| 488 if (!video_encoder_) { | 496 if (!video_encoder_) |
| 489 ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size()); | 497 ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size()); |
| 490 first_frame_.reset( | |
| 491 new std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>( | |
| 492 frame, capture_timestamp)); | |
| 493 } | |
| 494 | 498 |
| 495 if (error_notified_) { | 499 if (error_notified_) { |
| 496 DVLOG(3) << "An error occurred in VEA encoder"; | 500 DVLOG(3) << "An error occurred in VEA encoder"; |
| 497 return; | 501 return; |
| 498 } | 502 } |
| 499 | 503 |
| 500 // Drop frames if there is no output buffers available. | 504 // Drop frames if there is no output buffers available. |
| 501 if (output_buffers_.empty()) { | 505 if (output_buffers_.empty()) { |
| 502 // TODO(emircan): Investigate if resetting encoder would help. | 506 // TODO(emircan): Investigate if resetting encoder would help. |
| 503 DVLOG(3) << "Dropped frame."; | 507 DVLOG(3) << "Might drop frame."; |
| 508 last_frame_.reset( | |
| 509 new std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>( | |
| 510 frame, capture_timestamp)); | |
| 504 return; | 511 return; |
| 505 } | 512 } |
| 506 | 513 |
| 507 // If first frame hasn't been encoded, do it first. | 514 // If first frame hasn't been encoded, do it first. |
| 508 if (first_frame_) { | 515 if (last_frame_) { |
| 509 std::unique_ptr<VideoFrameAndTimestamp> first_frame(first_frame_.release()); | 516 std::unique_ptr<VideoFrameAndTimestamp> last_frame(last_frame_.release()); |
| 510 EncodeOnEncodingTaskRunner(first_frame->first, first_frame->second); | 517 EncodeOnEncodingTaskRunner(last_frame->first, last_frame->second); |
| 511 } | 518 } |
| 512 | 519 |
| 513 // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac. | 520 // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac. |
| 514 // In that case, the encoder expects more frames before returning result. | 521 // In that case, the encoder expects more frames before returning result. |
| 515 // Therefore, a copy is necessary to release the current frame. | 522 // Therefore, a copy is necessary to release the current frame. |
| 516 scoped_refptr<media::VideoFrame> video_frame = frame; | 523 scoped_refptr<media::VideoFrame> video_frame = frame; |
| 517 if (vea_requested_input_size_ != input_size_ || | 524 if (vea_requested_input_size_ != input_size_ || |
| 518 input_size_.width() < kVEAEncoderMinResolutionWidth || | 525 input_size_.width() < kVEAEncoderMinResolutionWidth || |
| 519 input_size_.height() < kVEAEncoderMinResolutionHeight) { | 526 input_size_.height() < kVEAEncoderMinResolutionHeight) { |
| 520 // Create SharedMemory backed input buffers as necessary. These SharedMemory | 527 // Create SharedMemory backed input buffers as necessary. These SharedMemory |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 929 } | 936 } |
| 930 #endif //#if BUILDFLAG(RTC_USE_H264) | 937 #endif //#if BUILDFLAG(RTC_USE_H264) |
| 931 | 938 |
| 932 } // anonymous namespace | 939 } // anonymous namespace |
| 933 | 940 |
| 934 VideoTrackRecorder::VideoTrackRecorder( | 941 VideoTrackRecorder::VideoTrackRecorder( |
| 935 CodecId codec, | 942 CodecId codec, |
| 936 const blink::WebMediaStreamTrack& track, | 943 const blink::WebMediaStreamTrack& track, |
| 937 const OnEncodedVideoCB& on_encoded_video_callback, | 944 const OnEncodedVideoCB& on_encoded_video_callback, |
| 938 int32_t bits_per_second) | 945 int32_t bits_per_second) |
| 939 : track_(track) { | 946 : track_(track), |
| 947 codec_(codec), | |
| 948 on_encoded_video_callback_(on_encoded_video_callback), | |
| 949 bits_per_second_(bits_per_second), | |
| 950 paused_before_init_(false), | |
| 951 weak_ptr_factory_(this) { | |
| 940 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 952 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 941 DCHECK(!track_.isNull()); | 953 DCHECK(!track_.isNull()); |
| 942 DCHECK(track_.getTrackData()); | 954 DCHECK(track_.getTrackData()); |
| 943 | 955 |
| 944 const auto& vea_supported_profile = CodecIdToVEAProfile(codec); | 956 // InitializeEncoder() will be called on Render Main thread. |
| 945 // TODO(emircan): Prioritize software based encoders in lower resolutions. | 957 // It is safe to use Unretained, because the class gets disconnected from |
| 946 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) { | 958 // track in dtor. |
| 947 encoder_ = new VEAEncoder(on_encoded_video_callback, bits_per_second, | |
| 948 vea_supported_profile); | |
| 949 } else { | |
| 950 switch (codec) { | |
| 951 #if BUILDFLAG(RTC_USE_H264) | |
| 952 case CodecId::H264: | |
| 953 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); | |
| 954 break; | |
| 955 #endif | |
| 956 case CodecId::VP8: | |
| 957 case CodecId::VP9: | |
| 958 encoder_ = new VpxEncoder(codec == CodecId::VP9, | |
| 959 on_encoded_video_callback, bits_per_second); | |
| 960 break; | |
| 961 default: | |
| 962 NOTREACHED() << "Unsupported codec"; | |
| 963 } | |
| 964 } | |
| 965 | |
| 966 // StartFrameEncode() will be called on Render IO thread. | |
| 967 MediaStreamVideoSink::ConnectToTrack( | 959 MediaStreamVideoSink::ConnectToTrack( |
| 968 track_, | 960 track_, |
| 969 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | 961 media::BindToCurrentLoop(base::Bind( |
| 962 &VideoTrackRecorder::InitializeEncoder, base::Unretained(this))), | |
| 970 false); | 963 false); |
| 971 } | 964 } |
| 972 | 965 |
| 973 VideoTrackRecorder::~VideoTrackRecorder() { | 966 VideoTrackRecorder::~VideoTrackRecorder() { |
| 974 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 967 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 975 MediaStreamVideoSink::DisconnectFromTrack(); | 968 MediaStreamVideoSink::DisconnectFromTrack(); |
| 976 track_.reset(); | 969 track_.reset(); |
| 977 } | 970 } |
| 978 | 971 |
| 979 void VideoTrackRecorder::Pause() { | 972 void VideoTrackRecorder::Pause() { |
| 980 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 973 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 981 DCHECK(encoder_); | 974 if (encoder_) |
| 982 encoder_->SetPaused(true); | 975 encoder_->SetPaused(true); |
| 976 else | |
| 977 paused_before_init_ = true; | |
| 983 } | 978 } |
| 984 | 979 |
| 985 void VideoTrackRecorder::Resume() { | 980 void VideoTrackRecorder::Resume() { |
| 986 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 981 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 987 DCHECK(encoder_); | 982 if (encoder_) |
| 988 encoder_->SetPaused(false); | 983 encoder_->SetPaused(false); |
| 984 else | |
| 985 paused_before_init_ = false; | |
| 989 } | 986 } |
| 990 | 987 |
| 991 void VideoTrackRecorder::OnVideoFrameForTesting( | 988 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 992 const scoped_refptr<media::VideoFrame>& frame, | 989 const scoped_refptr<media::VideoFrame>& frame, |
| 993 base::TimeTicks timestamp) { | 990 base::TimeTicks timestamp) { |
| 991 DVLOG(3) << __FUNCTION__; | |
| 992 | |
| 993 if (!encoder_) | |
| 994 InitializeEncoder(frame, timestamp); | |
| 995 | |
| 994 encoder_->StartFrameEncode(frame, timestamp); | 996 encoder_->StartFrameEncode(frame, timestamp); |
| 995 } | 997 } |
| 996 | 998 |
| 999 | |
| 1000 void VideoTrackRecorder::InitializeEncoder( | |
| 1001 const scoped_refptr<media::VideoFrame>& frame, | |
| 1002 base::TimeTicks capture_time) { | |
| 1003 DVLOG(3) << __FUNCTION__ << frame->visible_rect().size().ToString(); | |
| 1004 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | |
| 1005 | |
| 1006 MediaStreamVideoSink::DisconnectFromTrack(); | |
| 1007 | |
| 1008 const gfx::Size& input_size = frame->visible_rect().size(); | |
| 1009 const auto& vea_supported_profile = CodecIdToVEAProfile(codec_); | |
| 1010 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN && | |
| 1011 input_size.width() >= kVEAEncoderMinResolutionWidth && | |
| 1012 input_size.height() >= kVEAEncoderMinResolutionHeight) { | |
| 1013 encoder_ = new VEAEncoder(on_encoded_video_callback_, bits_per_second_, | |
| 1014 vea_supported_profile, input_size); | |
| 1015 } else { | |
| 1016 switch (codec_) { | |
| 1017 #if BUILDFLAG(RTC_USE_H264) | |
| 1018 case CodecId::H264: | |
| 1019 encoder_ = | |
| 1020 new H264Encoder(on_encoded_video_callback_, bits_per_second_); | |
| 1021 break; | |
| 1022 #endif | |
| 1023 case CodecId::VP8: | |
| 1024 case CodecId::VP9: | |
| 1025 encoder_ = new VpxEncoder(codec_ == CodecId::VP9, | |
| 1026 on_encoded_video_callback_, bits_per_second_); | |
| 1027 break; | |
| 1028 default: | |
| 1029 NOTREACHED() << "Unsupported codec"; | |
| 1030 } | |
| 1031 } | |
| 1032 | |
| 1033 if (paused_before_init_) | |
| 1034 encoder_->SetPaused(paused_before_init_); | |
| 1035 | |
| 1036 // StartFrameEncode() will be called on Render IO thread. | |
| 1037 MediaStreamVideoSink::ConnectToTrack( | |
| 1038 track_, | |
| 1039 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | |
| 1040 false); | |
| 1041 } | |
| 1042 | |
| 997 } // namespace content | 1043 } // namespace content |
| OLD | NEW |