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 "content/common/gpu/media/dxva_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" |
6 | 6 |
7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
10 | 10 |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
331 | 331 |
332 hr = decoder.device_->StretchRect(dest_surface, NULL, d3d_surface.get(), NULL, | 332 hr = decoder.device_->StretchRect(dest_surface, NULL, d3d_surface.get(), NULL, |
333 D3DTEXF_NONE); | 333 D3DTEXF_NONE); |
334 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", | 334 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", |
335 false); | 335 false); |
336 | 336 |
337 // Ideally, this should be done immediately before the draw call that uses | 337 // Ideally, this should be done immediately before the draw call that uses |
338 // the texture. Flush it once here though. | 338 // the texture. Flush it once here though. |
339 hr = decoder.query_->Issue(D3DISSUE_END); | 339 hr = decoder.query_->Issue(D3DISSUE_END); |
340 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); | 340 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); |
341 | |
342 // The DXVA decoder has its own device which it uses for decoding. ANGLE | 341 // The DXVA decoder has its own device which it uses for decoding. ANGLE |
343 // has its own device which we don't have access to. | 342 // has its own device which we don't have access to. |
344 // The above code attempts to copy the decoded picture into a surface | 343 // The above code attempts to copy the decoded picture into a surface |
345 // which is owned by ANGLE. As there are multiple devices involved in | 344 // which is owned by ANGLE. As there are multiple devices involved in |
346 // this, the StretchRect call above is not synchronous. | 345 // this, the StretchRect call above is not synchronous. |
347 // We attempt to flush the batched operations to ensure that the picture is | 346 // We attempt to flush the batched operations to ensure that the picture is |
348 // copied to the surface owned by ANGLE. | 347 // copied to the surface owned by ANGLE. |
349 // We need to do this in a loop and call flush multiple times. | 348 // We need to do this in a loop and call flush multiple times. |
350 // We have seen the GetData call for flushing the command buffer fail to | 349 // We have seen the GetData call for flushing the command buffer fail to |
351 // return success occassionally on multi core machines, leading to an | 350 // return success occassionally on multi core machines, leading to an |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
424 | 423 |
425 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( | 424 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
426 const base::Callback<bool(void)>& make_context_current) | 425 const base::Callback<bool(void)>& make_context_current) |
427 : client_(NULL), | 426 : client_(NULL), |
428 dev_manager_reset_token_(0), | 427 dev_manager_reset_token_(0), |
429 egl_config_(NULL), | 428 egl_config_(NULL), |
430 state_(kUninitialized), | 429 state_(kUninitialized), |
431 pictures_requested_(false), | 430 pictures_requested_(false), |
432 inputs_before_decode_(0), | 431 inputs_before_decode_(0), |
433 make_context_current_(make_context_current), | 432 make_context_current_(make_context_current), |
434 weak_this_factory_(this) { | 433 weak_this_factory_(this), |
434 decoder_thread_("DXVAVideoDecoderThread") { | |
435 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 435 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
436 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 436 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
437 } | 437 } |
438 | 438 |
439 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 439 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
440 client_ = NULL; | 440 client_ = NULL; |
441 } | 441 } |
442 | 442 |
443 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, | 443 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
444 Client* client) { | 444 Client* client) { |
445 DCHECK(CalledOnValidThread()); | 445 DCHECK(CalledOnValidThread()); |
446 | 446 |
447 client_ = client; | 447 client_ = client; |
448 | 448 |
449 // Not all versions of Windows 7 and later include Media Foundation DLLs. | 449 // Not all versions of Windows 7 and later include Media Foundation DLLs. |
450 // Instead of crashing while delay loading the DLL when calling MFStartup() | 450 // Instead of crashing while delay loading the DLL when calling MFStartup() |
451 // below, probe whether we can successfully load the DLL now. | 451 // below, probe whether we can successfully load the DLL now. |
452 // | 452 // |
453 // See http://crbug.com/339678 for details. | 453 // See http://crbug.com/339678 for details. |
454 HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll"); | 454 HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll"); |
455 RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", false); | 455 RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", false); |
456 | 456 |
457 // TODO(ananta) | |
458 // H264PROFILE_HIGH video decoding is janky at times. Needs more | |
459 // investigation. http://crbug.com/426707 | |
460 if (profile != media::H264PROFILE_BASELINE && | 457 if (profile != media::H264PROFILE_BASELINE && |
461 profile != media::H264PROFILE_MAIN) { | 458 profile != media::H264PROFILE_MAIN && |
459 profile != media::H264PROFILE_HIGH) { | |
462 RETURN_AND_NOTIFY_ON_FAILURE(false, | 460 RETURN_AND_NOTIFY_ON_FAILURE(false, |
463 "Unsupported h264 profile", PLATFORM_FAILURE, false); | 461 "Unsupported h264 profile", PLATFORM_FAILURE, false); |
464 } | 462 } |
465 | 463 |
466 RETURN_AND_NOTIFY_ON_FAILURE( | 464 RETURN_AND_NOTIFY_ON_FAILURE( |
467 gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, | 465 gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, |
468 "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", | 466 "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", |
469 PLATFORM_FAILURE, | 467 PLATFORM_FAILURE, |
470 false); | 468 false); |
471 | 469 |
472 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kUninitialized), | 470 State state = GetState(); |
473 "Initialize: invalid state: " << state_, ILLEGAL_STATE, false); | 471 RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), |
472 "Initialize: invalid state: " << state, ILLEGAL_STATE, false); | |
474 | 473 |
475 HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); | 474 HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); |
476 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE, | 475 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE, |
477 false); | 476 false); |
478 | 477 |
479 RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(), | 478 RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(), |
480 "Failed to initialize D3D device and manager", | 479 "Failed to initialize D3D device and manager", |
481 PLATFORM_FAILURE, | 480 PLATFORM_FAILURE, |
482 false); | 481 false); |
483 | 482 |
484 RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile), | 483 RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile), |
485 "Failed to initialize decoder", PLATFORM_FAILURE, false); | 484 "Failed to initialize decoder", PLATFORM_FAILURE, false); |
486 | 485 |
487 RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), | 486 RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), |
488 "Failed to get input/output stream info.", PLATFORM_FAILURE, false); | 487 "Failed to get input/output stream info.", PLATFORM_FAILURE, false); |
489 | 488 |
490 RETURN_AND_NOTIFY_ON_FAILURE( | 489 RETURN_AND_NOTIFY_ON_FAILURE( |
491 SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), | 490 SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), |
492 "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", | 491 "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", |
493 PLATFORM_FAILURE, false); | 492 PLATFORM_FAILURE, false); |
494 | 493 |
495 RETURN_AND_NOTIFY_ON_FAILURE( | 494 RETURN_AND_NOTIFY_ON_FAILURE( |
496 SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), | 495 SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), |
497 "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", | 496 "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", |
498 PLATFORM_FAILURE, false); | 497 PLATFORM_FAILURE, false); |
499 | 498 |
500 state_ = kNormal; | 499 SetState(kNormal); |
500 | |
501 main_thread_task_runner_ = base::MessageLoop::current()->task_runner(); | |
502 | |
503 decoder_thread_.init_com_with_mta(false); | |
504 decoder_thread_.Start(); | |
505 decoder_thread_task_runner_ = decoder_thread_.task_runner(); | |
501 return true; | 506 return true; |
502 } | 507 } |
503 | 508 |
504 void DXVAVideoDecodeAccelerator::Decode( | 509 void DXVAVideoDecodeAccelerator::Decode( |
505 const media::BitstreamBuffer& bitstream_buffer) { | 510 const media::BitstreamBuffer& bitstream_buffer) { |
506 DCHECK(CalledOnValidThread()); | 511 DCHECK(CalledOnValidThread()); |
507 | 512 |
508 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped || | 513 State state = GetState(); |
509 state_ == kFlushing), | 514 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || |
510 "Invalid state: " << state_, ILLEGAL_STATE,); | 515 state == kFlushing), |
516 "Invalid state: " << state, ILLEGAL_STATE,); | |
511 | 517 |
512 base::win::ScopedComPtr<IMFSample> sample; | 518 base::win::ScopedComPtr<IMFSample> sample; |
513 sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer, | 519 sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer, |
514 input_stream_info_.cbSize, | 520 input_stream_info_.cbSize, |
515 input_stream_info_.cbAlignment)); | 521 input_stream_info_.cbAlignment)); |
516 RETURN_AND_NOTIFY_ON_FAILURE(sample.get(), "Failed to create input sample", | 522 RETURN_AND_NOTIFY_ON_FAILURE(sample.get(), "Failed to create input sample", |
517 PLATFORM_FAILURE, ); | 523 PLATFORM_FAILURE, ); |
518 | 524 |
519 RETURN_AND_NOTIFY_ON_HR_FAILURE(sample->SetSampleTime(bitstream_buffer.id()), | 525 RETURN_AND_NOTIFY_ON_HR_FAILURE(sample->SetSampleTime(bitstream_buffer.id()), |
520 "Failed to associate input buffer id with sample", PLATFORM_FAILURE,); | 526 "Failed to associate input buffer id with sample", PLATFORM_FAILURE,); |
521 | 527 |
522 DecodeInternal(sample); | 528 decoder_thread_task_runner_->PostTask(FROM_HERE, |
529 base::Bind(&DXVAVideoDecodeAccelerator::DecodeInternal, | |
530 base::Unretained(this), sample)); | |
523 } | 531 } |
524 | 532 |
525 void DXVAVideoDecodeAccelerator::AssignPictureBuffers( | 533 void DXVAVideoDecodeAccelerator::AssignPictureBuffers( |
526 const std::vector<media::PictureBuffer>& buffers) { | 534 const std::vector<media::PictureBuffer>& buffers) { |
527 DCHECK(CalledOnValidThread()); | 535 DCHECK(CalledOnValidThread()); |
528 | 536 |
529 RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), | 537 State state = GetState(); |
530 "Invalid state: " << state_, ILLEGAL_STATE,); | 538 RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized), |
539 "Invalid state: " << state, ILLEGAL_STATE,); | |
531 RETURN_AND_NOTIFY_ON_FAILURE((kNumPictureBuffers == buffers.size()), | 540 RETURN_AND_NOTIFY_ON_FAILURE((kNumPictureBuffers == buffers.size()), |
532 "Failed to provide requested picture buffers. (Got " << buffers.size() << | 541 "Failed to provide requested picture buffers. (Got " << buffers.size() << |
533 ", requested " << kNumPictureBuffers << ")", INVALID_ARGUMENT,); | 542 ", requested " << kNumPictureBuffers << ")", INVALID_ARGUMENT,); |
534 | 543 |
535 // Copy the picture buffers provided by the client to the available list, | 544 // Copy the picture buffers provided by the client to the available list, |
536 // and mark these buffers as available for use. | 545 // and mark these buffers as available for use. |
537 for (size_t buffer_index = 0; buffer_index < buffers.size(); | 546 for (size_t buffer_index = 0; buffer_index < buffers.size(); |
538 ++buffer_index) { | 547 ++buffer_index) { |
539 linked_ptr<DXVAPictureBuffer> picture_buffer = | 548 linked_ptr<DXVAPictureBuffer> picture_buffer = |
540 DXVAPictureBuffer::Create(*this, buffers[buffer_index], egl_config_); | 549 DXVAPictureBuffer::Create(*this, buffers[buffer_index], egl_config_); |
541 RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer.get(), | 550 RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer.get(), |
542 "Failed to allocate picture buffer", PLATFORM_FAILURE,); | 551 "Failed to allocate picture buffer", PLATFORM_FAILURE,); |
543 | 552 |
544 bool inserted = output_picture_buffers_.insert(std::make_pair( | 553 bool inserted = output_picture_buffers_.insert(std::make_pair( |
545 buffers[buffer_index].id(), picture_buffer)).second; | 554 buffers[buffer_index].id(), picture_buffer)).second; |
546 DCHECK(inserted); | 555 DCHECK(inserted); |
547 } | 556 } |
548 ProcessPendingSamples(); | 557 ProcessPendingSamples(); |
549 if (state_ == kFlushing && pending_output_samples_.empty()) | 558 |
559 if (GetState() == kFlushing && pending_output_samples_.empty()) | |
550 FlushInternal(); | 560 FlushInternal(); |
551 } | 561 } |
552 | 562 |
553 void DXVAVideoDecodeAccelerator::ReusePictureBuffer( | 563 void DXVAVideoDecodeAccelerator::ReusePictureBuffer( |
554 int32 picture_buffer_id) { | 564 int32 picture_buffer_id) { |
555 DCHECK(CalledOnValidThread()); | 565 DCHECK(CalledOnValidThread()); |
556 | 566 |
557 RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), | 567 State state = GetState(); |
558 "Invalid state: " << state_, ILLEGAL_STATE,); | 568 RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized), |
569 "Invalid state: " << state, ILLEGAL_STATE,); | |
559 | 570 |
560 if (output_picture_buffers_.empty() && stale_output_picture_buffers_.empty()) | 571 if (output_picture_buffers_.empty() && stale_output_picture_buffers_.empty()) |
561 return; | 572 return; |
562 | 573 |
563 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); | 574 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); |
564 // If we didn't find the picture id in the |output_picture_buffers_| map we | 575 // If we didn't find the picture id in the |output_picture_buffers_| map we |
565 // try the |stale_output_picture_buffers_| map, as this may have been an | 576 // try the |stale_output_picture_buffers_| map, as this may have been an |
566 // output picture buffer from before a resolution change, that at resolution | 577 // output picture buffer from before a resolution change, that at resolution |
567 // change time had yet to be displayed. The client is calling us back to tell | 578 // change time had yet to be displayed. The client is calling us back to tell |
568 // us that we can now recycle this picture buffer, so if we were waiting to | 579 // us that we can now recycle this picture buffer, so if we were waiting to |
569 // dispose of it we now can. | 580 // dispose of it we now can. |
570 if (it == output_picture_buffers_.end()) { | 581 if (it == output_picture_buffers_.end()) { |
571 it = stale_output_picture_buffers_.find(picture_buffer_id); | 582 it = stale_output_picture_buffers_.find(picture_buffer_id); |
572 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), | 583 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), |
573 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); | 584 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); |
574 base::MessageLoop::current()->PostTask(FROM_HERE, | 585 base::MessageLoop::current()->PostTask(FROM_HERE, |
575 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, | 586 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, |
576 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); | 587 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); |
577 return; | 588 return; |
578 } | 589 } |
579 | 590 |
580 it->second->ReusePictureBuffer(); | 591 it->second->ReusePictureBuffer(); |
581 ProcessPendingSamples(); | 592 ProcessPendingSamples(); |
582 | 593 |
583 if (state_ == kFlushing && pending_output_samples_.empty()) | 594 if (GetState() == kFlushing && pending_output_samples_.empty()) |
584 FlushInternal(); | 595 FlushInternal(); |
585 } | 596 } |
586 | 597 |
587 void DXVAVideoDecodeAccelerator::Flush() { | 598 void DXVAVideoDecodeAccelerator::Flush() { |
588 DCHECK(CalledOnValidThread()); | 599 DCHECK(CalledOnValidThread()); |
589 | 600 |
590 DVLOG(1) << "DXVAVideoDecodeAccelerator::Flush"; | 601 DVLOG(1) << "DXVAVideoDecodeAccelerator::Flush"; |
591 | 602 |
592 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped), | 603 State state = GetState(); |
593 "Unexpected decoder state: " << state_, ILLEGAL_STATE,); | 604 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped), |
605 "Unexpected decoder state: " << state, ILLEGAL_STATE,); | |
594 | 606 |
595 state_ = kFlushing; | 607 SetState(kFlushing); |
596 | 608 |
597 RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0), | 609 RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0), |
598 "Failed to send drain message", PLATFORM_FAILURE,); | 610 "Failed to send drain message", PLATFORM_FAILURE,); |
599 | 611 |
600 if (!pending_output_samples_.empty()) | 612 if (!pending_output_samples_.empty()) |
601 return; | 613 return; |
602 | 614 |
603 FlushInternal(); | 615 FlushInternal(); |
604 } | 616 } |
605 | 617 |
606 void DXVAVideoDecodeAccelerator::Reset() { | 618 void DXVAVideoDecodeAccelerator::Reset() { |
607 DCHECK(CalledOnValidThread()); | |
608 | |
609 DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset"; | 619 DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset"; |
610 | 620 |
611 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped), | 621 State state = GetState(); |
612 "Reset: invalid state: " << state_, ILLEGAL_STATE,); | 622 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped), |
623 "Reset: invalid state: " << state, ILLEGAL_STATE,); | |
613 | 624 |
614 state_ = kResetting; | 625 if (decoder_thread_.thread_id() != ::GetCurrentThreadId()) { |
615 | 626 decoder_thread_task_runner_->PostTask(FROM_HERE, |
616 pending_output_samples_.clear(); | 627 base::Bind(&DXVAVideoDecodeAccelerator::ResetHelper, |
617 | 628 base::Unretained(this))); |
618 NotifyInputBuffersDropped(); | 629 return; |
619 | 630 } |
620 RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), | |
621 "Reset: Failed to send message.", PLATFORM_FAILURE,); | |
622 | |
623 base::MessageLoop::current()->PostTask( | |
624 FROM_HERE, | |
625 base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone, | |
626 weak_this_factory_.GetWeakPtr())); | |
627 | |
628 state_ = DXVAVideoDecodeAccelerator::kNormal; | |
629 } | 631 } |
630 | 632 |
631 void DXVAVideoDecodeAccelerator::Destroy() { | 633 void DXVAVideoDecodeAccelerator::Destroy() { |
632 DCHECK(CalledOnValidThread()); | 634 DCHECK(CalledOnValidThread()); |
633 Invalidate(); | 635 Invalidate(); |
634 delete this; | 636 delete this; |
635 } | 637 } |
636 | 638 |
637 bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() { | 639 bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() { |
638 return false; | 640 return false; |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
815 << std::hex << std::showbase << output_stream_info_.dwFlags; | 817 << std::hex << std::showbase << output_stream_info_.dwFlags; |
816 CHECK_EQ(output_stream_info_.dwFlags, 0x107u); | 818 CHECK_EQ(output_stream_info_.dwFlags, 0x107u); |
817 DVLOG(1) << "Min buffer size: " << output_stream_info_.cbSize; | 819 DVLOG(1) << "Min buffer size: " << output_stream_info_.cbSize; |
818 DVLOG(1) << "Alignment: " << output_stream_info_.cbAlignment; | 820 DVLOG(1) << "Alignment: " << output_stream_info_.cbAlignment; |
819 return true; | 821 return true; |
820 } | 822 } |
821 | 823 |
822 void DXVAVideoDecodeAccelerator::DoDecode() { | 824 void DXVAVideoDecodeAccelerator::DoDecode() { |
823 // This function is also called from FlushInternal in a loop which could | 825 // This function is also called from FlushInternal in a loop which could |
824 // result in the state transitioning to kStopped due to no decoded output. | 826 // result in the state transitioning to kStopped due to no decoded output. |
827 State state = GetState(); | |
825 RETURN_AND_NOTIFY_ON_FAILURE( | 828 RETURN_AND_NOTIFY_ON_FAILURE( |
826 (state_ == kNormal || state_ == kFlushing || | 829 (state == kNormal || state == kFlushing || |
827 state_ == kStopped || state_ == kFlushingPendingInputBuffers), | 830 state == kStopped || state == kFlushingPendingInputBuffers), |
828 "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,); | 831 "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,); |
829 | 832 |
830 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; | 833 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; |
831 DWORD status = 0; | 834 DWORD status = 0; |
832 | 835 |
833 HRESULT hr = decoder_->ProcessOutput(0, // No flags | 836 HRESULT hr = decoder_->ProcessOutput(0, // No flags |
834 1, // # of out streams to pull from | 837 1, // # of out streams to pull from |
835 &output_data_buffer, | 838 &output_data_buffer, |
836 &status); | 839 &status); |
837 IMFCollection* events = output_data_buffer.pEvents; | 840 IMFCollection* events = output_data_buffer.pEvents; |
838 if (events != NULL) { | 841 if (events != NULL) { |
839 DVLOG(1) << "Got events from ProcessOuput, but discarding"; | 842 DVLOG(1) << "Got events from ProcessOuput, but discarding"; |
840 events->Release(); | 843 events->Release(); |
841 } | 844 } |
842 if (FAILED(hr)) { | 845 if (FAILED(hr)) { |
843 // A stream change needs further ProcessInput calls to get back decoder | 846 // A stream change needs further ProcessInput calls to get back decoder |
844 // output which is why we need to set the state to stopped. | 847 // output which is why we need to set the state to stopped. |
845 if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { | 848 if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { |
846 if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) { | 849 if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) { |
847 // Decoder didn't let us set NV12 output format. Not sure as to why | 850 // Decoder didn't let us set NV12 output format. Not sure as to why |
848 // this can happen. Give up in disgust. | 851 // this can happen. Give up in disgust. |
849 NOTREACHED() << "Failed to set decoder output media type to NV12"; | 852 NOTREACHED() << "Failed to set decoder output media type to NV12"; |
850 state_ = kStopped; | 853 SetState(kStopped); |
851 } else { | 854 } else { |
852 DVLOG(1) << "Received output format change from the decoder." | 855 DVLOG(1) << "Received output format change from the decoder." |
853 " Recursively invoking DoDecode"; | 856 " Recursively invoking DoDecode"; |
854 DoDecode(); | 857 DoDecode(); |
855 } | 858 } |
856 return; | 859 return; |
857 } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { | 860 } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { |
858 // No more output from the decoder. Stop playback. | 861 // No more output from the decoder. Stop playback. |
859 if (state_ != kFlushingPendingInputBuffers) | 862 if (GetState() != kFlushingPendingInputBuffers) |
860 state_ = kStopped; | 863 SetState(kStopped); |
861 return; | 864 return; |
862 } else { | 865 } else { |
863 NOTREACHED() << "Unhandled error in DoDecode()"; | 866 NOTREACHED() << "Unhandled error in DoDecode()"; |
864 return; | 867 return; |
865 } | 868 } |
866 } | 869 } |
867 TRACE_EVENT_END_ETW("DXVAVideoDecodeAccelerator.Decoding", this, ""); | 870 TRACE_EVENT_END_ETW("DXVAVideoDecodeAccelerator.Decoding", this, ""); |
868 | 871 |
869 TRACE_COUNTER1("DXVA Decoding", "TotalPacketsBeforeDecode", | 872 TRACE_COUNTER1("DXVA Decoding", "TotalPacketsBeforeDecode", |
870 inputs_before_decode_); | 873 inputs_before_decode_); |
(...skipping 21 matching lines...) Expand all Loading... | |
892 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), | 895 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), |
893 "Failed to get input buffer id associated with sample", | 896 "Failed to get input buffer id associated with sample", |
894 false); | 897 false); |
895 | 898 |
896 pending_output_samples_.push_back( | 899 pending_output_samples_.push_back( |
897 PendingSampleInfo(input_buffer_id, sample)); | 900 PendingSampleInfo(input_buffer_id, sample)); |
898 | 901 |
899 // If we have available picture buffers to copy the output data then use the | 902 // If we have available picture buffers to copy the output data then use the |
900 // first one and then flag it as not being available for use. | 903 // first one and then flag it as not being available for use. |
901 if (output_picture_buffers_.size()) { | 904 if (output_picture_buffers_.size()) { |
902 ProcessPendingSamples(); | 905 main_thread_task_runner_->PostTask( |
906 FROM_HERE, | |
907 base::Bind(&DXVAVideoDecodeAccelerator::ProcessPendingSamples, | |
908 weak_this_factory_.GetWeakPtr())); | |
903 return true; | 909 return true; |
904 } | 910 } |
905 if (pictures_requested_) { | 911 if (pictures_requested_) { |
906 DVLOG(1) << "Waiting for picture slots from the client."; | 912 DVLOG(1) << "Waiting for picture slots from the client."; |
907 return true; | 913 return true; |
908 } | 914 } |
909 | 915 |
910 // We only read the surface description, which contains its width/height when | 916 // We only read the surface description, which contains its width/height when |
911 // we need the picture buffers from the client. Once we have those, then they | 917 // we need the picture buffers from the client. Once we have those, then they |
912 // are reused. | 918 // are reused. |
913 D3DSURFACE_DESC surface_desc; | 919 D3DSURFACE_DESC surface_desc; |
914 hr = surface->GetDesc(&surface_desc); | 920 hr = surface->GetDesc(&surface_desc); |
915 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 921 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
916 | 922 |
917 // Go ahead and request picture buffers. | 923 // Go ahead and request picture buffers. |
918 base::MessageLoop::current()->PostTask( | 924 main_thread_task_runner_->PostTask( |
919 FROM_HERE, | 925 FROM_HERE, |
920 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, | 926 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
921 weak_this_factory_.GetWeakPtr(), | 927 weak_this_factory_.GetWeakPtr(), |
922 surface_desc.Width, | 928 surface_desc.Width, |
923 surface_desc.Height)); | 929 surface_desc.Height)); |
924 | 930 |
925 pictures_requested_ = true; | 931 pictures_requested_ = true; |
926 return true; | 932 return true; |
927 } | 933 } |
928 | 934 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
966 } | 972 } |
967 | 973 |
968 RETURN_AND_NOTIFY_ON_FAILURE( | 974 RETURN_AND_NOTIFY_ON_FAILURE( |
969 index->second->CopyOutputSampleDataToPictureBuffer(*this, | 975 index->second->CopyOutputSampleDataToPictureBuffer(*this, |
970 surface.get()), | 976 surface.get()), |
971 "Failed to copy output sample", PLATFORM_FAILURE, ); | 977 "Failed to copy output sample", PLATFORM_FAILURE, ); |
972 | 978 |
973 media::Picture output_picture(index->second->id(), | 979 media::Picture output_picture(index->second->id(), |
974 sample_info.input_buffer_id, | 980 sample_info.input_buffer_id, |
975 gfx::Rect(index->second->size())); | 981 gfx::Rect(index->second->size())); |
976 base::MessageLoop::current()->PostTask( | 982 main_thread_task_runner_->PostTask( |
977 FROM_HERE, | 983 FROM_HERE, |
978 base::Bind(&DXVAVideoDecodeAccelerator::NotifyPictureReady, | 984 base::Bind(&DXVAVideoDecodeAccelerator::NotifyPictureReady, |
979 weak_this_factory_.GetWeakPtr(), | 985 weak_this_factory_.GetWeakPtr(), |
980 output_picture)); | 986 output_picture)); |
981 | 987 |
982 index->second->set_available(false); | 988 index->second->set_available(false); |
983 pending_output_samples_.pop_front(); | 989 pending_output_samples_.pop_front(); |
984 } | 990 } |
985 } | 991 } |
986 | 992 decoder_thread_task_runner_->PostTask( |
987 if (!pending_input_buffers_.empty() && pending_output_samples_.empty()) { | 993 FROM_HERE, |
988 base::MessageLoop::current()->PostTask( | 994 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
989 FROM_HERE, | 995 base::Unretained(this))); |
990 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | |
991 weak_this_factory_.GetWeakPtr())); | |
992 } | |
993 } | 996 } |
994 | 997 |
995 void DXVAVideoDecodeAccelerator::StopOnError( | 998 void DXVAVideoDecodeAccelerator::StopOnError( |
996 media::VideoDecodeAccelerator::Error error) { | 999 media::VideoDecodeAccelerator::Error error) { |
997 DCHECK(CalledOnValidThread()); | 1000 DCHECK(CalledOnValidThread()); |
998 | 1001 |
999 if (client_) | 1002 if (client_) |
1000 client_->NotifyError(error); | 1003 client_->NotifyError(error); |
1001 client_ = NULL; | 1004 client_ = NULL; |
1002 | 1005 |
1003 if (state_ != kUninitialized) { | 1006 if (GetState() != kUninitialized) { |
1004 Invalidate(); | 1007 Invalidate(); |
1005 } | 1008 } |
1006 } | 1009 } |
1007 | 1010 |
1008 void DXVAVideoDecodeAccelerator::Invalidate() { | 1011 void DXVAVideoDecodeAccelerator::Invalidate() { |
1009 if (state_ == kUninitialized) | 1012 if (GetState() == kUninitialized) |
1010 return; | 1013 return; |
1014 decoder_thread_.Stop(); | |
1011 weak_this_factory_.InvalidateWeakPtrs(); | 1015 weak_this_factory_.InvalidateWeakPtrs(); |
1012 output_picture_buffers_.clear(); | 1016 output_picture_buffers_.clear(); |
1013 stale_output_picture_buffers_.clear(); | 1017 stale_output_picture_buffers_.clear(); |
1014 pending_output_samples_.clear(); | 1018 pending_output_samples_.clear(); |
1015 pending_input_buffers_.clear(); | 1019 pending_input_buffers_.clear(); |
1016 decoder_.Release(); | 1020 decoder_.Release(); |
1017 MFShutdown(); | 1021 MFShutdown(); |
1018 state_ = kUninitialized; | 1022 SetState(kUninitialized); |
1019 } | 1023 } |
1020 | 1024 |
1021 void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { | 1025 void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { |
1022 if (client_) | 1026 if (client_) |
1023 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | 1027 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
1024 } | 1028 } |
1025 | 1029 |
1026 void DXVAVideoDecodeAccelerator::NotifyFlushDone() { | 1030 void DXVAVideoDecodeAccelerator::NotifyFlushDone() { |
1027 if (client_) | 1031 if (client_) |
1028 client_->NotifyFlushDone(); | 1032 client_->NotifyFlushDone(); |
1029 } | 1033 } |
1030 | 1034 |
1031 void DXVAVideoDecodeAccelerator::NotifyResetDone() { | 1035 void DXVAVideoDecodeAccelerator::NotifyResetDone() { |
1036 pending_output_samples_.clear(); | |
1032 if (client_) | 1037 if (client_) |
1033 client_->NotifyResetDone(); | 1038 client_->NotifyResetDone(); |
1034 } | 1039 } |
1035 | 1040 |
1036 void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) { | 1041 void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) { |
1037 // This task could execute after the decoder has been torn down. | 1042 // This task could execute after the decoder has been torn down. |
1038 if (state_ != kUninitialized && client_) { | 1043 if (GetState() != kUninitialized && client_) { |
1039 client_->ProvidePictureBuffers( | 1044 client_->ProvidePictureBuffers( |
1040 kNumPictureBuffers, | 1045 kNumPictureBuffers, |
1041 gfx::Size(width, height), | 1046 gfx::Size(width, height), |
1042 GL_TEXTURE_2D); | 1047 GL_TEXTURE_2D); |
1043 } | 1048 } |
1044 } | 1049 } |
1045 | 1050 |
1046 void DXVAVideoDecodeAccelerator::NotifyPictureReady( | 1051 void DXVAVideoDecodeAccelerator::NotifyPictureReady( |
1047 const media::Picture& picture) { | 1052 const media::Picture& picture) { |
1048 // This task could execute after the decoder has been torn down. | 1053 // This task could execute after the decoder has been torn down. |
1049 if (state_ != kUninitialized && client_) | 1054 if (GetState() != kUninitialized && client_) |
1050 client_->PictureReady(picture); | 1055 client_->PictureReady(picture); |
1051 } | 1056 } |
1052 | 1057 |
1053 void DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped() { | 1058 void DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped( |
1054 if (!client_ || !pending_output_samples_.empty()) | 1059 const PendingInputs& input_buffers) { |
1060 if (!client_) | |
1055 return; | 1061 return; |
1056 | 1062 |
1057 for (PendingInputs::iterator it = pending_input_buffers_.begin(); | 1063 for (PendingInputs::const_iterator it = input_buffers.begin(); |
1058 it != pending_input_buffers_.end(); ++it) { | 1064 it != input_buffers.end(); ++it) { |
1059 LONGLONG input_buffer_id = 0; | 1065 LONGLONG input_buffer_id = 0; |
1060 RETURN_ON_HR_FAILURE((*it)->GetSampleTime(&input_buffer_id), | 1066 RETURN_ON_HR_FAILURE((*it)->GetSampleTime(&input_buffer_id), |
1061 "Failed to get buffer id associated with sample",); | 1067 "Failed to get buffer id associated with sample",); |
1062 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | 1068 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
1063 } | 1069 } |
1064 pending_input_buffers_.clear(); | |
1065 } | 1070 } |
1066 | 1071 |
1067 void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() { | 1072 void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() { |
1068 RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), | 1073 State state = GetState(); |
1069 "Invalid state: " << state_, ILLEGAL_STATE,); | 1074 RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized), |
1075 "Invalid state: " << state, ILLEGAL_STATE,); | |
1070 | 1076 |
1071 if (pending_input_buffers_.empty() || !pending_output_samples_.empty()) | 1077 if (pending_input_buffers_.empty() || !pending_output_samples_.empty()) |
1072 return; | 1078 return; |
1073 | 1079 |
1074 PendingInputs pending_input_buffers_copy; | 1080 PendingInputs pending_input_buffers_copy; |
1075 std::swap(pending_input_buffers_, pending_input_buffers_copy); | 1081 std::swap(pending_input_buffers_, pending_input_buffers_copy); |
1076 | 1082 |
1077 for (PendingInputs::iterator it = pending_input_buffers_copy.begin(); | 1083 for (PendingInputs::iterator it = pending_input_buffers_copy.begin(); |
1078 it != pending_input_buffers_copy.end(); ++it) { | 1084 it != pending_input_buffers_copy.end(); ++it) { |
1079 DecodeInternal(*it); | 1085 DecodeInternal(*it); |
1080 } | 1086 } |
1081 | 1087 |
1082 if (state_ != kFlushingPendingInputBuffers) | 1088 if (GetState() != kFlushingPendingInputBuffers) |
1083 return; | 1089 return; |
1084 | 1090 |
1085 // If we are scheduled during a flush operation then mark the flush as | 1091 // If we are scheduled during a flush operation then mark the flush as |
1086 // complete if we have no pending input and pending output frames. | 1092 // complete if we have no pending input and pending output frames. |
1087 // If we don't have available output slots then this function will be | 1093 // If we don't have available output slots then this function will be |
1088 // scheduled again by the ProcessPendingSamples function once slots become | 1094 // scheduled again by the ProcessPendingSamples function once slots become |
1089 // available. | 1095 // available. |
1090 if (pending_input_buffers_.empty() && pending_output_samples_.empty()) { | 1096 if (pending_input_buffers_.empty() && pending_output_samples_.empty()) { |
1091 state_ = kNormal; | 1097 SetState(kNormal); |
1092 base::MessageLoop::current()->PostTask( | 1098 base::MessageLoop::current()->PostTask( |
1093 FROM_HERE, | 1099 FROM_HERE, |
1094 base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, | 1100 base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, |
1095 weak_this_factory_.GetWeakPtr())); | 1101 weak_this_factory_.GetWeakPtr())); |
1096 } | 1102 } |
1097 } | 1103 } |
1098 | 1104 |
1099 void DXVAVideoDecodeAccelerator::FlushInternal() { | 1105 void DXVAVideoDecodeAccelerator::FlushInternal() { |
1106 if (decoder_thread_.thread_id() != ::GetCurrentThreadId()) { | |
1107 decoder_thread_task_runner_->PostTask(FROM_HERE, | |
1108 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | |
1109 base::Unretained(this))); | |
1110 return; | |
1111 } | |
1100 // The DoDecode function sets the state to kStopped when the decoder returns | 1112 // The DoDecode function sets the state to kStopped when the decoder returns |
1101 // MF_E_TRANSFORM_NEED_MORE_INPUT. | 1113 // MF_E_TRANSFORM_NEED_MORE_INPUT. |
1102 // The MFT decoder can buffer upto 30 frames worth of input before returning | 1114 // The MFT decoder can buffer upto 30 frames worth of input before returning |
1103 // an output frame. This loop here attempts to retrieve as many output frames | 1115 // an output frame. This loop here attempts to retrieve as many output frames |
1104 // as possible from the buffered set. | 1116 // as possible from the buffered set. |
1105 while (state_ != kStopped) { | 1117 while (GetState() != kStopped) { |
1106 DoDecode(); | 1118 DoDecode(); |
1107 if (!pending_output_samples_.empty()) | 1119 if (!pending_output_samples_.empty()) |
1108 return; | 1120 return; |
1109 } | 1121 } |
1110 | 1122 |
1111 // TODO(ananta) | 1123 // TODO(ananta) |
1112 // Look into whether we can simplify this function by combining the while | 1124 // Look into whether we can simplify this function by combining the while |
1113 // above and the code below into a single block which achieves both. The Flush | 1125 // above and the code below into a single block which achieves both. The Flush |
1114 // transitions in the decoder are a touch intertwined with other portions of | 1126 // transitions in the decoder are a touch intertwined with other portions of |
1115 // the code like AssignPictureBuffers, ReusePictureBuffers etc. | 1127 // the code like AssignPictureBuffers, ReusePictureBuffers etc. |
1116 if (!pending_input_buffers_.empty()) { | 1128 if (!pending_input_buffers_.empty()) { |
1117 state_ = kFlushingPendingInputBuffers; | 1129 SetState(kFlushingPendingInputBuffers); |
1118 base::MessageLoop::current()->PostTask( | 1130 main_thread_task_runner_->PostTask( |
1119 FROM_HERE, | 1131 FROM_HERE, |
1120 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 1132 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
1121 weak_this_factory_.GetWeakPtr())); | 1133 weak_this_factory_.GetWeakPtr())); |
1122 return; | 1134 return; |
1123 } | 1135 } |
1124 | 1136 |
1125 base::MessageLoop::current()->PostTask( | 1137 main_thread_task_runner_->PostTask( |
1126 FROM_HERE, | 1138 FROM_HERE, |
1127 base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, | 1139 base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, |
1128 weak_this_factory_.GetWeakPtr())); | 1140 weak_this_factory_.GetWeakPtr())); |
1129 | 1141 |
1130 state_ = kNormal; | 1142 SetState(kNormal); |
1131 } | 1143 } |
1132 | 1144 |
1133 void DXVAVideoDecodeAccelerator::DecodeInternal( | 1145 void DXVAVideoDecodeAccelerator::DecodeInternal( |
1134 const base::win::ScopedComPtr<IMFSample>& sample) { | 1146 const base::win::ScopedComPtr<IMFSample>& sample) { |
1135 DCHECK(CalledOnValidThread()); | 1147 if (GetState() == kUninitialized) |
1136 | |
1137 if (state_ == kUninitialized) | |
1138 return; | 1148 return; |
1139 | 1149 |
1140 if (!pending_output_samples_.empty() || !pending_input_buffers_.empty()) { | 1150 if (!pending_output_samples_.empty() || !pending_input_buffers_.empty()) { |
1141 pending_input_buffers_.push_back(sample); | 1151 pending_input_buffers_.push_back(sample); |
1142 return; | 1152 return; |
1143 } | 1153 } |
1144 | 1154 |
1145 if (!inputs_before_decode_) { | 1155 if (!inputs_before_decode_) { |
1146 TRACE_EVENT_BEGIN_ETW("DXVAVideoDecodeAccelerator.Decoding", this, ""); | 1156 TRACE_EVENT_BEGIN_ETW("DXVAVideoDecodeAccelerator.Decoding", this, ""); |
1147 } | 1157 } |
1148 inputs_before_decode_++; | 1158 inputs_before_decode_++; |
1149 | 1159 |
1150 HRESULT hr = decoder_->ProcessInput(0, sample.get(), 0); | 1160 HRESULT hr = decoder_->ProcessInput(0, sample.get(), 0); |
1151 // As per msdn if the decoder returns MF_E_NOTACCEPTING then it means that it | 1161 // As per msdn if the decoder returns MF_E_NOTACCEPTING then it means that it |
1152 // has enough data to produce one or more output samples. In this case the | 1162 // has enough data to produce one or more output samples. In this case the |
1153 // recommended options are to | 1163 // recommended options are to |
1154 // 1. Generate new output by calling IMFTransform::ProcessOutput until it | 1164 // 1. Generate new output by calling IMFTransform::ProcessOutput until it |
1155 // returns MF_E_TRANSFORM_NEED_MORE_INPUT. | 1165 // returns MF_E_TRANSFORM_NEED_MORE_INPUT. |
1156 // 2. Flush the input data | 1166 // 2. Flush the input data |
1157 // We implement the first option, i.e to retrieve the output sample and then | 1167 // We implement the first option, i.e to retrieve the output sample and then |
1158 // process the input again. Failure in either of these steps is treated as a | 1168 // process the input again. Failure in either of these steps is treated as a |
1159 // decoder failure. | 1169 // decoder failure. |
1160 if (hr == MF_E_NOTACCEPTING) { | 1170 if (hr == MF_E_NOTACCEPTING) { |
1161 DoDecode(); | 1171 DoDecode(); |
1162 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal), | 1172 State state = GetState(); |
1163 "Failed to process output. Unexpected decoder state: " << state_, | 1173 RETURN_AND_NOTIFY_ON_FAILURE((state == kStopped || state == kNormal || |
1174 state == kFlushing), | |
1175 "Failed to process output. Unexpected decoder state: " << state, | |
1164 PLATFORM_FAILURE,); | 1176 PLATFORM_FAILURE,); |
1165 hr = decoder_->ProcessInput(0, sample.get(), 0); | 1177 hr = decoder_->ProcessInput(0, sample.get(), 0); |
1166 // If we continue to get the MF_E_NOTACCEPTING error we do the following:- | 1178 // If we continue to get the MF_E_NOTACCEPTING error we do the following:- |
1167 // 1. Add the input sample to the pending queue. | 1179 // 1. Add the input sample to the pending queue. |
1168 // 2. If we don't have any output samples we post the | 1180 // 2. If we don't have any output samples we post the |
1169 // DecodePendingInputBuffers task to process the pending input samples. | 1181 // DecodePendingInputBuffers task to process the pending input samples. |
1170 // If we have an output sample then the above task is posted when the | 1182 // If we have an output sample then the above task is posted when the |
1171 // output samples are sent to the client. | 1183 // output samples are sent to the client. |
1172 // This is because we only support 1 pending output sample at any | 1184 // This is because we only support 1 pending output sample at any |
1173 // given time due to the limitation with the Microsoft media foundation | 1185 // given time due to the limitation with the Microsoft media foundation |
1174 // decoder where it recycles the output Decoder surfaces. | 1186 // decoder where it recycles the output Decoder surfaces. |
1175 if (hr == MF_E_NOTACCEPTING) { | 1187 if (hr == MF_E_NOTACCEPTING) { |
1176 pending_input_buffers_.push_back(sample); | 1188 pending_input_buffers_.push_back(sample); |
1177 if (pending_output_samples_.empty()) { | 1189 if (pending_output_samples_.empty()) { |
1178 base::MessageLoop::current()->PostTask( | 1190 base::MessageLoop::current()->PostTask( |
1179 FROM_HERE, | 1191 FROM_HERE, |
1180 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 1192 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
1181 weak_this_factory_.GetWeakPtr())); | 1193 weak_this_factory_.GetWeakPtr())); |
1182 } | 1194 } |
1183 return; | 1195 return; |
1184 } | 1196 } |
1185 } | 1197 } |
1186 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to process input sample", | 1198 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to process input sample", |
1187 PLATFORM_FAILURE,); | 1199 PLATFORM_FAILURE,); |
1188 | 1200 |
1189 DoDecode(); | 1201 DoDecode(); |
1190 | 1202 |
1191 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal || | 1203 State state = GetState(); |
1192 state_ == kFlushingPendingInputBuffers), | 1204 RETURN_AND_NOTIFY_ON_FAILURE((state == kStopped || state == kNormal || |
1193 "Failed to process output. Unexpected decoder state: " << state_, | 1205 state == kFlushingPendingInputBuffers || |
1206 state == kFlushing), | |
ananta
2014/12/03 00:12:44
We need to allow kFlushing here and below because
| |
1207 "Failed to process output. Unexpected decoder state: " << state, | |
1194 ILLEGAL_STATE,); | 1208 ILLEGAL_STATE,); |
1195 | 1209 |
1196 LONGLONG input_buffer_id = 0; | 1210 LONGLONG input_buffer_id = 0; |
1197 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), | 1211 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), |
1198 "Failed to get input buffer id associated with sample",); | 1212 "Failed to get input buffer id associated with sample",); |
1199 // The Microsoft Media foundation decoder internally buffers up to 30 frames | 1213 // The Microsoft Media foundation decoder internally buffers up to 30 frames |
1200 // before returning a decoded frame. We need to inform the client that this | 1214 // before returning a decoded frame. We need to inform the client that this |
1201 // input buffer is processed as it may stop sending us further input. | 1215 // input buffer is processed as it may stop sending us further input. |
1202 // Note: This may break clients which expect every input buffer to be | 1216 // Note: This may break clients which expect every input buffer to be |
1203 // associated with a decoded output buffer. | 1217 // associated with a decoded output buffer. |
1204 // TODO(ananta) | 1218 // TODO(ananta) |
1205 // Do some more investigation into whether it is possible to get the MFT | 1219 // Do some more investigation into whether it is possible to get the MFT |
1206 // decoder to emit an output packet for every input packet. | 1220 // decoder to emit an output packet for every input packet. |
1207 // http://code.google.com/p/chromium/issues/detail?id=108121 | 1221 // http://code.google.com/p/chromium/issues/detail?id=108121 |
1208 // http://code.google.com/p/chromium/issues/detail?id=150925 | 1222 // http://code.google.com/p/chromium/issues/detail?id=150925 |
1209 base::MessageLoop::current()->PostTask( | 1223 main_thread_task_runner_->PostTask( |
1210 FROM_HERE, | 1224 FROM_HERE, |
1211 base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead, | 1225 base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead, |
1212 weak_this_factory_.GetWeakPtr(), | 1226 weak_this_factory_.GetWeakPtr(), |
1213 input_buffer_id)); | 1227 input_buffer_id)); |
1214 } | 1228 } |
1215 | 1229 |
1216 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, | 1230 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, |
1217 int height) { | 1231 int height) { |
1218 base::MessageLoop::current()->PostTask( | 1232 base::MessageLoop::current()->PostTask( |
1219 FROM_HERE, | 1233 FROM_HERE, |
(...skipping 30 matching lines...) Expand all Loading... | |
1250 void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer( | 1264 void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer( |
1251 int32 picture_buffer_id) { | 1265 int32 picture_buffer_id) { |
1252 OutputBuffers::iterator it = stale_output_picture_buffers_.find( | 1266 OutputBuffers::iterator it = stale_output_picture_buffers_.find( |
1253 picture_buffer_id); | 1267 picture_buffer_id); |
1254 DCHECK(it != stale_output_picture_buffers_.end()); | 1268 DCHECK(it != stale_output_picture_buffers_.end()); |
1255 DVLOG(1) << "Dismissing picture id: " << it->second->id(); | 1269 DVLOG(1) << "Dismissing picture id: " << it->second->id(); |
1256 client_->DismissPictureBuffer(it->second->id()); | 1270 client_->DismissPictureBuffer(it->second->id()); |
1257 stale_output_picture_buffers_.erase(it); | 1271 stale_output_picture_buffers_.erase(it); |
1258 } | 1272 } |
1259 | 1273 |
1274 DXVAVideoDecodeAccelerator::State | |
1275 DXVAVideoDecodeAccelerator::GetState() const { | |
1276 State state = kUninitialized; | |
1277 ::InterlockedExchange(reinterpret_cast<long*>(&state), | |
1278 state_); | |
1279 return state; | |
1280 } | |
1281 | |
1282 void DXVAVideoDecodeAccelerator::SetState(State new_state) { | |
1283 ::InterlockedCompareExchange(reinterpret_cast<long*>(&state_), | |
1284 new_state, state_); | |
1285 } | |
1286 | |
1287 void DXVAVideoDecodeAccelerator::ResetHelper() { | |
1288 SetState(kResetting); | |
1289 | |
1290 PendingInputs pending_input_buffers_copy; | |
1291 std::swap(pending_input_buffers_, pending_input_buffers_copy); | |
1292 pending_input_buffers_.clear(); | |
1293 | |
1294 main_thread_task_runner_->PostTask( | |
1295 FROM_HERE, | |
1296 base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped, | |
1297 weak_this_factory_.GetWeakPtr(), | |
1298 pending_input_buffers_copy)); | |
1299 | |
1300 RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), | |
1301 "Reset: Failed to send message.", PLATFORM_FAILURE,); | |
1302 | |
1303 main_thread_task_runner_->PostTask( | |
1304 FROM_HERE, | |
1305 base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone, | |
1306 weak_this_factory_.GetWeakPtr())); | |
1307 | |
1308 SetState(DXVAVideoDecodeAccelerator::kNormal); | |
1309 } | |
1310 | |
1260 } // namespace content | 1311 } // namespace content |
OLD | NEW |