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/rand_util.h"
14 #include "base/synchronization/waitable_event.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/filters/h264_parser.h"
20 #include "media/video/video_encode_accelerator.h"
21 #include "third_party/webrtc/system_wrappers/interface/tick_util.h"
23 #define NOTIFY_ERROR(x) \
25 DLOG(ERROR) << "calling NotifyError(): " << x; \
33 // Populates struct webrtc::RTPFragmentationHeader for H264 codec.
34 // Each entry specifies the offset and length (excluding start code) of a NALU.
35 // Returns true if successful.
36 bool GetRTPFragmentationHeaderH264(webrtc::RTPFragmentationHeader
* header
,
37 const uint8_t* data
, uint32_t length
) {
38 media::H264Parser parser
;
39 parser
.SetStream(data
, length
);
41 std::vector
<media::H264NALU
> nalu_vector
;
44 const media::H264Parser::Result result
= parser
.AdvanceToNextNALU(&nalu
);
45 if (result
== media::H264Parser::kOk
) {
46 nalu_vector
.push_back(nalu
);
47 } else if (result
== media::H264Parser::kEOStream
) {
50 DLOG(ERROR
) << "Unexpected H264 parser result";
55 header
->VerifyAndAllocateFragmentationHeader(nalu_vector
.size());
56 for (size_t i
= 0; i
< nalu_vector
.size(); ++i
) {
57 header
->fragmentationOffset
[i
] = nalu_vector
[i
].data
- data
;
58 header
->fragmentationLength
[i
] = nalu_vector
[i
].size
;
59 header
->fragmentationPlType
[i
] = 0;
60 header
->fragmentationTimeDiff
[i
] = 0;
67 // This private class of RTCVideoEncoder does the actual work of communicating
68 // with a media::VideoEncodeAccelerator for handling video encoding. It can
69 // be created on any thread, but should subsequently be posted to (and Destroy()
70 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the
71 // thread on which the instance was constructed.
73 // This class separates state related to the thread that RTCVideoEncoder
74 // operates on (presently the libjingle worker thread) from the thread that
75 // |gpu_factories_| provides for accelerator operations (presently the media
76 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while
77 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA.
78 class RTCVideoEncoder::Impl
79 : public media::VideoEncodeAccelerator::Client
,
80 public base::RefCountedThreadSafe
<RTCVideoEncoder::Impl
> {
82 Impl(const base::WeakPtr
<RTCVideoEncoder
>& weak_encoder
,
83 const scoped_refptr
<media::GpuVideoAcceleratorFactories
>& gpu_factories
);
85 // Create the VEA and call Initialize() on it. Called once per instantiation,
86 // and then the instance is bound forevermore to whichever thread made the
88 // RTCVideoEncoder expects to be able to call this function synchronously from
89 // its own thread, hence the |async_waiter| and |async_retval| arguments.
90 void CreateAndInitializeVEA(const gfx::Size
& input_visible_size
,
92 media::VideoCodecProfile profile
,
93 base::WaitableEvent
* async_waiter
,
94 int32_t* async_retval
);
95 // Enqueue a frame from WebRTC for encoding.
96 // RTCVideoEncoder expects to be able to call this function synchronously from
97 // its own thread, hence the |async_waiter| and |async_retval| arguments.
98 void Enqueue(const webrtc::I420VideoFrame
* input_frame
,
100 base::WaitableEvent
* async_waiter
,
101 int32_t* async_retval
);
103 // RTCVideoEncoder is given a buffer to be passed to WebRTC through the
104 // RTCVideoEncoder::ReturnEncodedImage() function. When that is complete,
105 // the buffer is returned to Impl by its index using this function.
106 void UseOutputBitstreamBufferId(int32 bitstream_buffer_id
);
108 // Request encoding parameter change for the underlying encoder.
109 void RequestEncodingParametersChange(uint32 bitrate
, uint32 framerate
);
111 // Destroy this Impl's encoder. The destructor is not explicitly called, as
112 // Impl is a base::RefCountedThreadSafe.
115 // media::VideoEncodeAccelerator::Client implementation.
116 virtual void RequireBitstreamBuffers(unsigned int input_count
,
117 const gfx::Size
& input_coded_size
,
118 size_t output_buffer_size
) override
;
119 virtual void BitstreamBufferReady(int32 bitstream_buffer_id
,
121 bool key_frame
) override
;
122 virtual void NotifyError(media::VideoEncodeAccelerator::Error error
) override
;
125 friend class base::RefCountedThreadSafe
<Impl
>;
128 kInputBufferExtraCount
= 1, // The number of input buffers allocated, more
129 // than what is requested by
130 // VEA::RequireBitstreamBuffers().
131 kOutputBufferCount
= 3,
136 // Perform encoding on an input frame from the input queue.
137 void EncodeOneFrame();
139 // Notify that an input frame is finished for encoding. |index| is the index
140 // of the completed frame in |input_buffers_|.
141 void EncodeFrameFinished(int index
);
143 // Set up/signal |async_waiter_| and |async_retval_|; see declarations below.
144 void RegisterAsyncWaiter(base::WaitableEvent
* waiter
, int32_t* retval
);
145 void SignalAsyncWaiter(int32_t retval
);
147 base::ThreadChecker thread_checker_
;
149 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
151 const base::WeakPtr
<RTCVideoEncoder
> weak_encoder_
;
153 // The message loop on which to post callbacks to |weak_encoder_|.
154 const scoped_refptr
<base::MessageLoopProxy
> encoder_message_loop_proxy_
;
156 // Factory for creating VEAs, shared memory buffers, etc.
157 const scoped_refptr
<media::GpuVideoAcceleratorFactories
> gpu_factories_
;
159 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
160 // Do this by waiting on the |async_waiter_| and returning the return value in
161 // |async_retval_| when initialization completes, encoding completes, or
163 base::WaitableEvent
* async_waiter_
;
164 int32_t* async_retval_
;
166 // The underlying VEA to perform encoding on.
167 scoped_ptr
<media::VideoEncodeAccelerator
> video_encoder_
;
169 // Next input frame. Since there is at most one next frame, a single-element
170 // queue is sufficient.
171 const webrtc::I420VideoFrame
* input_next_frame_
;
173 // Whether to encode a keyframe next.
174 bool input_next_frame_keyframe_
;
177 gfx::Size input_frame_coded_size_
;
178 gfx::Size input_visible_size_
;
180 // Shared memory buffers for input/output with the VEA.
181 ScopedVector
<base::SharedMemory
> input_buffers_
;
182 ScopedVector
<base::SharedMemory
> output_buffers_
;
184 // Input buffers ready to be filled with input from Encode(). As a LIFO since
185 // we don't care about ordering.
186 std::vector
<int> input_buffers_free_
;
188 // The number of output buffers ready to be filled with output from the
190 int output_buffers_free_count_
;
192 // 15 bits running index of the VP8 frames. See VP8 RTP spec for details.
195 DISALLOW_COPY_AND_ASSIGN(Impl
);
198 RTCVideoEncoder::Impl::Impl(
199 const base::WeakPtr
<RTCVideoEncoder
>& weak_encoder
,
200 const scoped_refptr
<media::GpuVideoAcceleratorFactories
>& gpu_factories
)
201 : weak_encoder_(weak_encoder
),
202 encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
203 gpu_factories_(gpu_factories
),
206 input_next_frame_(NULL
),
207 input_next_frame_keyframe_(false),
208 output_buffers_free_count_(0) {
209 thread_checker_
.DetachFromThread();
210 // Picture ID should start on a random number.
211 picture_id_
= static_cast<uint16_t>(base::RandInt(0, 0x7FFF));
214 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
215 const gfx::Size
& input_visible_size
,
217 media::VideoCodecProfile profile
,
218 base::WaitableEvent
* async_waiter
,
219 int32_t* async_retval
) {
220 DVLOG(3) << "Impl::CreateAndInitializeVEA()";
221 DCHECK(thread_checker_
.CalledOnValidThread());
223 RegisterAsyncWaiter(async_waiter
, async_retval
);
225 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
226 if (bitrate
> kuint32max
/ 1000) {
227 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError
);
231 video_encoder_
= gpu_factories_
->CreateVideoEncodeAccelerator().Pass();
232 if (!video_encoder_
) {
233 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
236 input_visible_size_
= input_visible_size
;
237 if (!video_encoder_
->Initialize(media::VideoFrame::I420
,
242 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError
);
247 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame
* input_frame
,
249 base::WaitableEvent
* async_waiter
,
250 int32_t* async_retval
) {
251 DVLOG(3) << "Impl::Enqueue()";
252 DCHECK(thread_checker_
.CalledOnValidThread());
253 DCHECK(!input_next_frame_
);
255 RegisterAsyncWaiter(async_waiter
, async_retval
);
256 // If there are no free input and output buffers, drop the frame to avoid a
257 // deadlock. If there is a free input buffer, EncodeOneFrame will run and
258 // unblock Encode(). If there are no free input buffers but there is a free
259 // output buffer, EncodeFrameFinished will be called later to unblock
262 // The caller of Encode() holds a webrtc lock. The deadlock happens when:
263 // (1) Encode() is waiting for the frame to be encoded in EncodeOneFrame().
264 // (2) There are no free input buffers and they cannot be freed because
265 // the encoder has no output buffers.
266 // (3) Output buffers cannot be freed because ReturnEncodedImage is queued
267 // on libjingle worker thread to be run. But the worker thread is waiting
268 // for the same webrtc lock held by the caller of Encode().
270 // Dropping a frame is fine. The encoder has been filled with all input
271 // buffers. Returning an error in Encode() is not fatal and WebRTC will just
272 // continue. If this is a key frame, WebRTC will request a key frame again.
273 // Besides, webrtc will drop a frame if Encode() blocks too long.
274 if (input_buffers_free_
.empty() && output_buffers_free_count_
== 0) {
275 DVLOG(2) << "Run out of input and output buffers. Drop the frame.";
276 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR
);
279 input_next_frame_
= input_frame
;
280 input_next_frame_keyframe_
= force_keyframe
;
282 if (!input_buffers_free_
.empty())
286 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId(
287 int32 bitstream_buffer_id
) {
288 DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): "
289 "bitstream_buffer_id=" << bitstream_buffer_id
;
290 DCHECK(thread_checker_
.CalledOnValidThread());
291 if (video_encoder_
) {
292 video_encoder_
->UseOutputBitstreamBuffer(media::BitstreamBuffer(
294 output_buffers_
[bitstream_buffer_id
]->handle(),
295 output_buffers_
[bitstream_buffer_id
]->mapped_size()));
296 output_buffers_free_count_
++;
300 void RTCVideoEncoder::Impl::RequestEncodingParametersChange(uint32 bitrate
,
302 DVLOG(3) << "Impl::RequestEncodingParametersChange(): bitrate=" << bitrate
303 << ", framerate=" << framerate
;
304 DCHECK(thread_checker_
.CalledOnValidThread());
306 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
307 if (bitrate
> kuint32max
/ 1000) {
308 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError
);
313 video_encoder_
->RequestEncodingParametersChange(bitrate
* 1000, framerate
);
316 void RTCVideoEncoder::Impl::Destroy() {
317 DVLOG(3) << "Impl::Destroy()";
318 DCHECK(thread_checker_
.CalledOnValidThread());
319 video_encoder_
.reset();
322 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
323 unsigned int input_count
,
324 const gfx::Size
& input_coded_size
,
325 size_t output_buffer_size
) {
326 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count
327 << ", input_coded_size=" << input_coded_size
.ToString()
328 << ", output_buffer_size=" << output_buffer_size
;
329 DCHECK(thread_checker_
.CalledOnValidThread());
334 input_frame_coded_size_
= input_coded_size
;
336 for (unsigned int i
= 0; i
< input_count
+ kInputBufferExtraCount
; ++i
) {
337 base::SharedMemory
* shm
=
338 gpu_factories_
->CreateSharedMemory(media::VideoFrame::AllocationSize(
339 media::VideoFrame::I420
, input_coded_size
));
341 DLOG(ERROR
) << "Impl::RequireBitstreamBuffers(): "
342 "failed to create input buffer " << i
;
343 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
346 input_buffers_
.push_back(shm
);
347 input_buffers_free_
.push_back(i
);
350 for (int i
= 0; i
< kOutputBufferCount
; ++i
) {
351 base::SharedMemory
* shm
=
352 gpu_factories_
->CreateSharedMemory(output_buffer_size
);
354 DLOG(ERROR
) << "Impl::RequireBitstreamBuffers(): "
355 "failed to create output buffer " << i
;
356 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
359 output_buffers_
.push_back(shm
);
362 // Immediately provide all output buffers to the VEA.
363 for (size_t i
= 0; i
< output_buffers_
.size(); ++i
) {
364 video_encoder_
->UseOutputBitstreamBuffer(media::BitstreamBuffer(
365 i
, output_buffers_
[i
]->handle(), output_buffers_
[i
]->mapped_size()));
366 output_buffers_free_count_
++;
368 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK
);
371 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id
,
374 DVLOG(3) << "Impl::BitstreamBufferReady(): "
375 "bitstream_buffer_id=" << bitstream_buffer_id
376 << ", payload_size=" << payload_size
377 << ", key_frame=" << key_frame
;
378 DCHECK(thread_checker_
.CalledOnValidThread());
380 if (bitstream_buffer_id
< 0 ||
381 bitstream_buffer_id
>= static_cast<int>(output_buffers_
.size())) {
382 DLOG(ERROR
) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id="
383 << bitstream_buffer_id
;
384 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
387 base::SharedMemory
* output_buffer
= output_buffers_
[bitstream_buffer_id
];
388 if (payload_size
> output_buffer
->mapped_size()) {
389 DLOG(ERROR
) << "Impl::BitstreamBufferReady(): invalid payload_size="
391 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
394 output_buffers_free_count_
--;
396 // Use webrtc timestamps to ensure correct RTP sender behavior.
397 // TODO(hshi): obtain timestamp from the capturer, see crbug.com/350106.
398 const int64 capture_time_us
= webrtc::TickTime::MicrosecondTimestamp();
400 // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks).
401 int64 capture_time_ms
= capture_time_us
/ 1000;
402 uint32_t rtp_timestamp
= static_cast<uint32_t>(capture_time_us
* 90 / 1000);
404 scoped_ptr
<webrtc::EncodedImage
> image(new webrtc::EncodedImage(
405 reinterpret_cast<uint8_t*>(output_buffer
->memory()),
407 output_buffer
->mapped_size()));
408 image
->_encodedWidth
= input_visible_size_
.width();
409 image
->_encodedHeight
= input_visible_size_
.height();
410 image
->_timeStamp
= rtp_timestamp
;
411 image
->capture_time_ms_
= capture_time_ms
;
412 image
->_frameType
= (key_frame
? webrtc::kKeyFrame
: webrtc::kDeltaFrame
);
413 image
->_completeFrame
= true;
415 encoder_message_loop_proxy_
->PostTask(
417 base::Bind(&RTCVideoEncoder::ReturnEncodedImage
,
419 base::Passed(&image
),
422 // Picture ID must wrap after reaching the maximum.
423 picture_id_
= (picture_id_
+ 1) & 0x7FFF;
426 void RTCVideoEncoder::Impl::NotifyError(
427 media::VideoEncodeAccelerator::Error error
) {
428 DVLOG(3) << "Impl::NotifyError(): error=" << error
;
429 DCHECK(thread_checker_
.CalledOnValidThread());
432 case media::VideoEncodeAccelerator::kInvalidArgumentError
:
433 retval
= WEBRTC_VIDEO_CODEC_ERR_PARAMETER
;
436 retval
= WEBRTC_VIDEO_CODEC_ERROR
;
439 video_encoder_
.reset();
442 SignalAsyncWaiter(retval
);
444 encoder_message_loop_proxy_
->PostTask(
446 base::Bind(&RTCVideoEncoder::NotifyError
, weak_encoder_
, retval
));
450 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_
); }
452 void RTCVideoEncoder::Impl::EncodeOneFrame() {
453 DVLOG(3) << "Impl::EncodeOneFrame()";
454 DCHECK(thread_checker_
.CalledOnValidThread());
455 DCHECK(input_next_frame_
);
456 DCHECK(!input_buffers_free_
.empty());
458 // EncodeOneFrame() may re-enter EncodeFrameFinished() if VEA::Encode() fails,
459 // we receive a VEA::NotifyError(), and the media::VideoFrame we pass to
460 // Encode() gets destroyed early. Handle this by resetting our
461 // input_next_frame_* state before we hand off the VideoFrame to the VEA.
462 const webrtc::I420VideoFrame
* next_frame
= input_next_frame_
;
463 bool next_frame_keyframe
= input_next_frame_keyframe_
;
464 input_next_frame_
= NULL
;
465 input_next_frame_keyframe_
= false;
467 if (!video_encoder_
) {
468 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR
);
472 const int index
= input_buffers_free_
.back();
473 base::SharedMemory
* input_buffer
= input_buffers_
[index
];
474 scoped_refptr
<media::VideoFrame
> frame
=
475 media::VideoFrame::WrapExternalPackedMemory(
476 media::VideoFrame::I420
,
477 input_frame_coded_size_
,
478 gfx::Rect(input_visible_size_
),
480 reinterpret_cast<uint8
*>(input_buffer
->memory()),
481 input_buffer
->mapped_size(),
482 input_buffer
->handle(),
484 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished
, this, index
));
486 DLOG(ERROR
) << "Impl::EncodeOneFrame(): failed to create frame";
487 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError
);
491 // Do a strided copy of the input frame to match the input requirements for
493 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312
494 media::CopyYPlane(next_frame
->buffer(webrtc::kYPlane
),
495 next_frame
->stride(webrtc::kYPlane
),
496 next_frame
->height(),
498 media::CopyUPlane(next_frame
->buffer(webrtc::kUPlane
),
499 next_frame
->stride(webrtc::kUPlane
),
500 next_frame
->height(),
502 media::CopyVPlane(next_frame
->buffer(webrtc::kVPlane
),
503 next_frame
->stride(webrtc::kVPlane
),
504 next_frame
->height(),
507 video_encoder_
->Encode(frame
, next_frame_keyframe
);
508 input_buffers_free_
.pop_back();
509 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK
);
512 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index
) {
513 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index
;
514 DCHECK(thread_checker_
.CalledOnValidThread());
516 DCHECK_LT(index
, static_cast<int>(input_buffers_
.size()));
517 input_buffers_free_
.push_back(index
);
518 if (input_next_frame_
)
522 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent
* waiter
,
524 DCHECK(thread_checker_
.CalledOnValidThread());
525 DCHECK(!async_waiter_
);
526 DCHECK(!async_retval_
);
527 async_waiter_
= waiter
;
528 async_retval_
= retval
;
531 void RTCVideoEncoder::Impl::SignalAsyncWaiter(int32_t retval
) {
532 DCHECK(thread_checker_
.CalledOnValidThread());
533 *async_retval_
= retval
;
534 async_waiter_
->Signal();
535 async_retval_
= NULL
;
536 async_waiter_
= NULL
;
541 ////////////////////////////////////////////////////////////////////////////////
545 ////////////////////////////////////////////////////////////////////////////////
547 RTCVideoEncoder::RTCVideoEncoder(
548 webrtc::VideoCodecType type
,
549 media::VideoCodecProfile profile
,
550 const scoped_refptr
<media::GpuVideoAcceleratorFactories
>& gpu_factories
)
551 : video_codec_type_(type
),
552 video_codec_profile_(profile
),
553 gpu_factories_(gpu_factories
),
554 encoded_image_callback_(NULL
),
555 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED
),
556 weak_factory_(this) {
557 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile
;
560 RTCVideoEncoder::~RTCVideoEncoder() {
561 DVLOG(3) << "~RTCVideoEncoder";
562 DCHECK(thread_checker_
.CalledOnValidThread());
564 DCHECK(!impl_
.get());
567 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec
* codec_settings
,
568 int32_t number_of_cores
,
569 uint32_t max_payload_size
) {
570 DVLOG(1) << "InitEncode(): codecType=" << codec_settings
->codecType
571 << ", width=" << codec_settings
->width
572 << ", height=" << codec_settings
->height
573 << ", startBitrate=" << codec_settings
->startBitrate
;
574 DCHECK(thread_checker_
.CalledOnValidThread());
575 DCHECK(!impl_
.get());
577 weak_factory_
.InvalidateWeakPtrs();
578 impl_
= new Impl(weak_factory_
.GetWeakPtr(), gpu_factories_
);
579 base::WaitableEvent
initialization_waiter(true, false);
580 int32_t initialization_retval
= WEBRTC_VIDEO_CODEC_UNINITIALIZED
;
581 gpu_factories_
->GetTaskRunner()->PostTask(
583 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA
,
585 gfx::Size(codec_settings
->width
, codec_settings
->height
),
586 codec_settings
->startBitrate
,
587 video_codec_profile_
,
588 &initialization_waiter
,
589 &initialization_retval
));
591 // webrtc::VideoEncoder expects this call to be synchronous.
592 initialization_waiter
.Wait();
593 RecordInitEncodeUMA(initialization_retval
);
594 return initialization_retval
;
597 int32_t RTCVideoEncoder::Encode(
598 const webrtc::I420VideoFrame
& input_image
,
599 const webrtc::CodecSpecificInfo
* codec_specific_info
,
600 const std::vector
<webrtc::VideoFrameType
>* frame_types
) {
601 DVLOG(3) << "Encode()";
603 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_
;
607 bool want_key_frame
= frame_types
&& frame_types
->size() &&
608 frame_types
->front() == webrtc::kKeyFrame
;
609 base::WaitableEvent
encode_waiter(true, false);
610 int32_t encode_retval
= WEBRTC_VIDEO_CODEC_UNINITIALIZED
;
611 gpu_factories_
->GetTaskRunner()->PostTask(
613 base::Bind(&RTCVideoEncoder::Impl::Enqueue
,
620 // webrtc::VideoEncoder expects this call to be synchronous.
621 encode_waiter
.Wait();
622 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval
;
623 return encode_retval
;
626 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
627 webrtc::EncodedImageCallback
* callback
) {
628 DVLOG(3) << "RegisterEncodeCompleteCallback()";
629 DCHECK(thread_checker_
.CalledOnValidThread());
631 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_
;
635 encoded_image_callback_
= callback
;
636 return WEBRTC_VIDEO_CODEC_OK
;
639 int32_t RTCVideoEncoder::Release() {
640 DVLOG(3) << "Release()";
641 DCHECK(thread_checker_
.CalledOnValidThread());
644 gpu_factories_
->GetTaskRunner()->PostTask(
645 FROM_HERE
, base::Bind(&RTCVideoEncoder::Impl::Destroy
, impl_
));
647 weak_factory_
.InvalidateWeakPtrs();
648 impl_status_
= WEBRTC_VIDEO_CODEC_UNINITIALIZED
;
650 return WEBRTC_VIDEO_CODEC_OK
;
653 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss
, int rtt
) {
654 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
657 return WEBRTC_VIDEO_CODEC_OK
;
660 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate
, uint32_t frame_rate
) {
661 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate
662 << ", frame_rate=" << frame_rate
;
664 DVLOG(3) << "SetRates(): returning " << impl_status_
;
668 gpu_factories_
->GetTaskRunner()->PostTask(
670 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange
,
674 return WEBRTC_VIDEO_CODEC_OK
;
677 void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr
<webrtc::EncodedImage
> image
,
678 int32 bitstream_buffer_id
,
680 DCHECK(thread_checker_
.CalledOnValidThread());
681 DVLOG(3) << "ReturnEncodedImage(): "
682 << "bitstream_buffer_id=" << bitstream_buffer_id
683 << ", picture_id=" << picture_id
;
685 if (!encoded_image_callback_
)
688 webrtc::RTPFragmentationHeader header
;
689 memset(&header
, 0, sizeof(header
));
690 switch (video_codec_type_
) {
691 case webrtc::kVideoCodecVP8
:
692 case webrtc::kVideoCodecGeneric
:
693 // Generate a header describing a single fragment.
694 // Note that webrtc treats the generic-type payload as an opaque buffer.
695 header
.VerifyAndAllocateFragmentationHeader(1);
696 header
.fragmentationOffset
[0] = 0;
697 header
.fragmentationLength
[0] = image
->_length
;
698 header
.fragmentationPlType
[0] = 0;
699 header
.fragmentationTimeDiff
[0] = 0;
701 case webrtc::kVideoCodecH264
:
702 if (!GetRTPFragmentationHeaderH264(
703 &header
, image
->_buffer
, image
->_length
)) {
704 DLOG(ERROR
) << "Failed to get RTP fragmentation header for H264";
705 NotifyError(WEBRTC_VIDEO_CODEC_ERROR
);
710 NOTREACHED() << "Invalid video codec type";
714 webrtc::CodecSpecificInfo info
;
715 memset(&info
, 0, sizeof(info
));
716 info
.codecType
= video_codec_type_
;
717 if (video_codec_type_
== webrtc::kVideoCodecVP8
) {
718 info
.codecSpecific
.VP8
.pictureId
= picture_id
;
719 info
.codecSpecific
.VP8
.tl0PicIdx
= -1;
720 info
.codecSpecific
.VP8
.keyIdx
= -1;
723 int32_t retval
= encoded_image_callback_
->Encoded(*image
, &info
, &header
);
725 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
729 // The call through webrtc::EncodedImageCallback is synchronous, so we can
730 // immediately recycle the output buffer back to the Impl.
731 gpu_factories_
->GetTaskRunner()->PostTask(
733 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId
,
735 bitstream_buffer_id
));
738 void RTCVideoEncoder::NotifyError(int32_t error
) {
739 DCHECK(thread_checker_
.CalledOnValidThread());
740 DVLOG(1) << "NotifyError(): error=" << error
;
742 impl_status_
= error
;
743 gpu_factories_
->GetTaskRunner()->PostTask(
744 FROM_HERE
, base::Bind(&RTCVideoEncoder::Impl::Destroy
, impl_
));
748 void RTCVideoEncoder::RecordInitEncodeUMA(int32_t init_retval
) {
749 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess",
750 init_retval
== WEBRTC_VIDEO_CODEC_OK
);
751 if (init_retval
== WEBRTC_VIDEO_CODEC_OK
) {
752 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile",
753 video_codec_profile_
,
754 media::VIDEO_CODEC_PROFILE_MAX
+ 1);
758 } // namespace content