• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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