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