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/time/time.h" | 16 #include "base/time/time.h" |
| 16 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
| 17 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" | 18 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" |
| 18 #include "content/renderer/render_thread_impl.h" | 19 #include "content/renderer/render_thread_impl.h" |
| 19 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
| 20 #include "media/base/video_frame.h" | 21 #include "media/base/video_frame.h" |
| 21 #include "media/base/video_util.h" | 22 #include "media/base/video_util.h" |
| (...skipping 906 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 928 } | 929 } |
| 929 #endif //#if BUILDFLAG(RTC_USE_H264) | 930 #endif //#if BUILDFLAG(RTC_USE_H264) |
| 930 | 931 |
| 931 } // anonymous namespace | 932 } // anonymous namespace |
| 932 | 933 |
| 933 VideoTrackRecorder::VideoTrackRecorder( | 934 VideoTrackRecorder::VideoTrackRecorder( |
| 934 CodecId codec, | 935 CodecId codec, |
| 935 const blink::WebMediaStreamTrack& track, | 936 const blink::WebMediaStreamTrack& track, |
| 936 const OnEncodedVideoCB& on_encoded_video_callback, | 937 const OnEncodedVideoCB& on_encoded_video_callback, |
| 937 int32_t bits_per_second) | 938 int32_t bits_per_second) |
| 938 : track_(track) { | 939 : main_task_runner_(base::MessageLoop::current()->task_runner()), |
| 940 track_(track), | |
| 941 codec_(codec), | |
| 942 on_encoded_video_callback_(on_encoded_video_callback), | |
| 943 bits_per_second_(bits_per_second), | |
| 944 paused_before_init_(false), | |
| 945 weak_ptr_factory_(this) { | |
| 939 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 946 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 940 DCHECK(!track_.isNull()); | 947 DCHECK(!track_.isNull()); |
| 941 DCHECK(track_.getTrackData()); | 948 DCHECK(track_.getTrackData()); |
| 942 | 949 |
| 943 const auto& vea_supported_profile = CodecIdToVEAProfile(codec); | 950 // InitializeEncoder() will be called on Render IO thread. |
| 944 // TODO(emircan): Prioritize software based encoders in lower resolutions. | 951 // It is safe to use Unretained, because the class gets disconnected from |
| 945 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) { | 952 // track in dtor. |
| 946 encoder_ = new VEAEncoder(on_encoded_video_callback, bits_per_second, | |
| 947 vea_supported_profile); | |
| 948 } else { | |
| 949 switch (codec) { | |
| 950 #if BUILDFLAG(RTC_USE_H264) | |
| 951 case CodecId::H264: | |
| 952 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); | |
| 953 break; | |
| 954 #endif | |
| 955 case CodecId::VP8: | |
| 956 case CodecId::VP9: | |
| 957 encoder_ = new VpxEncoder(codec == CodecId::VP9, | |
| 958 on_encoded_video_callback, bits_per_second); | |
| 959 break; | |
| 960 default: | |
| 961 NOTREACHED() << "Unsupported codec"; | |
| 962 } | |
| 963 } | |
| 964 | |
| 965 // StartFrameEncode() will be called on Render IO thread. | |
| 966 MediaStreamVideoSink::ConnectToTrack( | 953 MediaStreamVideoSink::ConnectToTrack( |
| 967 track_, | 954 track_, base::Bind(&VideoTrackRecorder::InitializeEncoder, |
| 968 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | 955 base::Unretained(this)), |
| 969 false); | 956 false); |
| 970 } | 957 } |
| 971 | 958 |
| 972 VideoTrackRecorder::~VideoTrackRecorder() { | 959 VideoTrackRecorder::~VideoTrackRecorder() { |
| 973 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 960 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 974 MediaStreamVideoSink::DisconnectFromTrack(); | 961 MediaStreamVideoSink::DisconnectFromTrack(); |
| 975 track_.reset(); | 962 track_.reset(); |
| 976 } | 963 } |
| 977 | 964 |
| 978 void VideoTrackRecorder::Pause() { | 965 void VideoTrackRecorder::Pause() { |
| 979 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 966 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 980 DCHECK(encoder_); | 967 if (encoder_) |
| 981 encoder_->SetPaused(true); | 968 encoder_->SetPaused(true); |
| 969 else | |
| 970 paused_before_init_ = true; | |
| 982 } | 971 } |
| 983 | 972 |
| 984 void VideoTrackRecorder::Resume() { | 973 void VideoTrackRecorder::Resume() { |
| 985 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 974 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 986 DCHECK(encoder_); | 975 if (encoder_) |
| 987 encoder_->SetPaused(false); | 976 encoder_->SetPaused(false); |
| 977 else | |
| 978 paused_before_init_ = false; | |
| 988 } | 979 } |
| 989 | 980 |
| 990 void VideoTrackRecorder::OnVideoFrameForTesting( | 981 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 991 const scoped_refptr<media::VideoFrame>& frame, | 982 const scoped_refptr<media::VideoFrame>& frame, |
| 992 base::TimeTicks timestamp) { | 983 base::TimeTicks timestamp) { |
| 993 encoder_->StartFrameEncode(frame, timestamp); | 984 // We run on a single thread for tests. However, we still need to initialize |
| 985 // these variables for checks. | |
| 986 if (!origin_task_runner_.get()) | |
| 987 origin_task_runner_ = base::MessageLoop::current()->task_runner(); | |
| 988 | |
| 989 if (encoder_) | |
| 990 encoder_->StartFrameEncode(frame, timestamp); | |
| 991 else | |
| 992 InitializeEncoderTask(frame, timestamp, nullptr); | |
| 993 } | |
| 994 | |
| 995 void VideoTrackRecorder::InitializeEncoder( | |
| 996 const scoped_refptr<media::VideoFrame>& frame, | |
| 997 base::TimeTicks capture_time) { | |
| 998 if (!origin_task_runner_.get()) | |
| 999 origin_task_runner_ = base::MessageLoop::current()->task_runner(); | |
| 1000 DCHECK(origin_task_runner_->BelongsToCurrentThread()); | |
| 1001 | |
| 1002 if (!encoder_) { | |
| 1003 base::WaitableEvent initialization_waiter( | |
| 1004 base::WaitableEvent::ResetPolicy::MANUAL, | |
| 1005 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
| 1006 main_task_runner_->PostTask( | |
| 1007 FROM_HERE, base::Bind(&VideoTrackRecorder::InitializeEncoderTask, | |
| 1008 weak_ptr_factory_.GetWeakPtr(), frame, | |
| 1009 capture_time, &initialization_waiter)); | |
| 1010 initialization_waiter.Wait(); | |
| 1011 } else { | |
| 1012 encoder_->StartFrameEncode(frame, capture_time); | |
| 1013 } | |
|
mcasas
2016/06/12 08:56:34
Assuming you take in my suggestion before
using m
emircan
2016/06/13 19:55:40
I agree that it is the right model if we are using
mcasas
2016/06/23 00:27:36
Reluctantly, because is ugly, I admit that this
th
emircan
2016/06/28 22:10:41
Done.
| |
| 1014 } | |
| 1015 | |
| 1016 void VideoTrackRecorder::InitializeEncoderTask( | |
| 1017 const scoped_refptr<media::VideoFrame>& frame, | |
| 1018 base::TimeTicks capture_time, | |
| 1019 base::WaitableEvent* async_waiter) { | |
| 1020 DVLOG(3) << __FUNCTION__; | |
| 1021 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | |
| 1022 | |
| 1023 MediaStreamVideoSink::DisconnectFromTrack(); | |
| 1024 | |
| 1025 const gfx::Size& input_size = frame->visible_rect().size(); | |
| 1026 const auto& vea_supported_profile = CodecIdToVEAProfile(codec_); | |
| 1027 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN && | |
| 1028 input_size.width() >= kVEAEncoderMinResolutionWidth && | |
| 1029 input_size.height() >= kVEAEncoderMinResolutionHeight) { | |
| 1030 encoder_ = new VEAEncoder(on_encoded_video_callback_, bits_per_second_, | |
| 1031 vea_supported_profile); | |
| 1032 } else { | |
| 1033 switch (codec_) { | |
| 1034 #if BUILDFLAG(RTC_USE_H264) | |
| 1035 case CodecId::H264: | |
| 1036 encoder_ = | |
| 1037 new H264Encoder(on_encoded_video_callback_, bits_per_second_); | |
| 1038 break; | |
| 1039 #endif | |
| 1040 case CodecId::VP8: | |
| 1041 case CodecId::VP9: | |
| 1042 encoder_ = new VpxEncoder(codec_ == CodecId::VP9, | |
| 1043 on_encoded_video_callback_, bits_per_second_); | |
| 1044 break; | |
| 1045 default: | |
| 1046 NOTREACHED() << "Unsupported codec"; | |
| 1047 } | |
| 1048 } | |
| 1049 | |
| 1050 if (paused_before_init_) { | |
| 1051 encoder_->SetPaused(paused_before_init_); | |
| 1052 } else { | |
| 1053 // Send the first frame for encode on Render IO thread. | |
| 1054 origin_task_runner_->PostTask( | |
| 1055 FROM_HERE, base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, | |
| 1056 encoder_, frame, capture_time)); | |
| 1057 } | |
| 1058 | |
| 1059 // StartFrameEncode() will be called on Render IO thread. | |
|
mcasas
2016/06/23 00:27:36
nit: s/on Render IO/on |origin_task_runner_|/
| |
| 1060 MediaStreamVideoSink::ConnectToTrack( | |
| 1061 track_, | |
| 1062 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | |
| 1063 false); | |
| 1064 | |
| 1065 if (async_waiter) | |
| 1066 async_waiter->Signal(); | |
| 994 } | 1067 } |
| 995 | 1068 |
| 996 } // namespace content | 1069 } // namespace content |
| OLD | NEW |