Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: content/common/gpu/media/dxva_video_decode_accelerator.cc

Issue 765533005: Move the DXVA decoder off the GPU thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/common/gpu/media/dxva_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/common/gpu/media/dxva_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698