Chromium Code Reviews| Index: content/common/gpu/media/dxva_video_decode_accelerator_win.cc |
| diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc |
| index a7587ad9e6bd51d98b497e4ce7ac00cc8b5efa27..811cadc2a3aa3b4caf834aafe9ff10e4fcad7aa1 100644 |
| --- a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc |
| +++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc |
| @@ -21,6 +21,7 @@ |
| #include "base/base_paths_win.h" |
| #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" |
| @@ -111,6 +112,11 @@ DEFINE_GUID(CLSID_VideoProcessorMFT, |
| DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, |
| 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); |
| +// Defines the GUID for the Intel H264 DXVA device. |
| +static const GUID DXVA2_Intel_ModeH264_E = { |
| + 0x604F8E68, 0x4951, 0x4c54,{ 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6} |
| +}; |
| + |
| // Provides scoped access to the underlying buffer in an IMFMediaBuffer |
| // instance. |
| class MediaBufferScopedPointer { |
| @@ -1007,37 +1013,9 @@ bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { |
| 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. |
| - 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); |
| + hr = CreateD3D11DeviceHelper(d3d11_device_.Receive(), |
| + d3d11_device_context_.Receive()); |
| + RETURN_ON_HR_FAILURE(hr, "Failed to create D3D11 device", false) |
| // Enable multithreaded mode on the device. This ensures that accesses to |
| // context are synchronized across threads. We have multiple threads |
| @@ -1344,14 +1322,13 @@ DXVAVideoDecodeAccelerator::GetSupportedProfiles() { |
| // TODO(henryhsu): Need to ensure the profiles are actually supported. |
| SupportedProfiles profiles; |
| for (const auto& supported_profile : kSupportedProfiles) { |
| + std::pair<int, int> min_resolution = GetMinResolution(supported_profile); |
|
sandersd (OOO until July 31)
2016/04/01 01:38:52
Please measure how much time this adds to browser
ananta
2016/04/01 03:28:16
I added TRACE_EVENT calls around this callstack to
|
| + std::pair<int, int> max_resolution = GetMaxResolution(supported_profile); |
| + |
| SupportedProfile profile; |
| profile.profile = supported_profile; |
| - // Windows Media Foundation H.264 decoding does not support decoding videos |
| - // with any dimension smaller than 48 pixels: |
| - // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815 |
| - profile.min_resolution.SetSize(48, 48); |
| - // Use 1088 to account for 16x16 macroblocks. |
| - profile.max_resolution.SetSize(1920, 1088); |
| + profile.min_resolution.SetSize(min_resolution.first, min_resolution.second); |
| + profile.max_resolution.SetSize(max_resolution.first, max_resolution.second); |
| profiles.push_back(profile); |
| } |
| return profiles; |
| @@ -1373,6 +1350,183 @@ void DXVAVideoDecodeAccelerator::PreSandboxInitialization() { |
| } |
| } |
| +// static |
| +std::pair<int, int> DXVAVideoDecodeAccelerator::GetMinResolution( |
| + media::VideoCodecProfile profile) { |
| + std::pair<int, int> min_resolution; |
| + if (profile >= media::H264PROFILE_BASELINE && |
| + profile <= media::H264PROFILE_HIGH) { |
| + // Windows Media Foundation H.264 decoding does not support decoding videos |
| + // with any dimension smaller than 48 pixels: |
| + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815 |
| + min_resolution = std::make_pair(48, 48); |
| + } else { |
| + // TODO(ananta) |
| + // Detect this properly for VP8/VP9 profiles. |
| + min_resolution = std::make_pair(16, 16); |
| + } |
| + return min_resolution; |
| +} |
| + |
| +// static |
| +std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxResolution( |
| + const media::VideoCodecProfile profile) { |
| + std::pair<int, int> max_resolution; |
| + if (profile >= media::H264PROFILE_BASELINE && |
| + profile <= media::H264PROFILE_HIGH) { |
| + max_resolution = GetMaxH264Resolution(); |
| + } |
| + else { |
| + // TODO(ananta) |
| + // Detect this properly for VP8/VP9 profiles. |
| + max_resolution = std::make_pair(4096, 2160); |
| + } |
| + return max_resolution; |
| +} |
| + |
| +std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxH264Resolution() { |
| + // The H.264 resolution detection operation is expensive. This static flag |
| + // allows us to run the detection once. |
| + static bool resolution_detected = false; |
| + // Use 1088 to account for 16x16 macroblocks. |
| + static std::pair<int, int> max_resolution = std::make_pair(1920, 1088); |
| + if (resolution_detected) |
| + return max_resolution; |
| + |
| + resolution_detected = true; |
| + |
| + // On Windows 7 the maximum resolution supported by media foundation is |
| + // 1920 x 1088. On Windows 8+ if we are running with D3D11 disabled, we |
| + // fallback to the above resolution. |
| + if (base::win::GetVersion() == base::win::VERSION_WIN7 || |
| + base::CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kDisableD3D11)) { |
|
jbauman
2016/04/01 01:23:49
Probably don't need to check the command-line swit
ananta
2016/04/01 01:37:06
Done.
|
| + return max_resolution; |
| + } |
| + |
| + // To detect if a driver supports the desired resolutions, we try and create |
| + // a DXVA decoder instance for that resolution and profile. If that succeeds |
| + // we assume that the driver supports H/W H.264 decoding for that resolution. |
| + HRESULT hr = E_FAIL; |
| + |
| + base::win::ScopedComPtr<ID3D11Device> device = |
| + QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); |
| + if (!device.get()) { |
| + hr = CreateD3D11DeviceHelper(device.Receive(), nullptr); |
|
jbauman
2016/04/01 01:23:49
I don't think we should bother trying to create ou
ananta
2016/04/01 01:37:06
Done.
|
| + if (FAILED(hr)) { |
| + CHECK(false); |
| + return max_resolution; |
| + } |
| + } |
| + |
| + base::win::ScopedComPtr<ID3D11VideoDevice> video_device; |
| + hr = device.QueryInterface(IID_ID3D11VideoDevice, |
| + video_device.ReceiveVoid()); |
| + if (FAILED(hr)) { |
| + CHECK(false); |
| + return max_resolution; |
| + } |
| + |
| + // Enumerate supported video profiles and look for the H264 profile. |
| + GUID decoder_guid = {}; |
| + bool found = false; |
| + UINT profile_count = video_device->GetVideoDecoderProfileCount(); |
| + for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) { |
| + GUID profile_id = {}; |
| + hr = video_device->GetVideoDecoderProfile(profile_idx, &profile_id); |
| + if (SUCCEEDED(hr) && |
| + (profile_id == DXVA2_ModeH264_E || |
| + profile_id == DXVA2_Intel_ModeH264_E)) { |
| + decoder_guid = profile_id; |
| + found = true; |
| + break; |
| + } |
| + } |
| + |
| + if (!found) { |
| + CHECK(false); |
| + return max_resolution; |
| + } |
| + |
| + // We look for the following resolutions in the driver. |
| + // TODO(ananta) |
| + // Look into whether this list needs to be expanded. |
| + static std::pair<int, int> resolution_array[] = { |
| + // Use 1088 to account for 16x16 macroblocks. |
| + std::make_pair(1920, 1088), |
| + std::make_pair(2560, 1440), |
| + std::make_pair(3840, 2160), |
| + std::make_pair(4096, 2160), |
| + std::make_pair(4096, 2304), |
| + }; |
| + |
| + for (size_t res_idx = 0; res_idx < arraysize(resolution_array); |
| + res_idx++) { |
| + D3D11_VIDEO_DECODER_DESC desc = {}; |
| + desc.Guid = decoder_guid; |
| + desc.SampleWidth = resolution_array[res_idx].first; |
| + desc.SampleHeight = resolution_array[res_idx].second; |
| + desc.OutputFormat = DXGI_FORMAT_NV12; |
| + UINT config_count = 0; |
| + hr = video_device->GetVideoDecoderConfigCount(&desc, &config_count); |
| + if (FAILED(hr) || config_count == 0) |
| + return max_resolution; |
| + |
| + for (UINT config_idx = 0; config_idx < config_count; config_idx++) { |
| + D3D11_VIDEO_DECODER_CONFIG config = {}; |
| + hr = video_device->GetVideoDecoderConfig(&desc, config_idx, &config); |
| + if (FAILED(hr)) |
| + return max_resolution; |
| + base::win::ScopedComPtr<ID3D11VideoDecoder> video_decoder; |
| + hr = video_device->CreateVideoDecoder(&desc, &config, |
| + video_decoder.Receive()); |
| + if (!video_decoder.get()) |
| + return max_resolution; |
| + max_resolution = resolution_array[res_idx]; |
| + } |
| + } |
| + return max_resolution; |
| +} |
| + |
| +// static |
| +HRESULT DXVAVideoDecodeAccelerator::CreateD3D11DeviceHelper( |
| + ID3D11Device** device, |
| + ID3D11DeviceContext** context) { |
| + if (!device) |
| + return E_INVALIDARG; |
| + // 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. |
| + 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; |
| + HRESULT hr = D3D11CreateDevice(NULL, |
| + D3D_DRIVER_TYPE_HARDWARE, |
| + NULL, |
| + flags, |
| + feature_levels, |
| + arraysize(feature_levels), |
| + D3D11_SDK_VERSION, |
| + device, |
| + &feature_level_out, |
| + context); |
| + return hr; |
| +} |
| + |
| bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { |
| HMODULE decoder_dll = NULL; |
| @@ -1737,7 +1891,6 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { |
| PendingSampleInfo* pending_sample = NULL; |
| { |
| base::AutoLock lock(decoder_lock_); |
| - |
| PendingSampleInfo& sample_info = pending_output_samples_.front(); |
| if (sample_info.picture_buffer_id != -1) |
| continue; |