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 "base/task_runner_util.h" |
13 #include "media/base/bind_to_loop.h" | 13 #include "media/base/bind_to_loop.h" |
14 #include "media/base/decoder_buffer.h" | 14 #include "media/base/decoder_buffer.h" |
15 #include "media/base/demuxer_stream.h" | |
16 #include "media/base/pipeline.h" | 15 #include "media/base/pipeline.h" |
17 #include "media/base/pipeline_status.h" | 16 #include "media/base/pipeline_status.h" |
18 #include "media/base/video_decoder_config.h" | 17 #include "media/base/video_decoder_config.h" |
19 | 18 |
20 namespace media { | 19 namespace media { |
21 | 20 |
22 // Proxies calls to a VideoDecodeAccelerator::Client from the calling thread to | 21 // Proxies calls to a VideoDecodeAccelerator::Client from the calling thread to |
23 // the client's thread. | 22 // the client's thread. |
24 // | 23 // |
25 // TODO(scherkus): VDAClientProxy should hold onto GpuVideoDecoder::Factories | 24 // TODO(scherkus): VDAClientProxy should hold onto GpuVideoDecoder::Factories |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns) | 152 int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns) |
154 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), | 153 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), |
155 natural_size(ns) { | 154 natural_size(ns) { |
156 } | 155 } |
157 | 156 |
158 GpuVideoDecoder::BufferData::~BufferData() {} | 157 GpuVideoDecoder::BufferData::~BufferData() {} |
159 | 158 |
160 GpuVideoDecoder::GpuVideoDecoder( | 159 GpuVideoDecoder::GpuVideoDecoder( |
161 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 160 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
162 const scoped_refptr<Factories>& factories) | 161 const scoped_refptr<Factories>& factories) |
163 : demuxer_stream_(NULL), | 162 : needs_bitstream_conversion_(false), |
164 needs_bitstream_conversion_(false), | |
165 gvd_loop_proxy_(message_loop), | 163 gvd_loop_proxy_(message_loop), |
166 weak_factory_(this), | 164 weak_factory_(this), |
167 vda_loop_proxy_(factories->GetMessageLoop()), | 165 vda_loop_proxy_(factories->GetMessageLoop()), |
168 factories_(factories), | 166 factories_(factories), |
169 state_(kNormal), | 167 state_(kNormal), |
170 demuxer_read_in_progress_(false), | |
171 decoder_texture_target_(0), | 168 decoder_texture_target_(0), |
172 next_picture_buffer_id_(0), | 169 next_picture_buffer_id_(0), |
173 next_bitstream_buffer_id_(0), | 170 next_bitstream_buffer_id_(0), |
174 available_pictures_(-1) { | 171 available_pictures_(-1) { |
175 DCHECK(factories_); | 172 DCHECK(factories_); |
| 173 DCHECK(!config_.IsValidConfig()); |
176 } | 174 } |
177 | 175 |
178 void GpuVideoDecoder::Reset(const base::Closure& closure) { | 176 void GpuVideoDecoder::Reset(const base::Closure& closure) { |
179 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 177 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
180 | 178 |
181 if (state_ == kDrainingDecoder && !factories_->IsAborted()) { | 179 if (state_ == kDrainingDecoder && !factories_->IsAborted()) { |
182 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 180 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
183 &GpuVideoDecoder::Reset, weak_this_, closure)); | 181 &GpuVideoDecoder::Reset, weak_this_, closure)); |
184 // NOTE: if we're deferring Reset() until a Flush() completes, return | 182 // NOTE: if we're deferring Reset() until a Flush() completes, return |
185 // queued pictures to the VDA so they can be used to finish that Flush(). | 183 // queued pictures to the VDA so they can be used to finish that Flush(). |
(...skipping 21 matching lines...) Expand all Loading... |
207 } | 205 } |
208 | 206 |
209 void GpuVideoDecoder::Stop(const base::Closure& closure) { | 207 void GpuVideoDecoder::Stop(const base::Closure& closure) { |
210 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 208 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
211 if (vda_) | 209 if (vda_) |
212 DestroyVDA(); | 210 DestroyVDA(); |
213 if (!pending_read_cb_.is_null()) | 211 if (!pending_read_cb_.is_null()) |
214 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 212 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
215 if (!pending_reset_cb_.is_null()) | 213 if (!pending_reset_cb_.is_null()) |
216 base::ResetAndReturn(&pending_reset_cb_).Run(); | 214 base::ResetAndReturn(&pending_reset_cb_).Run(); |
217 demuxer_stream_ = NULL; | |
218 BindToCurrentLoop(closure).Run(); | 215 BindToCurrentLoop(closure).Run(); |
219 } | 216 } |
220 | 217 |
221 static bool IsCodedSizeSupported(const gfx::Size& coded_size) { | 218 static bool IsCodedSizeSupported(const gfx::Size& coded_size) { |
222 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080. | 219 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080. |
223 // We test against 1088 to account for 16x16 macroblocks. | 220 // We test against 1088 to account for 16x16 macroblocks. |
224 if (coded_size.width() <= 1920 && coded_size.height() <= 1088) | 221 if (coded_size.width() <= 1920 && coded_size.height() <= 1088) |
225 return true; | 222 return true; |
226 | 223 |
227 base::CPU cpu; | 224 base::CPU cpu; |
228 bool hw_large_video_support = | 225 bool hw_large_video_support = |
229 (cpu.vendor_name() == "GenuineIntel") && cpu.model() >= 58; | 226 (cpu.vendor_name() == "GenuineIntel") && cpu.model() >= 58; |
230 bool os_large_video_support = true; | 227 bool os_large_video_support = true; |
231 #if defined(OS_WIN) | 228 #if defined(OS_WIN) |
232 os_large_video_support = false; | 229 os_large_video_support = false; |
233 #endif | 230 #endif |
234 return os_large_video_support && hw_large_video_support; | 231 return os_large_video_support && hw_large_video_support; |
235 } | 232 } |
236 | 233 |
237 void GpuVideoDecoder::Initialize(DemuxerStream* stream, | 234 void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config, |
238 const PipelineStatusCB& orig_status_cb, | 235 const PipelineStatusCB& orig_status_cb, |
239 const StatisticsCB& statistics_cb) { | 236 const StatisticsCB& statistics_cb) { |
240 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 237 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
241 DCHECK(stream); | 238 DCHECK(config.IsValidConfig()); |
| 239 DCHECK(!config.is_encrypted()); |
242 | 240 |
243 weak_this_ = weak_factory_.GetWeakPtr(); | 241 weak_this_ = weak_factory_.GetWeakPtr(); |
244 | 242 |
245 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( | 243 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB( |
246 "Media.GpuVideoDecoderInitializeStatus", | 244 "Media.GpuVideoDecoderInitializeStatus", |
247 BindToCurrentLoop(orig_status_cb)); | 245 BindToCurrentLoop(orig_status_cb)); |
248 | 246 |
249 if (demuxer_stream_) { | 247 if (config_.IsValidConfig()) { |
250 // TODO(xhwang): Make GpuVideoDecoder reinitializable. | 248 // TODO(xhwang): Make GpuVideoDecoder reinitializable. |
251 // See http://crbug.com/233608 | 249 // See http://crbug.com/233608 |
252 DVLOG(1) << "GpuVideoDecoder reinitialization not supported."; | 250 DVLOG(1) << "GpuVideoDecoder reinitialization not supported."; |
253 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 251 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
254 return; | 252 return; |
255 } | 253 } |
256 | 254 |
257 const VideoDecoderConfig& config = stream->video_decoder_config(); | |
258 DCHECK(config.IsValidConfig()); | |
259 DCHECK(!config.is_encrypted()); | |
260 | |
261 if (!IsCodedSizeSupported(config.coded_size())) { | 255 if (!IsCodedSizeSupported(config.coded_size())) { |
262 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 256 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
263 return; | 257 return; |
264 } | 258 } |
265 | 259 |
266 client_proxy_ = new VDAClientProxy(this); | 260 client_proxy_ = new VDAClientProxy(this); |
267 VideoDecodeAccelerator* vda = | 261 VideoDecodeAccelerator* vda = |
268 factories_->CreateVideoDecodeAccelerator(config.profile(), client_proxy_); | 262 factories_->CreateVideoDecodeAccelerator(config.profile(), client_proxy_); |
269 if (!vda) { | 263 if (!vda) { |
270 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 264 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
271 return; | 265 return; |
272 } | 266 } |
273 | 267 |
274 demuxer_stream_ = stream; | |
275 statistics_cb_ = statistics_cb; | 268 statistics_cb_ = statistics_cb; |
276 needs_bitstream_conversion_ = (config.codec() == kCodecH264); | 269 needs_bitstream_conversion_ = (config.codec() == kCodecH264); |
277 | 270 |
278 DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded."; | 271 DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded."; |
279 PostTaskAndReplyWithResult( | 272 PostTaskAndReplyWithResult( |
280 vda_loop_proxy_, FROM_HERE, | 273 vda_loop_proxy_, FROM_HERE, |
281 base::Bind(&VideoDecodeAccelerator::AsWeakPtr, base::Unretained(vda)), | 274 base::Bind(&VideoDecodeAccelerator::AsWeakPtr, base::Unretained(vda)), |
282 base::Bind(&GpuVideoDecoder::SetVDA, weak_this_, status_cb, vda)); | 275 base::Bind(&GpuVideoDecoder::SetVDA, weak_this_, status_cb, vda)); |
283 } | 276 } |
284 | 277 |
285 void GpuVideoDecoder::SetVDA( | 278 void GpuVideoDecoder::SetVDA( |
286 const PipelineStatusCB& status_cb, | 279 const PipelineStatusCB& status_cb, |
287 VideoDecodeAccelerator* vda, | 280 VideoDecodeAccelerator* vda, |
288 base::WeakPtr<VideoDecodeAccelerator> weak_vda) { | 281 base::WeakPtr<VideoDecodeAccelerator> weak_vda) { |
289 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 282 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
290 DCHECK(!vda_.get()); | 283 DCHECK(!vda_.get()); |
291 vda_.reset(vda); | 284 vda_.reset(vda); |
292 weak_vda_ = weak_vda; | 285 weak_vda_ = weak_vda; |
293 status_cb.Run(PIPELINE_OK); | 286 status_cb.Run(PIPELINE_OK); |
294 } | 287 } |
295 | 288 |
296 void GpuVideoDecoder::DestroyTextures() { | 289 void GpuVideoDecoder::DestroyTextures() { |
297 for (std::map<int32, PictureBuffer>::iterator it = | 290 for (std::map<int32, PictureBuffer>::iterator it = |
298 picture_buffers_in_decoder_.begin(); | 291 picture_buffers_in_decoder_.begin(); |
299 it != picture_buffers_in_decoder_.end(); ++it) { | 292 it != picture_buffers_in_decoder_.end(); |
| 293 ++it) { |
300 factories_->DeleteTexture(it->second.texture_id()); | 294 factories_->DeleteTexture(it->second.texture_id()); |
301 } | 295 } |
302 picture_buffers_in_decoder_.clear(); | 296 picture_buffers_in_decoder_.clear(); |
303 } | 297 } |
304 | 298 |
305 static void DestroyVDAWithClientProxy( | 299 static void DestroyVDAWithClientProxy( |
306 const scoped_refptr<VDAClientProxy>& client_proxy, | 300 const scoped_refptr<VDAClientProxy>& client_proxy, |
307 base::WeakPtr<VideoDecodeAccelerator> weak_vda) { | 301 base::WeakPtr<VideoDecodeAccelerator> weak_vda) { |
308 if (weak_vda) { | 302 if (weak_vda) { |
309 weak_vda->Destroy(); | 303 weak_vda->Destroy(); |
310 DCHECK(!weak_vda); // Check VDA::Destroy() contract. | 304 DCHECK(!weak_vda); // Check VDA::Destroy() contract. |
311 } | 305 } |
312 } | 306 } |
313 | 307 |
314 void GpuVideoDecoder::DestroyVDA() { | 308 void GpuVideoDecoder::DestroyVDA() { |
315 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 309 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
316 | 310 |
317 // |client_proxy| must stay alive until |weak_vda_| has been destroyed. | 311 // |client_proxy| must stay alive until |weak_vda_| has been destroyed. |
318 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 312 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
319 &DestroyVDAWithClientProxy, client_proxy_, weak_vda_)); | 313 &DestroyVDAWithClientProxy, client_proxy_, weak_vda_)); |
320 | 314 |
321 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); | 315 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); |
322 client_proxy_->Detach(); | 316 client_proxy_->Detach(); |
323 client_proxy_ = NULL; | 317 client_proxy_ = NULL; |
324 | 318 |
325 DestroyTextures(); | 319 DestroyTextures(); |
326 } | 320 } |
327 | 321 |
328 void GpuVideoDecoder::Read(const ReadCB& read_cb) { | 322 void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 323 const ReadCB& read_cb) { |
329 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 324 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
330 DCHECK(pending_reset_cb_.is_null()); | 325 DCHECK(pending_reset_cb_.is_null()); |
331 DCHECK(pending_read_cb_.is_null()); | 326 DCHECK(pending_read_cb_.is_null()); |
| 327 |
332 pending_read_cb_ = BindToCurrentLoop(read_cb); | 328 pending_read_cb_ = BindToCurrentLoop(read_cb); |
333 | 329 |
334 if (state_ == kError) { | 330 if (state_ == kError) { |
335 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); | 331 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); |
336 return; | 332 return; |
337 } | 333 } |
338 | 334 |
339 // TODO(xhwang): It's odd that we return kOk after VDA has been released. | |
340 // Fix this and simplify cases. | |
341 if (!vda_) { | 335 if (!vda_) { |
342 base::ResetAndReturn(&pending_read_cb_).Run( | 336 base::ResetAndReturn(&pending_read_cb_).Run( |
343 kOk, VideoFrame::CreateEmptyFrame()); | 337 kDecodeError, VideoFrame::CreateEmptyFrame()); |
344 return; | 338 return; |
345 } | 339 } |
346 | 340 |
347 if (!ready_video_frames_.empty()) { | 341 if (!ready_video_frames_.empty()) |
348 EnqueueFrameAndTriggerFrameDelivery(NULL); | 342 EnqueueFrameAndTriggerFrameDelivery(NULL); |
349 return; | 343 |
| 344 if (buffer->IsEndOfStream()) { |
| 345 if (state_ == kNormal) { |
| 346 state_ = kDrainingDecoder; |
| 347 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 348 &VideoDecodeAccelerator::Flush, weak_vda_)); |
| 349 } |
| 350 } else { |
| 351 size_t size = buffer->GetDataSize(); |
| 352 SHMBuffer* shm_buffer = GetSHM(size); |
| 353 if (!shm_buffer) { |
| 354 state_ = kError; |
| 355 return; |
| 356 } |
| 357 |
| 358 memcpy(shm_buffer->shm->memory(), buffer->GetData(), size); |
| 359 BitstreamBuffer bitstream_buffer( |
| 360 next_bitstream_buffer_id_, shm_buffer->shm->handle(), size); |
| 361 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
| 362 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; |
| 363 bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair( |
| 364 bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second; |
| 365 DCHECK(inserted); |
| 366 RecordBufferData(bitstream_buffer, *buffer); |
| 367 |
| 368 vda_loop_proxy_->PostTask( |
| 369 FROM_HERE, |
| 370 base::Bind( |
| 371 &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer)); |
350 } | 372 } |
351 | 373 |
| 374 if (CanMoreDecodeWorkBeDone()) { |
| 375 base::ResetAndReturn(&pending_read_cb_).Run(kNotEnoughData, NULL); |
| 376 } |
| 377 |
| 378 /* |
352 switch (state_) { | 379 switch (state_) { |
353 case kDecoderDrained: | 380 case kDecoderDrained: |
354 state_ = kNormal; | 381 state_ = kNormal; |
355 // Fall-through. | 382 // Fall-through. |
356 case kNormal: | 383 case kNormal: |
357 EnsureDemuxOrDecode(); | 384 EnsureDemuxOrDecode(); |
358 break; | 385 break; |
359 case kDrainingDecoder: | 386 case kDrainingDecoder: |
360 // Do nothing. Will be satisfied either by a PictureReady or | 387 // Do nothing. Will be satisfied either by a PictureReady or |
361 // NotifyFlushDone below. | 388 // NotifyFlushDone below. |
362 break; | 389 break; |
363 case kError: | 390 case kError: |
364 NOTREACHED(); | 391 NOTREACHED(); |
365 break; | 392 break; |
366 } | 393 } |
| 394 */ |
367 } | 395 } |
368 | 396 |
369 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { | 397 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { |
370 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; | 398 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; |
371 } | 399 } |
372 | 400 |
373 void GpuVideoDecoder::RequestBufferDecode( | 401 void GpuVideoDecoder::RecordBufferData(const BitstreamBuffer& bitstream_buffer, |
374 DemuxerStream::Status status, | 402 const DecoderBuffer& buffer) { |
375 const scoped_refptr<DecoderBuffer>& buffer) { | 403 input_buffer_data_.push_front(BufferData(bitstream_buffer.id(), |
376 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 404 buffer.GetTimestamp(), |
377 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; | 405 config_.visible_rect(), |
378 | 406 config_.natural_size())); |
379 demuxer_read_in_progress_ = false; | |
380 | |
381 if (status == DemuxerStream::kAborted) { | |
382 if (pending_read_cb_.is_null()) | |
383 return; | |
384 base::ResetAndReturn(&pending_read_cb_).Run(kOk, NULL); | |
385 return; | |
386 } | |
387 | |
388 // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders. | |
389 DCHECK_EQ(status, DemuxerStream::kOk) << status; | |
390 | |
391 if (!vda_) { | |
392 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | |
393 return; | |
394 } | |
395 | |
396 if (buffer->IsEndOfStream()) { | |
397 if (state_ == kNormal) { | |
398 state_ = kDrainingDecoder; | |
399 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
400 &VideoDecodeAccelerator::Flush, weak_vda_)); | |
401 } | |
402 return; | |
403 } | |
404 | |
405 if (!pending_reset_cb_.is_null()) | |
406 return; | |
407 | |
408 size_t size = buffer->GetDataSize(); | |
409 SHMBuffer* shm_buffer = GetSHM(size); | |
410 if (!shm_buffer) | |
411 return; | |
412 | |
413 memcpy(shm_buffer->shm->memory(), buffer->GetData(), size); | |
414 BitstreamBuffer bitstream_buffer( | |
415 next_bitstream_buffer_id_, shm_buffer->shm->handle(), size); | |
416 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | |
417 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; | |
418 bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair( | |
419 bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second; | |
420 DCHECK(inserted); | |
421 RecordBufferData(bitstream_buffer, *buffer); | |
422 | |
423 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
424 &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer)); | |
425 | |
426 if (CanMoreDecodeWorkBeDone()) { | |
427 // Force post here to prevent reentrancy into DemuxerStream. | |
428 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
429 &GpuVideoDecoder::EnsureDemuxOrDecode, weak_this_)); | |
430 } | |
431 } | |
432 | |
433 void GpuVideoDecoder::RecordBufferData( | |
434 const BitstreamBuffer& bitstream_buffer, const DecoderBuffer& buffer) { | |
435 input_buffer_data_.push_front(BufferData( | |
436 bitstream_buffer.id(), buffer.GetTimestamp(), | |
437 demuxer_stream_->video_decoder_config().visible_rect(), | |
438 demuxer_stream_->video_decoder_config().natural_size())); | |
439 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but | 407 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but |
440 // that's too small for some pathological B-frame test videos. The cost of | 408 // that's too small for some pathological B-frame test videos. The cost of |
441 // using too-high a value is low (192 bits per extra slot). | 409 // using too-high a value is low (192 bits per extra slot). |
442 static const size_t kMaxInputBufferDataSize = 128; | 410 static const size_t kMaxInputBufferDataSize = 128; |
443 // Pop from the back of the list, because that's the oldest and least likely | 411 // Pop from the back of the list, because that's the oldest and least likely |
444 // to be useful in the future data. | 412 // to be useful in the future data. |
445 if (input_buffer_data_.size() > kMaxInputBufferDataSize) | 413 if (input_buffer_data_.size() > kMaxInputBufferDataSize) |
446 input_buffer_data_.pop_back(); | 414 input_buffer_data_.pop_back(); |
447 } | 415 } |
448 | 416 |
449 void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, | 417 void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, |
450 gfx::Rect* visible_rect, | 418 gfx::Rect* visible_rect, |
451 gfx::Size* natural_size) { | 419 gfx::Size* natural_size) { |
452 for (std::list<BufferData>::const_iterator it = | 420 for (std::list<BufferData>::const_iterator it = input_buffer_data_.begin(); |
453 input_buffer_data_.begin(); it != input_buffer_data_.end(); | 421 it != input_buffer_data_.end(); |
454 ++it) { | 422 ++it) { |
455 if (it->bitstream_buffer_id != id) | 423 if (it->bitstream_buffer_id != id) |
456 continue; | 424 continue; |
457 *timestamp = it->timestamp; | 425 *timestamp = it->timestamp; |
458 *visible_rect = it->visible_rect; | 426 *visible_rect = it->visible_rect; |
459 *natural_size = it->natural_size; | 427 *natural_size = it->natural_size; |
460 return; | 428 return; |
461 } | 429 } |
462 NOTREACHED() << "Missing bitstreambuffer id: " << id; | 430 NOTREACHED() << "Missing bitstreambuffer id: " << id; |
463 } | 431 } |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 for (std::map<int32, BufferPair>::iterator it = | 620 for (std::map<int32, BufferPair>::iterator it = |
653 bitstream_buffers_in_decoder_.begin(); | 621 bitstream_buffers_in_decoder_.begin(); |
654 it != bitstream_buffers_in_decoder_.end(); ++it) { | 622 it != bitstream_buffers_in_decoder_.end(); ++it) { |
655 it->second.shm_buffer->shm->Close(); | 623 it->second.shm_buffer->shm->Close(); |
656 } | 624 } |
657 bitstream_buffers_in_decoder_.clear(); | 625 bitstream_buffers_in_decoder_.clear(); |
658 | 626 |
659 DestroyTextures(); | 627 DestroyTextures(); |
660 } | 628 } |
661 | 629 |
662 void GpuVideoDecoder::EnsureDemuxOrDecode() { | |
663 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | |
664 | |
665 // The second condition can happen during the tear-down process. | |
666 // GpuVideoDecoder::Stop() returns the |pending_read_cb_| immediately without | |
667 // waiting for the demuxer read to be returned. Therefore, this function could | |
668 // be called even after the decoder has been stopped. | |
669 if (demuxer_read_in_progress_ || !demuxer_stream_) | |
670 return; | |
671 | |
672 demuxer_read_in_progress_ = true; | |
673 demuxer_stream_->Read(base::Bind( | |
674 &GpuVideoDecoder::RequestBufferDecode, weak_this_)); | |
675 } | |
676 | |
677 void GpuVideoDecoder::NotifyFlushDone() { | 630 void GpuVideoDecoder::NotifyFlushDone() { |
678 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 631 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
679 DCHECK_EQ(state_, kDrainingDecoder); | 632 DCHECK_EQ(state_, kDrainingDecoder); |
680 state_ = kDecoderDrained; | 633 state_ = kDecoderDrained; |
681 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); | 634 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); |
682 } | 635 } |
683 | 636 |
684 void GpuVideoDecoder::NotifyResetDone() { | 637 void GpuVideoDecoder::NotifyResetDone() { |
685 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); | 638 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
686 DCHECK(ready_video_frames_.empty()); | 639 DCHECK(ready_video_frames_.empty()); |
(...skipping 19 matching lines...) Expand all Loading... |
706 | 659 |
707 state_ = kError; | 660 state_ = kError; |
708 | 661 |
709 if (!pending_read_cb_.is_null()) { | 662 if (!pending_read_cb_.is_null()) { |
710 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); | 663 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL); |
711 return; | 664 return; |
712 } | 665 } |
713 } | 666 } |
714 | 667 |
715 } // namespace media | 668 } // namespace media |
OLD | NEW |