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

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

Issue 20632002: Add media::VideoEncodeAccelerator with WebRTC integration (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@git-svn
Patch Set: 9e8f21a0 Comments addressed. Created 7 years, 4 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
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/rtc_video_encoder.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
14 #include "media/base/bitstream_buffer.h"
15 #include "media/base/video_frame.h"
16 #include "media/filters/gpu_video_accelerator_factories.h"
17 #include "media/video/video_encode_accelerator.h"
18
19 #define NOTIFY_ERROR(x) \
20 do { \
21 DLOG(ERROR) << "calling NotifyError(): " << x; \
22 NotifyError(x); \
23 } while (0)
24
25 namespace content {
26
27 // This private class of RTCVideoEncoder does the actual work of communicating
28 // with a media::VideoEncodeAccelerator for handling video encoding. It can
29 // be created on any thread, but should subsequently be posted to (and Destroy()
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Since CreateAndInitializeVEA is one of the methods
sheu 2013/08/06 06:16:36 Done.
30 // called on) the thread that calls CreateAndInitializeVEA(). Notifications
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/Notifications returned by the encoder/Callbacks
sheu 2013/08/06 06:16:36 Done.
31 // returned by the encoder are posted to the thread on which the instance was
32 // constructed.
33 //
34 // This class is separated from the RTCVideoEncoder class to allow
35 // RTCVideoEncoder to be deleted directly by WebRTC, while RTCVideoEncoder::Impl
36 // stays long enough to properly shut down the VEA.
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 I would emph the thread-separation more.
sheu 2013/08/06 06:16:36 Done.
37 class RTCVideoEncoder::Impl
38 : public media::VideoEncodeAccelerator::Client,
39 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
40 public:
41 explicit Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder);
42
43 // Create the VEA and call Initialize() on it. This instance of Impl is bound
44 // to whichever thread makes this call.
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Comment should explain it's only legal to call thi
sheu 2013/08/06 06:16:36 Done.
45 void CreateAndInitializeVEA(
46 const webrtc::VideoCodec& codecSettings,
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/codecSettings/codec_settings/ but I think it's a
sheu 2013/08/06 06:16:36 Sure, makes sense.
47 media::VideoCodecProfile profile,
48 base::WaitableEvent* async_waiter,
49 int32_t* async_retval,
50 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 This is known at ctor time so why not pass it in t
sheu 2013/08/06 06:16:36 Done.
51 void Enqueue(const webrtc::I420VideoFrame* input_frame,
52 bool force_keyframe,
53 base::WaitableEvent* async_waiter,
54 int32_t* async_retval);
55 void UseOutputBitstreamBufferId(int32 bitstream_buffer_id);
56 void RequestEncodingParameterChange(int32 bitrate);
57 void Destroy();
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 doco
sheu 2013/08/06 06:16:36 Done.
58
59 // media::VideoEncodeAccelerator::Client implementation.
60 virtual void NotifyInitializeDone() OVERRIDE;
61 virtual void RequireBitstreamBuffers(int input_count,
62 const gfx::Size& input_input_coded_size,
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 input_input
sheu 2013/08/06 06:16:36 Done.
63 size_t output_buffer_size) OVERRIDE;
64 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
65 size_t payload_size,
66 bool key_frame) OVERRIDE;
67 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
68
69 private:
70 friend class base::RefCountedThreadSafe<Impl>;
71
72 enum {
73 kInputBufferExtraCount = 1, // The number of input buffers allocated, more
74 // than what is requested by
75 // VEA::RequireBitstreamBuffers().
76 kOutputBufferCount = 3,
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 per comment on VEA.h this seems like it should be
sheu 2013/08/06 06:16:36 (see VEA)
77 };
78
79 virtual ~Impl();
80
81 // Perform encoding on an input frame from the input queue.
82 void EncodeOneFrame();
83
84 // Notify that an input frame is finished for encoding.
85 void EncodeFrameFinished(int index);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Doco what |index| is an index into.
sheu 2013/08/06 06:16:36 Done.
86
87 base::ThreadChecker thread_checker_;
88
89 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
90 // notifications.
91 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
92
93 // Factory for creating VEAs, shared memory buffers, etc.
94 scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
95
96 // The message loop on which to post notifications.
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/notifications/callbacks to weak_encoder_/
sheu 2013/08/06 06:16:36 Done.
97 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Put this right above or below weak_encoder_?
sheu 2013/08/06 06:16:36 Done.
98
99 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
100 // Do this by waiting on the |async_waiter_| and returning the return value in
101 // |async_retval_| when we initialization completes, encoding completes, or
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/we//
sheu 2013/08/06 06:16:36 Done.
102 // an error occurs.
103 base::WaitableEvent* async_waiter_;
104 int32_t* async_retval_;
105
106 // The underling VEA to perform encoding on.
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/underling/underlying/ unless you've got your opp
sheu 2013/08/06 06:16:36 we don't recognize an oppressor, we're an anarcho-
107 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
108
109 // Next input frame. Since there is at most one next frame, a single-element
110 // queue is sufficient.
111 const webrtc::I420VideoFrame* input_next_frame_;
112
113 // Whether to encode a keyframe next.
114 bool input_next_frame_keyframe_;
115
116 // Frame sizes.
117 gfx::Size input_frame_coded_size_;
118 gfx::Size output_frame_dimensions_;
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Isn't this input_frame_visible_size_?
sheu 2013/08/06 06:16:36 Yeah, I was on the fence about renaming this. If
119
120 // Shared memory buffers for input/output with the VEA.
121 ScopedVector<base::SharedMemory> input_buffers_;
122 ScopedVector<base::SharedMemory> output_buffers_;
123
124 // Input buffers ready to be filled with input from Encode(). As a LIFO since
125 // we don't care about ordering.
126 std::vector<int> input_buffers_free_;
127
128 DISALLOW_COPY_AND_ASSIGN(Impl);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/COPY_AND_ASSIGN/IMPLICIT_CONSTRUCTORS/?
sheu 2013/08/06 06:16:36 DISALLOW_COPY_AND_ASSIGN is my reflexive weapon of
129 };
130
131 RTCVideoEncoder::Impl::Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder)
132 : weak_encoder_(weak_encoder),
133 encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
134 async_waiter_(NULL),
135 async_retval_(NULL),
136 input_next_frame_(NULL),
137 input_next_frame_keyframe_(false) {
138 thread_checker_.DetachFromThread();
139 }
140
141 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
142 const webrtc::VideoCodec& codecSettings,
143 media::VideoCodecProfile profile,
144 base::WaitableEvent* async_waiter,
145 int32_t* async_retval,
146 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) {
147 DVLOG(3) << "Impl::CreateAndInitializeVEA()";
148 DCHECK(thread_checker_.CalledOnValidThread());
149
150 async_waiter_ = async_waiter;
151 async_retval_ = async_retval;
152
153 // Check for overflow converting codecSettings.startBitrate (kilobits/sec) to
154 // bits/sec.
155 const int32 bitrate = codecSettings.startBitrate * 1000;
156 if (bitrate <= 0) {
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Signed integer overflow is undefined behavior. Bet
sheu 2013/08/06 06:16:36 I was hoping to get something more generic with sa
157 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
158 return;
159 }
160
161 gpu_factories_ = gpu_factories;
162 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass();
163 if (!video_encoder_) {
164 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
165 return;
166 }
167 output_frame_dimensions_.SetSize(codecSettings.width, codecSettings.height);
168 video_encoder_->Initialize(
169 media::VideoFrame::I420, output_frame_dimensions_, profile, bitrate);
170 }
171
172 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame,
173 bool force_keyframe,
174 base::WaitableEvent* async_waiter,
175 int32_t* async_retval) {
176 DVLOG(3) << "Impl::Enqueue()";
177 DCHECK(thread_checker_.CalledOnValidThread());
178 DCHECK(!input_next_frame_);
179
180 async_waiter_ = async_waiter;
181 async_retval_ = async_retval;
182 input_next_frame_ = input_frame;
183 input_next_frame_keyframe_ = force_keyframe;
184
185 if (!input_buffers_free_.empty())
186 EncodeOneFrame();
187 }
188
189 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId(
190 int32 bitstream_buffer_id) {
191 DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): "
192 "bitstream_buffer_id=" << bitstream_buffer_id;
193 DCHECK(thread_checker_.CalledOnValidThread());
194 if (video_encoder_) {
195 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
196 bitstream_buffer_id,
197 output_buffers_[bitstream_buffer_id]->handle(),
198 output_buffers_[bitstream_buffer_id]->mapped_size()));
199 }
200 }
201
202 void RTCVideoEncoder::Impl::RequestEncodingParameterChange(int32 bitrate) {
203 DVLOG(3) << "Impl::RequestEncodingParameterChange(): bitrate=" << bitrate;
204 DCHECK(thread_checker_.CalledOnValidThread());
205 if (video_encoder_)
206 video_encoder_->RequestEncodingParameterChange(bitrate);
207 }
208
209 void RTCVideoEncoder::Impl::Destroy() {
210 DVLOG(3) << "Impl::Destroy()";
211 DCHECK(thread_checker_.CalledOnValidThread());
212 if (video_encoder_)
213 video_encoder_.release()->Destroy();
214 }
215
216 void RTCVideoEncoder::Impl::NotifyInitializeDone() {
217 DVLOG(3) << "Impl::NotifyInitializeDone()";
218 DCHECK(thread_checker_.CalledOnValidThread());
219 *async_retval_ = WEBRTC_VIDEO_CODEC_OK;
220 async_waiter_->Signal();
221 async_retval_ = NULL;
222 async_waiter_ = NULL;
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 This stanza is repeated frequently. Extract to he
sheu 2013/08/06 06:16:36 Done.
223 }
224
225 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
226 int input_count,
227 const gfx::Size& input_coded_size,
228 size_t output_buffer_size) {
229 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count
230 << ", input_coded_size=" << input_coded_size.ToString()
231 << ", output_buffer_size=" << output_buffer_size;
232 DCHECK(thread_checker_.CalledOnValidThread());
233
234 if (!video_encoder_)
235 return;
236
237 input_frame_coded_size_ = input_coded_size;
238
239 for (int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
240 base::SharedMemory* shm =
241 gpu_factories_->CreateSharedMemory(input_coded_size.GetArea() * 3 / 2);
242 if (!shm) {
243 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
244 "failed to create input buffer " << i;
245 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 I thought the point of using a macro for NOTIFY_ER
sheu 2013/08/06 06:16:36 I'd like to see exactly what the parameters were t
Ami GONE FROM CHROMIUM 2013/08/06 20:41:13 Then you might enjoy putting them in the NOTIFY_ER
246 return;
247 }
248 input_buffers_.push_back(shm);
249 }
250 for (size_t i = 0; i < input_buffers_.size(); ++i)
251 input_buffers_free_.push_back(i);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 could do this at l.248, fwiw.
sheu 2013/08/06 06:16:36 Done.
252
253 for (int i = 0; i < kOutputBufferCount; ++i) {
254 base::SharedMemory* shm =
255 gpu_factories_->CreateSharedMemory(output_buffer_size);
256 if (!shm) {
257 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
258 "failed to create output buffer " << i;
259 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
260 return;
261 }
262 output_buffers_.push_back(shm);
263 }
264
265 // Immediately provide all output buffers to the VEA.
266 for (size_t i = 0; i < output_buffers_.size(); ++i) {
267 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
268 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Oh, wow, I didn't realize https://chromiumcoderevi
sheu 2013/08/06 06:16:36 Don't think so. BitstreamBuffer comes across as a
269 }
270 }
271
272 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
273 size_t payload_size,
274 bool key_frame) {
275 DVLOG(3) << "Impl::BitstreamBufferReady(): "
276 "bitstream_buffer_id=" << bitstream_buffer_id
277 << ", payload_size=" << payload_size
278 << ", key_frame=" << key_frame;
279 DCHECK(thread_checker_.CalledOnValidThread());
280
281 if (bitstream_buffer_id < 0 ||
282 bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) {
283 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id="
284 << bitstream_buffer_id;
285 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 This is a platform error.
sheu 2013/08/06 06:16:36 Is it? It's an invalid argument coming back over
286 return;
287 }
288 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
289 if (payload_size > output_buffer->mapped_size()) {
290 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size="
291 << payload_size;
292 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
293 return;
294 }
295
296 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage(
297 reinterpret_cast<uint8_t*>(output_buffer->memory()),
298 payload_size,
299 output_buffer->mapped_size()));
300 image->_encodedWidth = output_frame_dimensions_.width();
301 image->_encodedHeight = output_frame_dimensions_.height();
302 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
303 image->_completeFrame = true;
304
305 encoder_message_loop_proxy_->PostTask(
306 FROM_HERE,
307 base::Bind(&RTCVideoEncoder::ReturnEncodedImage,
308 weak_encoder_,
309 make_scoped_refptr(this),
310 base::Passed(&image),
311 bitstream_buffer_id));
312 }
313
314 void RTCVideoEncoder::Impl::NotifyError(
315 media::VideoEncodeAccelerator::Error error) {
316 DVLOG(3) << "Impl::NotifyError(): error=" << error;
317 DCHECK(thread_checker_.CalledOnValidThread());
318 int32_t retval;
319 switch (error) {
320 default:
321 retval = WEBRTC_VIDEO_CODEC_ERROR;
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 You could do a more specific job of mapping VEA's
sheu 2013/08/06 06:16:36 Gave it a shot. Tell me what you think.
322 }
323
324 if (video_encoder_)
325 video_encoder_.release()->Destroy();
326
327 if (async_waiter_) {
328 *async_retval_ = retval;
329 async_waiter_->Signal();
330 async_retval_ = NULL;
331 async_waiter_ = NULL;
332 } else {
333 encoder_message_loop_proxy_->PostTask(
334 FROM_HERE,
335 base::Bind(&RTCVideoEncoder::NotifyError,
336 weak_encoder_,
337 make_scoped_refptr(this),
338 retval));
339 }
340 }
341
342 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
343
344 void RTCVideoEncoder::Impl::EncodeOneFrame() {
345 DVLOG(3) << "Impl::EncodeOneFrame()";
346 DCHECK(thread_checker_.CalledOnValidThread());
347 DCHECK(input_next_frame_);
348 DCHECK(!input_buffers_free_.empty());
349 DCHECK(async_waiter_);
350 DCHECK(async_retval_);
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 drop these in favor of DCHECKs in the proposed Sig
sheu 2013/08/06 06:16:36 Done.
351
352 const int index = input_buffers_free_.back();
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 why not pop_back right here?
sheu 2013/08/06 06:16:36 I tend to get in the habit of only destructively p
Ami GONE FROM CHROMIUM 2013/08/06 20:41:13 FWIW I consider that a dangerous habit and would e
353 base::SharedMemory* input_buffer = input_buffers_[index];
354
355 if (video_encoder_) {
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 why not reverse the test and early-return at the t
sheu 2013/08/06 06:16:36 We'd still like to consume the buffers and signal
356 // Do a strided copy of the input frame to match the input requirements for
357 // the encoder.
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Can you avoid the copy in the case where the requi
sheu 2013/08/06 06:16:36 That will require support for passing SharedMemory
358 const uint8_t* src = input_next_frame_->buffer(webrtc::kYPlane);
359 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory());
360 uint8* const y_dst = dst;
361 int width = input_frame_coded_size_.width();
362 int stride = input_next_frame_->stride(webrtc::kYPlane);
363 for (int i = 0; i < input_next_frame_->height(); ++i) {
364 memcpy(dst, src, width);
365 dst += stride;
366 src += width;
367 }
368 src = input_next_frame_->buffer(webrtc::kUPlane);
369 width = input_frame_coded_size_.width() / 2;
370 stride = input_next_frame_->stride(webrtc::kUPlane);
371 uint8* const u_dst = dst;
372 for (int i = 0; i < input_next_frame_->height() / 2; ++i) {
373 memcpy(dst, src, width);
374 dst += stride;
375 src += width;
376 }
377 src = input_next_frame_->buffer(webrtc::kVPlane);
378 width = input_frame_coded_size_.width() / 2;
379 stride = input_next_frame_->stride(webrtc::kVPlane);
380 uint8* const v_dst = dst;
381 for (int i = 0; i < input_next_frame_->height() / 2; ++i) {
382 memcpy(dst, src, width);
383 dst += stride;
384 src += width;
385 }
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Extract CopyPlaneWithStride() helper to avoid the
sheu 2013/08/06 06:16:36 Tried it. The copypasta just gets a little more c
386
387 scoped_refptr<media::VideoFrame> frame =
388 media::VideoFrame::WrapExternalYuvData(
389 media::VideoFrame::I420,
390 input_frame_coded_size_,
391 gfx::Rect(output_frame_dimensions_),
392 output_frame_dimensions_,
393 input_frame_coded_size_.width(),
394 input_frame_coded_size_.width() / 2,
395 input_frame_coded_size_.width() / 2,
396 y_dst,
397 u_dst,
398 v_dst,
399 base::TimeDelta(),
400 input_buffer->handle(),
401 base::Bind(
402 &RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
403 video_encoder_->Encode(frame, input_next_frame_keyframe_);
404 }
405
406 input_next_frame_ = NULL;
407 input_next_frame_keyframe_ = false;
408 input_buffers_free_.pop_back();
409
410 *async_retval_ = WEBRTC_VIDEO_CODEC_OK;
411 async_waiter_->Signal();
412 async_retval_ = NULL;
413 async_waiter_ = NULL;
414 }
415
416 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) {
417 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index;
418 DCHECK(thread_checker_.CalledOnValidThread());
419 DCHECK_GE(index, 0);
420 DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
421 input_buffers_free_.push_back(index);
422 if (input_next_frame_)
423 EncodeOneFrame();
424 }
425
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 This might be a good place for a ///////////////
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 #undef NOTIFY_ERROR (I care because N_E has threa
sheu 2013/08/06 06:16:36 Done.
sheu 2013/08/06 06:16:36 Done.
426 RTCVideoEncoder::RTCVideoEncoder(
427 media::VideoCodecProfile profile,
428 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
429 : video_codec_profile_(profile),
430 gpu_factories_(gpu_factories),
431 impl_message_loop_proxy_(gpu_factories_->GetMessageLoop()),
432 weak_this_factory_(this),
433 weak_this_(weak_this_factory_.GetWeakPtr()),
434 encoded_image_callback_(NULL),
435 impl_status_(WEBRTC_VIDEO_CODEC_OK) {
436 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile;
437 }
438
439 RTCVideoEncoder::~RTCVideoEncoder() {
440 DCHECK(thread_checker_.CalledOnValidThread());
441 Release();
442 DCHECK(!impl_);
443 }
444
445 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
446 int32_t number_of_cores,
447 uint32_t max_payload_size) {
448 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
449 << ", width=" << codec_settings->width
450 << ", height=" << codec_settings->height
451 << ", startBitrate=" << codec_settings->startBitrate;
452 DCHECK(thread_checker_.CalledOnValidThread());
453 DCHECK(!impl_);
454
455 impl_ = new Impl(weak_this_);
456 base::WaitableEvent initialization_waiter(true, false);
457 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 any reason not to use impl_status_ for this? (he
sheu 2013/08/06 06:16:36 impl_status_ belongs on another thread.
458 impl_message_loop_proxy_->PostTask(
459 FROM_HERE,
460 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
461 impl_,
462 *codec_settings,
463 video_codec_profile_,
464 &initialization_waiter,
465 &initialization_retval,
466 gpu_factories_));
467
468 // webrtc::VideoEncoder expects this call to be synchronous.
469 initialization_waiter.Wait();
470 return initialization_retval;
471 }
472
473 int32_t RTCVideoEncoder::Encode(
474 const webrtc::I420VideoFrame& input_image,
475 const webrtc::CodecSpecificInfo* codec_specific_info,
476 const std::vector<webrtc::VideoFrameType>* frame_types) {
477 DVLOG(3) << "Encode()";
478 // DCHECK(thread_checker_.CalledOnValidThread());
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 uncomment
sheu 2013/08/06 06:16:36 This fails presently for reasons unknown that I st
479 if (!impl_) {
480 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
481 return impl_status_;
482 }
483
484 base::WaitableEvent encode_waiter(true, false);
485 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
486 impl_message_loop_proxy_->PostTask(
487 FROM_HERE,
488 base::Bind(&RTCVideoEncoder::Impl::Enqueue,
489 impl_,
490 &input_image,
491 (frame_types->front() == webrtc::kKeyFrame),
492 &encode_waiter,
493 &encode_retval));
494
495 // webrtc::VideoEncoder expects this call to be synchronous.
496 encode_waiter.Wait();
497 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
498 return encode_retval;
499 }
500
501 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
502 webrtc::EncodedImageCallback* callback) {
503 DVLOG(3) << "RegisterEncodeCompleteCallback()";
504 DCHECK(thread_checker_.CalledOnValidThread());
505 if (!impl_) {
506 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_;
507 return impl_status_;
508 }
509
510 encoded_image_callback_ = callback;
511 return WEBRTC_VIDEO_CODEC_OK;
512 }
513
514 int32_t RTCVideoEncoder::Release() {
515 DVLOG(3) << "Release()";
516 DCHECK(thread_checker_.CalledOnValidThread());
517
518 // Reset the gpu_factory_, in case we reuse this encoder.
519 gpu_factories_->Abort();
520 gpu_factories_ = gpu_factories_->Clone();
521 impl_message_loop_proxy_->PostTask(
522 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
523 impl_ = NULL;
524 impl_status_ = WEBRTC_VIDEO_CODEC_OK;
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 s/OK/UNINITIALIZED?
sheu 2013/08/06 06:16:36 Done.
525 return WEBRTC_VIDEO_CODEC_OK;
526 }
527
528 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
529 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
530 << ", rtt=" << rtt;
531 DCHECK(thread_checker_.CalledOnValidThread());
532 // Ignored.
533 return WEBRTC_VIDEO_CODEC_OK;
534 }
535
536 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 frame_rate is ignored; should that be noted someho
sheu 2013/08/06 06:16:36 Done.
537 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate
538 << ", frame_rate=" << frame_rate;
539 DCHECK(thread_checker_.CalledOnValidThread());
540 if (!impl_) {
541 DVLOG(3) << "SetRates(): returning " << impl_status_;
542 return impl_status_;
543 }
544
545 impl_message_loop_proxy_->PostTask(
546 FROM_HERE,
547 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParameterChange,
548 impl_,
549 new_bit_rate));
550 return WEBRTC_VIDEO_CODEC_OK;
551 }
552
553 void RTCVideoEncoder::ReturnEncodedImage(const scoped_refptr<Impl>& impl,
554 scoped_ptr<webrtc::EncodedImage> image,
555 int32 bitstream_buffer_id) {
556 DCHECK(thread_checker_.CalledOnValidThread());
557
558 if (impl != impl_)
559 return;
560
561 DVLOG(3) << "ReturnEncodedImage(): "
562 "bitstream_buffer_id=" << bitstream_buffer_id;
563
564 if (!impl_)
Ami GONE FROM CHROMIUM 2013/08/05 18:44:38 Impossible given l.558.
sheu 2013/08/06 06:16:36 Done.
565 return;
566 if (!encoded_image_callback_)
567 return;
568
569 int32_t retval = encoded_image_callback_->Encoded(*image, NULL, NULL);
570 if (retval < 0) {
571 NotifyError(impl_, retval);
572 return;
573 }
574
575 // The call through webrtc::EncodedImageCallback is synchronous, so we can
576 // immediately recycle the output buffer back to the Impl.
577 impl_message_loop_proxy_->PostTask(
578 FROM_HERE,
579 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
580 impl_,
581 bitstream_buffer_id));
582 }
583
584 void RTCVideoEncoder::NotifyError(const scoped_refptr<Impl>& impl,
585 int32_t error) {
586 DCHECK(thread_checker_.CalledOnValidThread());
587
588 if (impl != impl_)
589 return;
590
591 DVLOG(1) << "NotifyError(): error=" << error;
592
593 impl_status_ = error;
594 impl_message_loop_proxy_->PostTask(
595 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
596 impl_ = NULL;
597 }
598
599 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698