| 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;
|
|
|