Home | History | Annotate | Download | only in filters
      1 // Copyright (c) 2012 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 "media/filters/gpu_video_decoder.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/bind.h"
     10 #include "base/callback_helpers.h"
     11 #include "base/command_line.h"
     12 #include "base/cpu.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/stl_util.h"
     16 #include "base/synchronization/waitable_event.h"
     17 #include "base/task_runner_util.h"
     18 #include "gpu/command_buffer/common/mailbox_holder.h"
     19 #include "media/base/bind_to_current_loop.h"
     20 #include "media/base/decoder_buffer.h"
     21 #include "media/base/media_switches.h"
     22 #include "media/base/pipeline.h"
     23 #include "media/base/pipeline_status.h"
     24 #include "media/base/video_decoder_config.h"
     25 #include "media/filters/gpu_video_accelerator_factories.h"
     26 #include "third_party/skia/include/core/SkBitmap.h"
     27 
     28 namespace media {
     29 
     30 // Maximum number of concurrent VDA::Decode() operations GVD will maintain.
     31 // Higher values allow better pipelining in the GPU, but also require more
     32 // resources.
     33 enum { kMaxInFlightDecodes = 4 };
     34 
     35 // Size of shared-memory segments we allocate.  Since we reuse them we let them
     36 // be on the beefy side.
     37 static const size_t kSharedMemorySegmentBytes = 100 << 10;
     38 
     39 GpuVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s)
     40     : shm(m), size(s) {
     41 }
     42 
     43 GpuVideoDecoder::SHMBuffer::~SHMBuffer() {}
     44 
     45 GpuVideoDecoder::PendingDecoderBuffer::PendingDecoderBuffer(
     46     SHMBuffer* s,
     47     const scoped_refptr<DecoderBuffer>& b,
     48     const DecodeCB& done_cb)
     49     : shm_buffer(s), buffer(b), done_cb(done_cb) {
     50 }
     51 
     52 GpuVideoDecoder::PendingDecoderBuffer::~PendingDecoderBuffer() {}
     53 
     54 GpuVideoDecoder::BufferData::BufferData(
     55     int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns)
     56     : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr),
     57       natural_size(ns) {
     58 }
     59 
     60 GpuVideoDecoder::BufferData::~BufferData() {}
     61 
     62 GpuVideoDecoder::GpuVideoDecoder(
     63     const scoped_refptr<GpuVideoAcceleratorFactories>& factories)
     64     : needs_bitstream_conversion_(false),
     65       factories_(factories),
     66       state_(kNormal),
     67       decoder_texture_target_(0),
     68       next_picture_buffer_id_(0),
     69       next_bitstream_buffer_id_(0),
     70       available_pictures_(0),
     71       weak_factory_(this) {
     72   DCHECK(factories_.get());
     73 }
     74 
     75 void GpuVideoDecoder::Reset(const base::Closure& closure)  {
     76   DVLOG(3) << "Reset()";
     77   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
     78 
     79   if (state_ == kDrainingDecoder) {
     80     base::MessageLoop::current()->PostTask(
     81         FROM_HERE,
     82         base::Bind(
     83             &GpuVideoDecoder::Reset, weak_factory_.GetWeakPtr(), closure));
     84     return;
     85   }
     86 
     87   if (!vda_) {
     88     base::MessageLoop::current()->PostTask(FROM_HERE, closure);
     89     return;
     90   }
     91 
     92   DCHECK(pending_reset_cb_.is_null());
     93   pending_reset_cb_ = BindToCurrentLoop(closure);
     94 
     95   vda_->Reset();
     96 }
     97 
     98 static bool IsCodedSizeSupported(const gfx::Size& coded_size) {
     99 #if defined(OS_WIN)
    100   // Windows Media Foundation H.264 decoding does not support decoding videos
    101   // with any dimension smaller than 48 pixels:
    102   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815
    103   if (coded_size.width() < 48 || coded_size.height() < 48)
    104     return false;
    105 #endif
    106 
    107   // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080.
    108   // We test against 1088 to account for 16x16 macroblocks.
    109   if (coded_size.width() <= 1920 && coded_size.height() <= 1088)
    110     return true;
    111 
    112   // NOTE: additional autodetection logic may require updating input buffer size
    113   // selection in platform-specific implementations, such as
    114   // V4L2VideoDecodeAccelerator.
    115   base::CPU cpu;
    116   bool hw_large_video_support =
    117       CommandLine::ForCurrentProcess()->HasSwitch(
    118           switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode) ||
    119       ((cpu.vendor_name() == "GenuineIntel") && cpu.model() >= 55);
    120   bool os_large_video_support = true;
    121 #if defined(OS_WIN)
    122   os_large_video_support = false;
    123 #endif
    124   return os_large_video_support && hw_large_video_support;
    125 }
    126 
    127 // Report |status| to UMA and run |cb| with it.  This is super-specific to the
    128 // UMA stat reported because the UMA_HISTOGRAM_ENUMERATION API requires a
    129 // callsite to always be called with the same stat name (can't parameterize it).
    130 static void ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB(
    131     const PipelineStatusCB& cb,
    132     PipelineStatus status) {
    133   UMA_HISTOGRAM_ENUMERATION(
    134       "Media.GpuVideoDecoderInitializeStatus", status, PIPELINE_STATUS_MAX + 1);
    135   cb.Run(status);
    136 }
    137 
    138 std::string GpuVideoDecoder::GetDisplayName() const {
    139   return "GpuVideoDecoder";
    140 }
    141 
    142 void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config,
    143                                  bool /* low_delay */,
    144                                  const PipelineStatusCB& orig_status_cb,
    145                                  const OutputCB& output_cb) {
    146   DVLOG(3) << "Initialize()";
    147   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    148   DCHECK(config.IsValidConfig());
    149   DCHECK(!config.is_encrypted());
    150 
    151   PipelineStatusCB status_cb =
    152       base::Bind(&ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB,
    153                  BindToCurrentLoop(orig_status_cb));
    154 
    155   bool previously_initialized = config_.IsValidConfig();
    156   DVLOG(1) << "(Re)initializing GVD with config: "
    157            << config.AsHumanReadableString();
    158 
    159   // TODO(posciak): destroy and create a new VDA on codec/profile change
    160   // (http://crbug.com/260224).
    161   if (previously_initialized && (config_.profile() != config.profile())) {
    162     DVLOG(1) << "Codec or profile changed, cannot reinitialize.";
    163     status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
    164     return;
    165   }
    166 
    167   if (!IsCodedSizeSupported(config.coded_size())) {
    168     status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
    169     return;
    170   }
    171 
    172   config_ = config;
    173   needs_bitstream_conversion_ = (config.codec() == kCodecH264);
    174   output_cb_ = BindToCurrentLoop(output_cb);
    175 
    176   if (previously_initialized) {
    177     // Reinitialization with a different config (but same codec and profile).
    178     // VDA should handle it by detecting this in-stream by itself,
    179     // no need to notify it.
    180     status_cb.Run(PIPELINE_OK);
    181     return;
    182   }
    183 
    184   vda_ = factories_->CreateVideoDecodeAccelerator().Pass();
    185   if (!vda_ || !vda_->Initialize(config.profile(), this)) {
    186     status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
    187     return;
    188   }
    189 
    190   DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded.";
    191   status_cb.Run(PIPELINE_OK);
    192 }
    193 
    194 void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) {
    195   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    196   for (PictureBufferMap::iterator it = buffers->begin(); it != buffers->end();
    197        ++it) {
    198     factories_->DeleteTexture(it->second.texture_id());
    199   }
    200 
    201   buffers->clear();
    202 }
    203 
    204 void GpuVideoDecoder::DestroyVDA() {
    205   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    206 
    207   vda_.reset();
    208 
    209   // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since
    210   // their textures may still be in use by the user of this GpuVideoDecoder.
    211   for (PictureBufferTextureMap::iterator it =
    212            picture_buffers_at_display_.begin();
    213        it != picture_buffers_at_display_.end();
    214        ++it) {
    215     assigned_picture_buffers_.erase(it->first);
    216   }
    217   DestroyPictureBuffers(&assigned_picture_buffers_);
    218 }
    219 
    220 void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
    221                              const DecodeCB& decode_cb) {
    222   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    223   DCHECK(pending_reset_cb_.is_null());
    224 
    225   DecodeCB bound_decode_cb = BindToCurrentLoop(decode_cb);
    226 
    227   if (state_ == kError || !vda_) {
    228     bound_decode_cb.Run(kDecodeError);
    229     return;
    230   }
    231 
    232   switch (state_) {
    233     case kDecoderDrained:
    234       state_ = kNormal;
    235       // Fall-through.
    236     case kNormal:
    237       break;
    238     case kDrainingDecoder:
    239     case kError:
    240       NOTREACHED();
    241       return;
    242   }
    243 
    244   DCHECK_EQ(state_, kNormal);
    245 
    246   if (buffer->end_of_stream()) {
    247     state_ = kDrainingDecoder;
    248     eos_decode_cb_ = bound_decode_cb;
    249     vda_->Flush();
    250     return;
    251   }
    252 
    253   size_t size = buffer->data_size();
    254   SHMBuffer* shm_buffer = GetSHM(size);
    255   if (!shm_buffer) {
    256     bound_decode_cb.Run(kDecodeError);
    257     return;
    258   }
    259 
    260   memcpy(shm_buffer->shm->memory(), buffer->data(), size);
    261   BitstreamBuffer bitstream_buffer(
    262       next_bitstream_buffer_id_, shm_buffer->shm->handle(), size);
    263   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
    264   next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
    265   DCHECK(!ContainsKey(bitstream_buffers_in_decoder_, bitstream_buffer.id()));
    266   bitstream_buffers_in_decoder_.insert(
    267       std::make_pair(bitstream_buffer.id(),
    268                      PendingDecoderBuffer(shm_buffer, buffer, decode_cb)));
    269   DCHECK_LE(static_cast<int>(bitstream_buffers_in_decoder_.size()),
    270             kMaxInFlightDecodes);
    271   RecordBufferData(bitstream_buffer, *buffer.get());
    272 
    273   vda_->Decode(bitstream_buffer);
    274 }
    275 
    276 void GpuVideoDecoder::RecordBufferData(const BitstreamBuffer& bitstream_buffer,
    277                                        const DecoderBuffer& buffer) {
    278   input_buffer_data_.push_front(BufferData(bitstream_buffer.id(),
    279                                            buffer.timestamp(),
    280                                            config_.visible_rect(),
    281                                            config_.natural_size()));
    282   // Why this value?  Because why not.  avformat.h:MAX_REORDER_DELAY is 16, but
    283   // that's too small for some pathological B-frame test videos.  The cost of
    284   // using too-high a value is low (192 bits per extra slot).
    285   static const size_t kMaxInputBufferDataSize = 128;
    286   // Pop from the back of the list, because that's the oldest and least likely
    287   // to be useful in the future data.
    288   if (input_buffer_data_.size() > kMaxInputBufferDataSize)
    289     input_buffer_data_.pop_back();
    290 }
    291 
    292 void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp,
    293                                     gfx::Rect* visible_rect,
    294                                     gfx::Size* natural_size) {
    295   for (std::list<BufferData>::const_iterator it =
    296            input_buffer_data_.begin(); it != input_buffer_data_.end();
    297        ++it) {
    298     if (it->bitstream_buffer_id != id)
    299       continue;
    300     *timestamp = it->timestamp;
    301     *visible_rect = it->visible_rect;
    302     *natural_size = it->natural_size;
    303     return;
    304   }
    305   NOTREACHED() << "Missing bitstreambuffer id: " << id;
    306 }
    307 
    308 bool GpuVideoDecoder::NeedsBitstreamConversion() const {
    309   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    310   return needs_bitstream_conversion_;
    311 }
    312 
    313 bool GpuVideoDecoder::CanReadWithoutStalling() const {
    314   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    315   return
    316       next_picture_buffer_id_ == 0 ||  // Decode() will ProvidePictureBuffers().
    317       available_pictures_ > 0;
    318 }
    319 
    320 int GpuVideoDecoder::GetMaxDecodeRequests() const {
    321   return kMaxInFlightDecodes;
    322 }
    323 
    324 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
    325                                             const gfx::Size& size,
    326                                             uint32 texture_target) {
    327   DVLOG(3) << "ProvidePictureBuffers(" << count << ", "
    328            << size.width() << "x" << size.height() << ")";
    329   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    330 
    331   std::vector<uint32> texture_ids;
    332   std::vector<gpu::Mailbox> texture_mailboxes;
    333   decoder_texture_target_ = texture_target;
    334   if (!factories_->CreateTextures(count,
    335                                   size,
    336                                   &texture_ids,
    337                                   &texture_mailboxes,
    338                                   decoder_texture_target_)) {
    339     NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
    340     return;
    341   }
    342   DCHECK_EQ(count, texture_ids.size());
    343   DCHECK_EQ(count, texture_mailboxes.size());
    344 
    345   if (!vda_)
    346     return;
    347 
    348   std::vector<PictureBuffer> picture_buffers;
    349   for (size_t i = 0; i < texture_ids.size(); ++i) {
    350     picture_buffers.push_back(PictureBuffer(
    351         next_picture_buffer_id_++, size, texture_ids[i], texture_mailboxes[i]));
    352     bool inserted = assigned_picture_buffers_.insert(std::make_pair(
    353         picture_buffers.back().id(), picture_buffers.back())).second;
    354     DCHECK(inserted);
    355   }
    356 
    357   available_pictures_ += count;
    358 
    359   vda_->AssignPictureBuffers(picture_buffers);
    360 }
    361 
    362 void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
    363   DVLOG(3) << "DismissPictureBuffer(" << id << ")";
    364   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    365 
    366   PictureBufferMap::iterator it = assigned_picture_buffers_.find(id);
    367   if (it == assigned_picture_buffers_.end()) {
    368     NOTREACHED() << "Missing picture buffer: " << id;
    369     return;
    370   }
    371 
    372   PictureBuffer buffer_to_dismiss = it->second;
    373   assigned_picture_buffers_.erase(it);
    374 
    375   if (!picture_buffers_at_display_.count(id)) {
    376     // We can delete the texture immediately as it's not being displayed.
    377     factories_->DeleteTexture(buffer_to_dismiss.texture_id());
    378     CHECK_GT(available_pictures_, 0);
    379     --available_pictures_;
    380   }
    381   // Not destroying a texture in display in |picture_buffers_at_display_|.
    382   // Postpone deletion until after it's returned to us.
    383 }
    384 
    385 static void ReadPixelsSyncInner(
    386     const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
    387     uint32 texture_id,
    388     const gfx::Rect& visible_rect,
    389     const SkBitmap& pixels,
    390     base::WaitableEvent* event) {
    391   factories->ReadPixels(texture_id, visible_rect, pixels);
    392   event->Signal();
    393 }
    394 
    395 static void ReadPixelsSync(
    396     const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
    397     uint32 texture_id,
    398     const gfx::Rect& visible_rect,
    399     const SkBitmap& pixels) {
    400   base::WaitableEvent event(true, false);
    401   if (!factories->GetTaskRunner()->PostTask(FROM_HERE,
    402                                             base::Bind(&ReadPixelsSyncInner,
    403                                                        factories,
    404                                                        texture_id,
    405                                                        visible_rect,
    406                                                        pixels,
    407                                                        &event)))
    408     return;
    409   event.Wait();
    410 }
    411 
    412 void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
    413   DVLOG(3) << "PictureReady()";
    414   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    415 
    416   PictureBufferMap::iterator it =
    417       assigned_picture_buffers_.find(picture.picture_buffer_id());
    418   if (it == assigned_picture_buffers_.end()) {
    419     NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id();
    420     NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
    421     return;
    422   }
    423   const PictureBuffer& pb = it->second;
    424 
    425   // Validate picture rectangle from GPU. This is for sanity/security check
    426   // even the rectangle is not used in this class.
    427   if (picture.visible_rect().IsEmpty() ||
    428       !gfx::Rect(pb.size()).Contains(picture.visible_rect())) {
    429     NOTREACHED() << "Invalid picture size from VDA: "
    430                  << picture.visible_rect().ToString() << " should fit in "
    431                  << pb.size().ToString();
    432     NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
    433     return;
    434   }
    435 
    436   // Update frame's timestamp.
    437   base::TimeDelta timestamp;
    438   // Some of the VDAs don't support and thus don't provide us with visible
    439   // size in picture.size, passing coded size instead, so always drop it and
    440   // use config information instead.
    441   gfx::Rect visible_rect;
    442   gfx::Size natural_size;
    443   GetBufferData(picture.bitstream_buffer_id(), &timestamp, &visible_rect,
    444                 &natural_size);
    445   DCHECK(decoder_texture_target_);
    446 
    447   scoped_refptr<VideoFrame> frame(VideoFrame::WrapNativeTexture(
    448       make_scoped_ptr(new gpu::MailboxHolder(
    449           pb.texture_mailbox(), decoder_texture_target_, 0 /* sync_point */)),
    450       BindToCurrentLoop(base::Bind(&GpuVideoDecoder::ReleaseMailbox,
    451                                    weak_factory_.GetWeakPtr(),
    452                                    factories_,
    453                                    picture.picture_buffer_id(),
    454                                    pb.texture_id())),
    455       pb.size(),
    456       visible_rect,
    457       natural_size,
    458       timestamp,
    459       base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect)));
    460   CHECK_GT(available_pictures_, 0);
    461   --available_pictures_;
    462   bool inserted =
    463       picture_buffers_at_display_.insert(std::make_pair(
    464                                              picture.picture_buffer_id(),
    465                                              pb.texture_id())).second;
    466   DCHECK(inserted);
    467 
    468   DeliverFrame(frame);
    469 }
    470 
    471 void GpuVideoDecoder::DeliverFrame(
    472     const scoped_refptr<VideoFrame>& frame) {
    473   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    474 
    475   // During a pending vda->Reset(), we don't accumulate frames.  Drop it on the
    476   // floor and return.
    477   if (!pending_reset_cb_.is_null())
    478     return;
    479 
    480   output_cb_.Run(frame);
    481 }
    482 
    483 // static
    484 void GpuVideoDecoder::ReleaseMailbox(
    485     base::WeakPtr<GpuVideoDecoder> decoder,
    486     const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
    487     int64 picture_buffer_id,
    488     uint32 texture_id,
    489     uint32 release_sync_point) {
    490   DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread());
    491   factories->WaitSyncPoint(release_sync_point);
    492 
    493   if (decoder) {
    494     decoder->ReusePictureBuffer(picture_buffer_id);
    495     return;
    496   }
    497   // It's the last chance to delete the texture after display,
    498   // because GpuVideoDecoder was destructed.
    499   factories->DeleteTexture(texture_id);
    500 }
    501 
    502 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) {
    503   DVLOG(3) << "ReusePictureBuffer(" << picture_buffer_id << ")";
    504   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    505 
    506   DCHECK(!picture_buffers_at_display_.empty());
    507   PictureBufferTextureMap::iterator display_iterator =
    508       picture_buffers_at_display_.find(picture_buffer_id);
    509   uint32 texture_id = display_iterator->second;
    510   DCHECK(display_iterator != picture_buffers_at_display_.end());
    511   picture_buffers_at_display_.erase(display_iterator);
    512 
    513   if (!assigned_picture_buffers_.count(picture_buffer_id)) {
    514     // This picture was dismissed while in display, so we postponed deletion.
    515     factories_->DeleteTexture(texture_id);
    516     return;
    517   }
    518 
    519   ++available_pictures_;
    520 
    521   // DestroyVDA() might already have been called.
    522   if (vda_)
    523     vda_->ReusePictureBuffer(picture_buffer_id);
    524 }
    525 
    526 GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) {
    527   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    528   if (available_shm_segments_.empty() ||
    529       available_shm_segments_.back()->size < min_size) {
    530     size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes);
    531     base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate);
    532     // CreateSharedMemory() can return NULL during Shutdown.
    533     if (!shm)
    534       return NULL;
    535     return new SHMBuffer(shm, size_to_allocate);
    536   }
    537   SHMBuffer* ret = available_shm_segments_.back();
    538   available_shm_segments_.pop_back();
    539   return ret;
    540 }
    541 
    542 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
    543   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    544   available_shm_segments_.push_back(shm_buffer);
    545 }
    546 
    547 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
    548   DVLOG(3) << "NotifyEndOfBitstreamBuffer(" << id << ")";
    549   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    550 
    551   std::map<int32, PendingDecoderBuffer>::iterator it =
    552       bitstream_buffers_in_decoder_.find(id);
    553   if (it == bitstream_buffers_in_decoder_.end()) {
    554     NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
    555     NOTREACHED() << "Missing bitstream buffer: " << id;
    556     return;
    557   }
    558 
    559   PutSHM(it->second.shm_buffer);
    560   it->second.done_cb.Run(state_ == kError ? kDecodeError : kOk);
    561   bitstream_buffers_in_decoder_.erase(it);
    562 }
    563 
    564 GpuVideoDecoder::~GpuVideoDecoder() {
    565   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    566   if (vda_)
    567     DestroyVDA();
    568   DCHECK(bitstream_buffers_in_decoder_.empty());
    569   DCHECK(assigned_picture_buffers_.empty());
    570 
    571   if (!pending_reset_cb_.is_null())
    572     base::ResetAndReturn(&pending_reset_cb_).Run();
    573 
    574   for (size_t i = 0; i < available_shm_segments_.size(); ++i) {
    575     available_shm_segments_[i]->shm->Close();
    576     delete available_shm_segments_[i];
    577   }
    578   available_shm_segments_.clear();
    579 
    580   for (std::map<int32, PendingDecoderBuffer>::iterator it =
    581            bitstream_buffers_in_decoder_.begin();
    582        it != bitstream_buffers_in_decoder_.end(); ++it) {
    583     it->second.shm_buffer->shm->Close();
    584   }
    585   bitstream_buffers_in_decoder_.clear();
    586 }
    587 
    588 void GpuVideoDecoder::NotifyFlushDone() {
    589   DVLOG(3) << "NotifyFlushDone()";
    590   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    591   DCHECK_EQ(state_, kDrainingDecoder);
    592   state_ = kDecoderDrained;
    593   base::ResetAndReturn(&eos_decode_cb_).Run(kOk);
    594 }
    595 
    596 void GpuVideoDecoder::NotifyResetDone() {
    597   DVLOG(3) << "NotifyResetDone()";
    598   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    599   DCHECK(bitstream_buffers_in_decoder_.empty());
    600 
    601   // This needs to happen after the Reset() on vda_ is done to ensure pictures
    602   // delivered during the reset can find their time data.
    603   input_buffer_data_.clear();
    604 
    605   if (!pending_reset_cb_.is_null())
    606     base::ResetAndReturn(&pending_reset_cb_).Run();
    607 }
    608 
    609 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
    610   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
    611   if (!vda_)
    612     return;
    613 
    614   state_ = kError;
    615 
    616   DLOG(ERROR) << "VDA Error: " << error;
    617   DestroyVDA();
    618 }
    619 
    620 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent()
    621     const {
    622   DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread());
    623 }
    624 
    625 }  // namespace media
    626