Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "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 |