• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SHMBuffer(base::SharedMemory * m,size_t s)40 GpuVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s)
41     : shm(m), size(s) {
42 }
43 
~SHMBuffer()44 GpuVideoDecoder::SHMBuffer::~SHMBuffer() {}
45 
PendingDecoderBuffer(SHMBuffer * s,const scoped_refptr<DecoderBuffer> & b,const DecodeCB & done_cb)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 
~PendingDecoderBuffer()53 GpuVideoDecoder::PendingDecoderBuffer::~PendingDecoderBuffer() {}
54 
BufferData(int32 bbid,base::TimeDelta ts,const gfx::Rect & vr,const gfx::Size & ns)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 
~BufferData()61 GpuVideoDecoder::BufferData::~BufferData() {}
62 
GpuVideoDecoder(const scoped_refptr<GpuVideoAcceleratorFactories> & factories,const scoped_refptr<MediaLog> & media_log)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 
Reset(const base::Closure & closure)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 
Stop()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 
IsCodedSizeSupported(const gfx::Size & coded_size)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).
ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB(const PipelineStatusCB & cb,PipelineStatus status)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 
Initialize(const VideoDecoderConfig & config,bool,const PipelineStatusCB & orig_status_cb,const OutputCB & output_cb)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 
DestroyPictureBuffers(PictureBufferMap * buffers)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 
DestroyVDA()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 
Decode(const scoped_refptr<DecoderBuffer> & buffer,const DecodeCB & decode_cb)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 
RecordBufferData(const BitstreamBuffer & bitstream_buffer,const DecoderBuffer & buffer)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 
GetBufferData(int32 id,base::TimeDelta * timestamp,gfx::Rect * visible_rect,gfx::Size * natural_size)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 
NeedsBitstreamConversion() const317 bool GpuVideoDecoder::NeedsBitstreamConversion() const {
318   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
319   return needs_bitstream_conversion_;
320 }
321 
CanReadWithoutStalling() const322 bool GpuVideoDecoder::CanReadWithoutStalling() const {
323   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
324   return
325       next_picture_buffer_id_ == 0 ||  // Decode() will ProvidePictureBuffers().
326       available_pictures_ > 0;
327 }
328 
GetMaxDecodeRequests() const329 int GpuVideoDecoder::GetMaxDecodeRequests() const {
330   return kMaxInFlightDecodes;
331 }
332 
ProvidePictureBuffers(uint32 count,const gfx::Size & size,uint32 texture_target)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 
DismissPictureBuffer(int32 id)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 
ReadPixelsSyncInner(const scoped_refptr<media::GpuVideoAcceleratorFactories> & factories,uint32 texture_id,const gfx::Rect & visible_rect,const SkBitmap & pixels,base::WaitableEvent * event)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 
ReadPixelsSync(const scoped_refptr<media::GpuVideoAcceleratorFactories> & factories,uint32 texture_id,const gfx::Rect & visible_rect,const SkBitmap & pixels)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 
PictureReady(const media::Picture & picture)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 
DeliverFrame(const scoped_refptr<VideoFrame> & frame)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
ReleaseMailbox(base::WeakPtr<GpuVideoDecoder> decoder,const scoped_refptr<media::GpuVideoAcceleratorFactories> & factories,int64 picture_buffer_id,uint32 texture_id,const std::vector<uint32> & release_sync_points)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 
ReusePictureBuffer(int64 picture_buffer_id)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 
GetSHM(size_t min_size)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 
PutSHM(SHMBuffer * shm_buffer)539 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
540   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
541   available_shm_segments_.push_back(shm_buffer);
542 }
543 
NotifyEndOfBitstreamBuffer(int32 id)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 
~GpuVideoDecoder()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 
NotifyFlushDone()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 
NotifyResetDone()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 
NotifyError(media::VideoDecodeAccelerator::Error error)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 
DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() const611 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent()
612     const {
613   DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread());
614 }
615 
616 }  // namespace media
617