| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/gpu_video_decoder.h" | 5 #include "media/filters/gpu_video_decoder.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), | 49 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), |
| 50 natural_size(ns) { | 50 natural_size(ns) { |
| 51 } | 51 } |
| 52 | 52 |
| 53 GpuVideoDecoder::BufferData::~BufferData() {} | 53 GpuVideoDecoder::BufferData::~BufferData() {} |
| 54 | 54 |
| 55 GpuVideoDecoder::GpuVideoDecoder( | 55 GpuVideoDecoder::GpuVideoDecoder( |
| 56 const scoped_refptr<GpuVideoAcceleratorFactories>& factories, | 56 const scoped_refptr<GpuVideoAcceleratorFactories>& factories, |
| 57 const scoped_refptr<MediaLog>& media_log) | 57 const scoped_refptr<MediaLog>& media_log) |
| 58 : needs_bitstream_conversion_(false), | 58 : needs_bitstream_conversion_(false), |
| 59 gvd_loop_proxy_(factories->GetMessageLoop()), | 59 gvd_task_runner_(factories->GetTaskRunner()), |
| 60 weak_factory_(this), | 60 weak_factory_(this), |
| 61 factories_(factories), | 61 factories_(factories), |
| 62 state_(kNormal), | 62 state_(kNormal), |
| 63 media_log_(media_log), | 63 media_log_(media_log), |
| 64 decoder_texture_target_(0), | 64 decoder_texture_target_(0), |
| 65 next_picture_buffer_id_(0), | 65 next_picture_buffer_id_(0), |
| 66 next_bitstream_buffer_id_(0), | 66 next_bitstream_buffer_id_(0), |
| 67 available_pictures_(0) { | 67 available_pictures_(0) { |
| 68 DCHECK(factories_.get()); | 68 DCHECK(factories_.get()); |
| 69 } | 69 } |
| 70 | 70 |
| 71 void GpuVideoDecoder::Reset(const base::Closure& closure) { | 71 void GpuVideoDecoder::Reset(const base::Closure& closure) { |
| 72 DVLOG(3) << "Reset()"; | 72 DVLOG(3) << "Reset()"; |
| 73 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 73 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 74 | 74 |
| 75 if (state_ == kDrainingDecoder && !factories_->IsAborted()) { | 75 if (state_ == kDrainingDecoder && !factories_->IsAborted()) { |
| 76 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 76 gvd_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 77 &GpuVideoDecoder::Reset, weak_this_, closure)); | 77 &GpuVideoDecoder::Reset, weak_this_, closure)); |
| 78 // NOTE: if we're deferring Reset() until a Flush() completes, return | 78 // NOTE: if we're deferring Reset() until a Flush() completes, return |
| 79 // queued pictures to the VDA so they can be used to finish that Flush(). | 79 // queued pictures to the VDA so they can be used to finish that Flush(). |
| 80 if (pending_decode_cb_.is_null()) | 80 if (pending_decode_cb_.is_null()) |
| 81 ready_video_frames_.clear(); | 81 ready_video_frames_.clear(); |
| 82 return; | 82 return; |
| 83 } | 83 } |
| 84 | 84 |
| 85 // Throw away any already-decoded, not-yet-delivered frames. | 85 // Throw away any already-decoded, not-yet-delivered frames. |
| 86 ready_video_frames_.clear(); | 86 ready_video_frames_.clear(); |
| 87 | 87 |
| 88 if (!vda_) { | 88 if (!vda_) { |
| 89 gvd_loop_proxy_->PostTask(FROM_HERE, closure); | 89 gvd_task_runner_->PostTask(FROM_HERE, closure); |
| 90 return; | 90 return; |
| 91 } | 91 } |
| 92 | 92 |
| 93 if (!pending_decode_cb_.is_null()) | 93 if (!pending_decode_cb_.is_null()) |
| 94 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 94 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 95 | 95 |
| 96 DCHECK(pending_reset_cb_.is_null()); | 96 DCHECK(pending_reset_cb_.is_null()); |
| 97 pending_reset_cb_ = BindToCurrentLoop(closure); | 97 pending_reset_cb_ = BindToCurrentLoop(closure); |
| 98 | 98 |
| 99 vda_->Reset(); | 99 vda_->Reset(); |
| 100 } | 100 } |
| 101 | 101 |
| 102 void GpuVideoDecoder::Stop(const base::Closure& closure) { | 102 void GpuVideoDecoder::Stop(const base::Closure& closure) { |
| 103 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 103 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 104 if (vda_) | 104 if (vda_) |
| 105 DestroyVDA(); | 105 DestroyVDA(); |
| 106 if (!pending_decode_cb_.is_null()) | 106 if (!pending_decode_cb_.is_null()) |
| 107 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 107 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 108 if (!pending_reset_cb_.is_null()) | 108 if (!pending_reset_cb_.is_null()) |
| 109 base::ResetAndReturn(&pending_reset_cb_).Run(); | 109 base::ResetAndReturn(&pending_reset_cb_).Run(); |
| 110 BindToCurrentLoop(closure).Run(); | 110 BindToCurrentLoop(closure).Run(); |
| 111 } | 111 } |
| 112 | 112 |
| 113 static bool IsCodedSizeSupported(const gfx::Size& coded_size) { | 113 static bool IsCodedSizeSupported(const gfx::Size& coded_size) { |
| 114 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080. | 114 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080. |
| 115 // We test against 1088 to account for 16x16 macroblocks. | 115 // We test against 1088 to account for 16x16 macroblocks. |
| 116 if (coded_size.width() <= 1920 && coded_size.height() <= 1088) | 116 if (coded_size.width() <= 1920 && coded_size.height() <= 1088) |
| 117 return true; | 117 return true; |
| 118 | 118 |
| 119 base::CPU cpu; | 119 base::CPU cpu; |
| 120 bool hw_large_video_support = | 120 bool hw_large_video_support = |
| 121 (cpu.vendor_name() == "GenuineIntel") && cpu.model() >= 58; | 121 (cpu.vendor_name() == "GenuineIntel") && cpu.model() >= 58; |
| 122 bool os_large_video_support = true; | 122 bool os_large_video_support = true; |
| 123 #if defined(OS_WIN) | 123 #if defined(OS_WIN) |
| 124 os_large_video_support = false; | 124 os_large_video_support = false; |
| 125 #endif | 125 #endif |
| 126 return os_large_video_support && hw_large_video_support; | 126 return os_large_video_support && hw_large_video_support; |
| 127 } | 127 } |
| 128 | 128 |
| 129 void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config, | 129 void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| 130 const PipelineStatusCB& orig_status_cb) { | 130 const PipelineStatusCB& orig_status_cb) { |
| 131 DVLOG(3) << "Initialize()"; | 131 DVLOG(3) << "Initialize()"; |
| 132 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 132 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 133 DCHECK(config.IsValidConfig()); | 133 DCHECK(config.IsValidConfig()); |
| 134 DCHECK(!config.is_encrypted()); | 134 DCHECK(!config.is_encrypted()); |
| 135 | 135 |
| 136 weak_this_ = weak_factory_.GetWeakPtr(); | 136 weak_this_ = weak_factory_.GetWeakPtr(); |
| 137 | 137 |
| 138 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( | 138 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( |
| 139 "Media.GpuVideoDecoderInitializeStatus", | 139 "Media.GpuVideoDecoderInitializeStatus", |
| 140 BindToCurrentLoop(orig_status_cb)); | 140 BindToCurrentLoop(orig_status_cb)); |
| 141 | 141 |
| 142 bool previously_initialized = config_.IsValidConfig(); | 142 bool previously_initialized = config_.IsValidConfig(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 182 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
| 183 return; | 183 return; |
| 184 } | 184 } |
| 185 | 185 |
| 186 DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded."; | 186 DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded."; |
| 187 media_log_->SetStringProperty("video_decoder", "gpu"); | 187 media_log_->SetStringProperty("video_decoder", "gpu"); |
| 188 status_cb.Run(PIPELINE_OK); | 188 status_cb.Run(PIPELINE_OK); |
| 189 } | 189 } |
| 190 | 190 |
| 191 void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) { | 191 void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) { |
| 192 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 192 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 193 for (PictureBufferMap::iterator it = buffers->begin(); it != buffers->end(); | 193 for (PictureBufferMap::iterator it = buffers->begin(); it != buffers->end(); |
| 194 ++it) { | 194 ++it) { |
| 195 factories_->DeleteTexture(it->second.texture_id()); | 195 factories_->DeleteTexture(it->second.texture_id()); |
| 196 } | 196 } |
| 197 | 197 |
| 198 buffers->clear(); | 198 buffers->clear(); |
| 199 } | 199 } |
| 200 | 200 |
| 201 void GpuVideoDecoder::DestroyVDA() { | 201 void GpuVideoDecoder::DestroyVDA() { |
| 202 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 202 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 203 | 203 |
| 204 if (vda_) | 204 if (vda_) |
| 205 vda_.release()->Destroy(); | 205 vda_.release()->Destroy(); |
| 206 | 206 |
| 207 DestroyPictureBuffers(&assigned_picture_buffers_); | 207 DestroyPictureBuffers(&assigned_picture_buffers_); |
| 208 // Not destroying PictureBuffers in |dismissed_picture_buffers_| yet, since | 208 // Not destroying PictureBuffers in |dismissed_picture_buffers_| yet, since |
| 209 // their textures may still be in use by the user of this GpuVideoDecoder. | 209 // their textures may still be in use by the user of this GpuVideoDecoder. |
| 210 } | 210 } |
| 211 | 211 |
| 212 void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 212 void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 213 const DecodeCB& decode_cb) { | 213 const DecodeCB& decode_cb) { |
| 214 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 214 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 215 DCHECK(pending_reset_cb_.is_null()); | 215 DCHECK(pending_reset_cb_.is_null()); |
| 216 DCHECK(pending_decode_cb_.is_null()); | 216 DCHECK(pending_decode_cb_.is_null()); |
| 217 | 217 |
| 218 pending_decode_cb_ = BindToCurrentLoop(decode_cb); | 218 pending_decode_cb_ = BindToCurrentLoop(decode_cb); |
| 219 | 219 |
| 220 if (state_ == kError || !vda_) { | 220 if (state_ == kError || !vda_) { |
| 221 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); | 221 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); |
| 222 return; | 222 return; |
| 223 } | 223 } |
| 224 | 224 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 continue; | 313 continue; |
| 314 *timestamp = it->timestamp; | 314 *timestamp = it->timestamp; |
| 315 *visible_rect = it->visible_rect; | 315 *visible_rect = it->visible_rect; |
| 316 *natural_size = it->natural_size; | 316 *natural_size = it->natural_size; |
| 317 return; | 317 return; |
| 318 } | 318 } |
| 319 NOTREACHED() << "Missing bitstreambuffer id: " << id; | 319 NOTREACHED() << "Missing bitstreambuffer id: " << id; |
| 320 } | 320 } |
| 321 | 321 |
| 322 bool GpuVideoDecoder::HasAlpha() const { | 322 bool GpuVideoDecoder::HasAlpha() const { |
| 323 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 323 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 324 return true; | 324 return true; |
| 325 } | 325 } |
| 326 | 326 |
| 327 bool GpuVideoDecoder::NeedsBitstreamConversion() const { | 327 bool GpuVideoDecoder::NeedsBitstreamConversion() const { |
| 328 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 328 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 329 return needs_bitstream_conversion_; | 329 return needs_bitstream_conversion_; |
| 330 } | 330 } |
| 331 | 331 |
| 332 bool GpuVideoDecoder::CanReadWithoutStalling() const { | 332 bool GpuVideoDecoder::CanReadWithoutStalling() const { |
| 333 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 333 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 334 return available_pictures_ > 0 || !ready_video_frames_.empty(); | 334 return available_pictures_ > 0 || !ready_video_frames_.empty(); |
| 335 } | 335 } |
| 336 | 336 |
| 337 void GpuVideoDecoder::NotifyInitializeDone() { | 337 void GpuVideoDecoder::NotifyInitializeDone() { |
| 338 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; | 338 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; |
| 339 } | 339 } |
| 340 | 340 |
| 341 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, | 341 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, |
| 342 const gfx::Size& size, | 342 const gfx::Size& size, |
| 343 uint32 texture_target) { | 343 uint32 texture_target) { |
| 344 DVLOG(3) << "ProvidePictureBuffers(" << count << ", " | 344 DVLOG(3) << "ProvidePictureBuffers(" << count << ", " |
| 345 << size.width() << "x" << size.height() << ")"; | 345 << size.width() << "x" << size.height() << ")"; |
| 346 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 346 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 347 | 347 |
| 348 std::vector<uint32> texture_ids; | 348 std::vector<uint32> texture_ids; |
| 349 std::vector<gpu::Mailbox> texture_mailboxes; | 349 std::vector<gpu::Mailbox> texture_mailboxes; |
| 350 decoder_texture_target_ = texture_target; | 350 decoder_texture_target_ = texture_target; |
| 351 // Discards the sync point returned here since PictureReady will imply that | 351 // Discards the sync point returned here since PictureReady will imply that |
| 352 // the produce has already happened, and the texture is ready for use. | 352 // the produce has already happened, and the texture is ready for use. |
| 353 if (!factories_->CreateTextures(count, | 353 if (!factories_->CreateTextures(count, |
| 354 size, | 354 size, |
| 355 &texture_ids, | 355 &texture_ids, |
| 356 &texture_mailboxes, | 356 &texture_mailboxes, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 373 DCHECK(inserted); | 373 DCHECK(inserted); |
| 374 } | 374 } |
| 375 | 375 |
| 376 available_pictures_ += count; | 376 available_pictures_ += count; |
| 377 | 377 |
| 378 vda_->AssignPictureBuffers(picture_buffers); | 378 vda_->AssignPictureBuffers(picture_buffers); |
| 379 } | 379 } |
| 380 | 380 |
| 381 void GpuVideoDecoder::DismissPictureBuffer(int32 id) { | 381 void GpuVideoDecoder::DismissPictureBuffer(int32 id) { |
| 382 DVLOG(3) << "DismissPictureBuffer(" << id << ")"; | 382 DVLOG(3) << "DismissPictureBuffer(" << id << ")"; |
| 383 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 383 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 384 | 384 |
| 385 PictureBufferMap::iterator it = assigned_picture_buffers_.find(id); | 385 PictureBufferMap::iterator it = assigned_picture_buffers_.find(id); |
| 386 if (it == assigned_picture_buffers_.end()) { | 386 if (it == assigned_picture_buffers_.end()) { |
| 387 NOTREACHED() << "Missing picture buffer: " << id; | 387 NOTREACHED() << "Missing picture buffer: " << id; |
| 388 return; | 388 return; |
| 389 } | 389 } |
| 390 | 390 |
| 391 PictureBuffer buffer_to_dismiss = it->second; | 391 PictureBuffer buffer_to_dismiss = it->second; |
| 392 assigned_picture_buffers_.erase(it); | 392 assigned_picture_buffers_.erase(it); |
| 393 | 393 |
| 394 std::set<int32>::iterator at_display_it = | 394 std::set<int32>::iterator at_display_it = |
| 395 picture_buffers_at_display_.find(id); | 395 picture_buffers_at_display_.find(id); |
| 396 | 396 |
| 397 if (at_display_it == picture_buffers_at_display_.end()) { | 397 if (at_display_it == picture_buffers_at_display_.end()) { |
| 398 // We can delete the texture immediately as it's not being displayed. | 398 // We can delete the texture immediately as it's not being displayed. |
| 399 factories_->DeleteTexture(buffer_to_dismiss.texture_id()); | 399 factories_->DeleteTexture(buffer_to_dismiss.texture_id()); |
| 400 CHECK_GT(available_pictures_, 0); | 400 CHECK_GT(available_pictures_, 0); |
| 401 --available_pictures_; | 401 --available_pictures_; |
| 402 } else { | 402 } else { |
| 403 // Texture in display. Postpone deletion until after it's returned to us. | 403 // Texture in display. Postpone deletion until after it's returned to us. |
| 404 bool inserted = dismissed_picture_buffers_.insert(std::make_pair( | 404 bool inserted = dismissed_picture_buffers_.insert(std::make_pair( |
| 405 id, buffer_to_dismiss)).second; | 405 id, buffer_to_dismiss)).second; |
| 406 DCHECK(inserted); | 406 DCHECK(inserted); |
| 407 } | 407 } |
| 408 } | 408 } |
| 409 | 409 |
| 410 void GpuVideoDecoder::PictureReady(const media::Picture& picture) { | 410 void GpuVideoDecoder::PictureReady(const media::Picture& picture) { |
| 411 DVLOG(3) << "PictureReady()"; | 411 DVLOG(3) << "PictureReady()"; |
| 412 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 412 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 413 | 413 |
| 414 PictureBufferMap::iterator it = | 414 PictureBufferMap::iterator it = |
| 415 assigned_picture_buffers_.find(picture.picture_buffer_id()); | 415 assigned_picture_buffers_.find(picture.picture_buffer_id()); |
| 416 if (it == assigned_picture_buffers_.end()) { | 416 if (it == assigned_picture_buffers_.end()) { |
| 417 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 417 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
| 418 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 418 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 419 return; | 419 return; |
| 420 } | 420 } |
| 421 const PictureBuffer& pb = it->second; | 421 const PictureBuffer& pb = it->second; |
| 422 | 422 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 449 --available_pictures_; | 449 --available_pictures_; |
| 450 bool inserted = | 450 bool inserted = |
| 451 picture_buffers_at_display_.insert(picture.picture_buffer_id()).second; | 451 picture_buffers_at_display_.insert(picture.picture_buffer_id()).second; |
| 452 DCHECK(inserted); | 452 DCHECK(inserted); |
| 453 | 453 |
| 454 EnqueueFrameAndTriggerFrameDelivery(frame); | 454 EnqueueFrameAndTriggerFrameDelivery(frame); |
| 455 } | 455 } |
| 456 | 456 |
| 457 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( | 457 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( |
| 458 const scoped_refptr<VideoFrame>& frame) { | 458 const scoped_refptr<VideoFrame>& frame) { |
| 459 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 459 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 460 | 460 |
| 461 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the | 461 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the |
| 462 // floor and return. | 462 // floor and return. |
| 463 if (!pending_reset_cb_.is_null()) | 463 if (!pending_reset_cb_.is_null()) |
| 464 return; | 464 return; |
| 465 | 465 |
| 466 if (frame.get()) | 466 if (frame.get()) |
| 467 ready_video_frames_.push_back(frame); | 467 ready_video_frames_.push_back(frame); |
| 468 else | 468 else |
| 469 DCHECK(!ready_video_frames_.empty()); | 469 DCHECK(!ready_video_frames_.empty()); |
| 470 | 470 |
| 471 if (pending_decode_cb_.is_null()) | 471 if (pending_decode_cb_.is_null()) |
| 472 return; | 472 return; |
| 473 | 473 |
| 474 base::ResetAndReturn(&pending_decode_cb_) | 474 base::ResetAndReturn(&pending_decode_cb_) |
| 475 .Run(kOk, ready_video_frames_.front()); | 475 .Run(kOk, ready_video_frames_.front()); |
| 476 ready_video_frames_.pop_front(); | 476 ready_video_frames_.pop_front(); |
| 477 } | 477 } |
| 478 | 478 |
| 479 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id, | 479 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id, |
| 480 uint32 sync_point) { | 480 uint32 sync_point) { |
| 481 DVLOG(3) << "ReusePictureBuffer(" << picture_buffer_id << ")"; | 481 DVLOG(3) << "ReusePictureBuffer(" << picture_buffer_id << ")"; |
| 482 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 482 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 483 | 483 |
| 484 if (!vda_) | 484 if (!vda_) |
| 485 return; | 485 return; |
| 486 | 486 |
| 487 CHECK(!picture_buffers_at_display_.empty()); | 487 CHECK(!picture_buffers_at_display_.empty()); |
| 488 | 488 |
| 489 size_t num_erased = picture_buffers_at_display_.erase(picture_buffer_id); | 489 size_t num_erased = picture_buffers_at_display_.erase(picture_buffer_id); |
| 490 DCHECK(num_erased); | 490 DCHECK(num_erased); |
| 491 | 491 |
| 492 PictureBufferMap::iterator it = | 492 PictureBufferMap::iterator it = |
| 493 assigned_picture_buffers_.find(picture_buffer_id); | 493 assigned_picture_buffers_.find(picture_buffer_id); |
| 494 | 494 |
| 495 if (it == assigned_picture_buffers_.end()) { | 495 if (it == assigned_picture_buffers_.end()) { |
| 496 // This picture was dismissed while in display, so we postponed deletion. | 496 // This picture was dismissed while in display, so we postponed deletion. |
| 497 it = dismissed_picture_buffers_.find(picture_buffer_id); | 497 it = dismissed_picture_buffers_.find(picture_buffer_id); |
| 498 DCHECK(it != dismissed_picture_buffers_.end()); | 498 DCHECK(it != dismissed_picture_buffers_.end()); |
| 499 factories_->DeleteTexture(it->second.texture_id()); | 499 factories_->DeleteTexture(it->second.texture_id()); |
| 500 dismissed_picture_buffers_.erase(it); | 500 dismissed_picture_buffers_.erase(it); |
| 501 return; | 501 return; |
| 502 } | 502 } |
| 503 | 503 |
| 504 factories_->WaitSyncPoint(sync_point); | 504 factories_->WaitSyncPoint(sync_point); |
| 505 ++available_pictures_; | 505 ++available_pictures_; |
| 506 | 506 |
| 507 vda_->ReusePictureBuffer(picture_buffer_id); | 507 vda_->ReusePictureBuffer(picture_buffer_id); |
| 508 } | 508 } |
| 509 | 509 |
| 510 GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) { | 510 GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) { |
| 511 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 511 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 512 if (available_shm_segments_.empty() || | 512 if (available_shm_segments_.empty() || |
| 513 available_shm_segments_.back()->size < min_size) { | 513 available_shm_segments_.back()->size < min_size) { |
| 514 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); | 514 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); |
| 515 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); | 515 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); |
| 516 // CreateSharedMemory() can return NULL during Shutdown. | 516 // CreateSharedMemory() can return NULL during Shutdown. |
| 517 if (!shm) | 517 if (!shm) |
| 518 return NULL; | 518 return NULL; |
| 519 return new SHMBuffer(shm, size_to_allocate); | 519 return new SHMBuffer(shm, size_to_allocate); |
| 520 } | 520 } |
| 521 SHMBuffer* ret = available_shm_segments_.back(); | 521 SHMBuffer* ret = available_shm_segments_.back(); |
| 522 available_shm_segments_.pop_back(); | 522 available_shm_segments_.pop_back(); |
| 523 return ret; | 523 return ret; |
| 524 } | 524 } |
| 525 | 525 |
| 526 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { | 526 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { |
| 527 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 527 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 528 available_shm_segments_.push_back(shm_buffer); | 528 available_shm_segments_.push_back(shm_buffer); |
| 529 } | 529 } |
| 530 | 530 |
| 531 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | 531 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
| 532 DVLOG(3) << "NotifyEndOfBitstreamBuffer(" << id << ")"; | 532 DVLOG(3) << "NotifyEndOfBitstreamBuffer(" << id << ")"; |
| 533 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 533 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 534 | 534 |
| 535 std::map<int32, BufferPair>::iterator it = | 535 std::map<int32, BufferPair>::iterator it = |
| 536 bitstream_buffers_in_decoder_.find(id); | 536 bitstream_buffers_in_decoder_.find(id); |
| 537 if (it == bitstream_buffers_in_decoder_.end()) { | 537 if (it == bitstream_buffers_in_decoder_.end()) { |
| 538 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 538 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 539 NOTREACHED() << "Missing bitstream buffer: " << id; | 539 NOTREACHED() << "Missing bitstream buffer: " << id; |
| 540 return; | 540 return; |
| 541 } | 541 } |
| 542 | 542 |
| 543 PutSHM(it->second.shm_buffer); | 543 PutSHM(it->second.shm_buffer); |
| 544 bitstream_buffers_in_decoder_.erase(it); | 544 bitstream_buffers_in_decoder_.erase(it); |
| 545 | 545 |
| 546 if (pending_reset_cb_.is_null() && state_ != kDrainingDecoder && | 546 if (pending_reset_cb_.is_null() && state_ != kDrainingDecoder && |
| 547 CanMoreDecodeWorkBeDone() && !pending_decode_cb_.is_null()) { | 547 CanMoreDecodeWorkBeDone() && !pending_decode_cb_.is_null()) { |
| 548 base::ResetAndReturn(&pending_decode_cb_).Run(kNotEnoughData, NULL); | 548 base::ResetAndReturn(&pending_decode_cb_).Run(kNotEnoughData, NULL); |
| 549 } | 549 } |
| 550 } | 550 } |
| 551 | 551 |
| 552 GpuVideoDecoder::~GpuVideoDecoder() { | 552 GpuVideoDecoder::~GpuVideoDecoder() { |
| 553 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 553 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 554 DCHECK(!vda_.get()); // Stop should have been already called. | 554 DCHECK(!vda_.get()); // Stop should have been already called. |
| 555 DCHECK(pending_decode_cb_.is_null()); | 555 DCHECK(pending_decode_cb_.is_null()); |
| 556 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { | 556 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { |
| 557 available_shm_segments_[i]->shm->Close(); | 557 available_shm_segments_[i]->shm->Close(); |
| 558 delete available_shm_segments_[i]; | 558 delete available_shm_segments_[i]; |
| 559 } | 559 } |
| 560 available_shm_segments_.clear(); | 560 available_shm_segments_.clear(); |
| 561 for (std::map<int32, BufferPair>::iterator it = | 561 for (std::map<int32, BufferPair>::iterator it = |
| 562 bitstream_buffers_in_decoder_.begin(); | 562 bitstream_buffers_in_decoder_.begin(); |
| 563 it != bitstream_buffers_in_decoder_.end(); ++it) { | 563 it != bitstream_buffers_in_decoder_.end(); ++it) { |
| 564 it->second.shm_buffer->shm->Close(); | 564 it->second.shm_buffer->shm->Close(); |
| 565 } | 565 } |
| 566 bitstream_buffers_in_decoder_.clear(); | 566 bitstream_buffers_in_decoder_.clear(); |
| 567 | 567 |
| 568 DestroyPictureBuffers(&assigned_picture_buffers_); | 568 DestroyPictureBuffers(&assigned_picture_buffers_); |
| 569 DestroyPictureBuffers(&dismissed_picture_buffers_); | 569 DestroyPictureBuffers(&dismissed_picture_buffers_); |
| 570 } | 570 } |
| 571 | 571 |
| 572 void GpuVideoDecoder::NotifyFlushDone() { | 572 void GpuVideoDecoder::NotifyFlushDone() { |
| 573 DVLOG(3) << "NotifyFlushDone()"; | 573 DVLOG(3) << "NotifyFlushDone()"; |
| 574 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 574 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 575 DCHECK_EQ(state_, kDrainingDecoder); | 575 DCHECK_EQ(state_, kDrainingDecoder); |
| 576 state_ = kDecoderDrained; | 576 state_ = kDecoderDrained; |
| 577 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 577 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 578 } | 578 } |
| 579 | 579 |
| 580 void GpuVideoDecoder::NotifyResetDone() { | 580 void GpuVideoDecoder::NotifyResetDone() { |
| 581 DVLOG(3) << "NotifyResetDone()"; | 581 DVLOG(3) << "NotifyResetDone()"; |
| 582 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 582 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 583 DCHECK(ready_video_frames_.empty()); | 583 DCHECK(ready_video_frames_.empty()); |
| 584 | 584 |
| 585 // This needs to happen after the Reset() on vda_ is done to ensure pictures | 585 // This needs to happen after the Reset() on vda_ is done to ensure pictures |
| 586 // delivered during the reset can find their time data. | 586 // delivered during the reset can find their time data. |
| 587 input_buffer_data_.clear(); | 587 input_buffer_data_.clear(); |
| 588 | 588 |
| 589 if (!pending_reset_cb_.is_null()) | 589 if (!pending_reset_cb_.is_null()) |
| 590 base::ResetAndReturn(&pending_reset_cb_).Run(); | 590 base::ResetAndReturn(&pending_reset_cb_).Run(); |
| 591 | 591 |
| 592 if (!pending_decode_cb_.is_null()) | 592 if (!pending_decode_cb_.is_null()) |
| 593 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 593 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 594 } | 594 } |
| 595 | 595 |
| 596 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { | 596 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { |
| 597 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 597 DCHECK(gvd_task_runner_->BelongsToCurrentThread()); |
| 598 if (!vda_) | 598 if (!vda_) |
| 599 return; | 599 return; |
| 600 | 600 |
| 601 DLOG(ERROR) << "VDA Error: " << error; | 601 DLOG(ERROR) << "VDA Error: " << error; |
| 602 DestroyVDA(); | 602 DestroyVDA(); |
| 603 | 603 |
| 604 state_ = kError; | 604 state_ = kError; |
| 605 | 605 |
| 606 if (!pending_decode_cb_.is_null()) { | 606 if (!pending_decode_cb_.is_null()) { |
| 607 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); | 607 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); |
| 608 return; | 608 return; |
| 609 } | 609 } |
| 610 } | 610 } |
| 611 | 611 |
| 612 } // namespace media | 612 } // namespace media |
| OLD | NEW |