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