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/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"
22
23 #define NOTIFY_ERROR(x) \
24 do { \
25 DLOG(ERROR) << "calling NotifyError(): " << x; \
26 NotifyError(x); \
27 } while (0)
28
29 namespace content {
30
31 namespace {
32
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.
GetRTPFragmentationHeaderH264(webrtc::RTPFragmentationHeader * header,const uint8_t * data,uint32_t length)36 bool GetRTPFragmentationHeaderH264(webrtc::RTPFragmentationHeader* header,
37 const uint8_t* data, uint32_t length) {
38 media::H264Parser parser;
39 parser.SetStream(data, length);
40
41 std::vector<media::H264NALU> nalu_vector;
42 while (true) {
43 media::H264NALU nalu;
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) {
48 break;
49 } else {
50 DLOG(ERROR) << "Unexpected H264 parser result";
51 return false;
52 }
53 }
54
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;
61 }
62 return true;
63 }
64
65 } // namespace
66
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.
72 //
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> {
81 public:
82 Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
83 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
84
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
87 // call.
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,
91 uint32 bitrate,
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,
99 bool force_keyframe,
100 base::WaitableEvent* async_waiter,
101 int32_t* async_retval);
102
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);
107
108 // Request encoding parameter change for the underlying encoder.
109 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
110
111 // Destroy this Impl's encoder. The destructor is not explicitly called, as
112 // Impl is a base::RefCountedThreadSafe.
113 void Destroy();
114
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,
120 size_t payload_size,
121 bool key_frame) OVERRIDE;
122 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
123
124 private:
125 friend class base::RefCountedThreadSafe<Impl>;
126
127 enum {
128 kInputBufferExtraCount = 1, // The number of input buffers allocated, more
129 // than what is requested by
130 // VEA::RequireBitstreamBuffers().
131 kOutputBufferCount = 3,
132 };
133
134 virtual ~Impl();
135
136 // Perform encoding on an input frame from the input queue.
137 void EncodeOneFrame();
138
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);
142
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);
146
147 base::ThreadChecker thread_checker_;
148
149 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
150 // notifications.
151 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
152
153 // The message loop on which to post callbacks to |weak_encoder_|.
154 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
155
156 // Factory for creating VEAs, shared memory buffers, etc.
157 const scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
158
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
162 // an error occurs.
163 base::WaitableEvent* async_waiter_;
164 int32_t* async_retval_;
165
166 // The underlying VEA to perform encoding on.
167 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
168
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_;
172
173 // Whether to encode a keyframe next.
174 bool input_next_frame_keyframe_;
175
176 // Frame sizes.
177 gfx::Size input_frame_coded_size_;
178 gfx::Size input_visible_size_;
179
180 // Shared memory buffers for input/output with the VEA.
181 ScopedVector<base::SharedMemory> input_buffers_;
182 ScopedVector<base::SharedMemory> output_buffers_;
183
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_;
187
188 // The number of output buffers ready to be filled with output from the
189 // encoder.
190 int output_buffers_free_count_;
191
192 // 15 bits running index of the VP8 frames. See VP8 RTP spec for details.
193 uint16 picture_id_;
194
195 DISALLOW_COPY_AND_ASSIGN(Impl);
196 };
197
Impl(const base::WeakPtr<RTCVideoEncoder> & weak_encoder,const scoped_refptr<media::GpuVideoAcceleratorFactories> & gpu_factories)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),
204 async_waiter_(NULL),
205 async_retval_(NULL),
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));
212 }
213
CreateAndInitializeVEA(const gfx::Size & input_visible_size,uint32 bitrate,media::VideoCodecProfile profile,base::WaitableEvent * async_waiter,int32_t * async_retval)214 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
215 const gfx::Size& input_visible_size,
216 uint32 bitrate,
217 media::VideoCodecProfile profile,
218 base::WaitableEvent* async_waiter,
219 int32_t* async_retval) {
220 DVLOG(3) << "Impl::CreateAndInitializeVEA()";
221 DCHECK(thread_checker_.CalledOnValidThread());
222
223 RegisterAsyncWaiter(async_waiter, async_retval);
224
225 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
226 if (bitrate > kuint32max / 1000) {
227 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
228 return;
229 }
230
231 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator().Pass();
232 if (!video_encoder_) {
233 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
234 return;
235 }
236 input_visible_size_ = input_visible_size;
237 if (!video_encoder_->Initialize(media::VideoFrame::I420,
238 input_visible_size_,
239 profile,
240 bitrate * 1000,
241 this)) {
242 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
243 return;
244 }
245 }
246
Enqueue(const webrtc::I420VideoFrame * input_frame,bool force_keyframe,base::WaitableEvent * async_waiter,int32_t * async_retval)247 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame,
248 bool force_keyframe,
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_);
254
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
260 // Encode().
261 //
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().
269 //
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);
277 return;
278 }
279 input_next_frame_ = input_frame;
280 input_next_frame_keyframe_ = force_keyframe;
281
282 if (!input_buffers_free_.empty())
283 EncodeOneFrame();
284 }
285
UseOutputBitstreamBufferId(int32 bitstream_buffer_id)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(
293 bitstream_buffer_id,
294 output_buffers_[bitstream_buffer_id]->handle(),
295 output_buffers_[bitstream_buffer_id]->mapped_size()));
296 output_buffers_free_count_++;
297 }
298 }
299
RequestEncodingParametersChange(uint32 bitrate,uint32 framerate)300 void RTCVideoEncoder::Impl::RequestEncodingParametersChange(uint32 bitrate,
301 uint32 framerate) {
302 DVLOG(3) << "Impl::RequestEncodingParametersChange(): bitrate=" << bitrate
303 << ", framerate=" << framerate;
304 DCHECK(thread_checker_.CalledOnValidThread());
305
306 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
307 if (bitrate > kuint32max / 1000) {
308 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
309 return;
310 }
311
312 if (video_encoder_)
313 video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate);
314 }
315
Destroy()316 void RTCVideoEncoder::Impl::Destroy() {
317 DVLOG(3) << "Impl::Destroy()";
318 DCHECK(thread_checker_.CalledOnValidThread());
319 video_encoder_.reset();
320 }
321
RequireBitstreamBuffers(unsigned int input_count,const gfx::Size & input_coded_size,size_t output_buffer_size)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());
330
331 if (!video_encoder_)
332 return;
333
334 input_frame_coded_size_ = input_coded_size;
335
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));
340 if (!shm) {
341 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
342 "failed to create input buffer " << i;
343 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
344 return;
345 }
346 input_buffers_.push_back(shm);
347 input_buffers_free_.push_back(i);
348 }
349
350 for (int i = 0; i < kOutputBufferCount; ++i) {
351 base::SharedMemory* shm =
352 gpu_factories_->CreateSharedMemory(output_buffer_size);
353 if (!shm) {
354 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
355 "failed to create output buffer " << i;
356 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
357 return;
358 }
359 output_buffers_.push_back(shm);
360 }
361
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_++;
367 }
368 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
369 }
370
BitstreamBufferReady(int32 bitstream_buffer_id,size_t payload_size,bool key_frame)371 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
372 size_t payload_size,
373 bool key_frame) {
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());
379
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);
385 return;
386 }
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="
390 << payload_size;
391 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
392 return;
393 }
394 output_buffers_free_count_--;
395
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();
399
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);
403
404 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage(
405 reinterpret_cast<uint8_t*>(output_buffer->memory()),
406 payload_size,
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;
414
415 encoder_message_loop_proxy_->PostTask(
416 FROM_HERE,
417 base::Bind(&RTCVideoEncoder::ReturnEncodedImage,
418 weak_encoder_,
419 base::Passed(&image),
420 bitstream_buffer_id,
421 picture_id_));
422 // Picture ID must wrap after reaching the maximum.
423 picture_id_ = (picture_id_ + 1) & 0x7FFF;
424 }
425
NotifyError(media::VideoEncodeAccelerator::Error error)426 void RTCVideoEncoder::Impl::NotifyError(
427 media::VideoEncodeAccelerator::Error error) {
428 DVLOG(3) << "Impl::NotifyError(): error=" << error;
429 DCHECK(thread_checker_.CalledOnValidThread());
430 int32_t retval;
431 switch (error) {
432 case media::VideoEncodeAccelerator::kInvalidArgumentError:
433 retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
434 break;
435 default:
436 retval = WEBRTC_VIDEO_CODEC_ERROR;
437 }
438
439 video_encoder_.reset();
440
441 if (async_waiter_) {
442 SignalAsyncWaiter(retval);
443 } else {
444 encoder_message_loop_proxy_->PostTask(
445 FROM_HERE,
446 base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
447 }
448 }
449
~Impl()450 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
451
EncodeOneFrame()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());
457
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;
466
467 if (!video_encoder_) {
468 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR);
469 return;
470 }
471
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_),
479 input_visible_size_,
480 reinterpret_cast<uint8*>(input_buffer->memory()),
481 input_buffer->mapped_size(),
482 input_buffer->handle(),
483 base::TimeDelta(),
484 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
485 if (!frame.get()) {
486 DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame";
487 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
488 return;
489 }
490
491 // Do a strided copy of the input frame to match the input requirements for
492 // the encoder.
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(),
497 frame.get());
498 media::CopyUPlane(next_frame->buffer(webrtc::kUPlane),
499 next_frame->stride(webrtc::kUPlane),
500 next_frame->height(),
501 frame.get());
502 media::CopyVPlane(next_frame->buffer(webrtc::kVPlane),
503 next_frame->stride(webrtc::kVPlane),
504 next_frame->height(),
505 frame.get());
506
507 video_encoder_->Encode(frame, next_frame_keyframe);
508 input_buffers_free_.pop_back();
509 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
510 }
511
EncodeFrameFinished(int index)512 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) {
513 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index;
514 DCHECK(thread_checker_.CalledOnValidThread());
515 DCHECK_GE(index, 0);
516 DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
517 input_buffers_free_.push_back(index);
518 if (input_next_frame_)
519 EncodeOneFrame();
520 }
521
RegisterAsyncWaiter(base::WaitableEvent * waiter,int32_t * retval)522 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent* waiter,
523 int32_t* retval) {
524 DCHECK(thread_checker_.CalledOnValidThread());
525 DCHECK(!async_waiter_);
526 DCHECK(!async_retval_);
527 async_waiter_ = waiter;
528 async_retval_ = retval;
529 }
530
SignalAsyncWaiter(int32_t 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;
537 }
538
539 #undef NOTIFY_ERROR
540
541 ////////////////////////////////////////////////////////////////////////////////
542 //
543 // RTCVideoEncoder
544 //
545 ////////////////////////////////////////////////////////////////////////////////
546
RTCVideoEncoder(webrtc::VideoCodecType type,media::VideoCodecProfile profile,const scoped_refptr<media::GpuVideoAcceleratorFactories> & gpu_factories)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;
558 }
559
~RTCVideoEncoder()560 RTCVideoEncoder::~RTCVideoEncoder() {
561 DVLOG(3) << "~RTCVideoEncoder";
562 DCHECK(thread_checker_.CalledOnValidThread());
563 Release();
564 DCHECK(!impl_.get());
565 }
566
InitEncode(const webrtc::VideoCodec * codec_settings,int32_t number_of_cores,uint32_t max_payload_size)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());
576
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(
582 FROM_HERE,
583 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
584 impl_,
585 gfx::Size(codec_settings->width, codec_settings->height),
586 codec_settings->startBitrate,
587 video_codec_profile_,
588 &initialization_waiter,
589 &initialization_retval));
590
591 // webrtc::VideoEncoder expects this call to be synchronous.
592 initialization_waiter.Wait();
593 RecordInitEncodeUMA(initialization_retval);
594 return initialization_retval;
595 }
596
Encode(const webrtc::I420VideoFrame & input_image,const webrtc::CodecSpecificInfo * codec_specific_info,const std::vector<webrtc::VideoFrameType> * frame_types)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()";
602 if (!impl_.get()) {
603 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
604 return impl_status_;
605 }
606
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(
612 FROM_HERE,
613 base::Bind(&RTCVideoEncoder::Impl::Enqueue,
614 impl_,
615 &input_image,
616 want_key_frame,
617 &encode_waiter,
618 &encode_retval));
619
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;
624 }
625
RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback * callback)626 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
627 webrtc::EncodedImageCallback* callback) {
628 DVLOG(3) << "RegisterEncodeCompleteCallback()";
629 DCHECK(thread_checker_.CalledOnValidThread());
630 if (!impl_.get()) {
631 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_;
632 return impl_status_;
633 }
634
635 encoded_image_callback_ = callback;
636 return WEBRTC_VIDEO_CODEC_OK;
637 }
638
Release()639 int32_t RTCVideoEncoder::Release() {
640 DVLOG(3) << "Release()";
641 DCHECK(thread_checker_.CalledOnValidThread());
642
643 if (impl_.get()) {
644 gpu_factories_->GetTaskRunner()->PostTask(
645 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
646 impl_ = NULL;
647 weak_factory_.InvalidateWeakPtrs();
648 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
649 }
650 return WEBRTC_VIDEO_CODEC_OK;
651 }
652
SetChannelParameters(uint32_t packet_loss,int rtt)653 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
654 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
655 << ", rtt=" << rtt;
656 // Ignored.
657 return WEBRTC_VIDEO_CODEC_OK;
658 }
659
SetRates(uint32_t new_bit_rate,uint32_t frame_rate)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;
663 if (!impl_.get()) {
664 DVLOG(3) << "SetRates(): returning " << impl_status_;
665 return impl_status_;
666 }
667
668 gpu_factories_->GetTaskRunner()->PostTask(
669 FROM_HERE,
670 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange,
671 impl_,
672 new_bit_rate,
673 frame_rate));
674 return WEBRTC_VIDEO_CODEC_OK;
675 }
676
ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,int32 bitstream_buffer_id,uint16 picture_id)677 void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
678 int32 bitstream_buffer_id,
679 uint16 picture_id) {
680 DCHECK(thread_checker_.CalledOnValidThread());
681 DVLOG(3) << "ReturnEncodedImage(): "
682 << "bitstream_buffer_id=" << bitstream_buffer_id
683 << ", picture_id=" << picture_id;
684
685 if (!encoded_image_callback_)
686 return;
687
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;
700 break;
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);
706 return;
707 }
708 break;
709 default:
710 NOTREACHED() << "Invalid video codec type";
711 return;
712 }
713
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;
721 }
722
723 int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
724 if (retval < 0) {
725 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
726 << retval;
727 }
728
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(
732 FROM_HERE,
733 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
734 impl_,
735 bitstream_buffer_id));
736 }
737
NotifyError(int32_t error)738 void RTCVideoEncoder::NotifyError(int32_t error) {
739 DCHECK(thread_checker_.CalledOnValidThread());
740 DVLOG(1) << "NotifyError(): error=" << error;
741
742 impl_status_ = error;
743 gpu_factories_->GetTaskRunner()->PostTask(
744 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
745 impl_ = NULL;
746 }
747
RecordInitEncodeUMA(int32_t init_retval)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);
755 }
756 }
757
758 } // namespace content
759