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(), ×tamp, &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