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

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: d9b0059b Comments, fixes from debugging. Works now. 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()
30 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the
31 // thread on which the instance was constructed.
32 //
33 // This class separates state related to the thread that RTCVideoEncoder
34 // operates on (presently the libjingle worker thread) from the thread that
35 // |gpu_factories_| provides for accelerator operations (presently the media
36 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while
37 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA.
38 class RTCVideoEncoder::Impl
39 : public media::VideoEncodeAccelerator::Client,
40 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
41 public:
42 Impl(
43 const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
44 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
45
46 // Create the VEA and call Initialize() on it. Called once per instantiation,
47 // and then the instance is bound forevermore to whichever thread made the
48 // call.
49 // RTCVideoEncoder expects to be able to call this function synchronously from
50 // its own thread, hence the |async_waiter| and |async_retval| arguments.
51 void CreateAndInitializeVEA(const gfx::Size& input_visible_size,
52 int32 bitrate,
53 media::VideoCodecProfile profile,
54 base::WaitableEvent* async_waiter,
55 int32_t* async_retval);
56 // Enqueue a frame from WebRTC for encoding.
57 // RTCVideoEncoder expects to be able to call this function synchronously from
58 // its own thread, hence the |async_waiter| and |async_retval| arguments.
59 void Enqueue(const webrtc::I420VideoFrame* input_frame,
60 bool force_keyframe,
61 base::WaitableEvent* async_waiter,
62 int32_t* async_retval);
63
64 // RTCVideoEncoder is given a buffer to be passed to WebRTC through the
65 // RTCVideoEncoder::ReturnEncodedImage() function. When that is complete,
66 // the buffer is returned to Impl by its index using this function.
67 void UseOutputBitstreamBufferId(int32 bitstream_buffer_id);
68
69 // Request encoding parameter change for the underlying encoder.
70 void RequestEncodingParameterChange(int32 bitrate);
71
72 // Destroy this Impl's encoder. The destructor is not explicitly called, as
73 // Impl is a base::RefCountedThreadSafe.
74 void Destroy();
75
76 // media::VideoEncodeAccelerator::Client implementation.
77 virtual void NotifyInitializeDone() OVERRIDE;
78 virtual void RequireBitstreamBuffers(int input_count,
79 const gfx::Size& input_coded_size,
80 size_t output_buffer_size) OVERRIDE;
81 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
82 size_t payload_size,
83 bool key_frame) OVERRIDE;
84 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
85
86 private:
87 friend class base::RefCountedThreadSafe<Impl>;
88
89 enum {
90 kInputBufferExtraCount = 1, // The number of input buffers allocated, more
91 // than what is requested by
92 // VEA::RequireBitstreamBuffers().
93 kOutputBufferCount = 3,
94 };
95
96 virtual ~Impl();
97
98 // Perform encoding on an input frame from the input queue.
99 void EncodeOneFrame();
100
101 // Notify that an input frame is finished for encoding. |index| is the index
102 // of the completed frame in |input_buffers_|.
103 void EncodeFrameFinished(int index);
104
105 // Set up/signal |async_waiter_| and |async_retval_|; see declarations below.
106 void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval);
107 void SignalAsyncWaiter(int32_t retval);
108
109 base::ThreadChecker thread_checker_;
110
111 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
112 // notifications.
113 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
114
115 // The message loop on which to post callbacks to |weak_encoder_|.
116 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
117
118 // Factory for creating VEAs, shared memory buffers, etc.
119 const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
120
121 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
122 // Do this by waiting on the |async_waiter_| and returning the return value in
123 // |async_retval_| when initialization completes, encoding completes, or
124 // an error occurs.
125 base::WaitableEvent* async_waiter_;
126 int32_t* async_retval_;
127
128 // The underlying VEA to perform encoding on.
129 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
130
131 // Next input frame. Since there is at most one next frame, a single-element
132 // queue is sufficient.
133 const webrtc::I420VideoFrame* input_next_frame_;
134
135 // Whether to encode a keyframe next.
136 bool input_next_frame_keyframe_;
137
138 // Frame sizes.
139 gfx::Size input_frame_coded_size_;
140 gfx::Size input_visible_size_;
141
142 // Shared memory buffers for input/output with the VEA.
143 ScopedVector<base::SharedMemory> input_buffers_;
144 ScopedVector<base::SharedMemory> output_buffers_;
145
146 // Input buffers ready to be filled with input from Encode(). As a LIFO since
147 // we don't care about ordering.
148 std::vector<int> input_buffers_free_;
149
150 // Timestamp of first frame returned from encoder. We calculate subsequent
151 // capture times as deltas from this base.
152 base::Time time_base_;
153
154 DISALLOW_COPY_AND_ASSIGN(Impl);
155 };
156
157 RTCVideoEncoder::Impl::Impl(
158 const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
159 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
160 : weak_encoder_(weak_encoder),
161 encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
162 gpu_factories_(gpu_factories),
163 async_waiter_(NULL),
164 async_retval_(NULL),
165 input_next_frame_(NULL),
166 input_next_frame_keyframe_(false) {
167 thread_checker_.DetachFromThread();
168 }
169
170 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
171 const gfx::Size& input_visible_size,
172 int32 bitrate,
173 media::VideoCodecProfile profile,
174 base::WaitableEvent* async_waiter,
175 int32_t* async_retval) {
176 DVLOG(3) << "Impl::CreateAndInitializeVEA()";
177 DCHECK(thread_checker_.CalledOnValidThread());
178
179 RegisterAsyncWaiter(async_waiter, async_retval);
180
181 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
182 if (bitrate > kint32max / 1000) {
183 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
184 return;
185 }
186
187 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass();
188 if (!video_encoder_) {
189 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
190 return;
191 }
192 input_visible_size_ = input_visible_size;
193 video_encoder_->Initialize(media::VideoFrame::I420,
194 input_visible_size_,
195 profile,
196 bitrate * 1000);
197 }
198
199 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame,
200 bool force_keyframe,
201 base::WaitableEvent* async_waiter,
202 int32_t* async_retval) {
203 DVLOG(3) << "Impl::Enqueue()";
204 DCHECK(thread_checker_.CalledOnValidThread());
205 DCHECK(!input_next_frame_);
206
207 RegisterAsyncWaiter(async_waiter, async_retval);
208 input_next_frame_ = input_frame;
209 input_next_frame_keyframe_ = force_keyframe;
210
211 if (!input_buffers_free_.empty())
212 EncodeOneFrame();
213 }
214
215 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId(
216 int32 bitstream_buffer_id) {
217 DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): "
218 "bitstream_buffer_id=" << bitstream_buffer_id;
219 DCHECK(thread_checker_.CalledOnValidThread());
220 if (video_encoder_) {
221 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
222 bitstream_buffer_id,
223 output_buffers_[bitstream_buffer_id]->handle(),
224 output_buffers_[bitstream_buffer_id]->mapped_size()));
225 }
226 }
227
228 void RTCVideoEncoder::Impl::RequestEncodingParameterChange(int32 bitrate) {
229 DVLOG(3) << "Impl::RequestEncodingParameterChange(): bitrate=" << bitrate;
230 DCHECK(thread_checker_.CalledOnValidThread());
231
232 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
233 if (bitrate > kint32max / 1000) {
234 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
235 return;
236 }
237
238 if (video_encoder_)
239 video_encoder_->RequestEncodingParameterChange(bitrate * 1000);
240 }
241
242 void RTCVideoEncoder::Impl::Destroy() {
243 DVLOG(3) << "Impl::Destroy()";
244 DCHECK(thread_checker_.CalledOnValidThread());
245 if (video_encoder_)
246 video_encoder_.release()->Destroy();
247 }
248
249 void RTCVideoEncoder::Impl::NotifyInitializeDone() {
250 DVLOG(3) << "Impl::NotifyInitializeDone()";
251 DCHECK(thread_checker_.CalledOnValidThread());
252 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
253 }
254
255 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
256 int input_count,
257 const gfx::Size& input_coded_size,
258 size_t output_buffer_size) {
259 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count
260 << ", input_coded_size=" << input_coded_size.ToString()
261 << ", output_buffer_size=" << output_buffer_size;
262 DCHECK(thread_checker_.CalledOnValidThread());
263
264 if (!video_encoder_)
265 return;
266
267 input_frame_coded_size_ = input_coded_size;
268
269 for (int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
270 base::SharedMemory* shm =
271 gpu_factories_->CreateSharedMemory(input_coded_size.GetArea() * 3 / 2);
272 if (!shm) {
273 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
274 "failed to create input buffer " << i;
275 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
276 return;
277 }
278 input_buffers_.push_back(shm);
279 input_buffers_free_.push_back(i);
280 }
281
282 for (int i = 0; i < kOutputBufferCount; ++i) {
283 base::SharedMemory* shm =
284 gpu_factories_->CreateSharedMemory(output_buffer_size);
285 if (!shm) {
286 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
287 "failed to create output buffer " << i;
288 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
289 return;
290 }
291 output_buffers_.push_back(shm);
292 }
293
294 // Immediately provide all output buffers to the VEA.
295 for (size_t i = 0; i < output_buffers_.size(); ++i) {
296 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
297 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
298 }
299 }
300
301 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
302 size_t payload_size,
303 bool key_frame) {
304 DVLOG(3) << "Impl::BitstreamBufferReady(): "
305 "bitstream_buffer_id=" << bitstream_buffer_id
306 << ", payload_size=" << payload_size
307 << ", key_frame=" << key_frame;
308 DCHECK(thread_checker_.CalledOnValidThread());
309
310 if (bitstream_buffer_id < 0 ||
311 bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) {
312 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id="
313 << bitstream_buffer_id;
314 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
Ami GONE FROM CHROMIUM 2013/08/07 21:07:15 My point is that the id here came from GVEAH which
sheu 2013/08/07 23:58:23 Alright sure, that makes sense. I've made the cor
315 return;
316 }
317 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
318 if (payload_size > output_buffer->mapped_size()) {
319 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size="
320 << payload_size;
321 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
322 return;
323 }
324
325 const base::Time now = base::Time::Now();
326 if (time_base_.is_null())
327 time_base_ = now;
328 const base::TimeDelta delta = now - time_base_;
329
330 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage(
331 reinterpret_cast<uint8_t*>(output_buffer->memory()),
332 payload_size,
333 output_buffer->mapped_size()));
334 image->_encodedWidth = input_visible_size_.width();
335 image->_encodedHeight = input_visible_size_.height();
336 // Convert capture time to 90 kHz RTP timestamp.
337 image->_timeStamp = (delta * 90000).InSeconds();
338 image->capture_time_ms_ = delta.InMilliseconds();
339 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
340 image->_completeFrame = true;
341
342 encoder_message_loop_proxy_->PostTask(
343 FROM_HERE,
344 base::Bind(&RTCVideoEncoder::ReturnEncodedImage,
345 weak_encoder_,
346 make_scoped_refptr(this),
347 base::Passed(&image),
348 bitstream_buffer_id));
349 }
350
351 void RTCVideoEncoder::Impl::NotifyError(
352 media::VideoEncodeAccelerator::Error error) {
353 DVLOG(3) << "Impl::NotifyError(): error=" << error;
354 DCHECK(thread_checker_.CalledOnValidThread());
355 int32_t retval;
356 switch (error) {
357 case media::VideoEncodeAccelerator::kInvalidArgumentError:
358 retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
359 break;
360 case media::VideoEncodeAccelerator::kPlatformFailureError:
361 retval = WEBRTC_VIDEO_CODEC_MEMORY;
sheu 2013/08/07 23:58:23 Done.
362 break;
363 default:
364 retval = WEBRTC_VIDEO_CODEC_ERROR;
365 }
366
367 if (video_encoder_)
368 video_encoder_.release()->Destroy();
369
370 if (async_waiter_) {
371 SignalAsyncWaiter(retval);
372 } else {
373 encoder_message_loop_proxy_->PostTask(
374 FROM_HERE,
375 base::Bind(&RTCVideoEncoder::NotifyError,
376 weak_encoder_,
377 make_scoped_refptr(this),
378 retval));
379 }
380 }
381
382 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
383
384 void RTCVideoEncoder::Impl::EncodeOneFrame() {
385 DVLOG(3) << "Impl::EncodeOneFrame()";
386 DCHECK(thread_checker_.CalledOnValidThread());
387 DCHECK(input_next_frame_);
388 DCHECK(!input_buffers_free_.empty());
389
390 if (video_encoder_) {
Ami GONE FROM CHROMIUM 2013/08/07 21:07:15 I don't get it. Why not replace this with if (!vi
sheu 2013/08/07 23:58:23 In the error state (where video_encoder_ is NULL),
391 const int index = input_buffers_free_.back();
392 base::SharedMemory* input_buffer = input_buffers_[index];
393
394 // Do a strided copy of the input frame to match the input requirements for
395 // the encoder.
396 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312
397 const uint8_t* src = input_next_frame_->buffer(webrtc::kYPlane);
398 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory());
399 uint8* const y_dst = dst;
400 int width = input_frame_coded_size_.width();
401 int stride = input_next_frame_->stride(webrtc::kYPlane);
402 for (int i = 0; i < input_next_frame_->height(); ++i) {
403 memcpy(dst, src, width);
404 src += stride;
405 dst += width;
406 }
407 src = input_next_frame_->buffer(webrtc::kUPlane);
408 width = input_frame_coded_size_.width() / 2;
409 stride = input_next_frame_->stride(webrtc::kUPlane);
410 uint8* const u_dst = dst;
411 for (int i = 0; i < input_next_frame_->height() / 2; ++i) {
412 memcpy(dst, src, width);
413 src += stride;
414 dst += width;
415 }
416 src = input_next_frame_->buffer(webrtc::kVPlane);
417 width = input_frame_coded_size_.width() / 2;
418 stride = input_next_frame_->stride(webrtc::kVPlane);
419 uint8* const v_dst = dst;
420 for (int i = 0; i < input_next_frame_->height() / 2; ++i) {
421 memcpy(dst, src, width);
422 src += stride;
423 dst += width;
424 }
425
426 scoped_refptr<media::VideoFrame> frame =
427 media::VideoFrame::WrapExternalYuvData(
428 media::VideoFrame::I420,
429 input_frame_coded_size_,
430 gfx::Rect(input_visible_size_),
431 input_visible_size_,
432 input_frame_coded_size_.width(),
433 input_frame_coded_size_.width() / 2,
434 input_frame_coded_size_.width() / 2,
435 y_dst,
436 u_dst,
437 v_dst,
438 base::TimeDelta(),
439 input_buffer->handle(),
440 base::Bind(
441 &RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
442 video_encoder_->Encode(frame, input_next_frame_keyframe_);
443 input_buffers_free_.pop_back();
444 }
445
446 input_next_frame_ = NULL;
447 input_next_frame_keyframe_ = false;
448
449 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
450 }
451
452 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) {
453 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index;
454 DCHECK(thread_checker_.CalledOnValidThread());
455 DCHECK_GE(index, 0);
456 DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
457 input_buffers_free_.push_back(index);
458 if (input_next_frame_)
459 EncodeOneFrame();
460 }
461
462 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent* waiter,
463 int32_t* retval) {
464 DCHECK(thread_checker_.CalledOnValidThread());
465 DCHECK(!async_waiter_);
466 DCHECK(!async_retval_);
467 async_waiter_ = waiter;
468 async_retval_ = retval;
469 }
470
471 void RTCVideoEncoder::Impl::SignalAsyncWaiter(int32_t retval) {
472 DCHECK(thread_checker_.CalledOnValidThread());
473 *async_retval_ = retval;
474 async_waiter_->Signal();
475 async_retval_ = NULL;
476 async_waiter_ = NULL;
477 }
478
479 #undef NOTIFY_ERROR
480
481 ////////////////////////////////////////////////////////////////////////////////
482 //
483 // RTCVideoEncoder
484 //
485 ////////////////////////////////////////////////////////////////////////////////
486
487 RTCVideoEncoder::RTCVideoEncoder(
488 webrtc::VideoCodecType type,
489 media::VideoCodecProfile profile,
490 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
491 : video_codec_type_(type),
492 video_codec_profile_(profile),
493 gpu_factories_(gpu_factories),
494 weak_this_factory_(this),
495 weak_this_(weak_this_factory_.GetWeakPtr()),
496 encoded_image_callback_(NULL),
497 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) {
498 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile;
499 }
500
501 RTCVideoEncoder::~RTCVideoEncoder() {
502 DCHECK(thread_checker_.CalledOnValidThread());
503 Release();
504 DCHECK(!impl_);
505 }
506
507 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
508 int32_t number_of_cores,
509 uint32_t max_payload_size) {
510 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
511 << ", width=" << codec_settings->width
512 << ", height=" << codec_settings->height
513 << ", startBitrate=" << codec_settings->startBitrate;
514 DCHECK(thread_checker_.CalledOnValidThread());
515 DCHECK(!impl_);
516
517 impl_ = new Impl(weak_this_, gpu_factories_);
518 base::WaitableEvent initialization_waiter(true, false);
519 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
520 gpu_factories_->GetMessageLoop()->PostTask(
521 FROM_HERE,
522 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
523 impl_,
524 gfx::Size(codec_settings->width, codec_settings->height),
525 codec_settings->startBitrate,
526 video_codec_profile_,
527 &initialization_waiter,
528 &initialization_retval));
529
530 // webrtc::VideoEncoder expects this call to be synchronous.
531 initialization_waiter.Wait();
532 return initialization_retval;
533 }
534
535 int32_t RTCVideoEncoder::Encode(
536 const webrtc::I420VideoFrame& input_image,
537 const webrtc::CodecSpecificInfo* codec_specific_info,
538 const std::vector<webrtc::VideoFrameType>* frame_types) {
539 DVLOG(3) << "Encode()";
540 // TODO(sheu): figure out why this check fails.
541 // DCHECK(thread_checker_.CalledOnValidThread());
542 if (!impl_) {
543 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
544 return impl_status_;
545 }
546
547 base::WaitableEvent encode_waiter(true, false);
548 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
549 gpu_factories_->GetMessageLoop()->PostTask(
550 FROM_HERE,
551 base::Bind(&RTCVideoEncoder::Impl::Enqueue,
552 impl_,
553 &input_image,
554 (frame_types->front() == webrtc::kKeyFrame),
555 &encode_waiter,
556 &encode_retval));
557
558 // webrtc::VideoEncoder expects this call to be synchronous.
559 encode_waiter.Wait();
560 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
561 return encode_retval;
562 }
563
564 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
565 webrtc::EncodedImageCallback* callback) {
566 DVLOG(3) << "RegisterEncodeCompleteCallback()";
567 DCHECK(thread_checker_.CalledOnValidThread());
568 if (!impl_) {
569 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_;
570 return impl_status_;
571 }
572
573 encoded_image_callback_ = callback;
574 return WEBRTC_VIDEO_CODEC_OK;
575 }
576
577 int32_t RTCVideoEncoder::Release() {
578 DVLOG(3) << "Release()";
579 DCHECK(thread_checker_.CalledOnValidThread());
580
581 // Reset the gpu_factory_, in case we reuse this encoder.
582 gpu_factories_->Abort();
583 gpu_factories_ = gpu_factories_->Clone();
584 if (impl_) {
585 gpu_factories_->GetMessageLoop()->PostTask(
586 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
587 impl_ = NULL;
588 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
589 }
590 return WEBRTC_VIDEO_CODEC_OK;
591 }
592
593 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
594 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
595 << ", rtt=" << rtt;
596 DCHECK(thread_checker_.CalledOnValidThread());
597 // Ignored.
598 return WEBRTC_VIDEO_CODEC_OK;
599 }
600
601 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate,
602 uint32_t /* ignored_frame_rate */) {
603 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate;
604 DCHECK(thread_checker_.CalledOnValidThread());
605 if (!impl_) {
606 DVLOG(3) << "SetRates(): returning " << impl_status_;
607 return impl_status_;
608 }
609
610 gpu_factories_->GetMessageLoop()->PostTask(
611 FROM_HERE,
612 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParameterChange,
613 impl_,
614 new_bit_rate));
615 return WEBRTC_VIDEO_CODEC_OK;
616 }
617
618 void RTCVideoEncoder::ReturnEncodedImage(const scoped_refptr<Impl>& impl,
619 scoped_ptr<webrtc::EncodedImage> image,
620 int32 bitstream_buffer_id) {
621 DCHECK(thread_checker_.CalledOnValidThread());
622
623 if (impl != impl_)
624 return;
625
626 DVLOG(3) << "ReturnEncodedImage(): "
627 "bitstream_buffer_id=" << bitstream_buffer_id;
628
629 if (!encoded_image_callback_)
630 return;
631
632 webrtc::CodecSpecificInfo info;
633 info.codecType = video_codec_type_;
634
635 // Generate a header describing a single fragment.
636 webrtc::RTPFragmentationHeader header;
637 header.VerifyAndAllocateFragmentationHeader(1);
638 header.fragmentationOffset[0] = 0;
639 header.fragmentationLength[0] = image->_length;
640 header.fragmentationPlType[0] = 0;
641 header.fragmentationTimeDiff[0] = 0;
642
643 int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
644 if (retval < 0) {
645 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
646 << retval;
647 }
648
649 // The call through webrtc::EncodedImageCallback is synchronous, so we can
650 // immediately recycle the output buffer back to the Impl.
651 gpu_factories_->GetMessageLoop()->PostTask(
652 FROM_HERE,
653 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
654 impl_,
655 bitstream_buffer_id));
656 }
657
658 void RTCVideoEncoder::NotifyError(const scoped_refptr<Impl>& impl,
659 int32_t error) {
660 DCHECK(thread_checker_.CalledOnValidThread());
661
662 if (impl != impl_)
663 return;
664
665 DVLOG(1) << "NotifyError(): error=" << error;
666
667 impl_status_ = error;
668 gpu_factories_->GetMessageLoop()->PostTask(
669 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
670 impl_ = NULL;
671 }
672
673 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698