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"
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) \
24 DLOG(ERROR) << "calling NotifyError(): " << x; \
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
> {
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
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
,
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
,
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.
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
,
86 bool key_frame
) OVERRIDE
;
87 virtual void NotifyError(media::VideoEncodeAccelerator::Error error
) OVERRIDE
;
90 friend class base::RefCountedThreadSafe
<Impl
>;
93 kInputBufferExtraCount
= 1, // The number of input buffers allocated, more
94 // than what is requested by
95 // VEA::RequireBitstreamBuffers().
96 kOutputBufferCount
= 3,
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
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
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_
;
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
),
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
,
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
);
186 video_encoder_
= gpu_factories_
->CreateVideoEncodeAccelerator(this).Pass();
187 if (!video_encoder_
) {
188 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
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
,
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())
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(
220 output_buffers_
[bitstream_buffer_id
]->handle(),
221 output_buffers_
[bitstream_buffer_id
]->mapped_size()));
225 void RTCVideoEncoder::Impl::RequestEncodingParametersChange(uint32 bitrate
,
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
);
238 video_encoder_
->RequestEncodingParametersChange(bitrate
* 1000, framerate
);
241 void RTCVideoEncoder::Impl::Destroy() {
242 DVLOG(3) << "Impl::Destroy()";
243 DCHECK(thread_checker_
.CalledOnValidThread());
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());
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
));
272 DLOG(ERROR
) << "Impl::RequireBitstreamBuffers(): "
273 "failed to create input buffer " << i
;
274 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
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
);
285 DLOG(ERROR
) << "Impl::RequireBitstreamBuffers(): "
286 "failed to create output buffer " << i
;
287 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
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
,
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
);
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="
321 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
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()),
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(
343 base::Bind(&RTCVideoEncoder::ReturnEncodedImage
,
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());
355 case media::VideoEncodeAccelerator::kInvalidArgumentError
:
356 retval
= WEBRTC_VIDEO_CODEC_ERR_PARAMETER
;
359 retval
= WEBRTC_VIDEO_CODEC_ERROR
;
363 video_encoder_
.release()->Destroy();
366 SignalAsyncWaiter(retval
);
368 encoder_message_loop_proxy_
->PostTask(
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
);
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_
),
404 reinterpret_cast<uint8
*>(input_buffer
->memory()),
405 input_buffer
->mapped_size(),
406 input_buffer
->handle(),
408 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished
, this, index
));
410 DLOG(ERROR
) << "Impl::EncodeOneFrame(): failed to create frame";
411 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
415 // Do a strided copy of the input frame to match the input requirements for
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(),
422 media::CopyUPlane(next_frame
->buffer(webrtc::kUPlane
),
423 next_frame
->stride(webrtc::kUPlane
),
424 next_frame
->height(),
426 media::CopyVPlane(next_frame
->buffer(webrtc::kVPlane
),
427 next_frame
->stride(webrtc::kVPlane
),
428 next_frame
->height(),
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());
440 DCHECK_LT(index
, static_cast<int>(input_buffers_
.size()));
441 input_buffers_free_
.push_back(index
);
442 if (input_next_frame_
)
446 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent
* waiter
,
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
;
465 ////////////////////////////////////////////////////////////////////////////////
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());
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());
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(
506 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA
,
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());
528 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_
;
532 base::WaitableEvent
encode_waiter(true, false);
533 int32_t encode_retval
= WEBRTC_VIDEO_CODEC_UNINITIALIZED
;
534 gpu_factories_
->GetTaskRunner()->PostTask(
536 base::Bind(&RTCVideoEncoder::Impl::Enqueue
,
539 (frame_types
->front() == webrtc::kKeyFrame
),
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());
554 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << 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();
570 gpu_factories_
->GetTaskRunner()->PostTask(
571 FROM_HERE
, base::Bind(&RTCVideoEncoder::Impl::Destroy
, impl_
));
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
582 DCHECK(thread_checker_
.CalledOnValidThread());
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());
592 DVLOG(3) << "SetRates(): returning " << impl_status_
;
596 gpu_factories_
->GetTaskRunner()->PostTask(
598 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange
,
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_
)
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
);
634 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
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(
642 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId
,
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_
));
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