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" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/synchronization/waitable_event.h" | |
| 12 #include "base/sys_info.h" | 13 #include "base/sys_info.h" |
| 13 #include "base/task_runner_util.h" | 14 #include "base/task_runner_util.h" |
| 14 #include "base/threading/thread.h" | 15 #include "base/threading/thread.h" |
| 15 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 17 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
| 18 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" | 19 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" |
| 19 #include "content/renderer/render_thread_impl.h" | 20 #include "content/renderer/render_thread_impl.h" |
| 20 #include "media/base/bind_to_current_loop.h" | 21 #include "media/base/bind_to_current_loop.h" |
| 21 #include "media/base/video_frame.h" | 22 #include "media/base/video_frame.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 64 media::H264PROFILE_MAX}}; | 65 media::H264PROFILE_MAX}}; |
| 65 | 66 |
| 66 // Returns the corresponding codec profile from VEA supported codecs. If no | 67 // Returns the corresponding codec profile from VEA supported codecs. If no |
| 67 // profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN. | 68 // profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN. |
| 68 media::VideoCodecProfile CodecIdToVEAProfile( | 69 media::VideoCodecProfile CodecIdToVEAProfile( |
| 69 content::VideoTrackRecorder::CodecId codec) { | 70 content::VideoTrackRecorder::CodecId codec) { |
| 70 // See https://crbug.com/616659. | 71 // See https://crbug.com/616659. |
| 71 #if defined(OS_CHROMEOS) | 72 #if defined(OS_CHROMEOS) |
| 72 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 73 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 73 #endif // defined(OS_CHROMEOS) | 74 #endif // defined(OS_CHROMEOS) |
| 74 content::RenderThreadImpl* render_thread_impl = | 75 content::RenderThreadImpl* const render_thread_impl = |
| 75 content::RenderThreadImpl::current(); | 76 content::RenderThreadImpl::current(); |
| 76 if (!render_thread_impl) | 77 if (!render_thread_impl) { |
| 78 DVLOG(3) << "Couldn't access the render thread"; | |
| 77 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 79 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 80 } | |
| 78 | 81 |
| 79 media::GpuVideoAcceleratorFactories* gpu_factories = | 82 media::GpuVideoAcceleratorFactories* const gpu_factories = |
| 80 content::RenderThreadImpl::current()->GetGpuFactories(); | 83 render_thread_impl->GetGpuFactories(); |
| 81 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { | 84 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { |
| 82 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; | 85 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; |
| 83 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 86 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 84 } | 87 } |
| 85 | 88 |
| 86 const media::VideoEncodeAccelerator::SupportedProfiles& vea_profiles = | 89 const media::VideoEncodeAccelerator::SupportedProfiles& vea_profiles = |
| 87 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); | 90 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); |
| 88 for (const auto& vea_profile : vea_profiles) { | 91 for (const auto& vea_profile : vea_profiles) { |
| 89 for (const auto& supported_profile : kSupportedVideoCodecIdToProfile) { | 92 for (const auto& supported_profile : kSupportedVideoCodecIdToProfile) { |
| 90 if (codec == supported_profile.codec_id && | 93 if (codec == supported_profile.codec_id && |
| (...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 929 } | 932 } |
| 930 #endif //#if BUILDFLAG(RTC_USE_H264) | 933 #endif //#if BUILDFLAG(RTC_USE_H264) |
| 931 | 934 |
| 932 } // anonymous namespace | 935 } // anonymous namespace |
| 933 | 936 |
| 934 VideoTrackRecorder::VideoTrackRecorder( | 937 VideoTrackRecorder::VideoTrackRecorder( |
| 935 CodecId codec, | 938 CodecId codec, |
| 936 const blink::WebMediaStreamTrack& track, | 939 const blink::WebMediaStreamTrack& track, |
| 937 const OnEncodedVideoCB& on_encoded_video_callback, | 940 const OnEncodedVideoCB& on_encoded_video_callback, |
| 938 int32_t bits_per_second) | 941 int32_t bits_per_second) |
| 939 : track_(track) { | 942 : main_task_runner_(base::MessageLoop::current()->task_runner()), |
| 943 track_(track), | |
| 944 codec_(codec), | |
| 945 on_encoded_video_callback_(on_encoded_video_callback), | |
| 946 bits_per_second_(bits_per_second), | |
| 947 paused_before_init_(false), | |
| 948 weak_ptr_factory_(this) { | |
| 940 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 949 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 941 DCHECK(!track_.isNull()); | 950 DCHECK(!track_.isNull()); |
| 942 DCHECK(track_.getTrackData()); | 951 DCHECK(track_.getTrackData()); |
| 943 | 952 |
| 944 const auto& vea_supported_profile = CodecIdToVEAProfile(codec); | 953 // ReceiveFirstFrameOnIOThread() will be called on Render IO thread. |
| 945 // TODO(emircan): Prioritize software based encoders in lower resolutions. | 954 // It is safe to use Unretained, because the class gets disconnected from |
| 946 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) { | 955 // 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( | 956 MediaStreamVideoSink::ConnectToTrack( |
| 968 track_, | 957 track_, base::Bind(&VideoTrackRecorder::ReceiveFirstFrameOnIOThread, |
| 969 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | 958 base::Unretained(this)), |
| 970 false); | 959 false); |
| 971 } | 960 } |
| 972 | 961 |
| 973 VideoTrackRecorder::~VideoTrackRecorder() { | 962 VideoTrackRecorder::~VideoTrackRecorder() { |
| 974 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 963 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 975 MediaStreamVideoSink::DisconnectFromTrack(); | 964 MediaStreamVideoSink::DisconnectFromTrack(); |
| 976 track_.reset(); | 965 track_.reset(); |
| 977 } | 966 } |
| 978 | 967 |
| 979 void VideoTrackRecorder::Pause() { | 968 void VideoTrackRecorder::Pause() { |
| 980 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 969 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 981 DCHECK(encoder_); | 970 if (encoder_) |
| 982 encoder_->SetPaused(true); | 971 encoder_->SetPaused(true); |
| 972 else | |
| 973 paused_before_init_ = true; | |
| 983 } | 974 } |
| 984 | 975 |
| 985 void VideoTrackRecorder::Resume() { | 976 void VideoTrackRecorder::Resume() { |
| 986 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 977 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 987 DCHECK(encoder_); | 978 if (encoder_) |
| 988 encoder_->SetPaused(false); | 979 encoder_->SetPaused(false); |
| 980 else | |
| 981 paused_before_init_ = false; | |
| 989 } | 982 } |
| 990 | 983 |
| 991 void VideoTrackRecorder::OnVideoFrameForTesting( | 984 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 992 const scoped_refptr<media::VideoFrame>& frame, | 985 const scoped_refptr<media::VideoFrame>& frame, |
| 993 base::TimeTicks timestamp) { | 986 base::TimeTicks timestamp) { |
| 994 encoder_->StartFrameEncode(frame, timestamp); | 987 DVLOG(3) << __FUNCTION__; |
| 988 // We run on a single thread for tests. However, we still need to initialize | |
| 989 // these variables for checks. | |
| 990 if (!origin_task_runner_.get()) | |
| 991 origin_task_runner_ = base::MessageLoop::current()->task_runner(); | |
| 992 | |
| 993 if (encoder_) | |
| 994 encoder_->StartFrameEncode(frame, timestamp); | |
| 995 else | |
| 996 InitializeEncoderOnMainThread(frame, timestamp, nullptr); | |
| 997 } | |
| 998 | |
| 999 void VideoTrackRecorder::ReceiveFirstFrameOnIOThread( | |
| 1000 const scoped_refptr<media::VideoFrame>& frame, | |
| 1001 base::TimeTicks capture_time) { | |
| 1002 DVLOG(3) << __FUNCTION__; | |
| 1003 if (!origin_task_runner_.get()) | |
| 1004 origin_task_runner_ = base::MessageLoop::current()->task_runner(); | |
| 1005 DCHECK(origin_task_runner_->BelongsToCurrentThread()); | |
| 1006 | |
| 1007 DCHECK(!encoder_); | |
| 1008 base::WaitableEvent initialization_waiter( | |
| 1009 base::WaitableEvent::ResetPolicy::MANUAL, | |
| 1010 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
| 1011 main_task_runner_->PostTask( | |
| 1012 FROM_HERE, base::Bind(&VideoTrackRecorder::InitializeEncoderOnMainThread, | |
| 1013 weak_ptr_factory_.GetWeakPtr(), frame, capture_time, | |
| 1014 &initialization_waiter)); | |
| 1015 initialization_waiter.Wait(); | |
| 1016 DCHECK(encoder_); | |
|
mcasas
2016/06/30 20:42:27
Keep this guy, right?
| |
| 1017 } | |
| 1018 | |
| 1019 void VideoTrackRecorder::InitializeEncoderOnMainThread( | |
| 1020 const scoped_refptr<media::VideoFrame>& frame, | |
| 1021 base::TimeTicks capture_time, | |
| 1022 base::WaitableEvent* async_waiter) { | |
| 1023 DVLOG(3) << __FUNCTION__ << frame->visible_rect().size().ToString(); | |
| 1024 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | |
| 1025 | |
| 1026 MediaStreamVideoSink::DisconnectFromTrack(); | |
| 1027 | |
| 1028 const gfx::Size& input_size = frame->visible_rect().size(); | |
| 1029 const auto& vea_supported_profile = CodecIdToVEAProfile(codec_); | |
| 1030 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN && | |
| 1031 input_size.width() >= kVEAEncoderMinResolutionWidth && | |
| 1032 input_size.height() >= kVEAEncoderMinResolutionHeight) { | |
| 1033 encoder_ = new VEAEncoder(on_encoded_video_callback_, bits_per_second_, | |
| 1034 vea_supported_profile); | |
| 1035 } else { | |
| 1036 switch (codec_) { | |
| 1037 #if BUILDFLAG(RTC_USE_H264) | |
| 1038 case CodecId::H264: | |
| 1039 encoder_ = | |
| 1040 new H264Encoder(on_encoded_video_callback_, bits_per_second_); | |
| 1041 break; | |
| 1042 #endif | |
| 1043 case CodecId::VP8: | |
| 1044 case CodecId::VP9: | |
| 1045 encoder_ = new VpxEncoder(codec_ == CodecId::VP9, | |
| 1046 on_encoded_video_callback_, bits_per_second_); | |
| 1047 break; | |
| 1048 default: | |
| 1049 NOTREACHED() << "Unsupported codec"; | |
| 1050 } | |
| 1051 } | |
| 1052 | |
| 1053 if (paused_before_init_) { | |
| 1054 encoder_->SetPaused(paused_before_init_); | |
| 1055 } else { | |
| 1056 // Send the first frame for encode on |origin_task_runner_|. | |
| 1057 origin_task_runner_->PostTask( | |
| 1058 FROM_HERE, base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, | |
| 1059 encoder_, frame, capture_time)); | |
| 1060 } | |
| 1061 | |
| 1062 // StartFrameEncode() will be called on Render IO thread. | |
| 1063 MediaStreamVideoSink::ConnectToTrack( | |
| 1064 track_, | |
| 1065 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | |
| 1066 false); | |
| 1067 | |
| 1068 if (async_waiter) | |
| 1069 async_waiter->Signal(); | |
| 995 } | 1070 } |
| 996 | 1071 |
| 997 } // namespace content | 1072 } // namespace content |
| OLD | NEW |