Revert of Remove threading from RendererGpuVideoAcceleratorFactories (https://coderev...
[chromium-blink-merge.git] / content / renderer / media / rtc_video_encoder.cc
blob83e49d656136d8b5f0a71c28e6f816688c32eb83
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.
5 #include "content/renderer/media/rtc_video_encoder.h"
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/metrics/histogram.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
15 #include "media/base/bitstream_buffer.h"
16 #include "media/base/video_frame.h"
17 #include "media/base/video_util.h"
18 #include "media/filters/gpu_video_accelerator_factories.h"
19 #include "media/video/video_encode_accelerator.h"
20 #include "third_party/webrtc/system_wrappers/interface/tick_util.h"
22 #define NOTIFY_ERROR(x) \
23 do { \
24 DLOG(ERROR) << "calling NotifyError(): " << x; \
25 NotifyError(x); \
26 } while (0)
28 namespace content {
30 // This private class of RTCVideoEncoder does the actual work of communicating
31 // with a media::VideoEncodeAccelerator for handling video encoding. It can
32 // be created on any thread, but should subsequently be posted to (and Destroy()
33 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the
34 // thread on which the instance was constructed.
36 // This class separates state related to the thread that RTCVideoEncoder
37 // operates on (presently the libjingle worker thread) from the thread that
38 // |gpu_factories_| provides for accelerator operations (presently the media
39 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while
40 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA.
41 class RTCVideoEncoder::Impl
42 : public media::VideoEncodeAccelerator::Client,
43 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
44 public:
45 Impl(
46 const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
47 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
49 // Create the VEA and call Initialize() on it. Called once per instantiation,
50 // and then the instance is bound forevermore to whichever thread made the
51 // call.
52 // RTCVideoEncoder expects to be able to call this function synchronously from
53 // its own thread, hence the |async_waiter| and |async_retval| arguments.
54 void CreateAndInitializeVEA(const gfx::Size& input_visible_size,
55 uint32 bitrate,
56 media::VideoCodecProfile profile,
57 base::WaitableEvent* async_waiter,
58 int32_t* async_retval);
59 // Enqueue a frame from WebRTC for encoding.
60 // RTCVideoEncoder expects to be able to call this function synchronously from
61 // its own thread, hence the |async_waiter| and |async_retval| arguments.
62 void Enqueue(const webrtc::I420VideoFrame* input_frame,
63 bool force_keyframe,
64 base::WaitableEvent* async_waiter,
65 int32_t* async_retval);
67 // RTCVideoEncoder is given a buffer to be passed to WebRTC through the
68 // RTCVideoEncoder::ReturnEncodedImage() function. When that is complete,
69 // the buffer is returned to Impl by its index using this function.
70 void UseOutputBitstreamBufferId(int32 bitstream_buffer_id);
72 // Request encoding parameter change for the underlying encoder.
73 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
75 // Destroy this Impl's encoder. The destructor is not explicitly called, as
76 // Impl is a base::RefCountedThreadSafe.
77 void Destroy();
79 // media::VideoEncodeAccelerator::Client implementation.
80 virtual void NotifyInitializeDone() OVERRIDE;
81 virtual void RequireBitstreamBuffers(unsigned int input_count,
82 const gfx::Size& input_coded_size,
83 size_t output_buffer_size) OVERRIDE;
84 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
85 size_t payload_size,
86 bool key_frame) OVERRIDE;
87 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
89 private:
90 friend class base::RefCountedThreadSafe<Impl>;
92 enum {
93 kInputBufferExtraCount = 1, // The number of input buffers allocated, more
94 // than what is requested by
95 // VEA::RequireBitstreamBuffers().
96 kOutputBufferCount = 3,
99 virtual ~Impl();
101 // Perform encoding on an input frame from the input queue.
102 void EncodeOneFrame();
104 // Notify that an input frame is finished for encoding. |index| is the index
105 // of the completed frame in |input_buffers_|.
106 void EncodeFrameFinished(int index);
108 // Set up/signal |async_waiter_| and |async_retval_|; see declarations below.
109 void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval);
110 void SignalAsyncWaiter(int32_t retval);
112 base::ThreadChecker thread_checker_;
114 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
115 // notifications.
116 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
118 // The message loop on which to post callbacks to |weak_encoder_|.
119 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
121 // Factory for creating VEAs, shared memory buffers, etc.
122 const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
124 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
125 // Do this by waiting on the |async_waiter_| and returning the return value in
126 // |async_retval_| when initialization completes, encoding completes, or
127 // an error occurs.
128 base::WaitableEvent* async_waiter_;
129 int32_t* async_retval_;
131 // The underlying VEA to perform encoding on.
132 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
134 // Next input frame. Since there is at most one next frame, a single-element
135 // queue is sufficient.
136 const webrtc::I420VideoFrame* input_next_frame_;
138 // Whether to encode a keyframe next.
139 bool input_next_frame_keyframe_;
141 // Frame sizes.
142 gfx::Size input_frame_coded_size_;
143 gfx::Size input_visible_size_;
145 // Shared memory buffers for input/output with the VEA.
146 ScopedVector<base::SharedMemory> input_buffers_;
147 ScopedVector<base::SharedMemory> output_buffers_;
149 // Input buffers ready to be filled with input from Encode(). As a LIFO since
150 // we don't care about ordering.
151 std::vector<int> input_buffers_free_;
153 DISALLOW_COPY_AND_ASSIGN(Impl);
156 RTCVideoEncoder::Impl::Impl(
157 const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
158 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
159 : weak_encoder_(weak_encoder),
160 encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
161 gpu_factories_(gpu_factories),
162 async_waiter_(NULL),
163 async_retval_(NULL),
164 input_next_frame_(NULL),
165 input_next_frame_keyframe_(false) {
166 thread_checker_.DetachFromThread();
169 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
170 const gfx::Size& input_visible_size,
171 uint32 bitrate,
172 media::VideoCodecProfile profile,
173 base::WaitableEvent* async_waiter,
174 int32_t* async_retval) {
175 DVLOG(3) << "Impl::CreateAndInitializeVEA()";
176 DCHECK(thread_checker_.CalledOnValidThread());
178 RegisterAsyncWaiter(async_waiter, async_retval);
180 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
181 if (bitrate > kuint32max / 1000) {
182 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
183 return;
186 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass();
187 if (!video_encoder_) {
188 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
189 return;
191 input_visible_size_ = input_visible_size;
192 video_encoder_->Initialize(
193 media::VideoFrame::I420, input_visible_size_, profile, bitrate * 1000);
196 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame,
197 bool force_keyframe,
198 base::WaitableEvent* async_waiter,
199 int32_t* async_retval) {
200 DVLOG(3) << "Impl::Enqueue()";
201 DCHECK(thread_checker_.CalledOnValidThread());
202 DCHECK(!input_next_frame_);
204 RegisterAsyncWaiter(async_waiter, async_retval);
205 input_next_frame_ = input_frame;
206 input_next_frame_keyframe_ = force_keyframe;
208 if (!input_buffers_free_.empty())
209 EncodeOneFrame();
212 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId(
213 int32 bitstream_buffer_id) {
214 DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): "
215 "bitstream_buffer_id=" << bitstream_buffer_id;
216 DCHECK(thread_checker_.CalledOnValidThread());
217 if (video_encoder_) {
218 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
219 bitstream_buffer_id,
220 output_buffers_[bitstream_buffer_id]->handle(),
221 output_buffers_[bitstream_buffer_id]->mapped_size()));
225 void RTCVideoEncoder::Impl::RequestEncodingParametersChange(uint32 bitrate,
226 uint32 framerate) {
227 DVLOG(3) << "Impl::RequestEncodingParametersChange(): bitrate=" << bitrate
228 << ", framerate=" << framerate;
229 DCHECK(thread_checker_.CalledOnValidThread());
231 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
232 if (bitrate > kuint32max / 1000) {
233 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
234 return;
237 if (video_encoder_)
238 video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate);
241 void RTCVideoEncoder::Impl::Destroy() {
242 DVLOG(3) << "Impl::Destroy()";
243 DCHECK(thread_checker_.CalledOnValidThread());
244 if (video_encoder_)
245 video_encoder_.release()->Destroy();
248 void RTCVideoEncoder::Impl::NotifyInitializeDone() {
249 DVLOG(3) << "Impl::NotifyInitializeDone()";
250 DCHECK(thread_checker_.CalledOnValidThread());
253 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
254 unsigned int input_count,
255 const gfx::Size& input_coded_size,
256 size_t output_buffer_size) {
257 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count
258 << ", input_coded_size=" << input_coded_size.ToString()
259 << ", output_buffer_size=" << output_buffer_size;
260 DCHECK(thread_checker_.CalledOnValidThread());
262 if (!video_encoder_)
263 return;
265 input_frame_coded_size_ = input_coded_size;
267 for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
268 base::SharedMemory* shm =
269 gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize(
270 media::VideoFrame::I420, input_coded_size));
271 if (!shm) {
272 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
273 "failed to create input buffer " << i;
274 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
275 return;
277 input_buffers_.push_back(shm);
278 input_buffers_free_.push_back(i);
281 for (int i = 0; i < kOutputBufferCount; ++i) {
282 base::SharedMemory* shm =
283 gpu_factories_->CreateSharedMemory(output_buffer_size);
284 if (!shm) {
285 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
286 "failed to create output buffer " << i;
287 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
288 return;
290 output_buffers_.push_back(shm);
293 // Immediately provide all output buffers to the VEA.
294 for (size_t i = 0; i < output_buffers_.size(); ++i) {
295 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
296 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
298 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
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());
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::kPlatformFailureError);
315 return;
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::kPlatformFailureError);
322 return;
325 // Use webrtc timestamps to ensure correct RTP sender behavior.
326 // TODO(hshi): obtain timestamp from the capturer, see crbug.com/284783.
327 const int64 capture_time_ms = webrtc::TickTime::MillisecondTimestamp();
329 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage(
330 reinterpret_cast<uint8_t*>(output_buffer->memory()),
331 payload_size,
332 output_buffer->mapped_size()));
333 image->_encodedWidth = input_visible_size_.width();
334 image->_encodedHeight = input_visible_size_.height();
335 // Convert capture time to 90 kHz RTP timestamp.
336 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
337 image->capture_time_ms_ = capture_time_ms;
338 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
339 image->_completeFrame = true;
341 encoder_message_loop_proxy_->PostTask(
342 FROM_HERE,
343 base::Bind(&RTCVideoEncoder::ReturnEncodedImage,
344 weak_encoder_,
345 base::Passed(&image),
346 bitstream_buffer_id));
349 void RTCVideoEncoder::Impl::NotifyError(
350 media::VideoEncodeAccelerator::Error error) {
351 DVLOG(3) << "Impl::NotifyError(): error=" << error;
352 DCHECK(thread_checker_.CalledOnValidThread());
353 int32_t retval;
354 switch (error) {
355 case media::VideoEncodeAccelerator::kInvalidArgumentError:
356 retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
357 break;
358 default:
359 retval = WEBRTC_VIDEO_CODEC_ERROR;
362 if (video_encoder_)
363 video_encoder_.release()->Destroy();
365 if (async_waiter_) {
366 SignalAsyncWaiter(retval);
367 } else {
368 encoder_message_loop_proxy_->PostTask(
369 FROM_HERE,
370 base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
374 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
376 void RTCVideoEncoder::Impl::EncodeOneFrame() {
377 DVLOG(3) << "Impl::EncodeOneFrame()";
378 DCHECK(thread_checker_.CalledOnValidThread());
379 DCHECK(input_next_frame_);
380 DCHECK(!input_buffers_free_.empty());
382 // EncodeOneFrame() may re-enter EncodeFrameFinished() if VEA::Encode() fails,
383 // we receive a VEA::NotifyError(), and the media::VideoFrame we pass to
384 // Encode() gets destroyed early. Handle this by resetting our
385 // input_next_frame_* state before we hand off the VideoFrame to the VEA.
386 const webrtc::I420VideoFrame* next_frame = input_next_frame_;
387 bool next_frame_keyframe = input_next_frame_keyframe_;
388 input_next_frame_ = NULL;
389 input_next_frame_keyframe_ = false;
391 if (!video_encoder_) {
392 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR);
393 return;
396 const int index = input_buffers_free_.back();
397 base::SharedMemory* input_buffer = input_buffers_[index];
398 scoped_refptr<media::VideoFrame> frame =
399 media::VideoFrame::WrapExternalPackedMemory(
400 media::VideoFrame::I420,
401 input_frame_coded_size_,
402 gfx::Rect(input_visible_size_),
403 input_visible_size_,
404 reinterpret_cast<uint8*>(input_buffer->memory()),
405 input_buffer->mapped_size(),
406 input_buffer->handle(),
407 base::TimeDelta(),
408 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
409 if (!frame) {
410 DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame";
411 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
412 return;
415 // Do a strided copy of the input frame to match the input requirements for
416 // the encoder.
417 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312
418 media::CopyYPlane(next_frame->buffer(webrtc::kYPlane),
419 next_frame->stride(webrtc::kYPlane),
420 next_frame->height(),
421 frame.get());
422 media::CopyUPlane(next_frame->buffer(webrtc::kUPlane),
423 next_frame->stride(webrtc::kUPlane),
424 next_frame->height(),
425 frame.get());
426 media::CopyVPlane(next_frame->buffer(webrtc::kVPlane),
427 next_frame->stride(webrtc::kVPlane),
428 next_frame->height(),
429 frame.get());
431 video_encoder_->Encode(frame, next_frame_keyframe);
432 input_buffers_free_.pop_back();
433 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
436 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) {
437 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index;
438 DCHECK(thread_checker_.CalledOnValidThread());
439 DCHECK_GE(index, 0);
440 DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
441 input_buffers_free_.push_back(index);
442 if (input_next_frame_)
443 EncodeOneFrame();
446 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent* waiter,
447 int32_t* retval) {
448 DCHECK(thread_checker_.CalledOnValidThread());
449 DCHECK(!async_waiter_);
450 DCHECK(!async_retval_);
451 async_waiter_ = waiter;
452 async_retval_ = retval;
455 void RTCVideoEncoder::Impl::SignalAsyncWaiter(int32_t retval) {
456 DCHECK(thread_checker_.CalledOnValidThread());
457 *async_retval_ = retval;
458 async_waiter_->Signal();
459 async_retval_ = NULL;
460 async_waiter_ = NULL;
463 #undef NOTIFY_ERROR
465 ////////////////////////////////////////////////////////////////////////////////
467 // RTCVideoEncoder
469 ////////////////////////////////////////////////////////////////////////////////
471 RTCVideoEncoder::RTCVideoEncoder(
472 webrtc::VideoCodecType type,
473 media::VideoCodecProfile profile,
474 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
475 : video_codec_type_(type),
476 video_codec_profile_(profile),
477 gpu_factories_(gpu_factories),
478 encoded_image_callback_(NULL),
479 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED),
480 weak_this_factory_(this) {
481 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile;
484 RTCVideoEncoder::~RTCVideoEncoder() {
485 DCHECK(thread_checker_.CalledOnValidThread());
486 Release();
487 DCHECK(!impl_);
490 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
491 int32_t number_of_cores,
492 uint32_t max_payload_size) {
493 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
494 << ", width=" << codec_settings->width
495 << ", height=" << codec_settings->height
496 << ", startBitrate=" << codec_settings->startBitrate;
497 DCHECK(thread_checker_.CalledOnValidThread());
498 DCHECK(!impl_);
500 weak_this_factory_.InvalidateWeakPtrs();
501 impl_ = new Impl(weak_this_factory_.GetWeakPtr(), gpu_factories_);
502 base::WaitableEvent initialization_waiter(true, false);
503 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
504 gpu_factories_->GetTaskRunner()->PostTask(
505 FROM_HERE,
506 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
507 impl_,
508 gfx::Size(codec_settings->width, codec_settings->height),
509 codec_settings->startBitrate,
510 video_codec_profile_,
511 &initialization_waiter,
512 &initialization_retval));
514 // webrtc::VideoEncoder expects this call to be synchronous.
515 initialization_waiter.Wait();
516 RecordInitEncodeUMA(initialization_retval);
517 return initialization_retval;
520 int32_t RTCVideoEncoder::Encode(
521 const webrtc::I420VideoFrame& input_image,
522 const webrtc::CodecSpecificInfo* codec_specific_info,
523 const std::vector<webrtc::VideoFrameType>* frame_types) {
524 DVLOG(3) << "Encode()";
525 // TODO(sheu): figure out why this check fails.
526 // DCHECK(thread_checker_.CalledOnValidThread());
527 if (!impl_) {
528 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
529 return impl_status_;
532 base::WaitableEvent encode_waiter(true, false);
533 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
534 gpu_factories_->GetTaskRunner()->PostTask(
535 FROM_HERE,
536 base::Bind(&RTCVideoEncoder::Impl::Enqueue,
537 impl_,
538 &input_image,
539 (frame_types->front() == webrtc::kKeyFrame),
540 &encode_waiter,
541 &encode_retval));
543 // webrtc::VideoEncoder expects this call to be synchronous.
544 encode_waiter.Wait();
545 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
546 return encode_retval;
549 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
550 webrtc::EncodedImageCallback* callback) {
551 DVLOG(3) << "RegisterEncodeCompleteCallback()";
552 DCHECK(thread_checker_.CalledOnValidThread());
553 if (!impl_) {
554 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_;
555 return impl_status_;
558 encoded_image_callback_ = callback;
559 return WEBRTC_VIDEO_CODEC_OK;
562 int32_t RTCVideoEncoder::Release() {
563 DVLOG(3) << "Release()";
564 DCHECK(thread_checker_.CalledOnValidThread());
566 // Reset the gpu_factory_, in case we reuse this encoder.
567 gpu_factories_->Abort();
568 gpu_factories_ = gpu_factories_->Clone();
569 if (impl_) {
570 gpu_factories_->GetTaskRunner()->PostTask(
571 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
572 impl_ = NULL;
573 weak_this_factory_.InvalidateWeakPtrs();
574 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
576 return WEBRTC_VIDEO_CODEC_OK;
579 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
580 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
581 << ", rtt=" << rtt;
582 DCHECK(thread_checker_.CalledOnValidThread());
583 // Ignored.
584 return WEBRTC_VIDEO_CODEC_OK;
587 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
588 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate
589 << ", frame_rate=" << frame_rate;
590 DCHECK(thread_checker_.CalledOnValidThread());
591 if (!impl_) {
592 DVLOG(3) << "SetRates(): returning " << impl_status_;
593 return impl_status_;
596 gpu_factories_->GetTaskRunner()->PostTask(
597 FROM_HERE,
598 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange,
599 impl_,
600 new_bit_rate,
601 frame_rate));
602 return WEBRTC_VIDEO_CODEC_OK;
605 void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
606 int32 bitstream_buffer_id) {
607 DCHECK(thread_checker_.CalledOnValidThread());
608 DVLOG(3) << "ReturnEncodedImage(): "
609 "bitstream_buffer_id=" << bitstream_buffer_id;
611 if (!encoded_image_callback_)
612 return;
614 webrtc::CodecSpecificInfo info;
615 memset(&info, 0, sizeof(info));
616 info.codecType = video_codec_type_;
617 if (video_codec_type_ == webrtc::kVideoCodecVP8) {
618 info.codecSpecific.VP8.pictureId = -1;
619 info.codecSpecific.VP8.tl0PicIdx = -1;
620 info.codecSpecific.VP8.keyIdx = -1;
623 // Generate a header describing a single fragment.
624 webrtc::RTPFragmentationHeader header;
625 memset(&header, 0, sizeof(header));
626 header.VerifyAndAllocateFragmentationHeader(1);
627 header.fragmentationOffset[0] = 0;
628 header.fragmentationLength[0] = image->_length;
629 header.fragmentationPlType[0] = 0;
630 header.fragmentationTimeDiff[0] = 0;
632 int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
633 if (retval < 0) {
634 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
635 << retval;
638 // The call through webrtc::EncodedImageCallback is synchronous, so we can
639 // immediately recycle the output buffer back to the Impl.
640 gpu_factories_->GetTaskRunner()->PostTask(
641 FROM_HERE,
642 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
643 impl_,
644 bitstream_buffer_id));
647 void RTCVideoEncoder::NotifyError(int32_t error) {
648 DCHECK(thread_checker_.CalledOnValidThread());
649 DVLOG(1) << "NotifyError(): error=" << error;
651 impl_status_ = error;
652 gpu_factories_->GetTaskRunner()->PostTask(
653 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
654 impl_ = NULL;
657 void RTCVideoEncoder::RecordInitEncodeUMA(int32_t init_retval) {
658 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess",
659 init_retval == WEBRTC_VIDEO_CODEC_OK);
660 if (init_retval == WEBRTC_VIDEO_CODEC_OK) {
661 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile",
662 video_codec_profile_,
663 media::VIDEO_CODEC_PROFILE_MAX);
667 } // namespace content