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. |weak_client_| will no longer be called and can be |
| 37 // safely deleted. Any pending/future calls will be discarded. |
| 38 // |
| 39 // Must be called on |client_loop_|. |
| 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_| after |
| 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 if (weak_vda) |
| 312 weak_vda->Destroy(); |
| 313 } |
| 314 |
191 void GpuVideoDecoder::DestroyVDA() { | 315 void GpuVideoDecoder::DestroyVDA() { |
192 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 316 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
| 317 |
| 318 // |client_proxy| must stay alive until |weak_vda_| has been destroyed. |
| 319 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 320 &DestroyVDAWithClientProxy, client_proxy_, weak_vda_)); |
| 321 |
193 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); | 322 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); |
194 // Tricky: |this| needs to stay alive until after VDA::Destroy is actually | 323 client_proxy_->Detach(); |
195 // called, not just posted, so we take an artificial ref to |this| and release | 324 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 | 325 |
203 DestroyTextures(); | 326 DestroyTextures(); |
204 } | 327 } |
205 | 328 |
206 void GpuVideoDecoder::Read(const ReadCB& read_cb) { | 329 void GpuVideoDecoder::Read(const ReadCB& read_cb) { |
207 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 330 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
208 DCHECK(pending_reset_cb_.is_null()); | 331 DCHECK(pending_reset_cb_.is_null()); |
209 DCHECK(pending_read_cb_.is_null()); | 332 DCHECK(pending_read_cb_.is_null()); |
210 pending_read_cb_ = BindToCurrentLoop(read_cb); | 333 pending_read_cb_ = BindToCurrentLoop(read_cb); |
211 | 334 |
(...skipping 27 matching lines...) Expand all Loading... |
239 } | 362 } |
240 } | 363 } |
241 | 364 |
242 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { | 365 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { |
243 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; | 366 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; |
244 } | 367 } |
245 | 368 |
246 void GpuVideoDecoder::RequestBufferDecode( | 369 void GpuVideoDecoder::RequestBufferDecode( |
247 DemuxerStream::Status status, | 370 DemuxerStream::Status status, |
248 const scoped_refptr<DecoderBuffer>& buffer) { | 371 const scoped_refptr<DecoderBuffer>& buffer) { |
| 372 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
249 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; | 373 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; |
250 | 374 |
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; | 375 demuxer_read_in_progress_ = false; |
257 | 376 |
258 if (status != DemuxerStream::kOk) { | 377 if (status != DemuxerStream::kOk) { |
259 if (pending_read_cb_.is_null()) | 378 if (pending_read_cb_.is_null()) |
260 return; | 379 return; |
261 | 380 |
262 // TODO(acolwell): Add support for reinitializing the decoder when | 381 // TODO(acolwell): Add support for reinitializing the decoder when |
263 // |status| == kConfigChanged. For now we just trigger a decode error. | 382 // |status| == kConfigChanged. For now we just trigger a decode error. |
264 Status decoder_status = | 383 Status decoder_status = |
265 (status == DemuxerStream::kAborted) ? kOk : kDecodeError; | 384 (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; | 419 bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second; |
301 DCHECK(inserted); | 420 DCHECK(inserted); |
302 RecordBufferData(bitstream_buffer, *buffer); | 421 RecordBufferData(bitstream_buffer, *buffer); |
303 | 422 |
304 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 423 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
305 &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer)); | 424 &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer)); |
306 | 425 |
307 if (CanMoreDecodeWorkBeDone()) { | 426 if (CanMoreDecodeWorkBeDone()) { |
308 // Force post here to prevent reentrancy into DemuxerStream. | 427 // Force post here to prevent reentrancy into DemuxerStream. |
309 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 428 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
310 &GpuVideoDecoder::EnsureDemuxOrDecode, this)); | 429 &GpuVideoDecoder::EnsureDemuxOrDecode, weak_this_)); |
311 } | 430 } |
312 } | 431 } |
313 | 432 |
314 void GpuVideoDecoder::RecordBufferData( | 433 void GpuVideoDecoder::RecordBufferData( |
315 const BitstreamBuffer& bitstream_buffer, const DecoderBuffer& buffer) { | 434 const BitstreamBuffer& bitstream_buffer, const DecoderBuffer& buffer) { |
316 input_buffer_data_.push_front(BufferData( | 435 input_buffer_data_.push_front(BufferData( |
317 bitstream_buffer.id(), buffer.GetTimestamp(), | 436 bitstream_buffer.id(), buffer.GetTimestamp(), |
318 demuxer_stream_->video_decoder_config().visible_rect(), | 437 demuxer_stream_->video_decoder_config().visible_rect(), |
319 demuxer_stream_->video_decoder_config().natural_size())); | 438 demuxer_stream_->video_decoder_config().natural_size())); |
320 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but | 439 // 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; | 472 return available_pictures_ > 0; |
354 } | 473 } |
355 | 474 |
356 void GpuVideoDecoder::NotifyInitializeDone() { | 475 void GpuVideoDecoder::NotifyInitializeDone() { |
357 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; | 476 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; |
358 } | 477 } |
359 | 478 |
360 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, | 479 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, |
361 const gfx::Size& size, | 480 const gfx::Size& size, |
362 uint32 texture_target) { | 481 uint32 texture_target) { |
363 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 482 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 | 483 |
370 std::vector<uint32> texture_ids; | 484 std::vector<uint32> texture_ids; |
371 decoder_texture_target_ = texture_target; | 485 decoder_texture_target_ = texture_target; |
372 if (!factories_->CreateTextures( | 486 if (!factories_->CreateTextures( |
373 count, size, &texture_ids, decoder_texture_target_)) { | 487 count, size, &texture_ids, decoder_texture_target_)) { |
374 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 488 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
375 return; | 489 return; |
376 } | 490 } |
377 | 491 |
378 if (!vda_.get()) | 492 if (!vda_.get()) |
379 return; | 493 return; |
380 | 494 |
381 CHECK_EQ(available_pictures_, -1); | 495 CHECK_EQ(available_pictures_, -1); |
382 available_pictures_ = count; | 496 available_pictures_ = count; |
383 | 497 |
384 std::vector<PictureBuffer> picture_buffers; | 498 std::vector<PictureBuffer> picture_buffers; |
385 for (size_t i = 0; i < texture_ids.size(); ++i) { | 499 for (size_t i = 0; i < texture_ids.size(); ++i) { |
386 picture_buffers.push_back(PictureBuffer( | 500 picture_buffers.push_back(PictureBuffer( |
387 next_picture_buffer_id_++, size, texture_ids[i])); | 501 next_picture_buffer_id_++, size, texture_ids[i])); |
388 bool inserted = picture_buffers_in_decoder_.insert(std::make_pair( | 502 bool inserted = picture_buffers_in_decoder_.insert(std::make_pair( |
389 picture_buffers.back().id(), picture_buffers.back())).second; | 503 picture_buffers.back().id(), picture_buffers.back())).second; |
390 DCHECK(inserted); | 504 DCHECK(inserted); |
391 } | 505 } |
392 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 506 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
393 &VideoDecodeAccelerator::AssignPictureBuffers, weak_vda_, | 507 &VideoDecodeAccelerator::AssignPictureBuffers, weak_vda_, |
394 picture_buffers)); | 508 picture_buffers)); |
395 } | 509 } |
396 | 510 |
397 void GpuVideoDecoder::DismissPictureBuffer(int32 id) { | 511 void GpuVideoDecoder::DismissPictureBuffer(int32 id) { |
398 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 512 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
399 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 513 |
400 &GpuVideoDecoder::DismissPictureBuffer, this, id)); | |
401 return; | |
402 } | |
403 std::map<int32, PictureBuffer>::iterator it = | 514 std::map<int32, PictureBuffer>::iterator it = |
404 picture_buffers_in_decoder_.find(id); | 515 picture_buffers_in_decoder_.find(id); |
405 if (it == picture_buffers_in_decoder_.end()) { | 516 if (it == picture_buffers_in_decoder_.end()) { |
406 NOTREACHED() << "Missing picture buffer: " << id; | 517 NOTREACHED() << "Missing picture buffer: " << id; |
407 return; | 518 return; |
408 } | 519 } |
409 factories_->DeleteTexture(it->second.texture_id()); | 520 factories_->DeleteTexture(it->second.texture_id()); |
410 picture_buffers_in_decoder_.erase(it); | 521 picture_buffers_in_decoder_.erase(it); |
411 } | 522 } |
412 | 523 |
413 void GpuVideoDecoder::PictureReady(const media::Picture& picture) { | 524 void GpuVideoDecoder::PictureReady(const media::Picture& picture) { |
414 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 525 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
415 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 526 |
416 &GpuVideoDecoder::PictureReady, this, picture)); | |
417 return; | |
418 } | |
419 std::map<int32, PictureBuffer>::iterator it = | 527 std::map<int32, PictureBuffer>::iterator it = |
420 picture_buffers_in_decoder_.find(picture.picture_buffer_id()); | 528 picture_buffers_in_decoder_.find(picture.picture_buffer_id()); |
421 if (it == picture_buffers_in_decoder_.end()) { | 529 if (it == picture_buffers_in_decoder_.end()) { |
422 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 530 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
423 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 531 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
424 return; | 532 return; |
425 } | 533 } |
426 const PictureBuffer& pb = it->second; | 534 const PictureBuffer& pb = it->second; |
427 | 535 |
428 // Update frame's timestamp. | 536 // Update frame's timestamp. |
429 base::TimeDelta timestamp; | 537 base::TimeDelta timestamp; |
430 gfx::Rect visible_rect; | 538 gfx::Rect visible_rect; |
431 gfx::Size natural_size; | 539 gfx::Size natural_size; |
432 GetBufferData(picture.bitstream_buffer_id(), ×tamp, &visible_rect, | 540 GetBufferData(picture.bitstream_buffer_id(), ×tamp, &visible_rect, |
433 &natural_size); | 541 &natural_size); |
434 DCHECK(decoder_texture_target_); | 542 DCHECK(decoder_texture_target_); |
435 scoped_refptr<VideoFrame> frame( | 543 scoped_refptr<VideoFrame> frame( |
436 VideoFrame::WrapNativeTexture( | 544 VideoFrame::WrapNativeTexture( |
437 pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, | 545 pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, |
438 natural_size, timestamp, | 546 natural_size, timestamp, |
439 base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), | 547 base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), |
440 decoder_texture_target_, | 548 decoder_texture_target_, |
441 gfx::Size(visible_rect.width(), visible_rect.height())), | 549 gfx::Size(visible_rect.width(), visible_rect.height())), |
442 base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this, | 550 BindToCurrentLoop(base::Bind( |
443 picture.picture_buffer_id()))); | 551 &GpuVideoDecoder::ReusePictureBuffer, weak_this_, |
| 552 picture.picture_buffer_id())))); |
444 CHECK_GT(available_pictures_, 0); | 553 CHECK_GT(available_pictures_, 0); |
445 available_pictures_--; | 554 available_pictures_--; |
446 | 555 |
447 EnqueueFrameAndTriggerFrameDelivery(frame); | 556 EnqueueFrameAndTriggerFrameDelivery(frame); |
448 } | 557 } |
449 | 558 |
450 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( | 559 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( |
451 const scoped_refptr<VideoFrame>& frame) { | 560 const scoped_refptr<VideoFrame>& frame) { |
452 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 561 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
453 | 562 |
454 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the | 563 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the |
455 // floor and return. | 564 // floor and return. |
456 if (!pending_reset_cb_.is_null()) | 565 if (!pending_reset_cb_.is_null()) |
457 return; | 566 return; |
458 | 567 |
459 if (frame) | 568 if (frame) |
460 ready_video_frames_.push_back(frame); | 569 ready_video_frames_.push_back(frame); |
461 else | 570 else |
462 DCHECK(!ready_video_frames_.empty()); | 571 DCHECK(!ready_video_frames_.empty()); |
463 | 572 |
464 if (pending_read_cb_.is_null()) | 573 if (pending_read_cb_.is_null()) |
465 return; | 574 return; |
466 | 575 |
467 base::ResetAndReturn(&pending_read_cb_).Run(kOk, ready_video_frames_.front()); | 576 base::ResetAndReturn(&pending_read_cb_).Run(kOk, ready_video_frames_.front()); |
468 ready_video_frames_.pop_front(); | 577 ready_video_frames_.pop_front(); |
469 } | 578 } |
470 | 579 |
471 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { | 580 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { |
472 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 581 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); | 582 CHECK_GE(available_pictures_, 0); |
478 available_pictures_++; | 583 available_pictures_++; |
479 | 584 |
480 if (!vda_.get()) | 585 if (!vda_.get()) |
481 return; | 586 return; |
482 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 587 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
483 &VideoDecodeAccelerator::ReusePictureBuffer, weak_vda_, | 588 &VideoDecodeAccelerator::ReusePictureBuffer, weak_vda_, |
484 picture_buffer_id)); | 589 picture_buffer_id)); |
485 } | 590 } |
486 | 591 |
(...skipping 12 matching lines...) Expand all Loading... |
499 available_shm_segments_.pop_back(); | 604 available_shm_segments_.pop_back(); |
500 return ret; | 605 return ret; |
501 } | 606 } |
502 | 607 |
503 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { | 608 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { |
504 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 609 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
505 available_shm_segments_.push_back(shm_buffer); | 610 available_shm_segments_.push_back(shm_buffer); |
506 } | 611 } |
507 | 612 |
508 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | 613 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
509 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 614 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
510 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
511 &GpuVideoDecoder::NotifyEndOfBitstreamBuffer, this, id)); | |
512 return; | |
513 } | |
514 | 615 |
515 std::map<int32, BufferPair>::iterator it = | 616 std::map<int32, BufferPair>::iterator it = |
516 bitstream_buffers_in_decoder_.find(id); | 617 bitstream_buffers_in_decoder_.find(id); |
517 if (it == bitstream_buffers_in_decoder_.end()) { | 618 if (it == bitstream_buffers_in_decoder_.end()) { |
518 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); | 619 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
519 NOTREACHED() << "Missing bitstream buffer: " << id; | 620 NOTREACHED() << "Missing bitstream buffer: " << id; |
520 return; | 621 return; |
521 } | 622 } |
522 | 623 |
523 PutSHM(it->second.shm_buffer); | 624 PutSHM(it->second.shm_buffer); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 | 659 |
559 // The second condition can happen during the tear-down process. | 660 // The second condition can happen during the tear-down process. |
560 // GpuVideoDecoder::Stop() returns the |pending_read_cb_| immediately without | 661 // GpuVideoDecoder::Stop() returns the |pending_read_cb_| immediately without |
561 // waiting for the demuxer read to be returned. Therefore, this function could | 662 // waiting for the demuxer read to be returned. Therefore, this function could |
562 // be called even after the decoder has been stopped. | 663 // be called even after the decoder has been stopped. |
563 if (demuxer_read_in_progress_ || !demuxer_stream_) | 664 if (demuxer_read_in_progress_ || !demuxer_stream_) |
564 return; | 665 return; |
565 | 666 |
566 demuxer_read_in_progress_ = true; | 667 demuxer_read_in_progress_ = true; |
567 demuxer_stream_->Read(base::Bind( | 668 demuxer_stream_->Read(base::Bind( |
568 &GpuVideoDecoder::RequestBufferDecode, this)); | 669 &GpuVideoDecoder::RequestBufferDecode, weak_this_)); |
569 } | 670 } |
570 | 671 |
571 void GpuVideoDecoder::NotifyFlushDone() { | 672 void GpuVideoDecoder::NotifyFlushDone() { |
572 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 673 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); | 674 DCHECK_EQ(state_, kDrainingDecoder); |
578 state_ = kDecoderDrained; | 675 state_ = kDecoderDrained; |
579 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 676 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
580 } | 677 } |
581 | 678 |
582 void GpuVideoDecoder::NotifyResetDone() { | 679 void GpuVideoDecoder::NotifyResetDone() { |
583 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 680 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()); | 681 DCHECK(ready_video_frames_.empty()); |
590 | 682 |
591 // This needs to happen after the Reset() on vda_ is done to ensure pictures | 683 // This needs to happen after the Reset() on vda_ is done to ensure pictures |
592 // delivered during the reset can find their time data. | 684 // delivered during the reset can find their time data. |
593 input_buffer_data_.clear(); | 685 input_buffer_data_.clear(); |
594 | 686 |
595 if (!pending_reset_cb_.is_null()) | 687 if (!pending_reset_cb_.is_null()) |
596 base::ResetAndReturn(&pending_reset_cb_).Run(); | 688 base::ResetAndReturn(&pending_reset_cb_).Run(); |
597 | 689 |
598 if (!pending_read_cb_.is_null()) | 690 if (!pending_read_cb_.is_null()) |
599 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 691 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
600 } | 692 } |
601 | 693 |
602 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { | 694 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { |
603 if (!gvd_loop_proxy_->BelongsToCurrentThread()) { | 695 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()) | 696 if (!vda_.get()) |
609 return; | 697 return; |
610 | 698 |
611 DLOG(ERROR) << "VDA Error: " << error; | 699 DLOG(ERROR) << "VDA Error: " << error; |
612 DestroyVDA(); | 700 DestroyVDA(); |
613 | 701 |
614 error_occured_ = true; | 702 error_occured_ = true; |
615 | 703 |
616 if (!pending_read_cb_.is_null()) { | 704 if (!pending_read_cb_.is_null()) { |
617 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); | 705 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); |
618 return; | 706 return; |
619 } | 707 } |
620 } | 708 } |
621 | 709 |
622 } // namespace media | 710 } // namespace media |
OLD | NEW |