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..bccb4d814c4c2a6d894cd39c71dbabfb61165c53 100644 |
--- a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc |
+++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc |
@@ -111,6 +111,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 { |
@@ -317,50 +322,75 @@ template<class T> |
base::win::ScopedComPtr<T> QueryDeviceObjectFromANGLE(int object_type) { |
base::win::ScopedComPtr<T> device_object; |
- EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
+ EGLDisplay egl_display = nullptr; |
intptr_t egl_device = 0; |
intptr_t device = 0; |
+ { |
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. GetHardwareDisplay"); |
+ egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
+ } |
+ |
RETURN_ON_FAILURE( |
gfx::GLSurfaceEGL::HasEGLExtension("EGL_EXT_device_query"), |
"EGL_EXT_device_query missing", |
device_object); |
- PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = |
- reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(eglGetProcAddress( |
- "eglQueryDisplayAttribEXT")); |
+ PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = nullptr; |
- RETURN_ON_FAILURE( |
- QueryDisplayAttribEXT, |
- "Failed to get the eglQueryDisplayAttribEXT function from ANGLE", |
- device_object); |
+ { |
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress"); |
- PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = |
- reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(eglGetProcAddress( |
- "eglQueryDeviceAttribEXT")); |
+ QueryDisplayAttribEXT = |
+ reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(eglGetProcAddress( |
+ "eglQueryDisplayAttribEXT")); |
- RETURN_ON_FAILURE( |
- QueryDeviceAttribEXT, |
- "Failed to get the eglQueryDeviceAttribEXT function from ANGLE", |
- device_object); |
+ RETURN_ON_FAILURE( |
+ QueryDisplayAttribEXT, |
+ "Failed to get the eglQueryDisplayAttribEXT function from ANGLE", |
+ device_object); |
+ } |
- RETURN_ON_FAILURE( |
- QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device), |
- "The eglQueryDisplayAttribEXT function failed to get the EGL device", |
- device_object); |
+ PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = nullptr; |
+ |
+ { |
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress"); |
+ |
+ QueryDeviceAttribEXT = |
+ reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(eglGetProcAddress( |
+ "eglQueryDeviceAttribEXT")); |
+ |
+ RETURN_ON_FAILURE( |
+ QueryDeviceAttribEXT, |
+ "Failed to get the eglQueryDeviceAttribEXT function from ANGLE", |
+ device_object); |
+ } |
+ |
+ { |
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT"); |
+ |
+ RETURN_ON_FAILURE( |
+ QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device), |
+ "The eglQueryDisplayAttribEXT function failed to get the EGL device", |
+ device_object); |
+ } |
RETURN_ON_FAILURE( |
egl_device, |
"Failed to get the EGL device", |
device_object); |
- RETURN_ON_FAILURE( |
- QueryDeviceAttribEXT( |
- reinterpret_cast<EGLDeviceEXT>(egl_device), object_type, &device), |
- "The eglQueryDeviceAttribEXT function failed to get the device", |
- device_object); |
+ { |
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT"); |
- RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object); |
+ RETURN_ON_FAILURE( |
+ QueryDeviceAttribEXT( |
+ reinterpret_cast<EGLDeviceEXT>(egl_device), object_type, &device), |
+ "The eglQueryDeviceAttribEXT function failed to get the device", |
+ device_object); |
+ |
+ RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object); |
+ } |
device_object = reinterpret_cast<T*>(device); |
return device_object; |
@@ -1341,17 +1371,19 @@ GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const { |
// static |
media::VideoDecodeAccelerator::SupportedProfiles |
DXVAVideoDecodeAccelerator::GetSupportedProfiles() { |
+ TRACE_EVENT0("gpu,startup", |
+ "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); |
+ 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 +1405,150 @@ void DXVAVideoDecodeAccelerator::PreSandboxInitialization() { |
} |
} |
+// static |
+std::pair<int, int> DXVAVideoDecodeAccelerator::GetMinResolution( |
+ media::VideoCodecProfile profile) { |
+ TRACE_EVENT0("gpu,startup", |
+ "DXVAVideoDecodeAccelerator::GetMinResolution"); |
+ 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) { |
+ TRACE_EVENT0("gpu,startup", |
+ "DXVAVideoDecodeAccelerator::GetMaxResolution"); |
+ 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() { |
+ TRACE_EVENT0("gpu,startup", |
+ "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. |
+ if (base::win::GetVersion() == base::win::VERSION_WIN7) |
+ 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; |
+ |
+ { |
+ TRACE_EVENT0("gpu,startup", |
+ "GetMaxH264Resolution. QueryDeviceObjectFromANGLE"); |
+ |
+ device = QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); |
+ if (!device.get()) |
+ return max_resolution; |
+ } |
+ |
+ base::win::ScopedComPtr<ID3D11VideoDevice> video_device; |
+ hr = device.QueryInterface(IID_ID3D11VideoDevice, |
+ video_device.ReceiveVoid()); |
+ if (FAILED(hr)) |
+ return max_resolution; |
+ |
+ GUID decoder_guid = {}; |
+ |
+ { |
+ TRACE_EVENT0("gpu,startup", |
+ "GetMaxH264Resolution. H.264 guid search begin"); |
+ // Enumerate supported video profiles and look for the H264 profile. |
+ 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) |
+ 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), |
+ }; |
+ |
+ { |
+ TRACE_EVENT0("gpu,startup", |
+ "GetMaxH264Resolution. Resolution search begin"); |
+ |
+ 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; |
+ |
+ D3D11_VIDEO_DECODER_CONFIG config = {}; |
+ hr = video_device->GetVideoDecoderConfig(&desc, 0, &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; |
+} |
+ |
bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { |
HMODULE decoder_dll = NULL; |
@@ -1737,7 +1913,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; |