Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: content/renderer/media/video_track_recorder.cc

Issue 1313603004: MediaRecorderHandler (video part) and unittests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moved DCHECK_EQ() Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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);
40 delete codec;
41 }
42 };
43
44 typedef scoped_ptr<vpx_codec_ctx_t, VpxCodecDeleter> ScopedVpxCodecCtxPtr;
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 must be ref-counted because the MediaStreamVideoTrack will hold a
50 // thread), 63 // reference to it, via the callback MediaStreamVideoSink passes along, and it's
51 // - receives VideoFrames and Run()s the callbacks on another thread (supposedly 64 // unknown when exactly it will release that reference. 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, and is supposed to be the render IO
69 // 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:
75 static void ShutdownEncoder(scoped_ptr<base::Thread> encoding_thread,
76 ScopedVpxCodecCtxPtr encoder);
77
58 explicit VpxEncoder(const OnEncodedVideoCB& on_encoded_video_callback); 78 explicit VpxEncoder(const OnEncodedVideoCB& on_encoded_video_callback);
59 ~VpxEncoder();
60 79
61 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame, 80 void StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
62 base::TimeTicks capture_timestamp); 81 base::TimeTicks capture_timestamp);
63 82
64 private: 83 private:
84 friend class base::RefCountedThreadSafe<VpxEncoder>;
85 ~VpxEncoder();
86
65 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame, 87 void EncodeOnEncodingThread(const scoped_refptr<VideoFrame>& frame,
66 base::TimeTicks capture_timestamp); 88 base::TimeTicks capture_timestamp);
67 89
68 void ConfigureVp8Encoding(const gfx::Size& size); 90 void ConfigureVp8Encoding(const gfx::Size& size);
69 91
70 // Returns true if |codec_config_| has been filled in at least once. 92 // Returns true if |codec_config_| has been filled in at least once.
71 bool IsInitialized() const; 93 bool IsInitialized() const;
72 94
73 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. 95 // Estimate the frame duration from |frame| and |last_frame_timestamp_|.
74 base::TimeDelta CalculateFrameDuration( 96 base::TimeDelta CalculateFrameDuration(
75 const scoped_refptr<VideoFrame>& frame); 97 const scoped_refptr<VideoFrame>& frame);
76 98
77 // Used to check that we are destroyed on the same thread we were created. 99 // Used to shutdown properly on the same thread we were created.
78 base::ThreadChecker main_render_thread_checker_; 100 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
79 101
80 // Task runner where frames to encode and reply callbacks must happen. 102 // Task runner where frames to encode and reply callbacks must happen.
81 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; 103 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
82 104
83 // This callback should be exercised on IO thread. 105 // This callback should be exercised on IO thread.
84 const OnEncodedVideoCB on_encoded_video_callback_; 106 const OnEncodedVideoCB on_encoded_video_callback_;
85 107
86 // Thread for encoding. Active as long as VpxEncoder exists. All variables 108 // Thread for encoding. Active for the lifetime of VpxEncoder. All variables
87 // below this are used in this thread. 109 // below this are used in this thread.
88 base::Thread encoding_thread_; 110 scoped_ptr<base::Thread> encoding_thread_;
89 // VP8 internal objects: configuration, encoder and Vpx Image wrapper. 111 // VP8 internal objects: configuration and encoder.
90 vpx_codec_enc_cfg_t codec_config_; 112 vpx_codec_enc_cfg_t codec_config_;
91 vpx_codec_ctx_t encoder_; 113 // |encoder_| is a special scoped pointer to guarantee proper destruction.
114 // Again, it should only be accessed on |encoding_thread_|.
115 ScopedVpxCodecCtxPtr encoder_;
92 116
93 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to 117 // The |VideoFrame::timestamp()| of the last encoded frame. This is used to
94 // predict the duration of the next frame. 118 // predict the duration of the next frame.
95 base::TimeDelta last_frame_timestamp_; 119 base::TimeDelta last_frame_timestamp_;
96 120
97 DISALLOW_COPY_AND_ASSIGN(VpxEncoder); 121 DISALLOW_COPY_AND_ASSIGN(VpxEncoder);
98 }; 122 };
99 123
124 // static
125 void VideoTrackRecorder::VpxEncoder::ShutdownEncoder(
126 scoped_ptr<base::Thread> encoding_thread,
127 ScopedVpxCodecCtxPtr encoder) {
128 DCHECK(encoding_thread->IsRunning());
129 encoding_thread->Stop();
130 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope.
131 }
132
100 VideoTrackRecorder::VpxEncoder::VpxEncoder( 133 VideoTrackRecorder::VpxEncoder::VpxEncoder(
101 const OnEncodedVideoCB& on_encoded_video_callback) 134 const OnEncodedVideoCB& on_encoded_video_callback)
102 : on_encoded_video_callback_(on_encoded_video_callback), 135 : main_task_runner_(base::MessageLoop::current()->task_runner()),
103 encoding_thread_("EncodingThread") { 136 on_encoded_video_callback_(on_encoded_video_callback),
137 encoding_thread_(new base::Thread("EncodingThread")) {
104 DCHECK(!on_encoded_video_callback_.is_null()); 138 DCHECK(!on_encoded_video_callback_.is_null());
105 139
106 codec_config_.g_timebase.den = 0; // Not initialized. 140 codec_config_.g_timebase.den = 0; // Not initialized.
107 141
108 DCHECK(!encoding_thread_.IsRunning()); 142 DCHECK(!encoding_thread_->IsRunning());
109 encoding_thread_.Start(); 143 encoding_thread_->Start();
110 } 144 }
111 145
112 VideoTrackRecorder::VpxEncoder::~VpxEncoder() { 146 VideoTrackRecorder::VpxEncoder::~VpxEncoder() {
113 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 147 main_task_runner_->PostTask(FROM_HERE,
114 DCHECK(encoding_thread_.IsRunning()); 148 base::Bind(&VpxEncoder::ShutdownEncoder,
115 encoding_thread_.Stop(); 149 base::Passed(&encoding_thread_),
116 vpx_codec_destroy(&encoder_); 150 base::Passed(&encoder_)));
117 } 151 }
118 152
119 void VideoTrackRecorder::VpxEncoder::StartFrameEncode( 153 void VideoTrackRecorder::VpxEncoder::StartFrameEncode(
120 const scoped_refptr<VideoFrame>& frame, 154 const scoped_refptr<VideoFrame>& frame,
121 base::TimeTicks capture_timestamp) { 155 base::TimeTicks capture_timestamp) {
122 // Cache the thread sending frames on first frame arrival. 156 // Cache the thread sending frames on first frame arrival.
123 if (!origin_task_runner_.get()) 157 if (!origin_task_runner_.get())
124 origin_task_runner_ = base::MessageLoop::current()->task_runner(); 158 origin_task_runner_ = base::MessageLoop::current()->task_runner();
125 DCHECK(origin_task_runner_->BelongsToCurrentThread()); 159 DCHECK(origin_task_runner_->BelongsToCurrentThread());
126 160
127 encoding_thread_.task_runner()->PostTask( 161 encoding_thread_->task_runner()->PostTask(
128 FROM_HERE, base::Bind(&VpxEncoder::EncodeOnEncodingThread, 162 FROM_HERE, base::Bind(&VpxEncoder::EncodeOnEncodingThread,
129 base::Unretained(this), frame, capture_timestamp)); 163 this, frame, capture_timestamp));
130 } 164 }
131 165
132 void VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread( 166 void VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread(
133 const scoped_refptr<VideoFrame>& frame, 167 const scoped_refptr<VideoFrame>& frame,
134 base::TimeTicks capture_timestamp) { 168 base::TimeTicks capture_timestamp) {
135 TRACE_EVENT0("video", 169 TRACE_EVENT0("video",
136 "VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread"); 170 "VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread");
137 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); 171 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
138 172
139 const gfx::Size frame_size = frame->visible_rect().size(); 173 const gfx::Size frame_size = frame->visible_rect().size();
140 if (!IsInitialized() || 174 if (!IsInitialized() ||
141 gfx::Size(codec_config_.g_w, codec_config_.g_h) != frame_size) { 175 gfx::Size(codec_config_.g_w, codec_config_.g_h) != frame_size) {
142 ConfigureVp8Encoding(frame_size); 176 ConfigureVp8Encoding(frame_size);
143 } 177 }
144 178
145 vpx_image_t vpx_image; 179 vpx_image_t vpx_image;
146 vpx_image_t* const result = vpx_img_wrap(&vpx_image, 180 vpx_image_t* const result = vpx_img_wrap(&vpx_image,
147 VPX_IMG_FMT_I420, 181 VPX_IMG_FMT_I420,
148 frame_size.width(), 182 frame_size.width(),
149 frame_size.height(), 183 frame_size.height(),
150 1 /* align */, 184 1 /* align */,
151 frame->data(VideoFrame::kYPlane)); 185 frame->data(VideoFrame::kYPlane));
152 DCHECK_EQ(result, &vpx_image); 186 DCHECK_EQ(result, &vpx_image);
153 vpx_image.planes[VPX_PLANE_Y] = frame->visible_data(VideoFrame::kYPlane); 187 vpx_image.planes[VPX_PLANE_Y] = frame->visible_data(VideoFrame::kYPlane);
154 vpx_image.planes[VPX_PLANE_U] = frame->visible_data(VideoFrame::kUPlane); 188 vpx_image.planes[VPX_PLANE_U] = frame->visible_data(VideoFrame::kUPlane);
155 vpx_image.planes[VPX_PLANE_V] = frame->visible_data(VideoFrame::kVPlane); 189 vpx_image.planes[VPX_PLANE_V] = frame->visible_data(VideoFrame::kVPlane);
156 vpx_image.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane); 190 vpx_image.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane);
157 vpx_image.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUPlane); 191 vpx_image.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUPlane);
158 vpx_image.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kVPlane); 192 vpx_image.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kVPlane);
159 193
160 const base::TimeDelta duration = CalculateFrameDuration(frame); 194 const base::TimeDelta duration = CalculateFrameDuration(frame);
161 // Encode the frame. The presentation time stamp argument here is fixed to 195 // 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 196 // zero to force the encoder to base its single-frame bandwidth calculations
163 // entirely on |predicted_frame_duration|. 197 // entirely on |predicted_frame_duration|.
164 const vpx_codec_err_t ret = vpx_codec_encode(&encoder_, 198 const vpx_codec_err_t ret = vpx_codec_encode(encoder_.get(),
165 &vpx_image, 199 &vpx_image,
166 0 /* pts */, 200 0 /* pts */,
167 duration.InMicroseconds(), 201 duration.InMicroseconds(),
168 kNoFlags, 202 kNoFlags,
169 VPX_DL_REALTIME); 203 VPX_DL_REALTIME);
170 DCHECK_EQ(ret, VPX_CODEC_OK) << vpx_codec_err_to_string(ret) << ", #" 204 DCHECK_EQ(ret, VPX_CODEC_OK) << vpx_codec_err_to_string(ret) << ", #"
171 << vpx_codec_error(&encoder_) << " -" 205 << vpx_codec_error(encoder_.get()) << " -"
172 << vpx_codec_error_detail(&encoder_); 206 << vpx_codec_error_detail(encoder_.get());
173 207
174 scoped_ptr<std::string> data(new std::string); 208 scoped_ptr<std::string> data(new std::string);
175 bool keyframe = false; 209 bool keyframe = false;
176 vpx_codec_iter_t iter = NULL; 210 vpx_codec_iter_t iter = NULL;
177 const vpx_codec_cx_pkt_t* pkt = NULL; 211 const vpx_codec_cx_pkt_t* pkt = NULL;
178 while ((pkt = vpx_codec_get_cx_data(&encoder_, &iter)) != NULL) { 212 while ((pkt = vpx_codec_get_cx_data(encoder_.get(), &iter)) != NULL) {
179 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) 213 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
180 continue; 214 continue;
181 data->assign(static_cast<char*>(pkt->data.frame.buf), pkt->data.frame.sz); 215 data->assign(static_cast<char*>(pkt->data.frame.buf), pkt->data.frame.sz);
182 keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; 216 keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
183 break; 217 break;
184 } 218 }
185 origin_task_runner_->PostTask(FROM_HERE, 219 origin_task_runner_->PostTask(FROM_HERE,
186 base::Bind(&OnFrameEncodeCompleted, 220 base::Bind(OnFrameEncodeCompleted,
187 on_encoded_video_callback_, 221 on_encoded_video_callback_,
188 frame, 222 frame,
189 base::Passed(&data), 223 base::Passed(&data),
190 capture_timestamp, 224 capture_timestamp,
191 keyframe)); 225 keyframe));
192 } 226 }
193 227
194 void VideoTrackRecorder::VpxEncoder::ConfigureVp8Encoding( 228 void VideoTrackRecorder::VpxEncoder::ConfigureVp8Encoding(
195 const gfx::Size& size) { 229 const gfx::Size& size) {
196 if (IsInitialized()) { 230 if (IsInitialized()) {
197 // TODO(mcasas) VP8 quirk/optimisation: If the new |size| is strictly less- 231 // 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 232 // 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}|. 233 // instance could be reused after changing |codec_config_.{g_w,g_h}|.
200 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: " 234 DVLOG(1) << "Destroying/Re-Creating encoder for new frame size: "
201 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString() 235 << gfx::Size(codec_config_.g_w, codec_config_.g_h).ToString()
202 << " --> " << size.ToString(); 236 << " --> " << size.ToString();
203 vpx_codec_destroy(&encoder_); 237 encoder_.reset();
204 } 238 }
205 239
206 const vpx_codec_iface_t* interface = vpx_codec_vp8_cx(); 240 const vpx_codec_iface_t* interface = vpx_codec_vp8_cx();
207 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface, 241 const vpx_codec_err_t result = vpx_codec_enc_config_default(interface,
208 &codec_config_, 242 &codec_config_,
209 0 /* reserved */); 243 0 /* reserved */);
210 DCHECK_EQ(VPX_CODEC_OK, result); 244 DCHECK_EQ(VPX_CODEC_OK, result);
211 245
212 // Adjust default bit rate to account for the actual size. 246 // Adjust default bit rate to account for the actual size.
213 DCHECK_EQ(320u, codec_config_.g_w); 247 DCHECK_EQ(320u, codec_config_.g_w);
(...skipping 25 matching lines...) Expand all
239 273
240 // Do not saturate CPU utilization just for encoding. On a lower-end system 274 // 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 275 // 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. 276 // more cores, allow half of the cores to be used for encoding.
243 codec_config_.g_threads = 277 codec_config_.g_threads =
244 std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); 278 std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2);
245 279
246 // Number of frames to consume before producing output. 280 // Number of frames to consume before producing output.
247 codec_config_.g_lag_in_frames = 0; 281 codec_config_.g_lag_in_frames = 0;
248 282
249 const vpx_codec_err_t ret = vpx_codec_enc_init(&encoder_, interface, 283 DCHECK(!encoder_);
284 encoder_.reset(new vpx_codec_ctx_t);
285 const vpx_codec_err_t ret = vpx_codec_enc_init(encoder_.get(), interface,
250 &codec_config_, kNoFlags); 286 &codec_config_, kNoFlags);
251 DCHECK_EQ(VPX_CODEC_OK, ret); 287 DCHECK_EQ(VPX_CODEC_OK, ret);
252 } 288 }
253 289
254 bool VideoTrackRecorder::VpxEncoder::IsInitialized() const { 290 bool VideoTrackRecorder::VpxEncoder::IsInitialized() const {
255 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); 291 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
256 return codec_config_.g_timebase.den != 0; 292 return codec_config_.g_timebase.den != 0;
257 } 293 }
258 294
259 base::TimeDelta VideoTrackRecorder::VpxEncoder::CalculateFrameDuration( 295 base::TimeDelta VideoTrackRecorder::VpxEncoder::CalculateFrameDuration(
260 const scoped_refptr<VideoFrame>& frame) { 296 const scoped_refptr<VideoFrame>& frame) {
261 DCHECK(encoding_thread_.task_runner()->BelongsToCurrentThread()); 297 DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread());
262 298
263 using base::TimeDelta; 299 using base::TimeDelta;
264 TimeDelta predicted_frame_duration; 300 TimeDelta predicted_frame_duration;
265 if (!frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION, 301 if (!frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION,
266 &predicted_frame_duration) || 302 &predicted_frame_duration) ||
267 predicted_frame_duration <= TimeDelta()) { 303 predicted_frame_duration <= TimeDelta()) {
268 // The source of the video frame did not provide the frame duration. Use 304 // The source of the video frame did not provide the frame duration. Use
269 // the actual amount of time between the current and previous frame as a 305 // the actual amount of time between the current and previous frame as a
270 // prediction for the next frame's duration. 306 // prediction for the next frame's duration.
271 // TODO(mcasas): This duration estimation could lead to artifacts if the 307 // TODO(mcasas): This duration estimation could lead to artifacts if the
272 // cadence of the received stream is compromised (e.g. camera freeze, pause, 308 // cadence of the received stream is compromised (e.g. camera freeze, pause,
273 // remote packet loss). Investigate using GetFrameRate() in this case. 309 // remote packet loss). Investigate using GetFrameRate() in this case.
274 predicted_frame_duration = frame->timestamp() - last_frame_timestamp_; 310 predicted_frame_duration = frame->timestamp() - last_frame_timestamp_;
275 } 311 }
276 last_frame_timestamp_ = frame->timestamp(); 312 last_frame_timestamp_ = frame->timestamp();
277 // Make sure |predicted_frame_duration| is in a safe range of values. 313 // Make sure |predicted_frame_duration| is in a safe range of values.
278 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8); 314 const TimeDelta kMaxFrameDuration = TimeDelta::FromSecondsD(1.0 / 8);
279 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1); 315 const TimeDelta kMinFrameDuration = TimeDelta::FromMilliseconds(1);
280 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration, 316 return std::min(kMaxFrameDuration, std::max(predicted_frame_duration,
281 kMinFrameDuration)); 317 kMinFrameDuration));
282 } 318 }
283 319
284 VideoTrackRecorder::VideoTrackRecorder( 320 VideoTrackRecorder::VideoTrackRecorder(
285 const blink::WebMediaStreamTrack& track, 321 const blink::WebMediaStreamTrack& track,
286 const OnEncodedVideoCB& on_encoded_video_callback) 322 const OnEncodedVideoCB& on_encoded_video_callback)
287 : track_(track), 323 : track_(track),
288 encoder_(new VpxEncoder(on_encoded_video_callback)), 324 encoder_(new VpxEncoder(on_encoded_video_callback)) {
289 weak_factory_(this) {
290 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 325 DCHECK(main_render_thread_checker_.CalledOnValidThread());
291 DCHECK(!track_.isNull()); 326 DCHECK(!track_.isNull());
292 DCHECK(track.extraData()); 327 DCHECK(track.extraData());
328
329 // StartFrameEncode() will be called on Render IO thread.
293 AddToVideoTrack(this, 330 AddToVideoTrack(this,
294 media::BindToCurrentLoop( 331 base::Bind(&VideoTrackRecorder::VpxEncoder::StartFrameEncode,
295 base::Bind(&VideoTrackRecorder::OnVideoFrame, 332 encoder_),
296 weak_factory_.GetWeakPtr())),
297 track_); 333 track_);
298 } 334 }
299 335
300 VideoTrackRecorder::~VideoTrackRecorder() { 336 VideoTrackRecorder::~VideoTrackRecorder() {
301 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 337 DCHECK(main_render_thread_checker_.CalledOnValidThread());
302 RemoveFromVideoTrack(this, track_); 338 RemoveFromVideoTrack(this, track_);
303 weak_factory_.InvalidateWeakPtrs();
304 track_.reset(); 339 track_.reset();
305 } 340 }
306 341
307 void VideoTrackRecorder::OnVideoFrame(const scoped_refptr<VideoFrame>& frame, 342 void VideoTrackRecorder::OnVideoFrameForTesting(
308 base::TimeTicks timestamp) { 343 const scoped_refptr<media::VideoFrame>& frame,
309 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 344 base::TimeTicks timestamp) {
310 encoder_->StartFrameEncode(frame, timestamp); 345 encoder_->StartFrameEncode(frame, timestamp);
311 } 346 }
312 347
313 } // namespace content 348 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/video_track_recorder.h ('k') | content/renderer/media/video_track_recorder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698