| Index: content/common/gpu/media/dxva_video_decode_accelerator.cc
|
| diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc
|
| index fb51f598811cc2a92f60922a9f49bc126b0660f0..ac813bd143587fa79ee28b9f4bb42cbaf345626c 100644
|
| --- a/content/common/gpu/media/dxva_video_decode_accelerator.cc
|
| +++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc
|
| @@ -10,6 +10,7 @@
|
|
|
| #include <ks.h>
|
| #include <codecapi.h>
|
| +#include <dxgi1_2.h>
|
| #include <mfapi.h>
|
| #include <mferror.h>
|
| #include <wmcodecdsp.h>
|
| @@ -18,6 +19,7 @@
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| #include "base/command_line.h"
|
| +#include "base/debug/alias.h"
|
| #include "base/file_version_info.h"
|
| #include "base/files/file_path.h"
|
| #include "base/logging.h"
|
| @@ -29,6 +31,7 @@
|
| #include "base/win/windows_version.h"
|
| #include "media/video/video_decode_accelerator.h"
|
| #include "ui/gl/gl_bindings.h"
|
| +#include "ui/gl/gl_context.h"
|
| #include "ui/gl/gl_surface_egl.h"
|
| #include "ui/gl/gl_switches.h"
|
|
|
| @@ -83,10 +86,26 @@ const CLSID MEDIASUBTYPE_VP90 = {
|
| { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
|
| };
|
|
|
| +// The CLSID of the video processor media foundation transform which we use for
|
| +// texture color conversion in DX11.
|
| +DEFINE_GUID(CLSID_VideoProcessorMFT,
|
| + 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78,
|
| + 0xc9, 0x82);
|
| +
|
| +// MF_XVP_PLAYBACK_MODE
|
| +// Data type: UINT32 (treat as BOOL)
|
| +// If this attribute is TRUE, the video processor will run in playback mode
|
| +// where it allows callers to allocate output samples and allows last frame
|
| +// regeneration (repaint).
|
| +DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12,
|
| + 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9);
|
| }
|
|
|
| namespace content {
|
|
|
| +CreateDXGIDeviceManager DXVAVideoDecodeAccelerator::create_dxgi_device_manager_
|
| + = NULL;
|
| +
|
| #define RETURN_ON_FAILURE(result, log, ret) \
|
| do { \
|
| if (!(result)) { \
|
| @@ -158,6 +177,7 @@ static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) {
|
| hr = sample->AddBuffer(buffer.get());
|
| RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL);
|
|
|
| + buffer->SetCurrentLength(0);
|
| return sample.Detach();
|
| }
|
|
|
| @@ -229,6 +249,7 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
|
| bool CopyOutputSampleDataToPictureBuffer(
|
| DXVAVideoDecodeAccelerator* decoder,
|
| IDirect3DSurface9* dest_surface,
|
| + ID3D11Texture2D* dx11_texture,
|
| int input_buffer_id);
|
|
|
| bool available() const {
|
| @@ -259,6 +280,7 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
|
| media::PictureBuffer picture_buffer_;
|
| EGLSurface decoding_surface_;
|
| base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_;
|
| + base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_;
|
|
|
| // The following |IDirect3DSurface9| interface pointers are used to hold
|
| // references on the surfaces during the course of a StretchRect operation
|
| @@ -267,6 +289,11 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
|
| base::win::ScopedComPtr<IDirect3DSurface9> decoder_surface_;
|
| base::win::ScopedComPtr<IDirect3DSurface9> target_surface_;
|
|
|
| + // This ID3D11Texture2D interface pointer is used to hold a reference to the
|
| + // decoder texture during the course of a copy operation. This reference is
|
| + // released when the copy completes.
|
| + base::win::ScopedComPtr<ID3D11Texture2D> decoder_dx11_texture_;
|
| +
|
| // Set to true if RGB is supported by the texture.
|
| // Defaults to true.
|
| bool use_rgb_;
|
| @@ -315,17 +342,27 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create(
|
| "Failed to query ANGLE surface pointer",
|
| linked_ptr<DXVAPictureBuffer>(NULL));
|
|
|
| - // TODO(dshwang): after moving to D3D11, use RGBA surface. crbug.com/438691
|
| - HRESULT hr = decoder.device_->CreateTexture(
|
| - buffer.size().width(),
|
| - buffer.size().height(),
|
| - 1,
|
| - D3DUSAGE_RENDERTARGET,
|
| - use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
|
| - D3DPOOL_DEFAULT,
|
| - picture_buffer->decoding_texture_.Receive(),
|
| - &share_handle);
|
| -
|
| + HRESULT hr = E_FAIL;
|
| + if (decoder.d3d11_device_) {
|
| + base::win::ScopedComPtr<ID3D11Resource> resource;
|
| + hr = decoder.d3d11_device_->OpenSharedResource(
|
| + share_handle,
|
| + __uuidof(ID3D11Resource),
|
| + reinterpret_cast<void**>(resource.Receive()));
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to open shared resource",
|
| + linked_ptr<DXVAPictureBuffer>(NULL));
|
| + hr = picture_buffer->dx11_decoding_texture_.QueryFrom(resource.get());
|
| + } else {
|
| + hr = decoder.d3d9_device_ex_->CreateTexture(
|
| + buffer.size().width(),
|
| + buffer.size().height(),
|
| + 1,
|
| + D3DUSAGE_RENDERTARGET,
|
| + use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
|
| + D3DPOOL_DEFAULT,
|
| + picture_buffer->decoding_texture_.Receive(),
|
| + &share_handle);
|
| + }
|
| RETURN_ON_HR_FAILURE(hr, "Failed to create texture",
|
| linked_ptr<DXVAPictureBuffer>(NULL));
|
| picture_buffer->use_rgb_ = !!use_rgb;
|
| @@ -365,6 +402,7 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() {
|
| EGL_BACK_BUFFER);
|
| decoder_surface_.Release();
|
| target_surface_.Release();
|
| + decoder_dx11_texture_.Release();
|
| set_available(true);
|
| }
|
|
|
| @@ -372,9 +410,18 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
|
| CopyOutputSampleDataToPictureBuffer(
|
| DXVAVideoDecodeAccelerator* decoder,
|
| IDirect3DSurface9* dest_surface,
|
| + ID3D11Texture2D* dx11_texture,
|
| int input_buffer_id) {
|
| - DCHECK(dest_surface);
|
| -
|
| + DCHECK(dest_surface || dx11_texture);
|
| + if (dx11_texture) {
|
| + // Grab a reference on the decoder texture. This reference will be released
|
| + // when we receive a notification that the copy was completed or when the
|
| + // DXVAPictureBuffer instance is destroyed.
|
| + decoder_dx11_texture_ = dx11_texture;
|
| + decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL,
|
| + id(), input_buffer_id);
|
| + return true;
|
| + }
|
| D3DSURFACE_DESC surface_desc;
|
| HRESULT hr = dest_surface->GetDesc(&surface_desc);
|
| RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
|
| @@ -424,11 +471,15 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete(
|
|
|
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
| - DCHECK_EQ(src_surface, decoder_surface_.get());
|
| - DCHECK_EQ(dest_surface, target_surface_.get());
|
| -
|
| - decoder_surface_.Release();
|
| - target_surface_.Release();
|
| + if (src_surface && dest_surface) {
|
| + DCHECK_EQ(src_surface, decoder_surface_.get());
|
| + DCHECK_EQ(dest_surface, target_surface_.get());
|
| + decoder_surface_.Release();
|
| + target_surface_.Release();
|
| + } else {
|
| + DCHECK(decoder_dx11_texture_.get());
|
| + decoder_dx11_texture_.Release();
|
| + }
|
|
|
| EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
|
| eglBindTexImage(
|
| @@ -449,57 +500,12 @@ DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo(
|
|
|
| DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {}
|
|
|
| -// static
|
| -bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() {
|
| - TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager");
|
| -
|
| - HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive());
|
| - RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false);
|
| -
|
| - D3DPRESENT_PARAMETERS present_params = {0};
|
| - present_params.BackBufferWidth = 1;
|
| - present_params.BackBufferHeight = 1;
|
| - present_params.BackBufferFormat = D3DFMT_UNKNOWN;
|
| - present_params.BackBufferCount = 1;
|
| - present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
| - present_params.hDeviceWindow = ::GetShellWindow();
|
| - present_params.Windowed = TRUE;
|
| - present_params.Flags = D3DPRESENTFLAG_VIDEO;
|
| - present_params.FullScreen_RefreshRateInHz = 0;
|
| - present_params.PresentationInterval = 0;
|
| -
|
| - hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT,
|
| - D3DDEVTYPE_HAL,
|
| - ::GetShellWindow(),
|
| - D3DCREATE_FPU_PRESERVE |
|
| - D3DCREATE_SOFTWARE_VERTEXPROCESSING |
|
| - D3DCREATE_DISABLE_PSGP_THREADING |
|
| - D3DCREATE_MULTITHREADED,
|
| - &present_params,
|
| - NULL,
|
| - device_.Receive());
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false);
|
| -
|
| - hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_,
|
| - device_manager_.Receive());
|
| - RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false);
|
| -
|
| - hr = device_manager_->ResetDevice(device_.get(), dev_manager_reset_token_);
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
|
| -
|
| - hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false);
|
| - // Ensure query_ API works (to avoid an infinite loop later in
|
| - // CopyOutputSampleDataToPictureBuffer).
|
| - hr = query_->Issue(D3DISSUE_END);
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false);
|
| - return true;
|
| -}
|
| -
|
| DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
|
| - const base::Callback<bool(void)>& make_context_current)
|
| + const base::Callback<bool(void)>& make_context_current,
|
| + gfx::GLContext* gl_context)
|
| : client_(NULL),
|
| dev_manager_reset_token_(0),
|
| + dx11_dev_manager_reset_token_(0),
|
| egl_config_(NULL),
|
| state_(kUninitialized),
|
| pictures_requested_(false),
|
| @@ -510,7 +516,10 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
|
| decoder_thread_("DXVAVideoDecoderThread"),
|
| weak_this_factory_(this),
|
| weak_ptr_(weak_this_factory_.GetWeakPtr()),
|
| - pending_flush_(false) {
|
| + pending_flush_(false),
|
| + use_dx11_(false),
|
| + dx11_video_format_converter_media_type_needs_init_(true),
|
| + gl_context_(gl_context) {
|
| memset(&input_stream_info_, 0, sizeof(input_stream_info_));
|
| memset(&output_stream_info_, 0, sizeof(output_stream_info_));
|
| }
|
| @@ -525,14 +534,6 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
|
|
|
| main_thread_task_runner_ = base::MessageLoop::current()->task_runner();
|
|
|
| - // Not all versions of Windows 7 and later include Media Foundation DLLs.
|
| - // Instead of crashing while delay loading the DLL when calling MFStartup()
|
| - // below, probe whether we can successfully load the DLL now.
|
| - //
|
| - // See http://crbug.com/339678 for details.
|
| - HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll");
|
| - RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", false);
|
| -
|
| if (profile != media::H264PROFILE_BASELINE &&
|
| profile != media::H264PROFILE_MAIN &&
|
| profile != media::H264PROFILE_HIGH &&
|
| @@ -542,6 +543,40 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
|
| "Unsupported h.264, vp8, or vp9 profile", PLATFORM_FAILURE, false);
|
| }
|
|
|
| + // Not all versions of Windows 7 and later include Media Foundation DLLs.
|
| + // Instead of crashing while delay loading the DLL when calling MFStartup()
|
| + // below, probe whether we can successfully load the DLL now.
|
| + // See http://crbug.com/339678 for details.
|
| + HMODULE dxgi_manager_dll = NULL;
|
| + if ((dxgi_manager_dll = ::GetModuleHandle(L"MFPlat.dll")) == NULL) {
|
| + HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll");
|
| + RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding",
|
| + false);
|
| + // On Windows 8+ mfplat.dll provides the MFCreateDXGIDeviceManager API.
|
| + // On Windows 7 mshtmlmedia.dll provides it.
|
| + dxgi_manager_dll = mfplat_dll;
|
| + }
|
| +
|
| + // TODO(ananta)
|
| + // The code below works, as in we can create the DX11 device manager for
|
| + // Windows 7. However the IMFTransform we use for texture conversion and
|
| + // copy does not exist on Windows 7. Look into an alternate approach
|
| + // and enable the code below.
|
| +#if defined ENABLE_DX11_FOR_WIN7
|
| + if ((base::win::GetVersion() == base::win::VERSION_WIN7) &&
|
| + ((dxgi_manager_dll = ::GetModuleHandle(L"mshtmlmedia.dll")) == NULL)) {
|
| + HMODULE mshtml_media_dll = ::LoadLibrary(L"mshtmlmedia.dll");
|
| + if (mshtml_media_dll)
|
| + dxgi_manager_dll = mshtml_media_dll;
|
| + }
|
| +#endif
|
| + // If we don't find the MFCreateDXGIDeviceManager API we fallback to D3D9
|
| + // decoding.
|
| + if (dxgi_manager_dll && !create_dxgi_device_manager_) {
|
| + create_dxgi_device_manager_ = reinterpret_cast<CreateDXGIDeviceManager>(
|
| + ::GetProcAddress(dxgi_manager_dll, "MFCreateDXGIDeviceManager"));
|
| + }
|
| +
|
| RETURN_AND_NOTIFY_ON_FAILURE(
|
| gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle,
|
| "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable",
|
| @@ -556,11 +591,6 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
|
| RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE,
|
| false);
|
|
|
| - RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(),
|
| - "Failed to initialize D3D device and manager",
|
| - PLATFORM_FAILURE,
|
| - false);
|
| -
|
| RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile),
|
| "Failed to initialize decoder", PLATFORM_FAILURE, false);
|
|
|
| @@ -583,6 +613,128 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
|
| return true;
|
| }
|
|
|
| +bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() {
|
| + TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager");
|
| +
|
| + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false);
|
| +
|
| + D3DPRESENT_PARAMETERS present_params = {0};
|
| + present_params.BackBufferWidth = 1;
|
| + present_params.BackBufferHeight = 1;
|
| + present_params.BackBufferFormat = D3DFMT_UNKNOWN;
|
| + present_params.BackBufferCount = 1;
|
| + present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
| + present_params.hDeviceWindow = ::GetShellWindow();
|
| + present_params.Windowed = TRUE;
|
| + present_params.Flags = D3DPRESENTFLAG_VIDEO;
|
| + present_params.FullScreen_RefreshRateInHz = 0;
|
| + present_params.PresentationInterval = 0;
|
| +
|
| + hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT,
|
| + D3DDEVTYPE_HAL,
|
| + ::GetShellWindow(),
|
| + D3DCREATE_FPU_PRESERVE |
|
| + D3DCREATE_SOFTWARE_VERTEXPROCESSING |
|
| + D3DCREATE_DISABLE_PSGP_THREADING |
|
| + D3DCREATE_MULTITHREADED,
|
| + &present_params,
|
| + NULL,
|
| + d3d9_device_ex_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false);
|
| +
|
| + hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_,
|
| + device_manager_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false);
|
| +
|
| + hr = device_manager_->ResetDevice(d3d9_device_ex_.get(),
|
| + dev_manager_reset_token_);
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
|
| +
|
| + hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false);
|
| + // Ensure query_ API works (to avoid an infinite loop later in
|
| + // CopyOutputSampleDataToPictureBuffer).
|
| + hr = query_->Issue(D3DISSUE_END);
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false);
|
| + return true;
|
| +}
|
| +
|
| +bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() {
|
| + HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_,
|
| + d3d11_device_manager_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false);
|
| +
|
| + // This array defines the set of DirectX hardware feature levels we support.
|
| + // The ordering MUST be preserved. All applications are assumed to support
|
| + // 9.1 unless otherwise stated by the application, which is not our case.
|
| + D3D_FEATURE_LEVEL feature_levels[] = {
|
| + D3D_FEATURE_LEVEL_11_1,
|
| + D3D_FEATURE_LEVEL_11_0,
|
| + D3D_FEATURE_LEVEL_10_1,
|
| + D3D_FEATURE_LEVEL_10_0,
|
| + D3D_FEATURE_LEVEL_9_3,
|
| + D3D_FEATURE_LEVEL_9_2,
|
| + D3D_FEATURE_LEVEL_9_1 };
|
| +
|
| + UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
| +
|
| +#if defined _DEBUG
|
| + flags |= D3D11_CREATE_DEVICE_DEBUG;
|
| +#endif
|
| +
|
| + D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_0;
|
| + hr = D3D11CreateDevice(NULL,
|
| + D3D_DRIVER_TYPE_HARDWARE,
|
| + NULL,
|
| + flags,
|
| + feature_levels,
|
| + arraysize(feature_levels),
|
| + D3D11_SDK_VERSION,
|
| + d3d11_device_.Receive(),
|
| + &feature_level_out,
|
| + d3d11_device_context_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device", false);
|
| +
|
| + // Enable multithreaded mode on the context. This ensures that accesses to
|
| + // context are synchronized across threads. We have multiple threads
|
| + // accessing the context, the media foundation decoder threads and the
|
| + // decoder thread via the video format conversion transform.
|
| + base::win::ScopedComPtr<ID3D10Multithread> multi_threaded;
|
| + hr = multi_threaded.QueryFrom(d3d11_device_context_.get());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false);
|
| + multi_threaded->SetMultithreadProtected(TRUE);
|
| +
|
| + hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(),
|
| + dx11_dev_manager_reset_token_);
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
|
| +
|
| + D3D11_QUERY_DESC query_desc;
|
| + query_desc.Query = D3D11_QUERY_EVENT;
|
| + query_desc.MiscFlags = 0;
|
| + hr = d3d11_device_->CreateQuery(
|
| + &query_desc,
|
| + d3d11_query_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false);
|
| +
|
| + hr = ::CoCreateInstance(
|
| + CLSID_VideoProcessorMFT,
|
| + NULL,
|
| + CLSCTX_INPROC_SERVER,
|
| + IID_IMFTransform,
|
| + reinterpret_cast<void**>(video_format_converter_mft_.Receive()));
|
| +
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + }
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create video format converter", false);
|
| + return true;
|
| +}
|
| +
|
| void DXVAVideoDecodeAccelerator::Decode(
|
| const media::BitstreamBuffer& bitstream_buffer) {
|
| DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
|
| @@ -632,6 +784,7 @@ void DXVAVideoDecodeAccelerator::AssignPictureBuffers(
|
| buffers[buffer_index].id(), picture_buffer)).second;
|
| DCHECK(inserted);
|
| }
|
| +
|
| ProcessPendingSamples();
|
| if (pending_flush_) {
|
| decoder_thread_task_runner_->PostTask(
|
| @@ -840,10 +993,31 @@ bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
|
| RETURN_ON_FAILURE(CheckDecoderDxvaSupport(),
|
| "Failed to check decoder DXVA support", false);
|
|
|
| + ULONG_PTR device_manager_to_use = NULL;
|
| + if (use_dx11_) {
|
| + CHECK(create_dxgi_device_manager_);
|
| + RETURN_AND_NOTIFY_ON_FAILURE(CreateDX11DevManager(),
|
| + "Failed to initialize DX11 device and manager",
|
| + PLATFORM_FAILURE,
|
| + false);
|
| + device_manager_to_use = reinterpret_cast<ULONG_PTR>(
|
| + d3d11_device_manager_.get());
|
| + } else {
|
| + RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(),
|
| + "Failed to initialize D3D device and manager",
|
| + PLATFORM_FAILURE,
|
| + false);
|
| + device_manager_to_use = reinterpret_cast<ULONG_PTR>(device_manager_.get());
|
| + }
|
| +
|
| hr = decoder_->ProcessMessage(
|
| MFT_MESSAGE_SET_D3D_MANAGER,
|
| - reinterpret_cast<ULONG_PTR>(device_manager_.get()));
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false);
|
| + device_manager_to_use);
|
| + if (use_dx11_) {
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to pass DX11 manager to decoder", false);
|
| + } else {
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false);
|
| + }
|
|
|
| EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
|
|
|
| @@ -890,6 +1064,20 @@ bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() {
|
| } else {
|
| DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr;
|
| }
|
| +
|
| + // The decoder should use DX11 iff
|
| + // 1. The underlying H/W decoder supports it.
|
| + // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for
|
| + // this. This should always be true for Windows 8+.
|
| + // 3. ANGLE is using DX11.
|
| + DCHECK(gl_context_);
|
| + if (create_dxgi_device_manager_ &&
|
| + (gl_context_->GetGLRenderer().find("Direct3D11") !=
|
| + std::string::npos)) {
|
| + UINT32 dx11_aware = 0;
|
| + attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware);
|
| + use_dx11_ = !!dx11_aware;
|
| + }
|
| return true;
|
| }
|
|
|
| @@ -1054,16 +1242,6 @@ void DXVAVideoDecodeAccelerator::DoDecode() {
|
| bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) {
|
| RETURN_ON_FAILURE(sample, "Decode succeeded with NULL output sample", false);
|
|
|
| - base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
|
| - HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive());
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false);
|
| -
|
| - base::win::ScopedComPtr<IDirect3DSurface9> surface;
|
| - hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE,
|
| - IID_PPV_ARGS(surface.Receive()));
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample",
|
| - false);
|
| -
|
| LONGLONG input_buffer_id = 0;
|
| RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id),
|
| "Failed to get input buffer id associated with sample",
|
| @@ -1085,20 +1263,20 @@ bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) {
|
| return true;
|
| }
|
|
|
| - // We only read the surface description, which contains its width/height when
|
| - // we need the picture buffers from the client. Once we have those, then they
|
| - // are reused.
|
| - D3DSURFACE_DESC surface_desc;
|
| - hr = surface->GetDesc(&surface_desc);
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
|
| + int width = 0;
|
| + int height = 0;
|
| + if (!GetVideoFrameDimensions(sample, &width, &height)) {
|
| + RETURN_ON_FAILURE(false, "Failed to get D3D surface from output sample",
|
| + false);
|
| + }
|
|
|
| // Go ahead and request picture buffers.
|
| main_thread_task_runner_->PostTask(
|
| FROM_HERE,
|
| base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
|
| weak_this_factory_.GetWeakPtr(),
|
| - surface_desc.Width,
|
| - surface_desc.Height));
|
| + width,
|
| + height));
|
|
|
| pictures_requested_ = true;
|
| return true;
|
| @@ -1130,31 +1308,43 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() {
|
| pending_sample = &sample_info;
|
| }
|
|
|
| + int width = 0;
|
| + int height = 0;
|
| + if (!GetVideoFrameDimensions(pending_sample->output_sample.get(),
|
| + &width, &height)) {
|
| + RETURN_AND_NOTIFY_ON_FAILURE(false,
|
| + "Failed to get D3D surface from output sample", PLATFORM_FAILURE,);
|
| + }
|
| +
|
| + if (width != index->second->size().width() ||
|
| + height != index->second->size().height()) {
|
| + HandleResolutionChanged(width, height);
|
| + return;
|
| + }
|
| +
|
| base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
|
| HRESULT hr = pending_sample->output_sample->GetBufferByIndex(
|
| 0, output_buffer.Receive());
|
| - RETURN_AND_NOTIFY_ON_HR_FAILURE(
|
| - hr, "Failed to get buffer from output sample", PLATFORM_FAILURE,);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to get buffer from output sample", PLATFORM_FAILURE,);
|
|
|
| base::win::ScopedComPtr<IDirect3DSurface9> surface;
|
| - hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE,
|
| - IID_PPV_ARGS(surface.Receive()));
|
| - RETURN_AND_NOTIFY_ON_HR_FAILURE(
|
| - hr, "Failed to get D3D surface from output sample",
|
| - PLATFORM_FAILURE,);
|
| -
|
| - D3DSURFACE_DESC surface_desc;
|
| - hr = surface->GetDesc(&surface_desc);
|
| - RETURN_AND_NOTIFY_ON_HR_FAILURE(
|
| - hr, "Failed to get surface description", PLATFORM_FAILURE,);
|
| -
|
| - if (surface_desc.Width !=
|
| - static_cast<uint32>(index->second->size().width()) ||
|
| - surface_desc.Height !=
|
| - static_cast<uint32>(index->second->size().height())) {
|
| - HandleResolutionChanged(surface_desc.Width, surface_desc.Height);
|
| - return;
|
| - }
|
| + base::win::ScopedComPtr<ID3D11Texture2D> d3d11_texture;
|
| +
|
| + if (use_dx11_) {
|
| + base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer;
|
| + hr = dxgi_buffer.QueryFrom(output_buffer.get());
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to get DXGIBuffer from output sample", PLATFORM_FAILURE,);
|
| + hr = dxgi_buffer->GetResource(
|
| + __uuidof(ID3D11Texture2D),
|
| + reinterpret_cast<void**>(d3d11_texture.Receive()));
|
| + } else {
|
| + hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE,
|
| + IID_PPV_ARGS(surface.Receive()));
|
| + }
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to get surface from output sample", PLATFORM_FAILURE,);
|
|
|
| pending_sample->picture_buffer_id = index->second->id();
|
|
|
| @@ -1162,8 +1352,9 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() {
|
| index->second->CopyOutputSampleDataToPictureBuffer(
|
| this,
|
| surface.get(),
|
| + d3d11_texture.get(),
|
| pending_sample->input_buffer_id),
|
| - "Failed to copy output sample", PLATFORM_FAILURE, );
|
| + "Failed to copy output sample", PLATFORM_FAILURE,);
|
|
|
| index->second->set_available(false);
|
| }
|
| @@ -1200,7 +1391,13 @@ void DXVAVideoDecodeAccelerator::Invalidate() {
|
| pending_output_samples_.clear();
|
| pending_input_buffers_.clear();
|
| decoder_.Release();
|
| + if (video_format_converter_mft_.get()) {
|
| + video_format_converter_mft_->ProcessMessage(
|
| + MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
|
| + video_format_converter_mft_.Release();
|
| + }
|
| MFShutdown();
|
| + dx11_video_format_converter_media_type_needs_init_ = true;
|
| SetState(kUninitialized);
|
| }
|
|
|
| @@ -1425,6 +1622,8 @@ void DXVAVideoDecodeAccelerator::DecodeInternal(
|
|
|
| void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width,
|
| int height) {
|
| + dx11_video_format_converter_media_type_needs_init_ = true;
|
| +
|
| main_thread_task_runner_->PostTask(
|
| FROM_HERE,
|
| base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers,
|
| @@ -1518,8 +1717,8 @@ void DXVAVideoDecodeAccelerator::CopySurface(IDirect3DSurface9* src_surface,
|
| return;
|
| }
|
|
|
| - HRESULT hr = device_->StretchRect(src_surface, NULL, dest_surface,
|
| - NULL, D3DTEXF_NONE);
|
| + HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface,
|
| + NULL, D3DTEXF_NONE);
|
| RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",);
|
|
|
| // Ideally, this should be done immediately before the draw call that uses
|
| @@ -1590,6 +1789,135 @@ void DXVAVideoDecodeAccelerator::CopySurfaceComplete(
|
| base::Unretained(this)));
|
| }
|
|
|
| +void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture,
|
| + ID3D11Texture2D* dest_texture,
|
| + IMFSample* video_frame,
|
| + int picture_buffer_id,
|
| + int input_buffer_id) {
|
| + HRESULT hr = E_FAIL;
|
| +
|
| + DCHECK(use_dx11_);
|
| +
|
| + if (!decoder_thread_task_runner_->BelongsToCurrentThread()) {
|
| + // The media foundation H.264 decoder outputs YUV12 textures which we
|
| + // cannot copy into ANGLE as they expect ARGB textures. In D3D land
|
| + // the StretchRect API in the IDirect3DDevice9Ex interface did the color
|
| + // space conversion for us. Sadly in DX11 land the API does not provide
|
| + // a straightforward way to do this.
|
| + // We use the video processor MFT.
|
| + // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx
|
| + // This object implements a media foundation transform (IMFTransform)
|
| + // which follows the same contract as the decoder. The color space
|
| + // conversion as per msdn is done in the GPU.
|
| +
|
| + D3D11_TEXTURE2D_DESC source_desc;
|
| + src_texture->GetDesc(&source_desc);
|
| +
|
| + // Set up the input and output types for the video processor MFT.
|
| + if (!InitializeDX11VideoFormatConverterMediaType(source_desc.Width,
|
| + source_desc.Height)) {
|
| + RETURN_AND_NOTIFY_ON_FAILURE(
|
| + false, "Failed to initialize media types for convesion.",
|
| + PLATFORM_FAILURE,);
|
| + }
|
| +
|
| + // The input to the video processor is the output sample.
|
| + base::win::ScopedComPtr<IMFSample> input_sample_for_conversion;
|
| + {
|
| + base::AutoLock lock(decoder_lock_);
|
| + PendingSampleInfo& sample_info = pending_output_samples_.front();
|
| + input_sample_for_conversion = sample_info.output_sample;
|
| + }
|
| +
|
| + decoder_thread_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture,
|
| + base::Unretained(this),
|
| + src_texture,
|
| + dest_texture,
|
| + input_sample_for_conversion.Detach(),
|
| + picture_buffer_id,
|
| + input_buffer_id));
|
| + return;
|
| + }
|
| +
|
| + DCHECK(video_frame);
|
| +
|
| + base::win::ScopedComPtr<IMFSample> input_sample;
|
| + input_sample.Attach(video_frame);
|
| +
|
| + DCHECK(video_format_converter_mft_.get());
|
| +
|
| + // d3d11_device_context_->Begin(d3d11_query_.get());
|
| +
|
| + hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0);
|
| + if (FAILED(hr)) {
|
| + DCHECK(false);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to convert output sample format.", PLATFORM_FAILURE,);
|
| + }
|
| +
|
| + // The video processor MFT requires output samples to be allocated by the
|
| + // caller. We create a sample with a buffer backed with the ID3D11Texture2D
|
| + // interface exposed by ANGLE. This works nicely as this ensures that the
|
| + // video processor coverts the color space of the output frame and copies
|
| + // the result into the ANGLE texture.
|
| + base::win::ScopedComPtr<IMFSample> output_sample;
|
| + hr = MFCreateSample(output_sample.Receive());
|
| + if (FAILED(hr)) {
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to create output sample.", PLATFORM_FAILURE,);
|
| + }
|
| +
|
| + base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
|
| + hr = MFCreateDXGISurfaceBuffer(
|
| + __uuidof(ID3D11Texture2D), dest_texture, 0, FALSE,
|
| + output_buffer.Receive());
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to create output sample.", PLATFORM_FAILURE,);
|
| + }
|
| +
|
| + output_sample->AddBuffer(output_buffer.get());
|
| +
|
| + DWORD status = 0;
|
| + MFT_OUTPUT_DATA_BUFFER format_converter_output = {};
|
| + format_converter_output.pSample = output_sample.get();
|
| + hr = video_format_converter_mft_->ProcessOutput(
|
| + 0, // No flags
|
| + 1, // # of out streams to pull from
|
| + &format_converter_output,
|
| + &status);
|
| +
|
| + d3d11_device_context_->Flush();
|
| + d3d11_device_context_->End(d3d11_query_.get());
|
| +
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to convert output sample format.", PLATFORM_FAILURE,);
|
| + }
|
| +
|
| + decoder_thread_task_runner_->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder,
|
| + base::Unretained(this), 0,
|
| + reinterpret_cast<IDirect3DSurface9*>(NULL),
|
| + reinterpret_cast<IDirect3DSurface9*>(NULL),
|
| + picture_buffer_id, input_buffer_id),
|
| + base::TimeDelta::FromMilliseconds(
|
| + kFlushDecoderSurfaceTimeoutMs));
|
| +}
|
| +
|
| void DXVAVideoDecodeAccelerator::FlushDecoder(
|
| int iterations,
|
| IDirect3DSurface9* src_surface,
|
| @@ -1611,7 +1939,22 @@ void DXVAVideoDecodeAccelerator::FlushDecoder(
|
| // infinite loop.
|
| // Workaround is to have an upper limit of 4 on the number of iterations to
|
| // wait for the Flush to finish.
|
| - HRESULT hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
|
| + HRESULT hr = E_FAIL;
|
| +
|
| + if (use_dx11_) {
|
| + BOOL query_data = 0;
|
| + hr = d3d11_device_context_->GetData(d3d11_query_.get(), &query_data,
|
| + sizeof(BOOL), 0);
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + }
|
| + } else {
|
| + hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
|
| + }
|
| if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) {
|
| decoder_thread_task_runner_->PostDelayedTask(
|
| FROM_HERE,
|
| @@ -1621,14 +1964,185 @@ void DXVAVideoDecodeAccelerator::FlushDecoder(
|
| base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
|
| return;
|
| }
|
| +
|
| main_thread_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
|
| - weak_this_factory_.GetWeakPtr(),
|
| - src_surface,
|
| - dest_surface,
|
| - picture_buffer_id,
|
| - input_buffer_id));
|
| + FROM_HERE,
|
| + base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
|
| + weak_this_factory_.GetWeakPtr(),
|
| + src_surface,
|
| + dest_surface,
|
| + picture_buffer_id,
|
| + input_buffer_id));
|
| +}
|
| +
|
| +bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType(
|
| + int width, int height) {
|
| + if (!dx11_video_format_converter_media_type_needs_init_)
|
| + return true;
|
| +
|
| + CHECK(video_format_converter_mft_.get());
|
| +
|
| + HRESULT hr = video_format_converter_mft_->ProcessMessage(
|
| + MFT_MESSAGE_SET_D3D_MANAGER,
|
| + reinterpret_cast<ULONG_PTR>(
|
| + d3d11_device_manager_.get()));
|
| +
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + }
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to initialize video format converter", PLATFORM_FAILURE, false);
|
| +
|
| + video_format_converter_mft_->ProcessMessage(
|
| + MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
|
| +
|
| + base::win::ScopedComPtr<IMFMediaType> media_type;
|
| + hr = MFCreateMediaType(media_type.Receive());
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFCreateMediaType failed",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set major input type",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to set attributes on media type", PLATFORM_FAILURE, false);
|
| +
|
| + hr = media_type->SetUINT32(MF_MT_INTERLACE_MODE,
|
| + MFVideoInterlace_Progressive);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to set attributes on media type", PLATFORM_FAILURE, false);
|
| +
|
| + base::win::ScopedComPtr<IMFAttributes> converter_attributes;
|
| + hr = video_format_converter_mft_->GetAttributes(
|
| + converter_attributes.Receive());
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get converter attributes",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = converter_attributes->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = converter_attributes->SetUINT32(MF_LOW_LATENCY, FALSE);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0);
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + }
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + base::win::ScopedComPtr<IMFMediaType> out_media_type;
|
| +
|
| + for (uint32 i = 0;
|
| + SUCCEEDED(video_format_converter_mft_->GetOutputAvailableType(0, i,
|
| + out_media_type.Receive()));
|
| + ++i) {
|
| + GUID out_subtype = {0};
|
| + hr = out_media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get output major type",
|
| + PLATFORM_FAILURE, false);
|
| +
|
| + if (out_subtype == MFVideoFormat_ARGB32) {
|
| + hr = out_media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to set attributes on media type", PLATFORM_FAILURE, false);
|
| +
|
| + hr = out_media_type->SetUINT32(MF_MT_INTERLACE_MODE,
|
| + MFVideoInterlace_Progressive);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to set attributes on media type", PLATFORM_FAILURE, false);
|
| +
|
| + hr = MFSetAttributeSize(out_media_type.get(), MF_MT_FRAME_SIZE, width,
|
| + height);
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to set media type attributes", PLATFORM_FAILURE, false);
|
| +
|
| + hr = video_format_converter_mft_->SetOutputType(
|
| + 0, out_media_type.get(), 0); // No flags
|
| + if (FAILED(hr)) {
|
| + base::debug::Alias(&hr);
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + CHECK(false);
|
| + }
|
| + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr,
|
| + "Failed to set converter output type", PLATFORM_FAILURE, false);
|
| +
|
| + hr = video_format_converter_mft_->ProcessMessage(
|
| + MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
|
| + if (FAILED(hr)) {
|
| + // TODO(ananta)
|
| + // Remove this CHECK when the change to use DX11 for H/W decoding
|
| + // stablizes.
|
| + RETURN_AND_NOTIFY_ON_FAILURE(
|
| + false, "Failed to initialize video converter.", PLATFORM_FAILURE,
|
| + false);
|
| + }
|
| + dx11_video_format_converter_media_type_needs_init_ = false;
|
| + return true;
|
| + }
|
| + out_media_type.Release();
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool DXVAVideoDecodeAccelerator::GetVideoFrameDimensions(
|
| + IMFSample* sample,
|
| + int* width,
|
| + int* height) {
|
| + base::win::ScopedComPtr<IMFMediaBuffer> output_buffer;
|
| + HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false);
|
| +
|
| + if (use_dx11_) {
|
| + base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer;
|
| + base::win::ScopedComPtr<ID3D11Texture2D> d3d11_texture;
|
| + hr = dxgi_buffer.QueryFrom(output_buffer.get());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to get DXGIBuffer from output sample",
|
| + false);
|
| + hr = dxgi_buffer->GetResource(
|
| + __uuidof(ID3D11Texture2D),
|
| + reinterpret_cast<void**>(d3d11_texture.Receive()));
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to get D3D11Texture from output buffer",
|
| + false);
|
| + D3D11_TEXTURE2D_DESC d3d11_texture_desc;
|
| + d3d11_texture->GetDesc(&d3d11_texture_desc);
|
| + *width = d3d11_texture_desc.Width;
|
| + *height = d3d11_texture_desc.Height;
|
| + } else {
|
| + base::win::ScopedComPtr<IDirect3DSurface9> surface;
|
| + hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE,
|
| + IID_PPV_ARGS(surface.Receive()));
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample",
|
| + false);
|
| + D3DSURFACE_DESC surface_desc;
|
| + hr = surface->GetDesc(&surface_desc);
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
|
| + *width = surface_desc.Width;
|
| + *height = surface_desc.Height;
|
| + }
|
| + return true;
|
| }
|
|
|
| } // namespace content
|
|
|