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_decoder.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/memory/ref_counted.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "base/metrics/histogram.h"
12#include "base/numerics/safe_conversions.h"
13#include "base/stl_util.h"
14#include "base/synchronization/waitable_event.h"
15#include "base/task_runner_util.h"
16#include "content/child/child_thread.h"
17#include "content/renderer/media/native_handle_impl.h"
18#include "gpu/command_buffer/common/mailbox_holder.h"
19#include "media/base/bind_to_current_loop.h"
20#include "media/filters/gpu_video_accelerator_factories.h"
21#include "third_party/skia/include/core/SkBitmap.h"
22#include "third_party/webrtc/common_video/interface/texture_video_frame.h"
23#include "third_party/webrtc/system_wrappers/interface/ref_count.h"
24
25namespace content {
26
27const int32 RTCVideoDecoder::ID_LAST = 0x3FFFFFFF;
28const int32 RTCVideoDecoder::ID_HALF = 0x20000000;
29const int32 RTCVideoDecoder::ID_INVALID = -1;
30
31// Maximum number of concurrent VDA::Decode() operations RVD will maintain.
32// Higher values allow better pipelining in the GPU, but also require more
33// resources.
34static const size_t kMaxInFlightDecodes = 8;
35
36// Size of shared-memory segments we allocate.  Since we reuse them we let them
37// be on the beefy side.
38static const size_t kSharedMemorySegmentBytes = 100 << 10;
39
40// Maximum number of allocated shared-memory segments.
41static const int kMaxNumSharedMemorySegments = 16;
42
43// Maximum number of pending WebRTC buffers that are waiting for the shared
44// memory. 10 seconds for 30 fps.
45static const size_t kMaxNumOfPendingBuffers = 300;
46
47// A shared memory segment and its allocated size. This class has the ownership
48// of |shm|.
49class RTCVideoDecoder::SHMBuffer {
50 public:
51  SHMBuffer(base::SharedMemory* shm, size_t size);
52  ~SHMBuffer();
53  base::SharedMemory* const shm;
54  const size_t size;
55};
56
57RTCVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* shm, size_t size)
58    : shm(shm), size(size) {}
59
60RTCVideoDecoder::SHMBuffer::~SHMBuffer() { shm->Close(); }
61
62RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id,
63                                        uint32_t timestamp,
64                                        int width,
65                                        int height,
66                                        size_t size)
67    : bitstream_buffer_id(bitstream_buffer_id),
68      timestamp(timestamp),
69      width(width),
70      height(height),
71      size(size) {}
72
73RTCVideoDecoder::BufferData::BufferData() {}
74
75RTCVideoDecoder::BufferData::~BufferData() {}
76
77RTCVideoDecoder::RTCVideoDecoder(
78    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories)
79    : factories_(factories),
80      decoder_texture_target_(0),
81      next_picture_buffer_id_(0),
82      state_(UNINITIALIZED),
83      decode_complete_callback_(NULL),
84      num_shm_buffers_(0),
85      next_bitstream_buffer_id_(0),
86      reset_bitstream_buffer_id_(ID_INVALID),
87      weak_factory_(this) {
88  DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread());
89}
90
91RTCVideoDecoder::~RTCVideoDecoder() {
92  DVLOG(2) << "~RTCVideoDecoder";
93  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
94  DestroyVDA();
95
96  // Delete all shared memories.
97  STLDeleteElements(&available_shm_segments_);
98  STLDeleteValues(&bitstream_buffers_in_decoder_);
99  STLDeleteContainerPairFirstPointers(decode_buffers_.begin(),
100                                      decode_buffers_.end());
101  decode_buffers_.clear();
102
103  // Delete WebRTC input buffers.
104  for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it =
105           pending_buffers_.begin();
106       it != pending_buffers_.end();
107       ++it) {
108    delete[] it->first._buffer;
109  }
110}
111
112// static
113scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
114    webrtc::VideoCodecType type,
115    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) {
116  scoped_ptr<RTCVideoDecoder> decoder;
117  // Convert WebRTC codec type to media codec profile.
118  media::VideoCodecProfile profile;
119  switch (type) {
120    case webrtc::kVideoCodecVP8:
121      profile = media::VP8PROFILE_MAIN;
122      break;
123    default:
124      DVLOG(2) << "Video codec not supported:" << type;
125      return decoder.Pass();
126  }
127
128  base::WaitableEvent waiter(true, false);
129  decoder.reset(new RTCVideoDecoder(factories));
130  decoder->factories_->GetTaskRunner()->PostTask(
131      FROM_HERE,
132      base::Bind(&RTCVideoDecoder::CreateVDA,
133                 base::Unretained(decoder.get()),
134                 profile,
135                 &waiter));
136  waiter.Wait();
137  // vda can be NULL if VP8 is not supported.
138  if (decoder->vda_ != NULL) {
139    decoder->state_ = INITIALIZED;
140  } else {
141    factories->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder.release());
142  }
143  return decoder.Pass();
144}
145
146int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings,
147                                    int32_t /*numberOfCores*/) {
148  DVLOG(2) << "InitDecode";
149  DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8);
150  if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
151    LOG(ERROR) << "Feedback mode not supported";
152    return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_ERROR);
153  }
154
155  base::AutoLock auto_lock(lock_);
156  if (state_ == UNINITIALIZED || state_ == DECODE_ERROR) {
157    LOG(ERROR) << "VDA is not initialized. state=" << state_;
158    return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_UNINITIALIZED);
159  }
160  // Create some shared memory if the queue is empty.
161  if (available_shm_segments_.size() == 0) {
162    factories_->GetTaskRunner()->PostTask(
163        FROM_HERE,
164        base::Bind(&RTCVideoDecoder::CreateSHM,
165                   weak_factory_.GetWeakPtr(),
166                   kMaxInFlightDecodes,
167                   kSharedMemorySegmentBytes));
168  }
169  return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_OK);
170}
171
172int32_t RTCVideoDecoder::Decode(
173    const webrtc::EncodedImage& inputImage,
174    bool missingFrames,
175    const webrtc::RTPFragmentationHeader* /*fragmentation*/,
176    const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/,
177    int64_t /*renderTimeMs*/) {
178  DVLOG(3) << "Decode";
179
180  base::AutoLock auto_lock(lock_);
181
182  if (state_ == UNINITIALIZED || decode_complete_callback_ == NULL) {
183    LOG(ERROR) << "The decoder has not initialized.";
184    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
185  }
186
187  if (state_ == DECODE_ERROR) {
188    LOG(ERROR) << "Decoding error occurred.";
189    return WEBRTC_VIDEO_CODEC_ERROR;
190  }
191
192  if (missingFrames || !inputImage._completeFrame) {
193    DLOG(ERROR) << "Missing or incomplete frames.";
194    // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames.
195    // Return an error to request a key frame.
196    return WEBRTC_VIDEO_CODEC_ERROR;
197  }
198
199  // Most platforms' VDA implementations support mid-stream resolution change
200  // internally.  Platforms whose VDAs fail to support mid-stream resolution
201  // change gracefully need to have their clients cover for them, and we do that
202  // here.
203#ifdef ANDROID
204  const bool kVDACanHandleMidstreamResize = false;
205#else
206  const bool kVDACanHandleMidstreamResize = true;
207#endif
208
209  bool need_to_reset_for_midstream_resize = false;
210  if (inputImage._frameType == webrtc::kKeyFrame) {
211    DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x"
212             << inputImage._encodedHeight;
213    gfx::Size prev_frame_size = frame_size_;
214    frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight);
215    if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() &&
216        prev_frame_size != frame_size_) {
217      need_to_reset_for_midstream_resize = true;
218    }
219  } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_,
220                                     reset_bitstream_buffer_id_)) {
221    // TODO(wuchengli): VDA should handle it. Remove this when
222    // http://crosbug.com/p/21913 is fixed.
223    DVLOG(1) << "The first frame should be a key frame. Drop this.";
224    return WEBRTC_VIDEO_CODEC_ERROR;
225  }
226
227  // Create buffer metadata.
228  BufferData buffer_data(next_bitstream_buffer_id_,
229                         inputImage._timeStamp,
230                         frame_size_.width(),
231                         frame_size_.height(),
232                         inputImage._length);
233  // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
234  next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST;
235
236  // If a shared memory segment is available, there are no pending buffers, and
237  // this isn't a mid-stream resolution change, then send the buffer for decode
238  // immediately. Otherwise, save the buffer in the queue for later decode.
239  scoped_ptr<SHMBuffer> shm_buffer;
240  if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0)
241    shm_buffer = GetSHM_Locked(inputImage._length);
242  if (!shm_buffer) {
243    if (!SaveToPendingBuffers_Locked(inputImage, buffer_data))
244      return WEBRTC_VIDEO_CODEC_ERROR;
245    if (need_to_reset_for_midstream_resize) {
246      base::AutoUnlock auto_unlock(lock_);
247      Reset();
248    }
249    return WEBRTC_VIDEO_CODEC_OK;
250  }
251
252  SaveToDecodeBuffers_Locked(inputImage, shm_buffer.Pass(), buffer_data);
253  factories_->GetTaskRunner()->PostTask(
254      FROM_HERE,
255      base::Bind(&RTCVideoDecoder::RequestBufferDecode,
256                 weak_factory_.GetWeakPtr()));
257  return WEBRTC_VIDEO_CODEC_OK;
258}
259
260int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback(
261    webrtc::DecodedImageCallback* callback) {
262  DVLOG(2) << "RegisterDecodeCompleteCallback";
263  base::AutoLock auto_lock(lock_);
264  decode_complete_callback_ = callback;
265  return WEBRTC_VIDEO_CODEC_OK;
266}
267
268int32_t RTCVideoDecoder::Release() {
269  DVLOG(2) << "Release";
270  // Do not destroy VDA because WebRTC can call InitDecode and start decoding
271  // again.
272  return Reset();
273}
274
275int32_t RTCVideoDecoder::Reset() {
276  DVLOG(2) << "Reset";
277  base::AutoLock auto_lock(lock_);
278  if (state_ == UNINITIALIZED) {
279    LOG(ERROR) << "Decoder not initialized.";
280    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
281  }
282  if (next_bitstream_buffer_id_ != 0)
283    reset_bitstream_buffer_id_ = next_bitstream_buffer_id_ - 1;
284  else
285    reset_bitstream_buffer_id_ = ID_LAST;
286  // If VDA is already resetting, no need to request the reset again.
287  if (state_ != RESETTING) {
288    state_ = RESETTING;
289    factories_->GetTaskRunner()->PostTask(
290        FROM_HERE,
291        base::Bind(&RTCVideoDecoder::ResetInternal,
292                   weak_factory_.GetWeakPtr()));
293  }
294  return WEBRTC_VIDEO_CODEC_OK;
295}
296
297void RTCVideoDecoder::ProvidePictureBuffers(uint32 count,
298                                            const gfx::Size& size,
299                                            uint32 texture_target) {
300  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
301  DVLOG(3) << "ProvidePictureBuffers. texture_target=" << texture_target;
302
303  if (!vda_)
304    return;
305
306  std::vector<uint32> texture_ids;
307  std::vector<gpu::Mailbox> texture_mailboxes;
308  decoder_texture_target_ = texture_target;
309  if (!factories_->CreateTextures(count,
310                                  size,
311                                  &texture_ids,
312                                  &texture_mailboxes,
313                                  decoder_texture_target_)) {
314    NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
315    return;
316  }
317  DCHECK_EQ(count, texture_ids.size());
318  DCHECK_EQ(count, texture_mailboxes.size());
319
320  std::vector<media::PictureBuffer> picture_buffers;
321  for (size_t i = 0; i < texture_ids.size(); ++i) {
322    picture_buffers.push_back(media::PictureBuffer(
323        next_picture_buffer_id_++, size, texture_ids[i], texture_mailboxes[i]));
324    bool inserted = assigned_picture_buffers_.insert(std::make_pair(
325        picture_buffers.back().id(), picture_buffers.back())).second;
326    DCHECK(inserted);
327  }
328  vda_->AssignPictureBuffers(picture_buffers);
329}
330
331void RTCVideoDecoder::DismissPictureBuffer(int32 id) {
332  DVLOG(3) << "DismissPictureBuffer. id=" << id;
333  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
334
335  std::map<int32, media::PictureBuffer>::iterator it =
336      assigned_picture_buffers_.find(id);
337  if (it == assigned_picture_buffers_.end()) {
338    NOTREACHED() << "Missing picture buffer: " << id;
339    return;
340  }
341
342  media::PictureBuffer buffer_to_dismiss = it->second;
343  assigned_picture_buffers_.erase(it);
344
345  if (!picture_buffers_at_display_.count(id)) {
346    // We can delete the texture immediately as it's not being displayed.
347    factories_->DeleteTexture(buffer_to_dismiss.texture_id());
348    return;
349  }
350  // Not destroying a texture in display in |picture_buffers_at_display_|.
351  // Postpone deletion until after it's returned to us.
352}
353
354void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
355  DVLOG(3) << "PictureReady";
356  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
357
358  std::map<int32, media::PictureBuffer>::iterator it =
359      assigned_picture_buffers_.find(picture.picture_buffer_id());
360  if (it == assigned_picture_buffers_.end()) {
361    NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id();
362    NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
363    return;
364  }
365  const media::PictureBuffer& pb = it->second;
366
367  // Create a media::VideoFrame.
368  uint32_t timestamp = 0, width = 0, height = 0;
369  size_t size = 0;
370  GetBufferData(
371      picture.bitstream_buffer_id(), &timestamp, &width, &height, &size);
372  scoped_refptr<media::VideoFrame> frame =
373      CreateVideoFrame(picture, pb, timestamp, width, height, size);
374  bool inserted =
375      picture_buffers_at_display_.insert(std::make_pair(
376                                             picture.picture_buffer_id(),
377                                             pb.texture_id())).second;
378  DCHECK(inserted);
379
380  // Create a WebRTC video frame.
381  webrtc::RefCountImpl<NativeHandleImpl>* handle =
382      new webrtc::RefCountImpl<NativeHandleImpl>(frame);
383  webrtc::TextureVideoFrame decoded_image(handle, width, height, timestamp, 0);
384
385  // Invoke decode callback. WebRTC expects no callback after Reset or Release.
386  {
387    base::AutoLock auto_lock(lock_);
388    DCHECK(decode_complete_callback_ != NULL);
389    if (IsBufferAfterReset(picture.bitstream_buffer_id(),
390                           reset_bitstream_buffer_id_)) {
391      decode_complete_callback_->Decoded(decoded_image);
392    }
393  }
394}
395
396static void ReadPixelsSyncInner(
397    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
398    uint32 texture_id,
399    const gfx::Rect& visible_rect,
400    const SkBitmap& pixels,
401    base::WaitableEvent* event) {
402  factories->ReadPixels(texture_id, visible_rect, pixels);
403  event->Signal();
404}
405
406static void ReadPixelsSync(
407    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
408    uint32 texture_id,
409    const gfx::Rect& visible_rect,
410    const SkBitmap& pixels) {
411  base::WaitableEvent event(true, false);
412  if (!factories->GetTaskRunner()->PostTask(FROM_HERE,
413                                            base::Bind(&ReadPixelsSyncInner,
414                                                       factories,
415                                                       texture_id,
416                                                       visible_rect,
417                                                       pixels,
418                                                       &event)))
419    return;
420  event.Wait();
421}
422
423scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
424    const media::Picture& picture,
425    const media::PictureBuffer& pb,
426    uint32_t timestamp,
427    uint32_t width,
428    uint32_t height,
429    size_t size) {
430  gfx::Rect visible_rect(width, height);
431  DCHECK(decoder_texture_target_);
432  // Convert timestamp from 90KHz to ms.
433  base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue(
434      base::checked_cast<uint64_t>(timestamp) * 1000 / 90);
435  return media::VideoFrame::WrapNativeTexture(
436      make_scoped_ptr(new gpu::MailboxHolder(
437          pb.texture_mailbox(), decoder_texture_target_, 0)),
438      media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox,
439                                          weak_factory_.GetWeakPtr(),
440                                          factories_,
441                                          picture.picture_buffer_id(),
442                                          pb.texture_id())),
443      pb.size(),
444      visible_rect,
445      visible_rect.size(),
446      timestamp_ms,
447      base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect));
448}
449
450void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
451  DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id;
452  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
453
454  std::map<int32, SHMBuffer*>::iterator it =
455      bitstream_buffers_in_decoder_.find(id);
456  if (it == bitstream_buffers_in_decoder_.end()) {
457    NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
458    NOTREACHED() << "Missing bitstream buffer: " << id;
459    return;
460  }
461
462  {
463    base::AutoLock auto_lock(lock_);
464    PutSHM_Locked(scoped_ptr<SHMBuffer>(it->second));
465  }
466  bitstream_buffers_in_decoder_.erase(it);
467
468  RequestBufferDecode();
469}
470
471void RTCVideoDecoder::NotifyFlushDone() {
472  DVLOG(3) << "NotifyFlushDone";
473  NOTREACHED() << "Unexpected flush done notification.";
474}
475
476void RTCVideoDecoder::NotifyResetDone() {
477  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
478  DVLOG(3) << "NotifyResetDone";
479
480  if (!vda_)
481    return;
482
483  input_buffer_data_.clear();
484  {
485    base::AutoLock auto_lock(lock_);
486    state_ = INITIALIZED;
487  }
488  // Send the pending buffers for decoding.
489  RequestBufferDecode();
490}
491
492void RTCVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
493  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
494  if (!vda_)
495    return;
496
497  LOG(ERROR) << "VDA Error:" << error;
498  UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError",
499                            error,
500                            media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM);
501  DestroyVDA();
502
503  base::AutoLock auto_lock(lock_);
504  state_ = DECODE_ERROR;
505}
506
507void RTCVideoDecoder::RequestBufferDecode() {
508  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
509  if (!vda_)
510    return;
511
512  MovePendingBuffersToDecodeBuffers();
513
514  while (CanMoreDecodeWorkBeDone()) {
515    // Get a buffer and data from the queue.
516    SHMBuffer* shm_buffer = NULL;
517    BufferData buffer_data;
518    {
519      base::AutoLock auto_lock(lock_);
520      // Do not request decode if VDA is resetting.
521      if (decode_buffers_.size() == 0 || state_ == RESETTING)
522        return;
523      shm_buffer = decode_buffers_.front().first;
524      buffer_data = decode_buffers_.front().second;
525      decode_buffers_.pop_front();
526      // Drop the buffers before Reset or Release is called.
527      if (!IsBufferAfterReset(buffer_data.bitstream_buffer_id,
528                              reset_bitstream_buffer_id_)) {
529        PutSHM_Locked(scoped_ptr<SHMBuffer>(shm_buffer));
530        continue;
531      }
532    }
533
534    // Create a BitstreamBuffer and send to VDA to decode.
535    media::BitstreamBuffer bitstream_buffer(buffer_data.bitstream_buffer_id,
536                                            shm_buffer->shm->handle(),
537                                            buffer_data.size);
538    bool inserted = bitstream_buffers_in_decoder_
539        .insert(std::make_pair(bitstream_buffer.id(), shm_buffer)).second;
540    DCHECK(inserted);
541    RecordBufferData(buffer_data);
542    vda_->Decode(bitstream_buffer);
543  }
544}
545
546bool RTCVideoDecoder::CanMoreDecodeWorkBeDone() {
547  return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes;
548}
549
550bool RTCVideoDecoder::IsBufferAfterReset(int32 id_buffer, int32 id_reset) {
551  if (id_reset == ID_INVALID)
552    return true;
553  int32 diff = id_buffer - id_reset;
554  if (diff <= 0)
555    diff += ID_LAST + 1;
556  return diff < ID_HALF;
557}
558
559bool RTCVideoDecoder::IsFirstBufferAfterReset(int32 id_buffer, int32 id_reset) {
560  if (id_reset == ID_INVALID)
561    return id_buffer == 0;
562  return id_buffer == ((id_reset + 1) & ID_LAST);
563}
564
565void RTCVideoDecoder::SaveToDecodeBuffers_Locked(
566    const webrtc::EncodedImage& input_image,
567    scoped_ptr<SHMBuffer> shm_buffer,
568    const BufferData& buffer_data) {
569  memcpy(shm_buffer->shm->memory(), input_image._buffer, input_image._length);
570  std::pair<SHMBuffer*, BufferData> buffer_pair =
571      std::make_pair(shm_buffer.release(), buffer_data);
572
573  // Store the buffer and the metadata to the queue.
574  decode_buffers_.push_back(buffer_pair);
575}
576
577bool RTCVideoDecoder::SaveToPendingBuffers_Locked(
578    const webrtc::EncodedImage& input_image,
579    const BufferData& buffer_data) {
580  DVLOG(2) << "SaveToPendingBuffers_Locked"
581           << ". pending_buffers size=" << pending_buffers_.size()
582           << ". decode_buffers_ size=" << decode_buffers_.size()
583           << ". available_shm size=" << available_shm_segments_.size();
584  // Queued too many buffers. Something goes wrong.
585  if (pending_buffers_.size() >= kMaxNumOfPendingBuffers) {
586    LOG(WARNING) << "Too many pending buffers!";
587    return false;
588  }
589
590  // Clone the input image and save it to the queue.
591  uint8_t* buffer = new uint8_t[input_image._length];
592  // TODO(wuchengli): avoid memcpy. Extend webrtc::VideoDecoder::Decode()
593  // interface to take a non-const ptr to the frame and add a method to the
594  // frame that will swap buffers with another.
595  memcpy(buffer, input_image._buffer, input_image._length);
596  webrtc::EncodedImage encoded_image(
597      buffer, input_image._length, input_image._length);
598  std::pair<webrtc::EncodedImage, BufferData> buffer_pair =
599      std::make_pair(encoded_image, buffer_data);
600
601  pending_buffers_.push_back(buffer_pair);
602  return true;
603}
604
605void RTCVideoDecoder::MovePendingBuffersToDecodeBuffers() {
606  base::AutoLock auto_lock(lock_);
607  while (pending_buffers_.size() > 0) {
608    // Get a pending buffer from the queue.
609    const webrtc::EncodedImage& input_image = pending_buffers_.front().first;
610    const BufferData& buffer_data = pending_buffers_.front().second;
611
612    // Drop the frame if it comes before Reset or Release.
613    if (!IsBufferAfterReset(buffer_data.bitstream_buffer_id,
614                            reset_bitstream_buffer_id_)) {
615      delete[] input_image._buffer;
616      pending_buffers_.pop_front();
617      continue;
618    }
619    // Get shared memory and save it to decode buffers.
620    scoped_ptr<SHMBuffer> shm_buffer = GetSHM_Locked(input_image._length);
621    if (!shm_buffer)
622      return;
623    SaveToDecodeBuffers_Locked(input_image, shm_buffer.Pass(), buffer_data);
624    delete[] input_image._buffer;
625    pending_buffers_.pop_front();
626  }
627}
628
629void RTCVideoDecoder::ResetInternal() {
630  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
631  DVLOG(2) << "ResetInternal";
632  if (vda_)
633    vda_->Reset();
634}
635
636// static
637void RTCVideoDecoder::ReleaseMailbox(
638    base::WeakPtr<RTCVideoDecoder> decoder,
639    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
640    int64 picture_buffer_id,
641    uint32 texture_id,
642    const std::vector<uint32>& release_sync_points) {
643  DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread());
644
645  for (size_t i = 0; i < release_sync_points.size(); i++)
646    factories->WaitSyncPoint(release_sync_points[i]);
647
648  if (decoder) {
649    decoder->ReusePictureBuffer(picture_buffer_id);
650    return;
651  }
652  // It's the last chance to delete the texture after display,
653  // because RTCVideoDecoder was destructed.
654  factories->DeleteTexture(texture_id);
655}
656
657void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) {
658  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
659  DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id;
660
661  DCHECK(!picture_buffers_at_display_.empty());
662  PictureBufferTextureMap::iterator display_iterator =
663      picture_buffers_at_display_.find(picture_buffer_id);
664  uint32 texture_id = display_iterator->second;
665  DCHECK(display_iterator != picture_buffers_at_display_.end());
666  picture_buffers_at_display_.erase(display_iterator);
667
668  if (!assigned_picture_buffers_.count(picture_buffer_id)) {
669    // This picture was dismissed while in display, so we postponed deletion.
670    factories_->DeleteTexture(texture_id);
671    return;
672  }
673
674  // DestroyVDA() might already have been called.
675  if (vda_)
676    vda_->ReusePictureBuffer(picture_buffer_id);
677}
678
679void RTCVideoDecoder::CreateVDA(media::VideoCodecProfile profile,
680                                base::WaitableEvent* waiter) {
681  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
682  vda_ = factories_->CreateVideoDecodeAccelerator();
683  if (vda_ && !vda_->Initialize(profile, this))
684    vda_.release()->Destroy();
685  waiter->Signal();
686}
687
688void RTCVideoDecoder::DestroyTextures() {
689  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
690
691  // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since
692  // their textures may still be in use by the user of this RTCVideoDecoder.
693  for (PictureBufferTextureMap::iterator it =
694           picture_buffers_at_display_.begin();
695       it != picture_buffers_at_display_.end();
696       ++it) {
697    assigned_picture_buffers_.erase(it->first);
698  }
699
700  for (std::map<int32, media::PictureBuffer>::iterator it =
701           assigned_picture_buffers_.begin();
702       it != assigned_picture_buffers_.end();
703       ++it) {
704    factories_->DeleteTexture(it->second.texture_id());
705  }
706  assigned_picture_buffers_.clear();
707}
708
709void RTCVideoDecoder::DestroyVDA() {
710  DVLOG(2) << "DestroyVDA";
711  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
712  if (vda_)
713    vda_.release()->Destroy();
714  DestroyTextures();
715  base::AutoLock auto_lock(lock_);
716  state_ = UNINITIALIZED;
717}
718
719scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked(
720    size_t min_size) {
721  // Reuse a SHM if possible.
722  SHMBuffer* ret = NULL;
723  if (!available_shm_segments_.empty() &&
724      available_shm_segments_.back()->size >= min_size) {
725    ret = available_shm_segments_.back();
726    available_shm_segments_.pop_back();
727  }
728  // Post to vda thread to create shared memory if SHM cannot be reused or the
729  // queue is almost empty.
730  if (num_shm_buffers_ < kMaxNumSharedMemorySegments &&
731      (ret == NULL || available_shm_segments_.size() <= 1)) {
732    factories_->GetTaskRunner()->PostTask(
733        FROM_HERE,
734        base::Bind(&RTCVideoDecoder::CreateSHM,
735                   weak_factory_.GetWeakPtr(),
736                   1,
737                   min_size));
738  }
739  return scoped_ptr<SHMBuffer>(ret);
740}
741
742void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) {
743  available_shm_segments_.push_back(shm_buffer.release());
744}
745
746void RTCVideoDecoder::CreateSHM(int number, size_t min_size) {
747  DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
748  DVLOG(2) << "CreateSHM. size=" << min_size;
749  int number_to_allocate;
750  {
751    base::AutoLock auto_lock(lock_);
752    number_to_allocate =
753        std::min(kMaxNumSharedMemorySegments - num_shm_buffers_, number);
754  }
755  size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes);
756  for (int i = 0; i < number_to_allocate; i++) {
757    base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate);
758    if (shm != NULL) {
759      base::AutoLock auto_lock(lock_);
760      num_shm_buffers_++;
761      PutSHM_Locked(
762          scoped_ptr<SHMBuffer>(new SHMBuffer(shm, size_to_allocate)));
763    }
764  }
765  // Kick off the decoding.
766  RequestBufferDecode();
767}
768
769void RTCVideoDecoder::RecordBufferData(const BufferData& buffer_data) {
770  input_buffer_data_.push_front(buffer_data);
771  // Why this value?  Because why not.  avformat.h:MAX_REORDER_DELAY is 16, but
772  // that's too small for some pathological B-frame test videos.  The cost of
773  // using too-high a value is low (192 bits per extra slot).
774  static const size_t kMaxInputBufferDataSize = 128;
775  // Pop from the back of the list, because that's the oldest and least likely
776  // to be useful in the future data.
777  if (input_buffer_data_.size() > kMaxInputBufferDataSize)
778    input_buffer_data_.pop_back();
779}
780
781void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id,
782                                    uint32_t* timestamp,
783                                    uint32_t* width,
784                                    uint32_t* height,
785                                    size_t* size) {
786  for (std::list<BufferData>::iterator it = input_buffer_data_.begin();
787       it != input_buffer_data_.end();
788       ++it) {
789    if (it->bitstream_buffer_id != bitstream_buffer_id)
790      continue;
791    *timestamp = it->timestamp;
792    *width = it->width;
793    *height = it->height;
794    return;
795  }
796  NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id;
797}
798
799int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) {
800  // Logging boolean is enough to know if HW decoding has been used. Also,
801  // InitDecode is less likely to return an error so enum is not used here.
802  bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false;
803  UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample);
804  return status;
805}
806
807void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent()
808    const {
809  DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread());
810}
811
812}  // namespace content
813