OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" |
6 | 6 |
7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
10 | 10 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, | 93 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, |
94 0xc9, 0x82); | 94 0xc9, 0x82); |
95 | 95 |
96 // MF_XVP_PLAYBACK_MODE | 96 // MF_XVP_PLAYBACK_MODE |
97 // Data type: UINT32 (treat as BOOL) | 97 // Data type: UINT32 (treat as BOOL) |
98 // If this attribute is TRUE, the video processor will run in playback mode | 98 // If this attribute is TRUE, the video processor will run in playback mode |
99 // where it allows callers to allocate output samples and allows last frame | 99 // where it allows callers to allocate output samples and allows last frame |
100 // regeneration (repaint). | 100 // regeneration (repaint). |
101 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, | 101 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, |
102 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); | 102 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); |
103 } | 103 |
| 104 } // namespace |
104 | 105 |
105 namespace content { | 106 namespace content { |
106 | 107 |
107 static const media::VideoCodecProfile kSupportedProfiles[] = { | 108 static const media::VideoCodecProfile kSupportedProfiles[] = { |
108 media::H264PROFILE_BASELINE, | 109 media::H264PROFILE_BASELINE, |
109 media::H264PROFILE_MAIN, | 110 media::H264PROFILE_MAIN, |
110 media::H264PROFILE_HIGH, | 111 media::H264PROFILE_HIGH, |
111 media::VP8PROFILE_ANY, | 112 media::VP8PROFILE_ANY, |
112 media::VP9PROFILE_ANY | 113 media::VP9PROFILE_ANY |
113 }; | 114 }; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 base::SharedMemory shm(bitstream_buffer.handle(), true); | 235 base::SharedMemory shm(bitstream_buffer.handle(), true); |
235 RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()), | 236 RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()), |
236 "Failed in base::SharedMemory::Map", NULL); | 237 "Failed in base::SharedMemory::Map", NULL); |
237 | 238 |
238 return CreateInputSample(reinterpret_cast<const uint8*>(shm.memory()), | 239 return CreateInputSample(reinterpret_cast<const uint8*>(shm.memory()), |
239 bitstream_buffer.size(), | 240 bitstream_buffer.size(), |
240 stream_size, | 241 stream_size, |
241 alignment); | 242 alignment); |
242 } | 243 } |
243 | 244 |
| 245 // Helper function to create a COM object instance from a DLL. The alternative |
| 246 // is to use the CoCreateInstance API which requires the COM apartment to be |
| 247 // initialized which is not the case on the GPU main thread. We want to avoid |
| 248 // initializing COM as it may have sideeffects. |
| 249 HRESULT CreateCOMObjectFromDll(HMODULE dll, const CLSID& clsid, const IID& iid, |
| 250 void** object) { |
| 251 if (!dll || !object) |
| 252 return E_INVALIDARG; |
| 253 |
| 254 using GetClassObject = HRESULT (WINAPI*)( |
| 255 const CLSID& clsid, const IID& iid, void** object); |
| 256 |
| 257 GetClassObject get_class_object = reinterpret_cast<GetClassObject>( |
| 258 GetProcAddress(dll, "DllGetClassObject")); |
| 259 RETURN_ON_FAILURE( |
| 260 get_class_object, "Failed to get DllGetClassObject pointer", false); |
| 261 |
| 262 base::win::ScopedComPtr<IClassFactory> factory; |
| 263 HRESULT hr = get_class_object( |
| 264 clsid, |
| 265 __uuidof(IClassFactory), |
| 266 factory.ReceiveVoid()); |
| 267 RETURN_ON_HR_FAILURE(hr, "DllGetClassObject failed", false); |
| 268 |
| 269 hr = factory->CreateInstance(NULL, iid, object); |
| 270 return hr; |
| 271 } |
| 272 |
244 // Maintains information about a DXVA picture buffer, i.e. whether it is | 273 // Maintains information about a DXVA picture buffer, i.e. whether it is |
245 // available for rendering, the texture information, etc. | 274 // available for rendering, the texture information, etc. |
246 struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { | 275 struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { |
247 public: | 276 public: |
248 static linked_ptr<DXVAPictureBuffer> Create( | 277 static linked_ptr<DXVAPictureBuffer> Create( |
249 const DXVAVideoDecodeAccelerator& decoder, | 278 const DXVAVideoDecodeAccelerator& decoder, |
250 const media::PictureBuffer& buffer, | 279 const media::PictureBuffer& buffer, |
251 EGLConfig egl_config); | 280 EGLConfig egl_config); |
252 ~DXVAPictureBuffer(); | 281 ~DXVAPictureBuffer(); |
253 | 282 |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
720 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 749 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
721 | 750 |
722 D3D11_QUERY_DESC query_desc; | 751 D3D11_QUERY_DESC query_desc; |
723 query_desc.Query = D3D11_QUERY_EVENT; | 752 query_desc.Query = D3D11_QUERY_EVENT; |
724 query_desc.MiscFlags = 0; | 753 query_desc.MiscFlags = 0; |
725 hr = d3d11_device_->CreateQuery( | 754 hr = d3d11_device_->CreateQuery( |
726 &query_desc, | 755 &query_desc, |
727 d3d11_query_.Receive()); | 756 d3d11_query_.Receive()); |
728 RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false); | 757 RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false); |
729 | 758 |
730 hr = ::CoCreateInstance( | 759 HMODULE video_processor_dll = ::LoadLibrary(L"msvproc.dll"); |
| 760 RETURN_ON_FAILURE(video_processor_dll, "Failed to load video processor", |
| 761 false); |
| 762 |
| 763 hr = CreateCOMObjectFromDll( |
| 764 video_processor_dll, |
731 CLSID_VideoProcessorMFT, | 765 CLSID_VideoProcessorMFT, |
732 NULL, | 766 __uuidof(IMFTransform), |
733 CLSCTX_INPROC_SERVER, | 767 video_format_converter_mft_.ReceiveVoid()); |
734 IID_IMFTransform, | |
735 reinterpret_cast<void**>(video_format_converter_mft_.Receive())); | |
736 | |
737 if (FAILED(hr)) { | 768 if (FAILED(hr)) { |
738 base::debug::Alias(&hr); | 769 base::debug::Alias(&hr); |
739 // TODO(ananta) | 770 // TODO(ananta) |
740 // Remove this CHECK when the change to use DX11 for H/W decoding | 771 // Remove this CHECK when the change to use DX11 for H/W decoding |
741 // stablizes. | 772 // stablizes. |
742 CHECK(false); | 773 CHECK(false); |
743 } | 774 } |
| 775 |
744 RETURN_ON_HR_FAILURE(hr, "Failed to create video format converter", false); | 776 RETURN_ON_HR_FAILURE(hr, "Failed to create video format converter", false); |
745 return true; | 777 return true; |
746 } | 778 } |
747 | 779 |
748 void DXVAVideoDecodeAccelerator::Decode( | 780 void DXVAVideoDecodeAccelerator::Decode( |
749 const media::BitstreamBuffer& bitstream_buffer) { | 781 const media::BitstreamBuffer& bitstream_buffer) { |
750 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 782 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
751 | 783 |
752 State state = GetState(); | 784 State state = GetState(); |
753 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || | 785 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
936 // Use 1088 to account for 16x16 macroblocks. | 968 // Use 1088 to account for 16x16 macroblocks. |
937 profile.max_resolution.SetSize(1920, 1088); | 969 profile.max_resolution.SetSize(1920, 1088); |
938 profiles.push_back(profile); | 970 profiles.push_back(profile); |
939 } | 971 } |
940 return profiles; | 972 return profiles; |
941 } | 973 } |
942 | 974 |
943 bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { | 975 bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { |
944 HMODULE decoder_dll = NULL; | 976 HMODULE decoder_dll = NULL; |
945 | 977 |
| 978 CLSID clsid = {}; |
| 979 |
946 // Profile must fall within the valid range for one of the supported codecs. | 980 // Profile must fall within the valid range for one of the supported codecs. |
947 if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) { | 981 if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) { |
948 // We mimic the steps CoCreateInstance uses to instantiate the object. This | 982 // We mimic the steps CoCreateInstance uses to instantiate the object. This |
949 // was previously done because it failed inside the sandbox, and now is done | 983 // was previously done because it failed inside the sandbox, and now is done |
950 // as a more minimal approach to avoid other side-effects CCI might have (as | 984 // as a more minimal approach to avoid other side-effects CCI might have (as |
951 // we are still in a reduced sandbox). | 985 // we are still in a reduced sandbox). |
952 decoder_dll = ::LoadLibrary(L"msmpeg2vdec.dll"); | 986 decoder_dll = ::LoadLibrary(L"msmpeg2vdec.dll"); |
953 RETURN_ON_FAILURE(decoder_dll, | 987 RETURN_ON_FAILURE(decoder_dll, |
954 "msmpeg2vdec.dll required for decoding is not loaded", | 988 "msmpeg2vdec.dll required for decoding is not loaded", |
955 false); | 989 false); |
956 | 990 |
957 // Check version of DLL, version 6.7.7140 is blacklisted due to high crash | 991 // Check version of DLL, version 6.7.7140 is blacklisted due to high crash |
958 // rates in browsers loading that DLL. If that is the version installed we | 992 // rates in browsers loading that DLL. If that is the version installed we |
959 // fall back to software decoding. See crbug/403440. | 993 // fall back to software decoding. See crbug/403440. |
960 FileVersionInfo* version_info = | 994 FileVersionInfo* version_info = |
961 FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll); | 995 FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll); |
962 RETURN_ON_FAILURE(version_info, | 996 RETURN_ON_FAILURE(version_info, |
963 "unable to get version of msmpeg2vdec.dll", | 997 "unable to get version of msmpeg2vdec.dll", |
964 false); | 998 false); |
965 base::string16 file_version = version_info->file_version(); | 999 base::string16 file_version = version_info->file_version(); |
966 RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos, | 1000 RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos, |
967 "blacklisted version of msmpeg2vdec.dll 6.7.7140", | 1001 "blacklisted version of msmpeg2vdec.dll 6.7.7140", |
968 false); | 1002 false); |
969 codec_ = media::kCodecH264; | 1003 codec_ = media::kCodecH264; |
| 1004 clsid = __uuidof(CMSH264DecoderMFT); |
970 } else if (profile == media::VP8PROFILE_ANY || | 1005 } else if (profile == media::VP8PROFILE_ANY || |
971 profile == media::VP9PROFILE_ANY) { | 1006 profile == media::VP9PROFILE_ANY) { |
972 int program_files_key = base::DIR_PROGRAM_FILES; | 1007 int program_files_key = base::DIR_PROGRAM_FILES; |
973 if (base::win::OSInfo::GetInstance()->wow64_status() == | 1008 if (base::win::OSInfo::GetInstance()->wow64_status() == |
974 base::win::OSInfo::WOW64_ENABLED) { | 1009 base::win::OSInfo::WOW64_ENABLED) { |
975 program_files_key = base::DIR_PROGRAM_FILES6432; | 1010 program_files_key = base::DIR_PROGRAM_FILES6432; |
976 } | 1011 } |
977 | 1012 |
978 base::FilePath dll_path; | 1013 base::FilePath dll_path; |
979 RETURN_ON_FAILURE(PathService::Get(program_files_key, &dll_path), | 1014 RETURN_ON_FAILURE(PathService::Get(program_files_key, &dll_path), |
980 "failed to get path for Program Files", false); | 1015 "failed to get path for Program Files", false); |
981 | 1016 |
982 dll_path = dll_path.Append(kVPXDecoderDLLPath); | 1017 dll_path = dll_path.Append(kVPXDecoderDLLPath); |
983 if (profile == media::VP8PROFILE_ANY) { | 1018 if (profile == media::VP8PROFILE_ANY) { |
984 codec_ = media::kCodecVP8; | 1019 codec_ = media::kCodecVP8; |
985 dll_path = dll_path.Append(kVP8DecoderDLLName); | 1020 dll_path = dll_path.Append(kVP8DecoderDLLName); |
| 1021 clsid = CLSID_WebmMfVp8Dec; |
986 } else { | 1022 } else { |
987 codec_ = media::kCodecVP9; | 1023 codec_ = media::kCodecVP9; |
988 dll_path = dll_path.Append(kVP9DecoderDLLName); | 1024 dll_path = dll_path.Append(kVP9DecoderDLLName); |
| 1025 clsid = CLSID_WebmMfVp9Dec; |
989 } | 1026 } |
990 decoder_dll = ::LoadLibraryEx(dll_path.value().data(), NULL, | 1027 decoder_dll = ::LoadLibraryEx(dll_path.value().data(), NULL, |
991 LOAD_WITH_ALTERED_SEARCH_PATH); | 1028 LOAD_WITH_ALTERED_SEARCH_PATH); |
992 RETURN_ON_FAILURE(decoder_dll, "vpx decoder dll is not loaded", false); | 1029 RETURN_ON_FAILURE(decoder_dll, "vpx decoder dll is not loaded", false); |
993 } else { | 1030 } else { |
994 RETURN_ON_FAILURE(false, "Unsupported codec.", false); | 1031 RETURN_ON_FAILURE(false, "Unsupported codec.", false); |
995 } | 1032 } |
996 | 1033 |
997 typedef HRESULT(WINAPI * GetClassObject)( | 1034 HRESULT hr = CreateCOMObjectFromDll(decoder_dll, |
998 const CLSID & clsid, const IID & iid, void * *object); | 1035 clsid, |
999 | 1036 __uuidof(IMFTransform), |
1000 GetClassObject get_class_object = reinterpret_cast<GetClassObject>( | 1037 decoder_.ReceiveVoid()); |
1001 GetProcAddress(decoder_dll, "DllGetClassObject")); | |
1002 RETURN_ON_FAILURE( | |
1003 get_class_object, "Failed to get DllGetClassObject pointer", false); | |
1004 | |
1005 base::win::ScopedComPtr<IClassFactory> factory; | |
1006 HRESULT hr; | |
1007 if (codec_ == media::kCodecH264) { | |
1008 hr = get_class_object(__uuidof(CMSH264DecoderMFT), | |
1009 __uuidof(IClassFactory), | |
1010 reinterpret_cast<void**>(factory.Receive())); | |
1011 } else if (codec_ == media::kCodecVP8) { | |
1012 hr = get_class_object(CLSID_WebmMfVp8Dec, | |
1013 __uuidof(IClassFactory), | |
1014 reinterpret_cast<void**>(factory.Receive())); | |
1015 } else if (codec_ == media::kCodecVP9) { | |
1016 hr = get_class_object(CLSID_WebmMfVp9Dec, | |
1017 __uuidof(IClassFactory), | |
1018 reinterpret_cast<void**>(factory.Receive())); | |
1019 } else { | |
1020 RETURN_ON_FAILURE(false, "Unsupported codec.", false); | |
1021 } | |
1022 RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false); | |
1023 | |
1024 hr = factory->CreateInstance(NULL, | |
1025 __uuidof(IMFTransform), | |
1026 reinterpret_cast<void**>(decoder_.Receive())); | |
1027 RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); | 1038 RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); |
1028 | 1039 |
1029 RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), | 1040 RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), |
1030 "Failed to check decoder DXVA support", false); | 1041 "Failed to check decoder DXVA support", false); |
1031 | 1042 |
1032 ULONG_PTR device_manager_to_use = NULL; | 1043 ULONG_PTR device_manager_to_use = NULL; |
1033 if (use_dx11_) { | 1044 if (use_dx11_) { |
1034 CHECK(create_dxgi_device_manager_); | 1045 CHECK(create_dxgi_device_manager_); |
1035 RETURN_AND_NOTIFY_ON_FAILURE(CreateDX11DevManager(), | 1046 RETURN_AND_NOTIFY_ON_FAILURE(CreateDX11DevManager(), |
1036 "Failed to initialize DX11 device and manager", | 1047 "Failed to initialize DX11 device and manager", |
(...skipping 1150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2187 D3DSURFACE_DESC surface_desc; | 2198 D3DSURFACE_DESC surface_desc; |
2188 hr = surface->GetDesc(&surface_desc); | 2199 hr = surface->GetDesc(&surface_desc); |
2189 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 2200 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
2190 *width = surface_desc.Width; | 2201 *width = surface_desc.Width; |
2191 *height = surface_desc.Height; | 2202 *height = surface_desc.Height; |
2192 } | 2203 } |
2193 return true; | 2204 return true; |
2194 } | 2205 } |
2195 | 2206 |
2196 } // namespace content | 2207 } // namespace content |
OLD | NEW |