Chromium Code Reviews| 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 "base/task_runner_util.h" | |
| 12 #include "media/base/bind_to_loop.h" | 13 #include "media/base/bind_to_loop.h" |
| 13 #include "media/base/decoder_buffer.h" | 14 #include "media/base/decoder_buffer.h" |
| 14 #include "media/base/demuxer_stream.h" | 15 #include "media/base/demuxer_stream.h" |
| 15 #include "media/base/pipeline.h" | 16 #include "media/base/pipeline.h" |
| 16 #include "media/base/pipeline_status.h" | 17 #include "media/base/pipeline_status.h" |
| 17 #include "media/base/video_decoder_config.h" | 18 #include "media/base/video_decoder_config.h" |
| 18 | 19 |
| 19 namespace media { | 20 namespace media { |
| 20 | 21 |
| 22 // Proxies calls to a VideoDecodeAccelerator::Client from the calling thread to | |
| 23 // a thread of the client's choice. | |
|
Ami GONE FROM CHROMIUM
2013/04/05 21:05:48
Crazy Question Time(tm):
What would happen if you
scherkus (not reviewing)
2013/04/05 21:16:12
I don't think it's too crazy but let's make sure I
| |
| 24 class VDAClientProxy | |
| 25 : public base::RefCountedThreadSafe<VDAClientProxy>, | |
| 26 public VideoDecodeAccelerator::Client { | |
| 27 public: | |
| 28 VDAClientProxy(const scoped_refptr<base::MessageLoopProxy>& client_loop, | |
|
Ami GONE FROM CHROMIUM
2013/04/05 21:05:48
This is always MessageLoopProxy::current() so I'd
scherkus (not reviewing)
2013/04/17 16:54:54
Done.
| |
| 29 VideoDecodeAccelerator::Client* client); | |
| 30 | |
| 31 // Detaches the proxy. |client| will no longer be called and can be safely | |
| 32 // deleted. Any pending/future calls will be discarded. | |
| 33 // | |
| 34 // Must be called on |client_loop|. | |
| 35 void Detach(); | |
| 36 | |
| 37 // VideoDecodeAccelerator::Client implementation. | |
| 38 virtual void NotifyInitializeDone() OVERRIDE; | |
| 39 virtual void ProvidePictureBuffers(uint32 count, | |
| 40 const gfx::Size& size, | |
| 41 uint32 texture_target) OVERRIDE; | |
| 42 virtual void DismissPictureBuffer(int32 id) OVERRIDE; | |
| 43 virtual void PictureReady(const media::Picture& picture) OVERRIDE; | |
| 44 virtual void NotifyEndOfBitstreamBuffer(int32 id) OVERRIDE; | |
| 45 virtual void NotifyFlushDone() OVERRIDE; | |
| 46 virtual void NotifyResetDone() OVERRIDE; | |
| 47 virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE; | |
| 48 | |
| 49 private: | |
| 50 friend class base::RefCountedThreadSafe<VDAClientProxy>; | |
| 51 virtual ~VDAClientProxy(); | |
| 52 | |
| 53 scoped_refptr<base::MessageLoopProxy> client_loop_; | |
| 54 | |
| 55 // Weak pointers are used to invalidate tasks posted to |client_loop_| that | |
| 56 // Detach() has been called. | |
| 57 base::WeakPtrFactory<VideoDecodeAccelerator::Client> weak_client_factory_; | |
| 58 base::WeakPtr<VideoDecodeAccelerator::Client> weak_client_; | |
| 59 | |
| 60 DISALLOW_COPY_AND_ASSIGN(VDAClientProxy); | |
| 61 }; | |
| 62 | |
| 63 VDAClientProxy::VDAClientProxy( | |
| 64 const scoped_refptr<base::MessageLoopProxy>& client_loop, | |
| 65 VideoDecodeAccelerator::Client* client) | |
| 66 : client_loop_(client_loop), | |
| 67 weak_client_factory_(client), | |
| 68 weak_client_(weak_client_factory_.GetWeakPtr()) { | |
| 69 } | |
| 70 | |
| 71 VDAClientProxy::~VDAClientProxy() {} | |
|
Ami GONE FROM CHROMIUM
2013/04/05 21:05:48
DCHECK already Detach()d
scherkus (not reviewing)
2013/04/17 16:54:54
Done.
| |
| 72 | |
| 73 void VDAClientProxy::Detach() { | |
| 74 DCHECK(client_loop_->BelongsToCurrentThread()); | |
|
Ami GONE FROM CHROMIUM
2013/04/05 21:05:48
DCHECK not already detached to catch programming e
scherkus (not reviewing)
2013/04/17 16:54:54
Done.
| |
| 75 weak_client_factory_.InvalidateWeakPtrs(); | |
| 76 DCHECK(!weak_client_); | |
| 77 } | |
| 78 | |
| 79 void VDAClientProxy::NotifyInitializeDone() { | |
| 80 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 81 &VideoDecodeAccelerator::Client::NotifyInitializeDone, weak_client_)); | |
| 82 } | |
| 83 | |
| 84 void VDAClientProxy::ProvidePictureBuffers(uint32 count, | |
| 85 const gfx::Size& size, | |
| 86 uint32 texture_target) { | |
| 87 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 88 &VideoDecodeAccelerator::Client::ProvidePictureBuffers, weak_client_, | |
| 89 count, size, texture_target)); | |
| 90 } | |
| 91 | |
| 92 void VDAClientProxy::DismissPictureBuffer(int32 id) { | |
| 93 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 94 &VideoDecodeAccelerator::Client::DismissPictureBuffer, weak_client_, id)); | |
| 95 } | |
| 96 | |
| 97 void VDAClientProxy::PictureReady(const media::Picture& picture) { | |
| 98 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 99 &VideoDecodeAccelerator::Client::PictureReady, weak_client_, picture)); | |
| 100 } | |
| 101 | |
| 102 void VDAClientProxy::NotifyEndOfBitstreamBuffer(int32 id) { | |
| 103 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 104 &VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, weak_client_, | |
| 105 id)); | |
| 106 } | |
| 107 | |
| 108 void VDAClientProxy::NotifyFlushDone() { | |
| 109 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 110 &VideoDecodeAccelerator::Client::NotifyFlushDone, weak_client_)); | |
| 111 } | |
| 112 | |
| 113 void VDAClientProxy::NotifyResetDone() { | |
| 114 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 115 &VideoDecodeAccelerator::Client::NotifyResetDone, weak_client_)); | |
| 116 } | |
| 117 | |
| 118 void VDAClientProxy::NotifyError(media::VideoDecodeAccelerator::Error error) { | |
| 119 client_loop_->PostTask(FROM_HERE, base::Bind( | |
| 120 &VideoDecodeAccelerator::Client::NotifyError, weak_client_, error)); | |
| 121 } | |
| 122 | |
| 123 | |
| 21 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. | 124 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. |
| 22 // Higher values allow better pipelining in the GPU, but also require more | 125 // Higher values allow better pipelining in the GPU, but also require more |
| 23 // resources. | 126 // resources. |
| 24 enum { kMaxInFlightDecodes = 4 }; | 127 enum { kMaxInFlightDecodes = 4 }; |
| 25 | 128 |
| 26 GpuVideoDecoder::Factories::~Factories() {} | 129 GpuVideoDecoder::Factories::~Factories() {} |
| 27 | 130 |
| 28 // Size of shared-memory segments we allocate. Since we reuse them we let them | 131 // Size of shared-memory segments we allocate. Since we reuse them we let them |
| 29 // be on the beefy side. | 132 // be on the beefy side. |
| 30 static const size_t kSharedMemorySegmentBytes = 100 << 10; | 133 static const size_t kSharedMemorySegmentBytes = 100 << 10; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 47 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), | 150 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), |
| 48 natural_size(ns) { | 151 natural_size(ns) { |
| 49 } | 152 } |
| 50 | 153 |
| 51 GpuVideoDecoder::BufferData::~BufferData() {} | 154 GpuVideoDecoder::BufferData::~BufferData() {} |
| 52 | 155 |
| 53 GpuVideoDecoder::GpuVideoDecoder( | 156 GpuVideoDecoder::GpuVideoDecoder( |
| 54 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 157 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
| 55 const scoped_refptr<Factories>& factories) | 158 const scoped_refptr<Factories>& factories) |
| 56 : gvd_loop_proxy_(message_loop), | 159 : gvd_loop_proxy_(message_loop), |
| 160 weak_factory_(this), | |
| 57 vda_loop_proxy_(factories->GetMessageLoop()), | 161 vda_loop_proxy_(factories->GetMessageLoop()), |
| 58 factories_(factories), | 162 factories_(factories), |
| 59 state_(kNormal), | 163 state_(kNormal), |
| 60 demuxer_read_in_progress_(false), | 164 demuxer_read_in_progress_(false), |
| 61 decoder_texture_target_(0), | 165 decoder_texture_target_(0), |
| 62 next_picture_buffer_id_(0), | 166 next_picture_buffer_id_(0), |
| 63 next_bitstream_buffer_id_(0), | 167 next_bitstream_buffer_id_(0), |
| 64 error_occured_(false), | 168 error_occured_(false), |
| 65 available_pictures_(-1) { | 169 available_pictures_(-1) { |
| 66 DCHECK(factories_); | 170 DCHECK(factories_); |
| 67 } | 171 } |
| 68 | 172 |
| 69 void GpuVideoDecoder::Reset(const base::Closure& closure) { | 173 void GpuVideoDecoder::Reset(const base::Closure& closure) { |
| 70 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 174 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 71 | 175 |
| 72 if (state_ == kDrainingDecoder && !factories_->IsAborted()) { | 176 if (state_ == kDrainingDecoder && !factories_->IsAborted()) { |
| 73 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 177 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 74 &GpuVideoDecoder::Reset, this, closure)); | 178 &GpuVideoDecoder::Reset, weak_this_, closure)); |
| 75 // NOTE: if we're deferring Reset() until a Flush() completes, return | 179 // NOTE: if we're deferring Reset() until a Flush() completes, return |
| 76 // queued pictures to the VDA so they can be used to finish that Flush(). | 180 // queued pictures to the VDA so they can be used to finish that Flush(). |
| 77 if (pending_read_cb_.is_null()) | 181 if (pending_read_cb_.is_null()) |
| 78 ready_video_frames_.clear(); | 182 ready_video_frames_.clear(); |
| 79 return; | 183 return; |
| 80 } | 184 } |
| 81 | 185 |
| 82 // Throw away any already-decoded, not-yet-delivered frames. | 186 // Throw away any already-decoded, not-yet-delivered frames. |
| 83 ready_video_frames_.clear(); | 187 ready_video_frames_.clear(); |
| 84 | 188 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 107 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 211 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 108 if (!pending_reset_cb_.is_null()) | 212 if (!pending_reset_cb_.is_null()) |
| 109 base::ResetAndReturn(&pending_reset_cb_).Run(); | 213 base::ResetAndReturn(&pending_reset_cb_).Run(); |
| 110 BindToCurrentLoop(closure).Run(); | 214 BindToCurrentLoop(closure).Run(); |
| 111 } | 215 } |
| 112 | 216 |
| 113 void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, | 217 void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, |
| 114 const PipelineStatusCB& orig_status_cb, | 218 const PipelineStatusCB& orig_status_cb, |
| 115 const StatisticsCB& statistics_cb) { | 219 const StatisticsCB& statistics_cb) { |
| 116 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 220 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 221 weak_this_ = weak_factory_.GetWeakPtr(); | |
| 222 | |
| 117 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( | 223 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( |
| 118 "Media.GpuVideoDecoderInitializeStatus", | 224 "Media.GpuVideoDecoderInitializeStatus", |
| 119 BindToCurrentLoop(orig_status_cb)); | 225 BindToCurrentLoop(orig_status_cb)); |
| 120 DCHECK(!demuxer_stream_); | 226 DCHECK(!demuxer_stream_); |
| 121 | 227 |
| 122 if (!stream) { | 228 if (!stream) { |
| 123 status_cb.Run(PIPELINE_ERROR_DECODE); | 229 status_cb.Run(PIPELINE_ERROR_DECODE); |
| 124 return; | 230 return; |
| 125 } | 231 } |
| 126 | 232 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 144 bool os_large_video_support = true; | 250 bool os_large_video_support = true; |
| 145 #if defined(OS_WIN) | 251 #if defined(OS_WIN) |
| 146 os_large_video_support = false; | 252 os_large_video_support = false; |
| 147 #endif | 253 #endif |
| 148 if (!(os_large_video_support && hw_large_video_support)) { | 254 if (!(os_large_video_support && hw_large_video_support)) { |
| 149 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 255 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
| 150 return; | 256 return; |
| 151 } | 257 } |
| 152 } | 258 } |
| 153 | 259 |
| 260 client_proxy_ = new VDAClientProxy(gvd_loop_proxy_, this); | |
| 154 VideoDecodeAccelerator* vda = | 261 VideoDecodeAccelerator* vda = |
| 155 factories_->CreateVideoDecodeAccelerator(config.profile(), this); | 262 factories_->CreateVideoDecodeAccelerator(config.profile(), client_proxy_); |
| 156 if (!vda) { | 263 if (!vda) { |
| 157 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 264 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
| 158 return; | 265 return; |
| 159 } | 266 } |
| 160 | 267 |
| 161 if (config.codec() == kCodecH264) | 268 if (config.codec() == kCodecH264) |
| 162 stream->EnableBitstreamConverter(); | 269 stream->EnableBitstreamConverter(); |
| 163 | 270 |
| 164 demuxer_stream_ = stream; | 271 demuxer_stream_ = stream; |
| 165 statistics_cb_ = statistics_cb; | 272 statistics_cb_ = statistics_cb; |
| 166 | 273 |
| 167 DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded."; | 274 DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded."; |
| 168 vda_loop_proxy_->PostTaskAndReply( | 275 PostTaskAndReplyWithResult( |
| 169 FROM_HERE, | 276 vda_loop_proxy_, FROM_HERE, |
| 170 base::Bind(&GpuVideoDecoder::SetVDA, this, vda), | 277 base::Bind(&VideoDecodeAccelerator::AsWeakPtr, base::Unretained(vda)), |
| 171 base::Bind(status_cb, PIPELINE_OK)); | 278 base::Bind(&GpuVideoDecoder::SetVDA, weak_this_, status_cb, vda)); |
| 172 } | 279 } |
| 173 | 280 |
| 174 void GpuVideoDecoder::SetVDA(VideoDecodeAccelerator* vda) { | 281 void GpuVideoDecoder::SetVDA( |
| 175 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 282 const PipelineStatusCB& status_cb, |
| 283 VideoDecodeAccelerator* vda, | |
| 284 base::WeakPtr<VideoDecodeAccelerator> weak_vda) { | |
| 285 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | |
| 176 DCHECK(!vda_.get()); | 286 DCHECK(!vda_.get()); |
| 177 vda_.reset(vda); | 287 vda_.reset(vda); |
| 178 weak_vda_ = vda->AsWeakPtr(); | 288 weak_vda_ = weak_vda; |
| 289 status_cb.Run(PIPELINE_OK); | |
| 179 } | 290 } |
| 180 | 291 |
| 181 void GpuVideoDecoder::DestroyTextures() { | 292 void GpuVideoDecoder::DestroyTextures() { |
| 182 for (std::map<int32, PictureBuffer>::iterator it = | 293 for (std::map<int32, PictureBuffer>::iterator it = |
| 183 picture_buffers_in_decoder_.begin(); | 294 picture_buffers_in_decoder_.begin(); |
| 184 it != picture_buffers_in_decoder_.end(); ++it) { | 295 it != picture_buffers_in_decoder_.end(); ++it) { |
| 185 factories_->DeleteTexture(it->second.texture_id()); | 296 factories_->DeleteTexture(it->second.texture_id()); |
| 186 } | 297 } |
| 187 picture_buffers_in_decoder_.clear(); | 298 picture_buffers_in_decoder_.clear(); |
| 188 } | 299 } |
| 189 | 300 |
| 301 static void DestroyVDAWithClientProxy( | |
| 302 const scoped_refptr<VDAClientProxy>& client_proxy, | |
|
Ami GONE FROM CHROMIUM
2013/04/05 21:05:48
so this is only here to keep the proxy alive until
scherkus (not reviewing)
2013/04/17 16:54:54
Done.
| |
| 303 base::WeakPtr<VideoDecodeAccelerator> weak_vda) { | |
| 304 if (weak_vda) | |
| 305 weak_vda->Destroy(); | |
| 306 } | |
| 307 | |
| 190 void GpuVideoDecoder::DestroyVDA() { | 308 void GpuVideoDecoder::DestroyVDA() { |
| 191 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 309 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 310 | |
| 311 // |client_proxy| must stay alive until |weak_vda_| has been destroyed. | |
| 312 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 313 &DestroyVDAWithClientProxy, client_proxy_, weak_vda_)); | |
| 314 | |
| 192 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); | 315 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); |
| 193 // Tricky: |this| needs to stay alive until after VDA::Destroy is actually | 316 client_proxy_->Detach(); |
| 194 // called, not just posted, so we take an artificial ref to |this| and release | 317 client_proxy_ = NULL; |
| 195 // it as |reply| after VDA::Destroy() returns. | |
| 196 AddRef(); | |
| 197 vda_loop_proxy_->PostTaskAndReply( | |
| 198 FROM_HERE, | |
| 199 base::Bind(&VideoDecodeAccelerator::Destroy, weak_vda_), | |
| 200 base::Bind(&GpuVideoDecoder::Release, this)); | |
| 201 | 318 |
| 202 DestroyTextures(); | 319 DestroyTextures(); |
| 203 } | 320 } |
| 204 | 321 |
| 205 void GpuVideoDecoder::Read(const ReadCB& read_cb) { | 322 void GpuVideoDecoder::Read(const ReadCB& read_cb) { |
| 206 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 323 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 207 DCHECK(pending_reset_cb_.is_null()); | 324 DCHECK(pending_reset_cb_.is_null()); |
| 208 DCHECK(pending_read_cb_.is_null()); | 325 DCHECK(pending_read_cb_.is_null()); |
| 209 pending_read_cb_ = BindToCurrentLoop(read_cb); | 326 pending_read_cb_ = BindToCurrentLoop(read_cb); |
| 210 | 327 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 238 } | 355 } |
| 239 } | 356 } |
| 240 | 357 |
| 241 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { | 358 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { |
| 242 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; | 359 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; |
| 243 } | 360 } |
| 244 | 361 |
| 245 void GpuVideoDecoder::RequestBufferDecode( | 362 void GpuVideoDecoder::RequestBufferDecode( |
| 246 DemuxerStream::Status status, | 363 DemuxerStream::Status status, |
| 247 const scoped_refptr<DecoderBuffer>& buffer) { | 364 const scoped_refptr<DecoderBuffer>& buffer) { |
| 365 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | |
| 248 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; | 366 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; |
| 249 | 367 |
| 250 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | |
| 251 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 252 &GpuVideoDecoder::RequestBufferDecode, this, status, buffer)); | |
| 253 return; | |
| 254 } | |
| 255 demuxer_read_in_progress_ = false; | 368 demuxer_read_in_progress_ = false; |
| 256 | 369 |
| 257 if (status != DemuxerStream::kOk) { | 370 if (status != DemuxerStream::kOk) { |
| 258 if (pending_read_cb_.is_null()) | 371 if (pending_read_cb_.is_null()) |
| 259 return; | 372 return; |
| 260 | 373 |
| 261 // TODO(acolwell): Add support for reinitializing the decoder when | 374 // TODO(acolwell): Add support for reinitializing the decoder when |
| 262 // |status| == kConfigChanged. For now we just trigger a decode error. | 375 // |status| == kConfigChanged. For now we just trigger a decode error. |
| 263 Status decoder_status = | 376 Status decoder_status = |
| 264 (status == DemuxerStream::kAborted) ? kOk : kDecodeError; | 377 (status == DemuxerStream::kAborted) ? kOk : kDecodeError; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 return available_pictures_ > 0; | 462 return available_pictures_ > 0; |
| 350 } | 463 } |
| 351 | 464 |
| 352 void GpuVideoDecoder::NotifyInitializeDone() { | 465 void GpuVideoDecoder::NotifyInitializeDone() { |
| 353 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; | 466 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; |
| 354 } | 467 } |
| 355 | 468 |
| 356 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, | 469 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, |
| 357 const gfx::Size& size, | 470 const gfx::Size& size, |
| 358 uint32 texture_target) { | 471 uint32 texture_target) { |
| 359 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 472 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 360 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 361 &GpuVideoDecoder::ProvidePictureBuffers, this, count, size, | |
| 362 texture_target)); | |
| 363 return; | |
| 364 } | |
| 365 | 473 |
| 366 std::vector<uint32> texture_ids; | 474 std::vector<uint32> texture_ids; |
| 367 decoder_texture_target_ = texture_target; | 475 decoder_texture_target_ = texture_target; |
| 368 if (!factories_->CreateTextures( | 476 if (!factories_->CreateTextures( |
| 369 count, size, &texture_ids, decoder_texture_target_)) { | 477 count, size, &texture_ids, decoder_texture_target_)) { |
| 370 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 478 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 371 return; | 479 return; |
| 372 } | 480 } |
| 373 | 481 |
| 374 if (!vda_.get()) | 482 if (!vda_.get()) |
| 375 return; | 483 return; |
| 376 | 484 |
| 377 CHECK_EQ(available_pictures_, -1); | 485 CHECK_EQ(available_pictures_, -1); |
| 378 available_pictures_ = count; | 486 available_pictures_ = count; |
| 379 | 487 |
| 380 std::vector<PictureBuffer> picture_buffers; | 488 std::vector<PictureBuffer> picture_buffers; |
| 381 for (size_t i = 0; i < texture_ids.size(); ++i) { | 489 for (size_t i = 0; i < texture_ids.size(); ++i) { |
| 382 picture_buffers.push_back(PictureBuffer( | 490 picture_buffers.push_back(PictureBuffer( |
| 383 next_picture_buffer_id_++, size, texture_ids[i])); | 491 next_picture_buffer_id_++, size, texture_ids[i])); |
| 384 bool inserted = picture_buffers_in_decoder_.insert(std::make_pair( | 492 bool inserted = picture_buffers_in_decoder_.insert(std::make_pair( |
| 385 picture_buffers.back().id(), picture_buffers.back())).second; | 493 picture_buffers.back().id(), picture_buffers.back())).second; |
| 386 DCHECK(inserted); | 494 DCHECK(inserted); |
| 387 } | 495 } |
| 388 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 496 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 389 &VideoDecodeAccelerator::AssignPictureBuffers, weak_vda_, | 497 &VideoDecodeAccelerator::AssignPictureBuffers, weak_vda_, |
| 390 picture_buffers)); | 498 picture_buffers)); |
| 391 } | 499 } |
| 392 | 500 |
| 393 void GpuVideoDecoder::DismissPictureBuffer(int32 id) { | 501 void GpuVideoDecoder::DismissPictureBuffer(int32 id) { |
| 394 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 502 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 395 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 503 |
| 396 &GpuVideoDecoder::DismissPictureBuffer, this, id)); | |
| 397 return; | |
| 398 } | |
| 399 std::map<int32, PictureBuffer>::iterator it = | 504 std::map<int32, PictureBuffer>::iterator it = |
| 400 picture_buffers_in_decoder_.find(id); | 505 picture_buffers_in_decoder_.find(id); |
| 401 if (it == picture_buffers_in_decoder_.end()) { | 506 if (it == picture_buffers_in_decoder_.end()) { |
| 402 NOTREACHED() << "Missing picture buffer: " << id; | 507 NOTREACHED() << "Missing picture buffer: " << id; |
| 403 return; | 508 return; |
| 404 } | 509 } |
| 405 factories_->DeleteTexture(it->second.texture_id()); | 510 factories_->DeleteTexture(it->second.texture_id()); |
| 406 picture_buffers_in_decoder_.erase(it); | 511 picture_buffers_in_decoder_.erase(it); |
| 407 } | 512 } |
| 408 | 513 |
| 409 void GpuVideoDecoder::PictureReady(const media::Picture& picture) { | 514 void GpuVideoDecoder::PictureReady(const media::Picture& picture) { |
| 410 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 515 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 411 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 516 |
| 412 &GpuVideoDecoder::PictureReady, this, picture)); | |
| 413 return; | |
| 414 } | |
| 415 std::map<int32, PictureBuffer>::iterator it = | 517 std::map<int32, PictureBuffer>::iterator it = |
| 416 picture_buffers_in_decoder_.find(picture.picture_buffer_id()); | 518 picture_buffers_in_decoder_.find(picture.picture_buffer_id()); |
| 417 if (it == picture_buffers_in_decoder_.end()) { | 519 if (it == picture_buffers_in_decoder_.end()) { |
| 418 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 520 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
| 419 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 521 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 420 return; | 522 return; |
| 421 } | 523 } |
| 422 const PictureBuffer& pb = it->second; | 524 const PictureBuffer& pb = it->second; |
| 423 | 525 |
| 424 // Update frame's timestamp. | 526 // Update frame's timestamp. |
| 425 base::TimeDelta timestamp; | 527 base::TimeDelta timestamp; |
| 426 gfx::Rect visible_rect; | 528 gfx::Rect visible_rect; |
| 427 gfx::Size natural_size; | 529 gfx::Size natural_size; |
| 428 GetBufferData(picture.bitstream_buffer_id(), ×tamp, &visible_rect, | 530 GetBufferData(picture.bitstream_buffer_id(), ×tamp, &visible_rect, |
| 429 &natural_size); | 531 &natural_size); |
| 430 DCHECK(decoder_texture_target_); | 532 DCHECK(decoder_texture_target_); |
| 431 scoped_refptr<VideoFrame> frame( | 533 scoped_refptr<VideoFrame> frame( |
| 432 VideoFrame::WrapNativeTexture( | 534 VideoFrame::WrapNativeTexture( |
| 433 pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, | 535 pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, |
| 434 natural_size, timestamp, | 536 natural_size, timestamp, |
| 435 base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), | 537 base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), |
| 436 decoder_texture_target_, | 538 decoder_texture_target_, |
| 437 gfx::Size(visible_rect.width(), visible_rect.height())), | 539 gfx::Size(visible_rect.width(), visible_rect.height())), |
| 438 base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this, | 540 BindToCurrentLoop(base::Bind( |
| 439 picture.picture_buffer_id()))); | 541 &GpuVideoDecoder::ReusePictureBuffer, weak_this_, |
| 542 picture.picture_buffer_id())))); | |
| 440 CHECK_GT(available_pictures_, 0); | 543 CHECK_GT(available_pictures_, 0); |
| 441 available_pictures_--; | 544 available_pictures_--; |
| 442 | 545 |
| 443 EnqueueFrameAndTriggerFrameDelivery(frame); | 546 EnqueueFrameAndTriggerFrameDelivery(frame); |
| 444 } | 547 } |
| 445 | 548 |
| 446 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( | 549 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( |
| 447 const scoped_refptr<VideoFrame>& frame) { | 550 const scoped_refptr<VideoFrame>& frame) { |
| 448 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 551 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 449 | 552 |
| 450 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the | 553 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the |
| 451 // floor and return. | 554 // floor and return. |
| 452 if (!pending_reset_cb_.is_null()) | 555 if (!pending_reset_cb_.is_null()) |
| 453 return; | 556 return; |
| 454 | 557 |
| 455 if (frame) | 558 if (frame) |
| 456 ready_video_frames_.push_back(frame); | 559 ready_video_frames_.push_back(frame); |
| 457 else | 560 else |
| 458 DCHECK(!ready_video_frames_.empty()); | 561 DCHECK(!ready_video_frames_.empty()); |
| 459 | 562 |
| 460 if (pending_read_cb_.is_null()) | 563 if (pending_read_cb_.is_null()) |
| 461 return; | 564 return; |
| 462 | 565 |
| 463 base::ResetAndReturn(&pending_read_cb_).Run(kOk, ready_video_frames_.front()); | 566 base::ResetAndReturn(&pending_read_cb_).Run(kOk, ready_video_frames_.front()); |
| 464 ready_video_frames_.pop_front(); | 567 ready_video_frames_.pop_front(); |
| 465 } | 568 } |
| 466 | 569 |
| 467 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { | 570 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { |
| 468 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 571 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 469 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 470 &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id)); | |
| 471 return; | |
| 472 } | |
| 473 CHECK_GE(available_pictures_, 0); | 572 CHECK_GE(available_pictures_, 0); |
| 474 available_pictures_++; | 573 available_pictures_++; |
| 475 | 574 |
| 476 if (!vda_.get()) | 575 if (!vda_.get()) |
| 477 return; | 576 return; |
| 478 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 577 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 479 &VideoDecodeAccelerator::ReusePictureBuffer, weak_vda_, | 578 &VideoDecodeAccelerator::ReusePictureBuffer, weak_vda_, |
| 480 picture_buffer_id)); | 579 picture_buffer_id)); |
| 481 } | 580 } |
| 482 | 581 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 495 available_shm_segments_.pop_back(); | 594 available_shm_segments_.pop_back(); |
| 496 return ret; | 595 return ret; |
| 497 } | 596 } |
| 498 | 597 |
| 499 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { | 598 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { |
| 500 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 599 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 501 available_shm_segments_.push_back(shm_buffer); | 600 available_shm_segments_.push_back(shm_buffer); |
| 502 } | 601 } |
| 503 | 602 |
| 504 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | 603 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
| 505 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 604 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 506 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 507 &GpuVideoDecoder::NotifyEndOfBitstreamBuffer, this, id)); | |
| 508 return; | |
| 509 } | |
| 510 | 605 |
| 511 std::map<int32, BufferPair>::iterator it = | 606 std::map<int32, BufferPair>::iterator it = |
| 512 bitstream_buffers_in_decoder_.find(id); | 607 bitstream_buffers_in_decoder_.find(id); |
| 513 if (it == bitstream_buffers_in_decoder_.end()) { | 608 if (it == bitstream_buffers_in_decoder_.end()) { |
| 514 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 609 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 515 NOTREACHED() << "Missing bitstream buffer: " << id; | 610 NOTREACHED() << "Missing bitstream buffer: " << id; |
| 516 return; | 611 return; |
| 517 } | 612 } |
| 518 | 613 |
| 519 PutSHM(it->second.shm_buffer); | 614 PutSHM(it->second.shm_buffer); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 549 DestroyTextures(); | 644 DestroyTextures(); |
| 550 } | 645 } |
| 551 | 646 |
| 552 void GpuVideoDecoder::EnsureDemuxOrDecode() { | 647 void GpuVideoDecoder::EnsureDemuxOrDecode() { |
| 553 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 648 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 554 if (demuxer_read_in_progress_) | 649 if (demuxer_read_in_progress_) |
| 555 return; | 650 return; |
| 556 demuxer_read_in_progress_ = true; | 651 demuxer_read_in_progress_ = true; |
| 557 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 652 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 558 &DemuxerStream::Read, demuxer_stream_.get(), | 653 &DemuxerStream::Read, demuxer_stream_.get(), |
| 559 base::Bind(&GpuVideoDecoder::RequestBufferDecode, this))); | 654 base::Bind(&GpuVideoDecoder::RequestBufferDecode, weak_this_))); |
| 560 } | 655 } |
| 561 | 656 |
| 562 void GpuVideoDecoder::NotifyFlushDone() { | 657 void GpuVideoDecoder::NotifyFlushDone() { |
| 563 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 658 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 564 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 565 &GpuVideoDecoder::NotifyFlushDone, this)); | |
| 566 return; | |
| 567 } | |
| 568 DCHECK_EQ(state_, kDrainingDecoder); | 659 DCHECK_EQ(state_, kDrainingDecoder); |
| 569 state_ = kDecoderDrained; | 660 state_ = kDecoderDrained; |
| 570 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 661 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 571 } | 662 } |
| 572 | 663 |
| 573 void GpuVideoDecoder::NotifyResetDone() { | 664 void GpuVideoDecoder::NotifyResetDone() { |
| 574 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 665 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 575 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 576 &GpuVideoDecoder::NotifyResetDone, this)); | |
| 577 return; | |
| 578 } | |
| 579 | |
| 580 DCHECK(ready_video_frames_.empty()); | 666 DCHECK(ready_video_frames_.empty()); |
| 581 | 667 |
| 582 // This needs to happen after the Reset() on vda_ is done to ensure pictures | 668 // This needs to happen after the Reset() on vda_ is done to ensure pictures |
| 583 // delivered during the reset can find their time data. | 669 // delivered during the reset can find their time data. |
| 584 input_buffer_data_.clear(); | 670 input_buffer_data_.clear(); |
| 585 | 671 |
| 586 if (!pending_reset_cb_.is_null()) | 672 if (!pending_reset_cb_.is_null()) |
| 587 base::ResetAndReturn(&pending_reset_cb_).Run(); | 673 base::ResetAndReturn(&pending_reset_cb_).Run(); |
| 588 | 674 |
| 589 if (!pending_read_cb_.is_null()) | 675 if (!pending_read_cb_.is_null()) |
| 590 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 676 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
| 591 } | 677 } |
| 592 | 678 |
| 593 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { | 679 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { |
| 594 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 680 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 595 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 596 &GpuVideoDecoder::NotifyError, this, error)); | |
| 597 return; | |
| 598 } | |
| 599 if (!vda_.get()) | 681 if (!vda_.get()) |
| 600 return; | 682 return; |
| 601 | 683 |
| 602 DLOG(ERROR) << "VDA Error: " << error; | 684 DLOG(ERROR) << "VDA Error: " << error; |
| 603 DestroyVDA(); | 685 DestroyVDA(); |
| 604 | 686 |
| 605 error_occured_ = true; | 687 error_occured_ = true; |
| 606 | 688 |
| 607 if (!pending_read_cb_.is_null()) { | 689 if (!pending_read_cb_.is_null()) { |
| 608 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); | 690 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); |
| 609 return; | 691 return; |
| 610 } | 692 } |
| 611 } | 693 } |
| 612 | 694 |
| 613 } // namespace media | 695 } // namespace media |
| OLD | NEW |