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

Unified Diff: content/common/gpu/media/dxva_video_decode_accelerator_win.cc

Issue 1851713002: Add support for detecting the maximum resolution supported by the GPU for H.264 videos. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix indentation Created 4 years, 9 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/common/gpu/media/dxva_video_decode_accelerator_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
« no previous file with comments | « content/common/gpu/media/dxva_video_decode_accelerator_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698