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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/sys_info.h" | 9 #include "base/sys_info.h" |
| 10 #include "base/threading/thread.h" | 10 #include "base/threading/thread.h" |
| 11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
| 12 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 13 #include "content/child/child_process.h" | |
| 14 #include "media/base/bind_to_current_loop.h" | |
| 15 #include "media/base/video_frame.h" | 13 #include "media/base/video_frame.h" |
| 16 | 14 |
| 17 extern "C" { | 15 extern "C" { |
| 18 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide | 16 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide |
| 19 // backwards compatibility for legacy applications using the library. | 17 // backwards compatibility for legacy applications using the library. |
| 20 #define VPX_CODEC_DISABLE_COMPAT 1 | 18 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 21 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" | 19 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" |
| 22 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" | 20 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" |
| 23 } | 21 } |
| 24 | 22 |
| 25 using media::VideoFrame; | 23 using media::VideoFrame; |
| 26 using media::VideoFrameMetadata; | 24 using media::VideoFrameMetadata; |
| 27 | 25 |
| 28 namespace content { | 26 namespace content { |
| 29 | 27 |
| 30 namespace { | 28 namespace { |
| 29 | |
| 31 const vpx_codec_flags_t kNoFlags = 0; | 30 const vpx_codec_flags_t kNoFlags = 0; |
| 32 | 31 |
| 32 // Originally from remoting/codec/scoped_vpx_codec.h. | |
| 33 // TODO(mcasas): Refactor into a common location. | |
| 34 struct VpxCodecDeleter { | |
| 35 void operator()(vpx_codec_ctx_t* codec) { | |
| 36 if (!codec) | |
| 37 return; | |
| 38 vpx_codec_err_t ret = vpx_codec_destroy(codec); | |
| 39 CHECK_EQ(ret, VPX_CODEC_OK) << "Failed to destroy codec"; | |
|
miu
2015/09/02 21:28:13
nit: No need for the logging string.
mcasas
2015/09/04 02:16:30
Done.
| |
| 40 delete codec; | |
| 41 } | |
| 42 }; | |
| 43 | |
| 44 typedef scoped_ptr<vpx_codec_ctx_t, VpxCodecDeleter> ScopedVpxCodec; | |
| 45 | |
| 33 void OnFrameEncodeCompleted( | 46 void OnFrameEncodeCompleted( |
| 34 const content::VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_cb, | 47 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_cb, |
| 35 const scoped_refptr<VideoFrame>& frame, | 48 const scoped_refptr<VideoFrame>& frame, |
| 36 scoped_ptr<std::string> data, | 49 scoped_ptr<std::string> data, |
| 37 base::TimeTicks capture_timestamp, | 50 base::TimeTicks capture_timestamp, |
| 38 bool keyframe) { | 51 bool keyframe) { |
| 39 DVLOG(1) << (keyframe ? "" : "non ") << "keyframe " | 52 DVLOG(1) << (keyframe ? "" : "non ") << "keyframe "<< data->length() << "B, " |
| 40 << capture_timestamp << " ms - " << data->length() << "B "; | 53 << capture_timestamp << " ms"; |
| 41 on_encoded_video_cb.Run(frame, base::StringPiece(*data), capture_timestamp, | 54 on_encoded_video_cb.Run(frame, base::StringPiece(*data), capture_timestamp, |
| 42 keyframe); | 55 keyframe); |
| 43 } | 56 } |
| 44 | 57 |
| 45 } // anonymous namespace | 58 } // anonymous namespace |
| 46 | 59 |
| 47 // Inner class encapsulating all libvpx interactions and the encoding+delivery | 60 // Inner class encapsulating all libvpx interactions and the encoding+delivery |
| 48 // of received frames. This class is: | 61 // of received frames. Limitation: Only VP8 is supported for the time being. |
| 49 // - created and destroyed on its parent's thread (usually the main render | 62 // This class needs to be ref-counted to avoid destruction (of |encoder_| in |
| 50 // thread), | 63 // particular) while there's still a frame being processed in either IO or |
| 51 // - receives VideoFrames and Run()s the callbacks on another thread (supposedly | 64 // encode threads. This class: |
| 52 // the render IO thread), which is cached on first frame arrival, | 65 // - is created and destroyed on its parent's thread, usually the main Render |
| 66 // thread; | |
| 67 // - receives VideoFrames and Run()s the callbacks on |origin_task_runner_|, | |
| 68 // which is cached on first frame arrival, usually this thread is to be the | |
| 69 // render IO thread, but this is not enforced; | |
| 53 // - uses an internal |encoding_thread_| for libvpx interactions, notably for | 70 // - uses an internal |encoding_thread_| for libvpx interactions, notably for |
| 54 // encoding (which might take some time). | 71 // encoding (which might take some time). |
| 55 // Only VP8 is supported for the time being. | 72 class VideoTrackRecorder::VpxEncoder final |
| 56 class VideoTrackRecorder::VpxEncoder final { | 73 : public base::RefCountedThreadSafe<VpxEncoder> { |
| 57 public: | 74 public: |
| 58 explicit VpxEncoder(const OnEncodedVideoCB& on_encoded_video_callback); | 75 explicit VpxEncoder(const OnEncodedVideoCB& on_encoded_video_callback); |
| 59 ~VpxEncoder(); | |
| 60 | 76 |
| 61 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, | 77 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, |
| 62 base::TimeTicks capture_timestamp); | 78 base::TimeTicks capture_timestamp); |
| 63 | 79 |
| 64 private: | 80 private: |
| 81 friend class base::RefCountedThreadSafe<VpxEncoder>; | |
| 82 ~VpxEncoder(); | |
| 83 | |
| 65 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, | 84 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, |
| 66 base::TimeTicks capture_timestamp); | 85 base::TimeTicks capture_timestamp); |
| 67 | 86 |
| 68 void ConfigureVp8Encoding(const gfx::Size& size); | 87 void ConfigureVp8Encoding(const gfx::Size& size); |
| 69 | 88 |
| 70 // Returns true if |codec_config_| has been filled in at least once. | 89 // Returns true if |codec_config_| has been filled in at least once. |
| 71 bool IsInitialized() const; | 90 bool IsInitialized() const; |
| 72 | 91 |
| 73 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. | 92 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. |
| 74 base::TimeDelta CalculateFrameDuration( | 93 base::TimeDelta CalculateFrameDuration( |
| 75 const scoped_refptr<VideoFrame>& frame); | 94 const scoped_refptr<VideoFrame>& frame); |
| 76 | 95 |
| 77 // Used to check that we are destroyed on the same thread we were created. | 96 // Used to check that we are destroyed on the same thread we were created. |
| 78 base::ThreadChecker main_render_thread_checker_; | 97 base::ThreadChecker main_render_thread_checker_; |
| 79 | 98 |
| 80 // Task runner where frames to encode and reply callbacks must happen. | 99 // Task runner where frames to encode and reply callbacks must happen. |
| 81 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; | 100 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; |
| 82 | 101 |
| 83 // This callback should be exercised on IO thread. | 102 // This callback should be exercised on IO thread. |
| 84 const OnEncodedVideoCB on_encoded_video_callback_; | 103 const OnEncodedVideoCB on_encoded_video_callback_; |
| 85 | 104 |
| 86 // Thread for encoding. Active as long as VpxEncoder exists. All variables | 105 // Thread for encoding. Active as long as VpxEncoder exists. All variables |
| 87 // below this are used in this thread. | 106 // below this are used in this thread. |
| 88 base::Thread encoding_thread_; | 107 base::Thread encoding_thread_; |
| 89 // VP8 internal objects: configuration, encoder and Vpx Image wrapper. | 108 // VP8 internal objects: configuration and encoder. |
| 90 vpx_codec_enc_cfg_t codec_config_; | 109 vpx_codec_enc_cfg_t codec_config_; |
| 91 vpx_codec_ctx_t encoder_; | 110 // |encoder_| is a special scoped pointer to guarantee proper destruction. |
| 111 ScopedVpxCodec encoder_; | |
| 92 | 112 |
| 93 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to | 113 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to |
| 94 // predict the duration of the next frame. | 114 // predict the duration of the next frame. |
| 95 base::TimeDelta last_frame_timestamp_; | 115 base::TimeDelta last_frame_timestamp_; |
| 96 | 116 |
| 97 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); | 117 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); |
| 98 }; | 118 }; |
| 99 | 119 |
| 100 VideoTrackRecorder::VpxEncoder::VpxEncoder( | 120 VideoTrackRecorder::VpxEncoder::VpxEncoder( |
| 101 const OnEncodedVideoCB& on_encoded_video_callback) | 121 const OnEncodedVideoCB& on_encoded_video_callback) |
| 102 : on_encoded_video_callback_(on_encoded_video_callback), | 122 : on_encoded_video_callback_(on_encoded_video_callback), |
| 103 encoding_thread_("EncodingThread") { | 123 encoding_thread_("EncodingThread") { |
| 104 DCHECK(!on_encoded_video_callback_.is_null()); | 124 DCHECK(!on_encoded_video_callback_.is_null()); |
| 105 | 125 |
| 106 codec_config_.g_timebase.den = 0; // Not initialized. | 126 codec_config_.g_timebase.den = 0; // Not initialized. |
| 107 | 127 |
| 108 DCHECK(!encoding_thread_.IsRunning()); | 128 DCHECK(!encoding_thread_.IsRunning()); |
| 109 encoding_thread_.Start(); | 129 encoding_thread_.Start(); |
| 110 } | 130 } |
| 111 | 131 |
| 112 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { | 132 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { |
| 113 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 133 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
|
miu
2015/09/02 21:28:13
Because this is now ref-counted, there is no guara
mcasas
2015/09/04 02:16:30
You're right.
I've checked other MediaStreamVideo
miu
2015/09/04 21:48:52
Seem to me that you can write a dtor that is able
mcasas
2015/09/05 02:43:01
Done.
| |
| 114 DCHECK(encoding_thread_.IsRunning()); | 134 DCHECK(encoding_thread_.IsRunning()); |
| 115 encoding_thread_.Stop(); | 135 encoding_thread_.Stop(); |
| 116 vpx_codec_destroy(&encoder_); | |
| 117 } | 136 } |
| 118 | 137 |
| 119 void VideoTrackRecorder::VpxEncoder::StartFrameEncode( | 138 void VideoTrackRecorder::VpxEncoder::StartFrameEncode( |
| 120 const scoped_refptr<VideoFrame>& frame, | 139 const scoped_refptr<VideoFrame>& frame, |
| 121 base::TimeTicks capture_timestamp) { | 140 base::TimeTicks capture_timestamp) { |
| 122 // Cache the thread sending frames on first frame arrival. | 141 // Cache the thread sending frames on first frame arrival. |
| 123 if (!origin_task_runner_.get()) | 142 if (!origin_task_runner_.get()) |
| 124 origin_task_runner_ = base::MessageLoop::current()->task_runner(); | 143 origin_task_runner_ = base::MessageLoop::current()->task_runner(); |
| 125 DCHECK(origin_task_runner_->BelongsToCurrentThread()); | 144 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
| 126 | 145 |
| 127 encoding_thread_.task_runner()->PostTask( | 146 encoding_thread_.task_runner()->PostTask( |
| 128 FROM_HERE, base::Bind(&VpxEncoder::EncodeOnEncodingThread, | 147 FROM_HERE, base::Bind(&VpxEncoder::EncodeOnEncodingThread, |
| 129 base::Unretained(this), frame, capture_timestamp)); | 148 this, frame, capture_timestamp)); |
| 130 } | 149 } |
| 131 | 150 |
| 132 void VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread( | 151 void VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread( |
| 133 const scoped_refptr<VideoFrame>& frame, | 152 const scoped_refptr<VideoFrame>& frame, |
| 134 base::TimeTicks capture_timestamp) { | 153 base::TimeTicks capture_timestamp) { |
| 135 TRACE_EVENT0("video", | 154 TRACE_EVENT0("video", |
| 136 "VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread"); | 155 "VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread"); |
| 137 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); | 156 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); |
| 138 | 157 |
| 139 const gfx::Size frame_size = frame->visible_rect().size(); | 158 const gfx::Size frame_size = frame->visible_rect().size(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 154 vpx_image.planes[VPX_PLANE_U] = frame->visible_data(VideoFrame::kUPlane); | 173 vpx_image.planes[VPX_PLANE_U] = frame->visible_data(VideoFrame::kUPlane); |
| 155 vpx_image.planes[VPX_PLANE_V] = frame->visible_data(VideoFrame::kVPlane); | 174 vpx_image.planes[VPX_PLANE_V] = frame->visible_data(VideoFrame::kVPlane); |
| 156 vpx_image.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane); | 175 vpx_image.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane); |
| 157 vpx_image.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUPlane); | 176 vpx_image.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUPlane); |
| 158 vpx_image.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kVPlane); | 177 vpx_image.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kVPlane); |
| 159 | 178 |
| 160 const base::TimeDelta duration = CalculateFrameDuration(frame); | 179 const base::TimeDelta duration = CalculateFrameDuration(frame); |
| 161 // Encode the frame. The presentation time stamp argument here is fixed to | 180 // Encode the frame. The presentation time stamp argument here is fixed to |
| 162 // zero to force the encoder to base its single-frame bandwidth calculations | 181 // zero to force the encoder to base its single-frame bandwidth calculations |
| 163 // entirely on |predicted_frame_duration|. | 182 // entirely on |predicted_frame_duration|. |
| 164 const vpx_codec_err_t ret = vpx_codec_encode(&encoder_, | 183 const vpx_codec_err_t ret = vpx_codec_encode(encoder_.get(), |
| 165 &vpx_image, | 184 &vpx_image, |
| 166 0 /* pts */, | 185 0 /* pts */, |
| 167 duration.InMicroseconds(), | 186 duration.InMicroseconds(), |
| 168 kNoFlags, | 187 kNoFlags, |
| 169 VPX_DL_REALTIME); | 188 VPX_DL_REALTIME); |
| 170 DCHECK_EQ(ret, VPX_CODEC_OK) << vpx_codec_err_to_string(ret) << ", #" | 189 DCHECK_EQ(ret, VPX_CODEC_OK) << vpx_codec_err_to_string(ret) << ", #" |
| 171 << vpx_codec_error(&encoder_) << " -" | 190 << vpx_codec_error(encoder_.get()) << " -" |
| 172 << vpx_codec_error_detail(&encoder_); | 191 << vpx_codec_error_detail(encoder_.get()); |
| 173 | 192 |
| 174 scoped_ptr<std::string> data(new std::string); | 193 scoped_ptr<std::string> data(new std::string); |
| 175 bool keyframe = false; | 194 bool keyframe = false; |
| 176 vpx_codec_iter_t iter = NULL; | 195 vpx_codec_iter_t iter = NULL; |
| 177 const vpx_codec_cx_pkt_t* pkt = NULL; | 196 const vpx_codec_cx_pkt_t* pkt = NULL; |
| 178 while ((pkt = vpx_codec_get_cx_data(&encoder_, &iter)) != NULL) { | 197 while ((pkt = vpx_codec_get_cx_data(encoder_.get(), &iter)) != NULL) { |
| 179 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) | 198 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) |
| 180 continue; | 199 continue; |
| 181 data->assign(static_cast<char*>(pkt->data.frame.buf), pkt->data.frame.sz); | 200 data->assign(static_cast<char*>(pkt->data.frame.buf), pkt->data.frame.sz); |
| 182 keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; | 201 keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; |
| 183 break; | 202 break; |
| 184 } | 203 } |
| 185 origin_task_runner_->PostTask(FROM_HERE, | 204 origin_task_runner_->PostTask(FROM_HERE, |
| 186 base::Bind(&OnFrameEncodeCompleted, | 205 base::Bind(OnFrameEncodeCompleted, |
| 187 on_encoded_video_callback_, | 206 on_encoded_video_callback_, |
| 188 frame, | 207 frame, |
| 189 base::Passed(&data), | 208 base::Passed(&data), |
| 190 capture_timestamp, | 209 capture_timestamp, |
| 191 keyframe)); | 210 keyframe)); |
| 192 } | 211 } |
| 193 | 212 |
| 194 void VideoTrackRecorder::VpxEncoder::ConfigureVp8Encoding( | 213 void VideoTrackRecorder::VpxEncoder::ConfigureVp8Encoding( |
| 195 const gfx::Size& size) { | 214 const gfx::Size& size) { |
| 196 if (IsInitialized()) { | 215 if (IsInitialized()) { |
| 197 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less- | 216 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less- |
| 198 // than-or-equal than the old size, in terms of area, the existing encoder | 217 // than-or-equal than the old size, in terms of area, the existing encoder |
| 199 // instance could be reused after changing |codec_config_.{g_w,g_h}|. | 218 // instance could be reused after changing |codec_config_.{g_w,g_h}|. |
| 200 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: " | 219 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: " |
| 201 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString() | 220 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString() |
| 202 << " --> " << size.ToString(); | 221 << " --> " << size.ToString(); |
| 203 vpx_codec_destroy(&encoder_); | 222 encoder_.reset(); |
| 204 } | 223 } |
| 205 | 224 |
| 206 const vpx_codec_iface_t* interface = vpx_codec_vp8_cx(); | 225 const vpx_codec_iface_t* interface = vpx_codec_vp8_cx(); |
| 207 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, | 226 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, |
| 208 &codec_config_, | 227 &codec_config_, |
| 209 0 /* reserved */); | 228 0 /* reserved */); |
| 210 DCHECK_EQ(VPX_CODEC_OK, result); | 229 DCHECK_EQ(VPX_CODEC_OK, result); |
| 211 | 230 |
| 212 // Adjust default bit rate to account for the actual size. | 231 // Adjust default bit rate to account for the actual size. |
| 213 DCHECK_EQ(320u, codec_config_.g_w); | 232 DCHECK_EQ(320u, codec_config_.g_w); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 239 | 258 |
| 240 // Do not saturate CPU utilization just for encoding. On a lower-end system | 259 // Do not saturate CPU utilization just for encoding. On a lower-end system |
| 241 // with only 1 or 2 cores, use only one thread for encoding. On systems with | 260 // with only 1 or 2 cores, use only one thread for encoding. On systems with |
| 242 // more cores, allow half of the cores to be used for encoding. | 261 // more cores, allow half of the cores to be used for encoding. |
| 243 codec_config_.g_threads = | 262 codec_config_.g_threads = |
| 244 std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); | 263 std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); |
| 245 | 264 |
| 246 // Number of frames to consume before producing output. | 265 // Number of frames to consume before producing output. |
| 247 codec_config_.g_lag_in_frames = 0; | 266 codec_config_.g_lag_in_frames = 0; |
| 248 | 267 |
| 249 const vpx_codec_err_t ret = vpx_codec_enc_init(&encoder_, interface, | 268 DCHECK(!encoder_); |
| 269 encoder_.reset(new vpx_codec_ctx_t); | |
|
miu
2015/09/02 21:28:13
Why did you change this to a custom scoped ptr? I
mcasas
2015/09/04 02:16:30
Is due to the possible case of ctor() + dtor() wit
miu
2015/09/04 21:48:52
But you have IsInitialized() to tell you whether y
mcasas
2015/09/05 02:43:01
Acknowledged.
| |
| 270 const vpx_codec_err_t ret = vpx_codec_enc_init(encoder_.get(), interface, | |
| 250 &codec_config_, kNoFlags); | 271 &codec_config_, kNoFlags); |
| 251 DCHECK_EQ(VPX_CODEC_OK, ret); | 272 DCHECK_EQ(VPX_CODEC_OK, ret); |
| 252 } | 273 } |
| 253 | 274 |
| 254 bool VideoTrackRecorder::VpxEncoder::IsInitialized() const { | 275 bool VideoTrackRecorder::VpxEncoder::IsInitialized() const { |
| 255 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); | 276 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); |
| 256 return codec_config_.g_timebase.den != 0; | 277 return codec_config_.g_timebase.den != 0; |
| 257 } | 278 } |
| 258 | 279 |
| 259 base::TimeDelta VideoTrackRecorder::VpxEncoder::CalculateFrameDuration( | 280 base::TimeDelta VideoTrackRecorder::VpxEncoder::CalculateFrameDuration( |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 278 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); | 299 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); |
| 279 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); | 300 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); |
| 280 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, | 301 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, |
| 281 kMinFrameDuration)); | 302 kMinFrameDuration)); |
| 282 } | 303 } |
| 283 | 304 |
| 284 VideoTrackRecorder::VideoTrackRecorder( | 305 VideoTrackRecorder::VideoTrackRecorder( |
| 285 const blink::WebMediaStreamTrack& track, | 306 const blink::WebMediaStreamTrack& track, |
| 286 const OnEncodedVideoCB& on_encoded_video_callback) | 307 const OnEncodedVideoCB& on_encoded_video_callback) |
| 287 : track_(track), | 308 : track_(track), |
| 288 encoder_(new VpxEncoder(on_encoded_video_callback)), | 309 encoder_(new VpxEncoder(on_encoded_video_callback)) { |
| 289 weak_factory_(this) { | |
| 290 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 310 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 291 DCHECK(!track_.isNull()); | 311 DCHECK(!track_.isNull()); |
| 292 DCHECK(track.extraData()); | 312 DCHECK(track.extraData()); |
| 313 | |
| 314 // StartFrameEncode() will be called on Render IO thread. | |
| 293 AddToVideoTrack(this, | 315 AddToVideoTrack(this, |
| 294 media::BindToCurrentLoop( | 316 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode, |
| 295 base::Bind(&VideoTrackRecorder::OnVideoFrame, | 317 encoder_), |
| 296 weak_factory_.GetWeakPtr())), | |
| 297 track_); | 318 track_); |
| 298 } | 319 } |
| 299 | 320 |
| 300 VideoTrackRecorder::~VideoTrackRecorder() { | 321 VideoTrackRecorder::~VideoTrackRecorder() { |
| 301 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 322 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 302 RemoveFromVideoTrack(this, track_); | 323 RemoveFromVideoTrack(this, track_); |
| 303 weak_factory_.InvalidateWeakPtrs(); | |
| 304 track_.reset(); | 324 track_.reset(); |
| 305 } | 325 } |
| 306 | 326 |
| 307 void VideoTrackRecorder::OnVideoFrame(const scoped_refptr<VideoFrame>& frame, | 327 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 308 base::TimeTicks timestamp) { | 328 const scoped_refptr<media::VideoFrame>& frame, |
| 309 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 329 base::TimeTicks timestamp) { |
| 310 encoder_->StartFrameEncode(frame, timestamp); | 330 encoder_->StartFrameEncode(frame, timestamp); |
| 311 } | 331 } |
| 312 | 332 |
| 313 } // namespace content | 333 } // namespace content |
| OLD | NEW |