| 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 fffceb706fa9f1746844ccc2f7974c98684b6831..2fc53e7188acfd223d8cb847dd96e2b866adc4c9 100644
|
| --- a/content/common/gpu/media/dxva_video_decode_accelerator.cc
|
| +++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc
|
| @@ -14,21 +14,77 @@
|
| #include <mferror.h>
|
| #include <wmcodecdsp.h>
|
|
|
| +#include "base/base_paths_win.h"
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| #include "base/command_line.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/file_version_info.h"
|
| +#include "base/files/file_path.h"
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/memory/shared_memory.h"
|
| #include "base/message_loop/message_loop.h"
|
| +#include "base/path_service.h"
|
| #include "base/win/windows_version.h"
|
| #include "media/video/video_decode_accelerator.h"
|
| #include "ui/gl/gl_bindings.h"
|
| #include "ui/gl/gl_surface_egl.h"
|
| #include "ui/gl/gl_switches.h"
|
|
|
| +namespace {
|
| +
|
| +// Path is appended on to the PROGRAM_FILES base path.
|
| +const wchar_t kVPXDecoderDLLPath[] = L"Intel\\Media SDK\\";
|
| +
|
| +const wchar_t kVP8DecoderDLLName[] =
|
| +#if defined(ARCH_CPU_X86)
|
| + L"mfx_mft_vp8vd_32.dll";
|
| +#elif defined(ARCH_CPU_X86_64)
|
| + L"mfx_mft_vp8vd_64.dll";
|
| +#else
|
| +#error Unsupported Windows CPU Architecture
|
| +#endif
|
| +
|
| +const wchar_t kVP9DecoderDLLName[] =
|
| +#if defined(ARCH_CPU_X86)
|
| + L"mfx_mft_vp9vd_32.dll";
|
| +#elif defined(ARCH_CPU_X86_64)
|
| + L"mfx_mft_vp9vd_64.dll";
|
| +#else
|
| +#error Unsupported Windows CPU Architecture
|
| +#endif
|
| +
|
| +const CLSID CLSID_WebmMfVp8Dec = {
|
| + 0x451e3cb7,
|
| + 0x2622,
|
| + 0x4ba5,
|
| + { 0x8e, 0x1d, 0x44, 0xb3, 0xc4, 0x1d, 0x09, 0x24 }
|
| +};
|
| +
|
| +const CLSID CLSID_WebmMfVp9Dec = {
|
| + 0x07ab4bd2,
|
| + 0x1979,
|
| + 0x4fcd,
|
| + { 0xa6, 0x97, 0xdf, 0x9a, 0xd1, 0x5b, 0x34, 0xfe }
|
| +};
|
| +
|
| +const CLSID MEDIASUBTYPE_VP80 = {
|
| + 0x30385056,
|
| + 0x0000,
|
| + 0x0010,
|
| + { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
|
| +};
|
| +
|
| +const CLSID MEDIASUBTYPE_VP90 = {
|
| + 0x30395056,
|
| + 0x0000,
|
| + 0x0010,
|
| + { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
|
| +};
|
| +
|
| +}
|
| +
|
| namespace content {
|
|
|
| // We only request 5 picture buffers from the client which are used to hold the
|
| @@ -431,7 +487,8 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
|
| pictures_requested_(false),
|
| inputs_before_decode_(0),
|
| make_context_current_(make_context_current),
|
| - weak_this_factory_(this) {
|
| + weak_this_factory_(this),
|
| + codec_(media::kUnknownVideoCodec) {
|
| memset(&input_stream_info_, 0, sizeof(input_stream_info_));
|
| memset(&output_stream_info_, 0, sizeof(output_stream_info_));
|
| }
|
| @@ -458,9 +515,11 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
|
| // H264PROFILE_HIGH video decoding is janky at times. Needs more
|
| // investigation. http://crbug.com/426707
|
| if (profile != media::H264PROFILE_BASELINE &&
|
| - profile != media::H264PROFILE_MAIN) {
|
| + profile != media::H264PROFILE_MAIN &&
|
| + profile != media::VP8PROFILE_ANY &&
|
| + profile != media::VP9PROFILE_ANY) {
|
| RETURN_AND_NOTIFY_ON_FAILURE(false,
|
| - "Unsupported h264 profile", PLATFORM_FAILURE, false);
|
| + "Unsupported h.264, vp8, or vp9 profile", PLATFORM_FAILURE, false);
|
| }
|
|
|
| RETURN_AND_NOTIFY_ON_FAILURE(
|
| @@ -639,30 +698,51 @@ bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() {
|
| }
|
|
|
| bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
|
| - if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
|
| - return false;
|
| -
|
| - // We mimic the steps CoCreateInstance uses to instantiate the object. This
|
| - // was previously done because it failed inside the sandbox, and now is done
|
| - // as a more minimal approach to avoid other side-effects CCI might have (as
|
| - // we are still in a reduced sandbox).
|
| - HMODULE decoder_dll = ::LoadLibrary(L"msmpeg2vdec.dll");
|
| - RETURN_ON_FAILURE(decoder_dll,
|
| - "msmpeg2vdec.dll required for decoding is not loaded",
|
| - false);
|
| -
|
| - // Check version of DLL, version 6.7.7140 is blacklisted due to high crash
|
| - // rates in browsers loading that DLL. If that is the version installed we
|
| - // fall back to software decoding. See crbug/403440.
|
| - FileVersionInfo* version_info =
|
| - FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll);
|
| - RETURN_ON_FAILURE(version_info,
|
| - "unable to get version of msmpeg2vdec.dll",
|
| - false);
|
| - base::string16 file_version = version_info->file_version();
|
| - RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos,
|
| - "blacklisted version of msmpeg2vdec.dll 6.7.7140",
|
| - false);
|
| + HMODULE decoder_dll = NULL;
|
| +
|
| + // Profile must fall within the valid range for one of the supported codecs.
|
| + if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) {
|
| + // We mimic the steps CoCreateInstance uses to instantiate the object. This
|
| + // was previously done because it failed inside the sandbox, and now is done
|
| + // as a more minimal approach to avoid other side-effects CCI might have (as
|
| + // we are still in a reduced sandbox).
|
| + decoder_dll = ::LoadLibrary(L"msmpeg2vdec.dll");
|
| + RETURN_ON_FAILURE(decoder_dll,
|
| + "msmpeg2vdec.dll required for decoding is not loaded",
|
| + false);
|
| +
|
| + // Check version of DLL, version 6.7.7140 is blacklisted due to high crash
|
| + // rates in browsers loading that DLL. If that is the version installed we
|
| + // fall back to software decoding. See crbug/403440.
|
| + FileVersionInfo* version_info =
|
| + FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll);
|
| + RETURN_ON_FAILURE(version_info,
|
| + "unable to get version of msmpeg2vdec.dll",
|
| + false);
|
| + base::string16 file_version = version_info->file_version();
|
| + RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos,
|
| + "blacklisted version of msmpeg2vdec.dll 6.7.7140",
|
| + false);
|
| + codec_ = media::kCodecH264;
|
| + } else if (profile == media::VP8PROFILE_ANY ||
|
| + profile == media::VP9PROFILE_ANY) {
|
| + base::FilePath dll_path;
|
| + RETURN_ON_FAILURE(PathService::Get(base::DIR_PROGRAM_FILES, &dll_path),
|
| + "failed to get path for DIR_PROGRAM_FILES", false);
|
| + dll_path = dll_path.Append(kVPXDecoderDLLPath);
|
| + if (profile == media::VP8PROFILE_ANY) {
|
| + codec_ = media::kCodecVP8;
|
| + dll_path = dll_path.Append(kVP8DecoderDLLName);
|
| + } else {
|
| + codec_ = media::kCodecVP9;
|
| + dll_path = dll_path.Append(kVP9DecoderDLLName);
|
| + }
|
| + decoder_dll = ::LoadLibraryEx(dll_path.value().data(), NULL,
|
| + LOAD_WITH_ALTERED_SEARCH_PATH);
|
| + RETURN_ON_FAILURE(decoder_dll, "vpx decoder dll is not loaded", false);
|
| + } else {
|
| + RETURN_ON_FAILURE(false, "Unsupported codec.", false);
|
| + }
|
|
|
| typedef HRESULT(WINAPI * GetClassObject)(
|
| const CLSID & clsid, const IID & iid, void * *object);
|
| @@ -673,9 +753,22 @@ bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
|
| get_class_object, "Failed to get DllGetClassObject pointer", false);
|
|
|
| base::win::ScopedComPtr<IClassFactory> factory;
|
| - HRESULT hr = get_class_object(__uuidof(CMSH264DecoderMFT),
|
| - __uuidof(IClassFactory),
|
| - reinterpret_cast<void**>(factory.Receive()));
|
| + HRESULT hr;
|
| + if (codec_ == media::kCodecH264) {
|
| + hr = get_class_object(__uuidof(CMSH264DecoderMFT),
|
| + __uuidof(IClassFactory),
|
| + reinterpret_cast<void**>(factory.Receive()));
|
| + } else if (codec_ == media::kCodecVP8) {
|
| + hr = get_class_object(CLSID_WebmMfVp8Dec,
|
| + __uuidof(IClassFactory),
|
| + reinterpret_cast<void**>(factory.Receive()));
|
| + } else if (codec_ == media::kCodecVP9) {
|
| + hr = get_class_object(CLSID_WebmMfVp9Dec,
|
| + __uuidof(IClassFactory),
|
| + reinterpret_cast<void**>(factory.Receive()));
|
| + } else {
|
| + RETURN_ON_FAILURE(false, "Unsupported codec.", false);
|
| + }
|
| RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false);
|
|
|
| hr = factory->CreateInstance(NULL,
|
| @@ -725,8 +818,11 @@ bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() {
|
| hr = attributes->GetUINT32(MF_SA_D3D_AWARE, &dxva);
|
| RETURN_ON_HR_FAILURE(hr, "Failed to check if decoder supports DXVA", false);
|
|
|
| - hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false);
|
| + if (codec_ == media::kCodecH264) {
|
| + hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false);
|
| + }
|
| +
|
| return true;
|
| }
|
|
|
| @@ -744,7 +840,16 @@ bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() {
|
| hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
|
| RETURN_ON_HR_FAILURE(hr, "Failed to set major input type", false);
|
|
|
| - hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
|
| + if (codec_ == media::kCodecH264) {
|
| + hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
|
| + } else if (codec_ == media::kCodecVP8) {
|
| + hr = media_type->SetGUID(MF_MT_SUBTYPE, MEDIASUBTYPE_VP80);
|
| + } else if (codec_ == media::kCodecVP9) {
|
| + hr = media_type->SetGUID(MF_MT_SUBTYPE, MEDIASUBTYPE_VP90);
|
| + } else {
|
| + NOTREACHED();
|
| + RETURN_ON_FAILURE(false, "Unsupported codec on input media type.", false);
|
| + }
|
| RETURN_ON_HR_FAILURE(hr, "Failed to set subtype", false);
|
|
|
| // Not sure about this. msdn recommends setting this value on the input
|
| @@ -798,10 +903,12 @@ bool DXVAVideoDecodeAccelerator::GetStreamsInfoAndBufferReqs() {
|
|
|
| DVLOG(1) << "Input stream info: ";
|
| DVLOG(1) << "Max latency: " << input_stream_info_.hnsMaxLatency;
|
| - // There should be three flags, one for requiring a whole frame be in a
|
| - // single sample, one for requiring there be one buffer only in a single
|
| - // sample, and one that specifies a fixed sample size. (as in cbSize)
|
| - CHECK_EQ(input_stream_info_.dwFlags, 0x7u);
|
| + if (codec_ == media::kCodecH264) {
|
| + // There should be three flags, one for requiring a whole frame be in a
|
| + // single sample, one for requiring there be one buffer only in a single
|
| + // sample, and one that specifies a fixed sample size. (as in cbSize)
|
| + CHECK_EQ(input_stream_info_.dwFlags, 0x7u);
|
| + }
|
|
|
| DVLOG(1) << "Min buffer size: " << input_stream_info_.cbSize;
|
| DVLOG(1) << "Max lookahead: " << input_stream_info_.cbMaxLookahead;
|
| @@ -813,7 +920,9 @@ bool DXVAVideoDecodeAccelerator::GetStreamsInfoAndBufferReqs() {
|
| // allocate its own sample.
|
| DVLOG(1) << "Flags: "
|
| << std::hex << std::showbase << output_stream_info_.dwFlags;
|
| - CHECK_EQ(output_stream_info_.dwFlags, 0x107u);
|
| + if (codec_ == media::kCodecH264) {
|
| + CHECK_EQ(output_stream_info_.dwFlags, 0x107u);
|
| + }
|
| DVLOG(1) << "Min buffer size: " << output_stream_info_.cbSize;
|
| DVLOG(1) << "Alignment: " << output_stream_info_.cbAlignment;
|
| return true;
|
|
|