| 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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/cpu.h" | 9 #include "base/cpu.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "media/base/bind_to_loop.h" |
| 12 #include "media/base/decoder_buffer.h" | 13 #include "media/base/decoder_buffer.h" |
| 13 #include "media/base/demuxer_stream.h" | 14 #include "media/base/demuxer_stream.h" |
| 14 #include "media/base/pipeline.h" | 15 #include "media/base/pipeline.h" |
| 15 #include "media/base/pipeline_status.h" | 16 #include "media/base/pipeline_status.h" |
| 16 #include "media/base/video_decoder_config.h" | 17 #include "media/base/video_decoder_config.h" |
| 17 | 18 |
| 18 namespace media { | 19 namespace media { |
| 19 | 20 |
| 20 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. | 21 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. |
| 21 // Higher values allow better pipelining in the GPU, but also require more | 22 // Higher values allow better pipelining in the GPU, but also require more |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 state_(kNormal), | 60 state_(kNormal), |
| 60 demuxer_read_in_progress_(false), | 61 demuxer_read_in_progress_(false), |
| 61 decoder_texture_target_(0), | 62 decoder_texture_target_(0), |
| 62 next_picture_buffer_id_(0), | 63 next_picture_buffer_id_(0), |
| 63 next_bitstream_buffer_id_(0), | 64 next_bitstream_buffer_id_(0), |
| 64 error_occured_(false) { | 65 error_occured_(false) { |
| 65 DCHECK(factories_); | 66 DCHECK(factories_); |
| 66 } | 67 } |
| 67 | 68 |
| 68 void GpuVideoDecoder::Reset(const base::Closure& closure) { | 69 void GpuVideoDecoder::Reset(const base::Closure& closure) { |
| 69 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 70 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 70 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 71 &GpuVideoDecoder::Reset, this, closure)); | |
| 72 return; | |
| 73 } | |
| 74 | 71 |
| 75 if (state_ == kDrainingDecoder) { | 72 if (state_ == kDrainingDecoder) { |
| 76 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 73 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 77 &GpuVideoDecoder::Reset, this, closure)); | 74 &GpuVideoDecoder::Reset, this, closure)); |
| 78 // NOTE: if we're deferring Reset() until a Flush() completes, return | 75 // 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(). | 76 // queued pictures to the VDA so they can be used to finish that Flush(). |
| 80 if (pending_read_cb_.is_null()) | 77 if (pending_read_cb_.is_null()) |
| 81 ready_video_frames_.clear(); | 78 ready_video_frames_.clear(); |
| 82 return; | 79 return; |
| 83 } | 80 } |
| 84 | 81 |
| 85 // Throw away any already-decoded, not-yet-delivered frames. | 82 // Throw away any already-decoded, not-yet-delivered frames. |
| 86 ready_video_frames_.clear(); | 83 ready_video_frames_.clear(); |
| 87 | 84 |
| 85 DCHECK(pending_reset_cb_.is_null()); |
| 86 pending_reset_cb_ = BindToCurrentLoop(closure); |
| 87 |
| 88 if (!vda_.get()) { | 88 if (!vda_.get()) { |
| 89 closure.Run(); | 89 base::ResetAndReturn(&pending_reset_cb_).Run(); |
| 90 return; | 90 return; |
| 91 } | 91 } |
| 92 | 92 |
| 93 DCHECK(pending_reset_cb_.is_null()); | |
| 94 DCHECK(!closure.is_null()); | |
| 95 | |
| 96 // VideoRendererBase::Flush() can't complete while it has a pending read to | 93 // VideoRendererBase::Flush() can't complete while it has a pending read to |
| 97 // us, so we fulfill such a read here. | 94 // us, so we fulfill such a read here. |
| 98 if (!pending_read_cb_.is_null()) | 95 if (!pending_read_cb_.is_null()) |
| 99 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 96 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 100 | 97 |
| 101 pending_reset_cb_ = closure; | |
| 102 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 98 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 103 &VideoDecodeAccelerator::Reset, weak_vda_)); | 99 &VideoDecodeAccelerator::Reset, weak_vda_)); |
| 104 } | 100 } |
| 105 | 101 |
| 106 void GpuVideoDecoder::Stop(const base::Closure& closure) { | 102 void GpuVideoDecoder::Stop(const base::Closure& closure) { |
| 107 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 103 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 108 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 104 if (vda_.get()) |
| 109 &GpuVideoDecoder::Stop, this, closure)); | 105 DestroyVDA(); |
| 110 return; | 106 BindToCurrentLoop(closure).Run(); |
| 111 } | |
| 112 if (!vda_.get()) { | |
| 113 closure.Run(); | |
| 114 return; | |
| 115 } | |
| 116 DestroyVDA(); | |
| 117 closure.Run(); | |
| 118 } | 107 } |
| 119 | 108 |
| 120 void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, | 109 void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, |
| 121 const PipelineStatusCB& orig_status_cb, | 110 const PipelineStatusCB& orig_status_cb, |
| 122 const StatisticsCB& statistics_cb) { | 111 const StatisticsCB& statistics_cb) { |
| 123 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | |
| 124 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 125 &GpuVideoDecoder::Initialize, | |
| 126 this, stream, orig_status_cb, statistics_cb)); | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 112 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 131 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( | 113 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( |
| 132 "Media.GpuVideoDecoderInitializeStatus", orig_status_cb); | 114 "Media.GpuVideoDecoderInitializeStatus", |
| 115 BindToCurrentLoop(orig_status_cb)); |
| 116 DCHECK(!demuxer_stream_); |
| 133 | 117 |
| 134 DCHECK(!demuxer_stream_); | |
| 135 if (!stream) { | 118 if (!stream) { |
| 136 status_cb.Run(PIPELINE_ERROR_DECODE); | 119 status_cb.Run(PIPELINE_ERROR_DECODE); |
| 137 return; | 120 return; |
| 138 } | 121 } |
| 139 | 122 |
| 140 // TODO(scherkus): this check should go in Pipeline prior to creating | 123 // TODO(scherkus): this check should go in Pipeline prior to creating |
| 141 // decoder objects. | 124 // decoder objects. |
| 142 const VideoDecoderConfig& config = stream->video_decoder_config(); | 125 const VideoDecoderConfig& config = stream->video_decoder_config(); |
| 143 if (!config.IsValidConfig() || config.is_encrypted()) { | 126 if (!config.IsValidConfig() || config.is_encrypted()) { |
| 144 DLOG(ERROR) << "Unsupported video stream - " | 127 DLOG(ERROR) << "Unsupported video stream - " |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 AddRef(); | 192 AddRef(); |
| 210 vda_loop_proxy_->PostTaskAndReply( | 193 vda_loop_proxy_->PostTaskAndReply( |
| 211 FROM_HERE, | 194 FROM_HERE, |
| 212 base::Bind(&VideoDecodeAccelerator::Destroy, weak_vda_), | 195 base::Bind(&VideoDecodeAccelerator::Destroy, weak_vda_), |
| 213 base::Bind(&GpuVideoDecoder::Release, this)); | 196 base::Bind(&GpuVideoDecoder::Release, this)); |
| 214 | 197 |
| 215 DestroyTextures(); | 198 DestroyTextures(); |
| 216 } | 199 } |
| 217 | 200 |
| 218 void GpuVideoDecoder::Read(const ReadCB& read_cb) { | 201 void GpuVideoDecoder::Read(const ReadCB& read_cb) { |
| 219 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 202 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 220 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 203 DCHECK(pending_reset_cb_.is_null()); |
| 221 &GpuVideoDecoder::Read, this, read_cb)); | 204 DCHECK(pending_read_cb_.is_null()); |
| 222 return; | 205 pending_read_cb_ = BindToCurrentLoop(read_cb); |
| 223 } | |
| 224 | 206 |
| 225 if (error_occured_) { | 207 if (error_occured_) { |
| 226 read_cb.Run(kDecodeError, NULL); | 208 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); |
| 227 return; | 209 return; |
| 228 } | 210 } |
| 229 | 211 |
| 230 if (!vda_.get()) { | 212 if (!vda_.get()) { |
| 231 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); | 213 base::ResetAndReturn(&pending_read_cb_).Run( |
| 214 kOk, VideoFrame::CreateEmptyFrame()); |
| 232 return; | 215 return; |
| 233 } | 216 } |
| 234 | 217 |
| 235 DCHECK(pending_reset_cb_.is_null()); | |
| 236 DCHECK(pending_read_cb_.is_null()); | |
| 237 pending_read_cb_ = read_cb; | |
| 238 | |
| 239 if (!ready_video_frames_.empty()) { | 218 if (!ready_video_frames_.empty()) { |
| 240 EnqueueFrameAndTriggerFrameDelivery(NULL); | 219 EnqueueFrameAndTriggerFrameDelivery(NULL); |
| 241 return; | 220 return; |
| 242 } | 221 } |
| 243 | 222 |
| 244 switch (state_) { | 223 switch (state_) { |
| 245 case kDecoderDrained: | 224 case kDecoderDrained: |
| 246 state_ = kNormal; | 225 state_ = kNormal; |
| 247 // Fall-through. | 226 // Fall-through. |
| 248 case kNormal: | 227 case kNormal: |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 continue; | 324 continue; |
| 346 *timestamp = it->timestamp; | 325 *timestamp = it->timestamp; |
| 347 *visible_rect = it->visible_rect; | 326 *visible_rect = it->visible_rect; |
| 348 *natural_size = it->natural_size; | 327 *natural_size = it->natural_size; |
| 349 return; | 328 return; |
| 350 } | 329 } |
| 351 NOTREACHED() << "Missing bitstreambuffer id: " << id; | 330 NOTREACHED() << "Missing bitstreambuffer id: " << id; |
| 352 } | 331 } |
| 353 | 332 |
| 354 bool GpuVideoDecoder::HasAlpha() const { | 333 bool GpuVideoDecoder::HasAlpha() const { |
| 334 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 355 return true; | 335 return true; |
| 356 } | 336 } |
| 357 | 337 |
| 358 void GpuVideoDecoder::NotifyInitializeDone() { | 338 void GpuVideoDecoder::NotifyInitializeDone() { |
| 359 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; | 339 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; |
| 360 } | 340 } |
| 361 | 341 |
| 362 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, | 342 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, |
| 363 const gfx::Size& size, | 343 const gfx::Size& size, |
| 364 uint32 texture_target) { | 344 uint32 texture_target) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 return; | 433 return; |
| 454 | 434 |
| 455 if (frame) | 435 if (frame) |
| 456 ready_video_frames_.push_back(frame); | 436 ready_video_frames_.push_back(frame); |
| 457 else | 437 else |
| 458 DCHECK(!ready_video_frames_.empty()); | 438 DCHECK(!ready_video_frames_.empty()); |
| 459 | 439 |
| 460 if (pending_read_cb_.is_null()) | 440 if (pending_read_cb_.is_null()) |
| 461 return; | 441 return; |
| 462 | 442 |
| 463 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 443 base::ResetAndReturn(&pending_read_cb_).Run(kOk, ready_video_frames_.front()); |
| 464 pending_read_cb_, kOk, ready_video_frames_.front())); | |
| 465 pending_read_cb_.Reset(); | |
| 466 ready_video_frames_.pop_front(); | 444 ready_video_frames_.pop_front(); |
| 467 } | 445 } |
| 468 | 446 |
| 469 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { | 447 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { |
| 470 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 448 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { |
| 471 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 449 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 472 &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id)); | 450 &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id)); |
| 473 return; | 451 return; |
| 474 } | 452 } |
| 475 if (!vda_.get()) | 453 if (!vda_.get()) |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 | 582 |
| 605 error_occured_ = true; | 583 error_occured_ = true; |
| 606 | 584 |
| 607 if (!pending_read_cb_.is_null()) { | 585 if (!pending_read_cb_.is_null()) { |
| 608 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); | 586 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); |
| 609 return; | 587 return; |
| 610 } | 588 } |
| 611 } | 589 } |
| 612 | 590 |
| 613 } // namespace media | 591 } // namespace media |
| OLD | NEW |