| 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 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 #endif | 102 #endif |
| 103 | 103 |
| 104 // MF_XVP_PLAYBACK_MODE | 104 // MF_XVP_PLAYBACK_MODE |
| 105 // Data type: UINT32 (treat as BOOL) | 105 // Data type: UINT32 (treat as BOOL) |
| 106 // If this attribute is TRUE, the video processor will run in playback mode | 106 // If this attribute is TRUE, the video processor will run in playback mode |
| 107 // where it allows callers to allocate output samples and allows last frame | 107 // where it allows callers to allocate output samples and allows last frame |
| 108 // regeneration (repaint). | 108 // regeneration (repaint). |
| 109 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, | 109 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, |
| 110 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); | 110 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); |
| 111 | 111 |
| 112 // Helper class to automatically lock unlock the DX11 device in a scope. |
| 113 class AutoDX11DeviceLock { |
| 114 public: |
| 115 explicit AutoDX11DeviceLock(ID3D10Multithread* multi_threaded) |
| 116 : multi_threaded_(multi_threaded) { |
| 117 multi_threaded_->Enter(); |
| 118 } |
| 119 |
| 120 ~AutoDX11DeviceLock() { |
| 121 multi_threaded_->Leave(); |
| 122 } |
| 123 |
| 124 private: |
| 125 base::win::ScopedComPtr<ID3D10Multithread> multi_threaded_; |
| 126 |
| 127 DISALLOW_COPY_AND_ASSIGN(AutoDX11DeviceLock); |
| 128 }; |
| 129 |
| 112 } // namespace | 130 } // namespace |
| 113 | 131 |
| 114 namespace content { | 132 namespace content { |
| 115 | 133 |
| 116 static const media::VideoCodecProfile kSupportedProfiles[] = { | 134 static const media::VideoCodecProfile kSupportedProfiles[] = { |
| 117 media::H264PROFILE_BASELINE, | 135 media::H264PROFILE_BASELINE, |
| 118 media::H264PROFILE_MAIN, | 136 media::H264PROFILE_MAIN, |
| 119 media::H264PROFILE_HIGH, | 137 media::H264PROFILE_HIGH, |
| 120 media::VP8PROFILE_ANY, | 138 media::VP8PROFILE_ANY, |
| 121 media::VP9PROFILE_ANY | 139 media::VP9PROFILE_ANY |
| (...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 | 800 |
| 783 base::win::ScopedComPtr<ID3D11Device> angle_device = | 801 base::win::ScopedComPtr<ID3D11Device> angle_device = |
| 784 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); | 802 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); |
| 785 RETURN_ON_FAILURE( | 803 RETURN_ON_FAILURE( |
| 786 angle_device.get(), | 804 angle_device.get(), |
| 787 "Failed to query DX11 device object from ANGLE", | 805 "Failed to query DX11 device object from ANGLE", |
| 788 false); | 806 false); |
| 789 | 807 |
| 790 using_angle_device_ = true; | 808 using_angle_device_ = true; |
| 791 d3d11_device_ = angle_device; | 809 d3d11_device_ = angle_device; |
| 792 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); | |
| 793 RETURN_ON_FAILURE( | |
| 794 d3d11_device_context_.get(), | |
| 795 "Failed to query DX11 device context from ANGLE device", | |
| 796 false); | |
| 797 | 810 |
| 798 // Enable multithreaded mode on the device. This ensures that accesses to | 811 // Enable multithreaded mode on the device. This ensures that accesses to |
| 799 // context are synchronized across threads. We have multiple threads | 812 // context are synchronized across threads. We have multiple threads |
| 800 // accessing the context, the media foundation decoder threads and the | 813 // accessing the context, the media foundation decoder threads and the |
| 801 // decoder thread via the video format conversion transform. | 814 // decoder thread via the video format conversion transform. |
| 802 hr = multi_threaded_.QueryFrom(angle_device.get()); | 815 hr = multi_threaded_.QueryFrom(angle_device.get()); |
| 803 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); | 816 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); |
| 804 multi_threaded_->SetMultithreadProtected(TRUE); | 817 multi_threaded_->SetMultithreadProtected(TRUE); |
| 805 | 818 |
| 806 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), | 819 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), |
| 807 dx11_dev_manager_reset_token_); | 820 dx11_dev_manager_reset_token_); |
| 808 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 821 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 809 | 822 |
| 810 D3D11_QUERY_DESC query_desc; | |
| 811 query_desc.Query = D3D11_QUERY_EVENT; | |
| 812 query_desc.MiscFlags = 0; | |
| 813 hr = d3d11_device_->CreateQuery( | |
| 814 &query_desc, | |
| 815 d3d11_query_.Receive()); | |
| 816 RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false); | |
| 817 | |
| 818 HMODULE video_processor_dll = ::GetModuleHandle(L"msvproc.dll"); | 823 HMODULE video_processor_dll = ::GetModuleHandle(L"msvproc.dll"); |
| 819 RETURN_ON_FAILURE(video_processor_dll, "Failed to load video processor", | 824 RETURN_ON_FAILURE(video_processor_dll, "Failed to load video processor", |
| 820 false); | 825 false); |
| 821 | 826 |
| 822 hr = CreateCOMObjectFromDll( | 827 hr = CreateCOMObjectFromDll( |
| 823 video_processor_dll, | 828 video_processor_dll, |
| 824 CLSID_VideoProcessorMFT, | 829 CLSID_VideoProcessorMFT, |
| 825 __uuidof(IMFTransform), | 830 __uuidof(IMFTransform), |
| 826 video_format_converter_mft_.ReceiveVoid()); | 831 video_format_converter_mft_.ReceiveVoid()); |
| 827 if (FAILED(hr)) { | 832 if (FAILED(hr)) { |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1515 pending_output_samples_.clear(); | 1520 pending_output_samples_.clear(); |
| 1516 pending_input_buffers_.clear(); | 1521 pending_input_buffers_.clear(); |
| 1517 decoder_.Release(); | 1522 decoder_.Release(); |
| 1518 | 1523 |
| 1519 if (use_dx11_) { | 1524 if (use_dx11_) { |
| 1520 if (video_format_converter_mft_.get()) { | 1525 if (video_format_converter_mft_.get()) { |
| 1521 video_format_converter_mft_->ProcessMessage( | 1526 video_format_converter_mft_->ProcessMessage( |
| 1522 MFT_MESSAGE_NOTIFY_END_STREAMING, 0); | 1527 MFT_MESSAGE_NOTIFY_END_STREAMING, 0); |
| 1523 video_format_converter_mft_.Release(); | 1528 video_format_converter_mft_.Release(); |
| 1524 } | 1529 } |
| 1525 d3d11_device_context_.Release(); | |
| 1526 d3d11_device_.Release(); | 1530 d3d11_device_.Release(); |
| 1527 d3d11_device_manager_.Release(); | 1531 d3d11_device_manager_.Release(); |
| 1528 d3d11_query_.Release(); | |
| 1529 dx11_video_format_converter_media_type_needs_init_ = true; | 1532 dx11_video_format_converter_media_type_needs_init_ = true; |
| 1530 } else { | 1533 } else { |
| 1531 d3d9_.Release(); | 1534 d3d9_.Release(); |
| 1532 d3d9_device_ex_.Release(); | 1535 d3d9_device_ex_.Release(); |
| 1533 device_manager_.Release(); | 1536 device_manager_.Release(); |
| 1534 query_.Release(); | 1537 query_.Release(); |
| 1535 } | 1538 } |
| 1536 | 1539 |
| 1537 SetState(kUninitialized); | 1540 SetState(kUninitialized); |
| 1538 } | 1541 } |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1991 return; | 1994 return; |
| 1992 } | 1995 } |
| 1993 | 1996 |
| 1994 DCHECK(video_frame); | 1997 DCHECK(video_frame); |
| 1995 | 1998 |
| 1996 base::win::ScopedComPtr<IMFSample> input_sample; | 1999 base::win::ScopedComPtr<IMFSample> input_sample; |
| 1997 input_sample.Attach(video_frame); | 2000 input_sample.Attach(video_frame); |
| 1998 | 2001 |
| 1999 DCHECK(video_format_converter_mft_.get()); | 2002 DCHECK(video_format_converter_mft_.get()); |
| 2000 | 2003 |
| 2001 // d3d11_device_context_->Begin(d3d11_query_.get()); | |
| 2002 | |
| 2003 hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0); | |
| 2004 if (FAILED(hr)) { | |
| 2005 DCHECK(false); | |
| 2006 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
| 2007 "Failed to convert output sample format.", PLATFORM_FAILURE,); | |
| 2008 } | |
| 2009 | |
| 2010 // The video processor MFT requires output samples to be allocated by the | 2004 // The video processor MFT requires output samples to be allocated by the |
| 2011 // caller. We create a sample with a buffer backed with the ID3D11Texture2D | 2005 // caller. We create a sample with a buffer backed with the ID3D11Texture2D |
| 2012 // interface exposed by ANGLE. This works nicely as this ensures that the | 2006 // interface exposed by ANGLE. This works nicely as this ensures that the |
| 2013 // video processor coverts the color space of the output frame and copies | 2007 // video processor coverts the color space of the output frame and copies |
| 2014 // the result into the ANGLE texture. | 2008 // the result into the ANGLE texture. |
| 2015 base::win::ScopedComPtr<IMFSample> output_sample; | 2009 base::win::ScopedComPtr<IMFSample> output_sample; |
| 2016 hr = MFCreateSample(output_sample.Receive()); | 2010 hr = MFCreateSample(output_sample.Receive()); |
| 2017 if (FAILED(hr)) { | 2011 if (FAILED(hr)) { |
| 2018 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2012 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2019 "Failed to create output sample.", PLATFORM_FAILURE,); | 2013 "Failed to create output sample.", PLATFORM_FAILURE,); |
| 2020 } | 2014 } |
| 2021 | 2015 |
| 2022 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | 2016 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; |
| 2023 hr = MFCreateDXGISurfaceBuffer( | 2017 hr = MFCreateDXGISurfaceBuffer( |
| 2024 __uuidof(ID3D11Texture2D), dest_texture, 0, FALSE, | 2018 __uuidof(ID3D11Texture2D), dest_texture, 0, FALSE, |
| 2025 output_buffer.Receive()); | 2019 output_buffer.Receive()); |
| 2026 if (FAILED(hr)) { | 2020 if (FAILED(hr)) { |
| 2027 base::debug::Alias(&hr); | 2021 base::debug::Alias(&hr); |
| 2028 // TODO(ananta) | 2022 // TODO(ananta) |
| 2029 // Remove this CHECK when the change to use DX11 for H/W decoding | 2023 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2030 // stablizes. | 2024 // stablizes. |
| 2031 CHECK(false); | 2025 CHECK(false); |
| 2032 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2026 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2033 "Failed to create output sample.", PLATFORM_FAILURE,); | 2027 "Failed to create output sample.", PLATFORM_FAILURE,); |
| 2034 } | 2028 } |
| 2035 | 2029 |
| 2036 output_sample->AddBuffer(output_buffer.get()); | 2030 output_sample->AddBuffer(output_buffer.get()); |
| 2037 | 2031 |
| 2038 // Lock the device here as we are accessing the destination texture created | 2032 // Lock the device here as we are accessing the DX11 video context and the |
| 2039 // on the main thread. | 2033 // texture which need to be synchronized with the main thread. |
| 2040 multi_threaded_->Enter(); | 2034 AutoDX11DeviceLock device_lock(multi_threaded_.get()); |
| 2035 |
| 2036 hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0); |
| 2037 if (FAILED(hr)) { |
| 2038 DCHECK(false); |
| 2039 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2040 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2041 } |
| 2041 | 2042 |
| 2042 DWORD status = 0; | 2043 DWORD status = 0; |
| 2043 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; | 2044 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; |
| 2044 format_converter_output.pSample = output_sample.get(); | 2045 format_converter_output.pSample = output_sample.get(); |
| 2045 hr = video_format_converter_mft_->ProcessOutput( | 2046 hr = video_format_converter_mft_->ProcessOutput( |
| 2046 0, // No flags | 2047 0, // No flags |
| 2047 1, // # of out streams to pull from | 2048 1, // # of out streams to pull from |
| 2048 &format_converter_output, | 2049 &format_converter_output, |
| 2049 &status); | 2050 &status); |
| 2050 | 2051 |
| 2051 d3d11_device_context_->Flush(); | |
| 2052 d3d11_device_context_->End(d3d11_query_.get()); | |
| 2053 | |
| 2054 multi_threaded_->Leave(); | |
| 2055 | |
| 2056 if (FAILED(hr)) { | 2052 if (FAILED(hr)) { |
| 2057 base::debug::Alias(&hr); | 2053 base::debug::Alias(&hr); |
| 2058 // TODO(ananta) | 2054 // TODO(ananta) |
| 2059 // Remove this CHECK when the change to use DX11 for H/W decoding | 2055 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2060 // stablizes. | 2056 // stablizes. |
| 2061 CHECK(false); | 2057 CHECK(false); |
| 2062 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2058 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2063 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2059 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2064 } | 2060 } |
| 2065 | 2061 |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2227 if (FAILED(hr)) { | 2223 if (FAILED(hr)) { |
| 2228 base::debug::Alias(&hr); | 2224 base::debug::Alias(&hr); |
| 2229 // TODO(ananta) | 2225 // TODO(ananta) |
| 2230 // Remove this CHECK when the change to use DX11 for H/W decoding | 2226 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2231 // stablizes. | 2227 // stablizes. |
| 2232 CHECK(false); | 2228 CHECK(false); |
| 2233 } | 2229 } |
| 2234 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2230 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2235 "Failed to set converter output type", PLATFORM_FAILURE, false); | 2231 "Failed to set converter output type", PLATFORM_FAILURE, false); |
| 2236 | 2232 |
| 2237 hr = video_format_converter_mft_->ProcessMessage( | |
| 2238 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); | |
| 2239 if (FAILED(hr)) { | |
| 2240 // TODO(ananta) | |
| 2241 // Remove this CHECK when the change to use DX11 for H/W decoding | |
| 2242 // stablizes. | |
| 2243 RETURN_AND_NOTIFY_ON_FAILURE( | |
| 2244 false, "Failed to initialize video converter.", PLATFORM_FAILURE, | |
| 2245 false); | |
| 2246 } | |
| 2247 dx11_video_format_converter_media_type_needs_init_ = false; | 2233 dx11_video_format_converter_media_type_needs_init_ = false; |
| 2248 return true; | 2234 return true; |
| 2249 } | 2235 } |
| 2250 out_media_type.Release(); | 2236 out_media_type.Release(); |
| 2251 } | 2237 } |
| 2252 return false; | 2238 return false; |
| 2253 } | 2239 } |
| 2254 | 2240 |
| 2255 bool DXVAVideoDecodeAccelerator::GetVideoFrameDimensions( | 2241 bool DXVAVideoDecodeAccelerator::GetVideoFrameDimensions( |
| 2256 IMFSample* sample, | 2242 IMFSample* sample, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2284 D3DSURFACE_DESC surface_desc; | 2270 D3DSURFACE_DESC surface_desc; |
| 2285 hr = surface->GetDesc(&surface_desc); | 2271 hr = surface->GetDesc(&surface_desc); |
| 2286 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 2272 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
| 2287 *width = surface_desc.Width; | 2273 *width = surface_desc.Width; |
| 2288 *height = surface_desc.Height; | 2274 *height = surface_desc.Height; |
| 2289 } | 2275 } |
| 2290 return true; | 2276 return true; |
| 2291 } | 2277 } |
| 2292 | 2278 |
| 2293 } // namespace content | 2279 } // namespace content |
| OLD | NEW |