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