- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / media / rtc_video_encoder.cc
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/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"
21
22 #define NOTIFY_ERROR(x)                             \
23   do {                                              \
24     DLOG(ERROR) << "calling NotifyError(): " << x;  \
25     NotifyError(x);                                 \
26   } while (0)
27
28 namespace content {
29
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.
35 //
36 // This class separates state related to the thread that RTCVideoEncoder
37 // operates on (presently the libjingle worker thread) from the thread that
38 // |gpu_factories_| provides for accelerator operations (presently the media
39 // thread).  The RTCVideoEncoder class can be deleted directly by WebRTC, while
40 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA.
41 class RTCVideoEncoder::Impl
42     : public media::VideoEncodeAccelerator::Client,
43       public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
44  public:
45   Impl(
46       const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
47       const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
48
49   // Create the VEA and call Initialize() on it.  Called once per instantiation,
50   // and then the instance is bound forevermore to whichever thread made the
51   // call.
52   // RTCVideoEncoder expects to be able to call this function synchronously from
53   // its own thread, hence the |async_waiter| and |async_retval| arguments.
54   void CreateAndInitializeVEA(const gfx::Size& input_visible_size,
55                               uint32 bitrate,
56                               media::VideoCodecProfile profile,
57                               base::WaitableEvent* async_waiter,
58                               int32_t* async_retval);
59   // Enqueue a frame from WebRTC for encoding.
60   // RTCVideoEncoder expects to be able to call this function synchronously from
61   // its own thread, hence the |async_waiter| and |async_retval| arguments.
62   void Enqueue(const webrtc::I420VideoFrame* input_frame,
63                bool force_keyframe,
64                base::WaitableEvent* async_waiter,
65                int32_t* async_retval);
66
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);
71
72   // Request encoding parameter change for the underlying encoder.
73   void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
74
75   // Destroy this Impl's encoder.  The destructor is not explicitly called, as
76   // Impl is a base::RefCountedThreadSafe.
77   void Destroy();
78
79   // media::VideoEncodeAccelerator::Client implementation.
80   virtual void NotifyInitializeDone() OVERRIDE;
81   virtual void RequireBitstreamBuffers(unsigned int input_count,
82                                        const gfx::Size& input_coded_size,
83                                        size_t output_buffer_size) OVERRIDE;
84   virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
85                                     size_t payload_size,
86                                     bool key_frame) OVERRIDE;
87   virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
88
89  private:
90   friend class base::RefCountedThreadSafe<Impl>;
91
92   enum {
93     kInputBufferExtraCount = 1,  // The number of input buffers allocated, more
94                                  // than what is requested by
95                                  // VEA::RequireBitstreamBuffers().
96     kOutputBufferCount = 3,
97   };
98
99   virtual ~Impl();
100
101   // Perform encoding on an input frame from the input queue.
102   void EncodeOneFrame();
103
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);
107
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);
111
112   base::ThreadChecker thread_checker_;
113
114   // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
115   // notifications.
116   const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
117
118   // The message loop on which to post callbacks to |weak_encoder_|.
119   const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
120
121   // Factory for creating VEAs, shared memory buffers, etc.
122   const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
123
124   // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
125   // Do this by waiting on the |async_waiter_| and returning the return value in
126   // |async_retval_| when initialization completes, encoding completes, or
127   // an error occurs.
128   base::WaitableEvent* async_waiter_;
129   int32_t* async_retval_;
130
131   // The underlying VEA to perform encoding on.
132   scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
133
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_;
137
138   // Whether to encode a keyframe next.
139   bool input_next_frame_keyframe_;
140
141   // Frame sizes.
142   gfx::Size input_frame_coded_size_;
143   gfx::Size input_visible_size_;
144
145   // Shared memory buffers for input/output with the VEA.
146   ScopedVector<base::SharedMemory> input_buffers_;
147   ScopedVector<base::SharedMemory> output_buffers_;
148
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_;
152
153   DISALLOW_COPY_AND_ASSIGN(Impl);
154 };
155
156 RTCVideoEncoder::Impl::Impl(
157     const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
158     const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
159     : weak_encoder_(weak_encoder),
160       encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
161       gpu_factories_(gpu_factories),
162       async_waiter_(NULL),
163       async_retval_(NULL),
164       input_next_frame_(NULL),
165       input_next_frame_keyframe_(false) {
166   thread_checker_.DetachFromThread();
167 }
168
169 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
170     const gfx::Size& input_visible_size,
171     uint32 bitrate,
172     media::VideoCodecProfile profile,
173     base::WaitableEvent* async_waiter,
174     int32_t* async_retval) {
175   DVLOG(3) << "Impl::CreateAndInitializeVEA()";
176   DCHECK(thread_checker_.CalledOnValidThread());
177
178   RegisterAsyncWaiter(async_waiter, async_retval);
179
180   // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
181   if (bitrate > kuint32max / 1000) {
182     NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
183     return;
184   }
185
186   video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass();
187   if (!video_encoder_) {
188     NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
189     return;
190   }
191   input_visible_size_ = input_visible_size;
192   video_encoder_->Initialize(
193       media::VideoFrame::I420, input_visible_size_, profile, bitrate * 1000);
194 }
195
196 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame,
197                                     bool force_keyframe,
198                                     base::WaitableEvent* async_waiter,
199                                     int32_t* async_retval) {
200   DVLOG(3) << "Impl::Enqueue()";
201   DCHECK(thread_checker_.CalledOnValidThread());
202   DCHECK(!input_next_frame_);
203
204   RegisterAsyncWaiter(async_waiter, async_retval);
205   input_next_frame_ = input_frame;
206   input_next_frame_keyframe_ = force_keyframe;
207
208   if (!input_buffers_free_.empty())
209     EncodeOneFrame();
210 }
211
212 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId(
213     int32 bitstream_buffer_id) {
214   DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): "
215               "bitstream_buffer_id=" << bitstream_buffer_id;
216   DCHECK(thread_checker_.CalledOnValidThread());
217   if (video_encoder_) {
218     video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
219         bitstream_buffer_id,
220         output_buffers_[bitstream_buffer_id]->handle(),
221         output_buffers_[bitstream_buffer_id]->mapped_size()));
222   }
223 }
224
225 void RTCVideoEncoder::Impl::RequestEncodingParametersChange(uint32 bitrate,
226                                                             uint32 framerate) {
227   DVLOG(3) << "Impl::RequestEncodingParametersChange(): bitrate=" << bitrate
228            << ", framerate=" << framerate;
229   DCHECK(thread_checker_.CalledOnValidThread());
230
231   // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
232   if (bitrate > kuint32max / 1000) {
233     NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
234     return;
235   }
236
237   if (video_encoder_)
238     video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate);
239 }
240
241 void RTCVideoEncoder::Impl::Destroy() {
242   DVLOG(3) << "Impl::Destroy()";
243   DCHECK(thread_checker_.CalledOnValidThread());
244   if (video_encoder_)
245     video_encoder_.release()->Destroy();
246 }
247
248 void RTCVideoEncoder::Impl::NotifyInitializeDone() {
249   DVLOG(3) << "Impl::NotifyInitializeDone()";
250   DCHECK(thread_checker_.CalledOnValidThread());
251 }
252
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());
261
262   if (!video_encoder_)
263     return;
264
265   input_frame_coded_size_ = input_coded_size;
266
267   for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
268     base::SharedMemory* shm =
269         gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize(
270             media::VideoFrame::I420, input_coded_size));
271     if (!shm) {
272       DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
273                      "failed to create input buffer " << i;
274       NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
275       return;
276     }
277     input_buffers_.push_back(shm);
278     input_buffers_free_.push_back(i);
279   }
280
281   for (int i = 0; i < kOutputBufferCount; ++i) {
282     base::SharedMemory* shm =
283         gpu_factories_->CreateSharedMemory(output_buffer_size);
284     if (!shm) {
285       DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
286                      "failed to create output buffer " << i;
287       NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
288       return;
289     }
290     output_buffers_.push_back(shm);
291   }
292
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()));
297   }
298   SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
299 }
300
301 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
302                                                  size_t payload_size,
303                                                  bool key_frame) {
304   DVLOG(3) << "Impl::BitstreamBufferReady(): "
305               "bitstream_buffer_id=" << bitstream_buffer_id
306            << ", payload_size=" << payload_size
307            << ", key_frame=" << key_frame;
308   DCHECK(thread_checker_.CalledOnValidThread());
309
310   if (bitstream_buffer_id < 0 ||
311       bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) {
312     DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id="
313                 << bitstream_buffer_id;
314     NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
315     return;
316   }
317   base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
318   if (payload_size > output_buffer->mapped_size()) {
319     DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size="
320                 << payload_size;
321     NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
322     return;
323   }
324
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();
328
329   scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage(
330       reinterpret_cast<uint8_t*>(output_buffer->memory()),
331       payload_size,
332       output_buffer->mapped_size()));
333   image->_encodedWidth = input_visible_size_.width();
334   image->_encodedHeight = input_visible_size_.height();
335   // Convert capture time to 90 kHz RTP timestamp.
336   image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
337   image->capture_time_ms_ = capture_time_ms;
338   image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
339   image->_completeFrame = true;
340
341   encoder_message_loop_proxy_->PostTask(
342       FROM_HERE,
343       base::Bind(&RTCVideoEncoder::ReturnEncodedImage,
344                  weak_encoder_,
345                  base::Passed(&image),
346                  bitstream_buffer_id));
347 }
348
349 void RTCVideoEncoder::Impl::NotifyError(
350     media::VideoEncodeAccelerator::Error error) {
351   DVLOG(3) << "Impl::NotifyError(): error=" << error;
352   DCHECK(thread_checker_.CalledOnValidThread());
353   int32_t retval;
354   switch (error) {
355     case media::VideoEncodeAccelerator::kInvalidArgumentError:
356       retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
357       break;
358     default:
359       retval = WEBRTC_VIDEO_CODEC_ERROR;
360   }
361
362   if (video_encoder_)
363     video_encoder_.release()->Destroy();
364
365   if (async_waiter_) {
366     SignalAsyncWaiter(retval);
367   } else {
368     encoder_message_loop_proxy_->PostTask(
369         FROM_HERE,
370         base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
371   }
372 }
373
374 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
375
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());
381
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;
390
391   if (!video_encoder_) {
392     SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR);
393     return;
394   }
395
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::WrapExternalSharedMemory(
400           media::VideoFrame::I420,
401           input_frame_coded_size_,
402           gfx::Rect(input_visible_size_),
403           input_visible_size_,
404           reinterpret_cast<uint8*>(input_buffer->memory()),
405           input_buffer->mapped_size(),
406           input_buffer->handle(),
407           base::TimeDelta(),
408           base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
409   if (!frame) {
410     DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame";
411     NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
412     return;
413   }
414
415   // Do a strided copy of the input frame to match the input requirements for
416   // the encoder.
417   // TODO(sheu): support zero-copy from WebRTC.  http://crbug.com/269312
418   media::CopyYPlane(next_frame->buffer(webrtc::kYPlane),
419                     next_frame->stride(webrtc::kYPlane),
420                     next_frame->height(),
421                     frame.get());
422   media::CopyUPlane(next_frame->buffer(webrtc::kUPlane),
423                     next_frame->stride(webrtc::kUPlane),
424                     next_frame->height(),
425                     frame.get());
426   media::CopyVPlane(next_frame->buffer(webrtc::kVPlane),
427                     next_frame->stride(webrtc::kVPlane),
428                     next_frame->height(),
429                     frame.get());
430
431   video_encoder_->Encode(frame, next_frame_keyframe);
432   input_buffers_free_.pop_back();
433   SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
434 }
435
436 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) {
437   DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index;
438   DCHECK(thread_checker_.CalledOnValidThread());
439   DCHECK_GE(index, 0);
440   DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
441   input_buffers_free_.push_back(index);
442   if (input_next_frame_)
443     EncodeOneFrame();
444 }
445
446 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent* waiter,
447                                                 int32_t* retval) {
448   DCHECK(thread_checker_.CalledOnValidThread());
449   DCHECK(!async_waiter_);
450   DCHECK(!async_retval_);
451   async_waiter_ = waiter;
452   async_retval_ = retval;
453 }
454
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;
461 }
462
463 #undef NOTIFY_ERROR
464
465 ////////////////////////////////////////////////////////////////////////////////
466 //
467 // RTCVideoEncoder
468 //
469 ////////////////////////////////////////////////////////////////////////////////
470
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       weak_this_factory_(this),
479       encoded_image_callback_(NULL),
480       impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) {
481   DVLOG(1) << "RTCVideoEncoder(): profile=" << profile;
482 }
483
484 RTCVideoEncoder::~RTCVideoEncoder() {
485   DCHECK(thread_checker_.CalledOnValidThread());
486   Release();
487   DCHECK(!impl_);
488 }
489
490 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
491                                     int32_t number_of_cores,
492                                     uint32_t max_payload_size) {
493   DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
494            << ", width=" << codec_settings->width
495            << ", height=" << codec_settings->height
496            << ", startBitrate=" << codec_settings->startBitrate;
497   DCHECK(thread_checker_.CalledOnValidThread());
498   DCHECK(!impl_);
499
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_->GetMessageLoop()->PostTask(
505       FROM_HERE,
506       base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
507                  impl_,
508                  gfx::Size(codec_settings->width, codec_settings->height),
509                  codec_settings->startBitrate,
510                  video_codec_profile_,
511                  &initialization_waiter,
512                  &initialization_retval));
513
514   // webrtc::VideoEncoder expects this call to be synchronous.
515   initialization_waiter.Wait();
516   RecordInitEncodeUMA(initialization_retval);
517   return initialization_retval;
518 }
519
520 int32_t RTCVideoEncoder::Encode(
521     const webrtc::I420VideoFrame& input_image,
522     const webrtc::CodecSpecificInfo* codec_specific_info,
523     const std::vector<webrtc::VideoFrameType>* frame_types) {
524   DVLOG(3) << "Encode()";
525   // TODO(sheu): figure out why this check fails.
526   // DCHECK(thread_checker_.CalledOnValidThread());
527   if (!impl_) {
528     DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
529     return impl_status_;
530   }
531
532   base::WaitableEvent encode_waiter(true, false);
533   int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
534   gpu_factories_->GetMessageLoop()->PostTask(
535       FROM_HERE,
536       base::Bind(&RTCVideoEncoder::Impl::Enqueue,
537                  impl_,
538                  &input_image,
539                  (frame_types->front() == webrtc::kKeyFrame),
540                  &encode_waiter,
541                  &encode_retval));
542
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;
547 }
548
549 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
550     webrtc::EncodedImageCallback* callback) {
551   DVLOG(3) << "RegisterEncodeCompleteCallback()";
552   DCHECK(thread_checker_.CalledOnValidThread());
553   if (!impl_) {
554     DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_;
555     return impl_status_;
556   }
557
558   encoded_image_callback_ = callback;
559   return WEBRTC_VIDEO_CODEC_OK;
560 }
561
562 int32_t RTCVideoEncoder::Release() {
563   DVLOG(3) << "Release()";
564   DCHECK(thread_checker_.CalledOnValidThread());
565
566   // Reset the gpu_factory_, in case we reuse this encoder.
567   gpu_factories_->Abort();
568   gpu_factories_ = gpu_factories_->Clone();
569   if (impl_) {
570     gpu_factories_->GetMessageLoop()->PostTask(
571         FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
572     impl_ = NULL;
573     weak_this_factory_.InvalidateWeakPtrs();
574     impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
575   }
576   return WEBRTC_VIDEO_CODEC_OK;
577 }
578
579 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
580   DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
581            << ", rtt=" << rtt;
582   DCHECK(thread_checker_.CalledOnValidThread());
583   // Ignored.
584   return WEBRTC_VIDEO_CODEC_OK;
585 }
586
587 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
588   DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate
589            << ", frame_rate=" << frame_rate;
590   DCHECK(thread_checker_.CalledOnValidThread());
591   if (!impl_) {
592     DVLOG(3) << "SetRates(): returning " << impl_status_;
593     return impl_status_;
594   }
595
596   gpu_factories_->GetMessageLoop()->PostTask(
597       FROM_HERE,
598       base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange,
599                  impl_,
600                  new_bit_rate,
601                  frame_rate));
602   return WEBRTC_VIDEO_CODEC_OK;
603 }
604
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;
610
611   if (!encoded_image_callback_)
612     return;
613
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;
621   }
622
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;
631
632   int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
633   if (retval < 0) {
634     DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
635              << retval;
636   }
637
638   // The call through webrtc::EncodedImageCallback is synchronous, so we can
639   // immediately recycle the output buffer back to the Impl.
640   gpu_factories_->GetMessageLoop()->PostTask(
641       FROM_HERE,
642       base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
643                  impl_,
644                  bitstream_buffer_id));
645 }
646
647 void RTCVideoEncoder::NotifyError(int32_t error) {
648   DCHECK(thread_checker_.CalledOnValidThread());
649   DVLOG(1) << "NotifyError(): error=" << error;
650
651   impl_status_ = error;
652   gpu_factories_->GetMessageLoop()->PostTask(
653       FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
654   impl_ = NULL;
655 }
656
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);
664   }
665 }
666
667 }  // namespace content