| 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_win.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator_win.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 | |
| 130 } // namespace | 112 } // namespace |
| 131 | 113 |
| 132 namespace content { | 114 namespace content { |
| 133 | 115 |
| 134 static const media::VideoCodecProfile kSupportedProfiles[] = { | 116 static const media::VideoCodecProfile kSupportedProfiles[] = { |
| 135 media::H264PROFILE_BASELINE, | 117 media::H264PROFILE_BASELINE, |
| 136 media::H264PROFILE_MAIN, | 118 media::H264PROFILE_MAIN, |
| 137 media::H264PROFILE_HIGH, | 119 media::H264PROFILE_HIGH, |
| 138 media::VP8PROFILE_ANY, | 120 media::VP8PROFILE_ANY, |
| 139 media::VP9PROFILE_ANY | 121 media::VP9PROFILE_ANY |
| (...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 hr = query_->Issue(D3DISSUE_END); | 778 hr = query_->Issue(D3DISSUE_END); |
| 797 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | 779 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); |
| 798 return true; | 780 return true; |
| 799 } | 781 } |
| 800 | 782 |
| 801 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { | 783 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { |
| 802 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, | 784 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, |
| 803 d3d11_device_manager_.Receive()); | 785 d3d11_device_manager_.Receive()); |
| 804 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); | 786 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); |
| 805 | 787 |
| 806 base::win::ScopedComPtr<ID3D11Device> angle_device = | 788 // This array defines the set of DirectX hardware feature levels we support. |
| 807 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); | 789 // The ordering MUST be preserved. All applications are assumed to support |
| 808 RETURN_ON_FAILURE( | 790 // 9.1 unless otherwise stated by the application. |
| 809 angle_device.get(), | 791 D3D_FEATURE_LEVEL feature_levels[] = { |
| 810 "Failed to query DX11 device object from ANGLE", | 792 D3D_FEATURE_LEVEL_11_1, |
| 811 false); | 793 D3D_FEATURE_LEVEL_11_0, |
| 794 D3D_FEATURE_LEVEL_10_1, |
| 795 D3D_FEATURE_LEVEL_10_0, |
| 796 D3D_FEATURE_LEVEL_9_3, |
| 797 D3D_FEATURE_LEVEL_9_2, |
| 798 D3D_FEATURE_LEVEL_9_1 |
| 799 }; |
| 812 | 800 |
| 813 using_angle_device_ = true; | 801 UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; |
| 814 d3d11_device_ = angle_device; | 802 |
| 803 #if defined _DEBUG |
| 804 flags |= D3D11_CREATE_DEVICE_DEBUG; |
| 805 #endif |
| 806 |
| 807 D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_0; |
| 808 hr = D3D11CreateDevice(NULL, |
| 809 D3D_DRIVER_TYPE_HARDWARE, |
| 810 NULL, |
| 811 flags, |
| 812 feature_levels, |
| 813 arraysize(feature_levels), |
| 814 D3D11_SDK_VERSION, |
| 815 d3d11_device_.Receive(), |
| 816 &feature_level_out, |
| 817 d3d11_device_context_.Receive()); |
| 818 RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device", false); |
| 815 | 819 |
| 816 // Enable multithreaded mode on the device. This ensures that accesses to | 820 // Enable multithreaded mode on the device. This ensures that accesses to |
| 817 // context are synchronized across threads. We have multiple threads | 821 // context are synchronized across threads. We have multiple threads |
| 818 // accessing the context, the media foundation decoder threads and the | 822 // accessing the context, the media foundation decoder threads and the |
| 819 // decoder thread via the video format conversion transform. | 823 // decoder thread via the video format conversion transform. |
| 820 hr = multi_threaded_.QueryFrom(angle_device.get()); | 824 hr = multi_threaded_.QueryFrom(d3d11_device_.get()); |
| 821 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); | 825 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); |
| 822 multi_threaded_->SetMultithreadProtected(TRUE); | 826 multi_threaded_->SetMultithreadProtected(TRUE); |
| 823 | 827 |
| 824 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), | 828 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), |
| 825 dx11_dev_manager_reset_token_); | 829 dx11_dev_manager_reset_token_); |
| 826 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 830 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 827 | 831 |
| 832 D3D11_QUERY_DESC query_desc; |
| 833 query_desc.Query = D3D11_QUERY_EVENT; |
| 834 query_desc.MiscFlags = 0; |
| 835 hr = d3d11_device_->CreateQuery( |
| 836 &query_desc, |
| 837 d3d11_query_.Receive()); |
| 838 RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false); |
| 839 |
| 828 HMODULE video_processor_dll = ::GetModuleHandle(L"msvproc.dll"); | 840 HMODULE video_processor_dll = ::GetModuleHandle(L"msvproc.dll"); |
| 829 RETURN_ON_FAILURE(video_processor_dll, "Failed to load video processor", | 841 RETURN_ON_FAILURE(video_processor_dll, "Failed to load video processor", |
| 830 false); | 842 false); |
| 831 | 843 |
| 832 hr = CreateCOMObjectFromDll( | 844 hr = CreateCOMObjectFromDll( |
| 833 video_processor_dll, | 845 video_processor_dll, |
| 834 CLSID_VideoProcessorMFT, | 846 CLSID_VideoProcessorMFT, |
| 835 __uuidof(IMFTransform), | 847 __uuidof(IMFTransform), |
| 836 video_format_converter_mft_.ReceiveVoid()); | 848 video_format_converter_mft_.ReceiveVoid()); |
| 837 if (FAILED(hr)) { | 849 if (FAILED(hr)) { |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1525 pending_output_samples_.clear(); | 1537 pending_output_samples_.clear(); |
| 1526 pending_input_buffers_.clear(); | 1538 pending_input_buffers_.clear(); |
| 1527 decoder_.Release(); | 1539 decoder_.Release(); |
| 1528 | 1540 |
| 1529 if (use_dx11_) { | 1541 if (use_dx11_) { |
| 1530 if (video_format_converter_mft_.get()) { | 1542 if (video_format_converter_mft_.get()) { |
| 1531 video_format_converter_mft_->ProcessMessage( | 1543 video_format_converter_mft_->ProcessMessage( |
| 1532 MFT_MESSAGE_NOTIFY_END_STREAMING, 0); | 1544 MFT_MESSAGE_NOTIFY_END_STREAMING, 0); |
| 1533 video_format_converter_mft_.Release(); | 1545 video_format_converter_mft_.Release(); |
| 1534 } | 1546 } |
| 1547 d3d11_device_context_.Release(); |
| 1535 d3d11_device_.Release(); | 1548 d3d11_device_.Release(); |
| 1536 d3d11_device_manager_.Release(); | 1549 d3d11_device_manager_.Release(); |
| 1550 d3d11_query_.Release(); |
| 1537 dx11_video_format_converter_media_type_needs_init_ = true; | 1551 dx11_video_format_converter_media_type_needs_init_ = true; |
| 1538 } else { | 1552 } else { |
| 1539 d3d9_.Release(); | 1553 d3d9_.Release(); |
| 1540 d3d9_device_ex_.Release(); | 1554 d3d9_device_ex_.Release(); |
| 1541 device_manager_.Release(); | 1555 device_manager_.Release(); |
| 1542 query_.Release(); | 1556 query_.Release(); |
| 1543 } | 1557 } |
| 1544 | 1558 |
| 1545 SetState(kUninitialized); | 1559 SetState(kUninitialized); |
| 1546 } | 1560 } |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2027 // TODO(ananta) | 2041 // TODO(ananta) |
| 2028 // Remove this CHECK when the change to use DX11 for H/W decoding | 2042 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2029 // stablizes. | 2043 // stablizes. |
| 2030 CHECK(false); | 2044 CHECK(false); |
| 2031 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2045 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2032 "Failed to create output sample.", PLATFORM_FAILURE,); | 2046 "Failed to create output sample.", PLATFORM_FAILURE,); |
| 2033 } | 2047 } |
| 2034 | 2048 |
| 2035 output_sample->AddBuffer(output_buffer.get()); | 2049 output_sample->AddBuffer(output_buffer.get()); |
| 2036 | 2050 |
| 2037 // Lock the device here as we are accessing the DX11 video context and the | |
| 2038 // texture which need to be synchronized with the main thread. | |
| 2039 AutoDX11DeviceLock device_lock(multi_threaded_.get()); | |
| 2040 | |
| 2041 hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0); | 2051 hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0); |
| 2042 if (FAILED(hr)) { | 2052 if (FAILED(hr)) { |
| 2043 DCHECK(false); | 2053 DCHECK(false); |
| 2044 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2054 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2045 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2055 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2046 } | 2056 } |
| 2047 | 2057 |
| 2048 DWORD status = 0; | 2058 DWORD status = 0; |
| 2049 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; | 2059 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; |
| 2050 format_converter_output.pSample = output_sample.get(); | 2060 format_converter_output.pSample = output_sample.get(); |
| 2051 hr = video_format_converter_mft_->ProcessOutput( | 2061 hr = video_format_converter_mft_->ProcessOutput( |
| 2052 0, // No flags | 2062 0, // No flags |
| 2053 1, // # of out streams to pull from | 2063 1, // # of out streams to pull from |
| 2054 &format_converter_output, | 2064 &format_converter_output, |
| 2055 &status); | 2065 &status); |
| 2056 | 2066 |
| 2057 if (FAILED(hr)) { | 2067 if (FAILED(hr)) { |
| 2058 base::debug::Alias(&hr); | 2068 base::debug::Alias(&hr); |
| 2059 // TODO(ananta) | 2069 // TODO(ananta) |
| 2060 // Remove this CHECK when the change to use DX11 for H/W decoding | 2070 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2061 // stablizes. | 2071 // stablizes. |
| 2062 CHECK(false); | 2072 CHECK(false); |
| 2063 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2073 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2064 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2074 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2065 } | 2075 } |
| 2066 | 2076 |
| 2067 main_thread_task_runner_->PostTask( | 2077 d3d11_device_context_->Flush(); |
| 2078 d3d11_device_context_->End(d3d11_query_.get()); |
| 2079 |
| 2080 decoder_thread_task_runner_->PostDelayedTask( |
| 2068 FROM_HERE, | 2081 FROM_HERE, |
| 2069 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 2082 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2070 weak_this_factory_.GetWeakPtr(), | 2083 base::Unretained(this), 0, |
| 2071 nullptr, | 2084 reinterpret_cast<IDirect3DSurface9*>(NULL), |
| 2072 nullptr, | 2085 reinterpret_cast<IDirect3DSurface9*>(NULL), |
| 2073 picture_buffer_id, | 2086 picture_buffer_id, input_buffer_id), |
| 2074 input_buffer_id)); | 2087 base::TimeDelta::FromMilliseconds( |
| 2088 kFlushDecoderSurfaceTimeoutMs)); |
| 2075 } | 2089 } |
| 2076 | 2090 |
| 2077 void DXVAVideoDecodeAccelerator::FlushDecoder( | 2091 void DXVAVideoDecodeAccelerator::FlushDecoder( |
| 2078 int iterations, | 2092 int iterations, |
| 2079 IDirect3DSurface9* src_surface, | 2093 IDirect3DSurface9* src_surface, |
| 2080 IDirect3DSurface9* dest_surface, | 2094 IDirect3DSurface9* dest_surface, |
| 2081 int picture_buffer_id, | 2095 int picture_buffer_id, |
| 2082 int input_buffer_id) { | 2096 int input_buffer_id) { |
| 2083 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2097 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 2084 | 2098 |
| 2085 // The DXVA decoder has its own device which it uses for decoding. ANGLE | 2099 // The DXVA decoder has its own device which it uses for decoding. ANGLE |
| 2086 // has its own device which we don't have access to. | 2100 // has its own device which we don't have access to. |
| 2087 // The above code attempts to copy the decoded picture into a surface | 2101 // The above code attempts to copy the decoded picture into a surface |
| 2088 // which is owned by ANGLE. As there are multiple devices involved in | 2102 // which is owned by ANGLE. As there are multiple devices involved in |
| 2089 // this, the StretchRect call above is not synchronous. | 2103 // this, the StretchRect call above is not synchronous. |
| 2090 // We attempt to flush the batched operations to ensure that the picture is | 2104 // We attempt to flush the batched operations to ensure that the picture is |
| 2091 // copied to the surface owned by ANGLE. | 2105 // copied to the surface owned by ANGLE. |
| 2092 // We need to do this in a loop and call flush multiple times. | 2106 // We need to do this in a loop and call flush multiple times. |
| 2093 // We have seen the GetData call for flushing the command buffer fail to | 2107 // We have seen the GetData call for flushing the command buffer fail to |
| 2094 // return success occassionally on multi core machines, leading to an | 2108 // return success occassionally on multi core machines, leading to an |
| 2095 // infinite loop. | 2109 // infinite loop. |
| 2096 // Workaround is to have an upper limit of 4 on the number of iterations to | 2110 // Workaround is to have an upper limit of 4 on the number of iterations to |
| 2097 // wait for the Flush to finish. | 2111 // wait for the Flush to finish. |
| 2098 DCHECK(!use_dx11_); | |
| 2099 | 2112 |
| 2100 HRESULT hr = E_FAIL; | 2113 HRESULT hr = E_FAIL; |
| 2101 | 2114 if (use_dx11_) { |
| 2102 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); | 2115 BOOL query_data = 0; |
| 2116 hr = d3d11_device_context_->GetData(d3d11_query_.get(), &query_data, |
| 2117 sizeof(BOOL), 0); |
| 2118 if (FAILED(hr)) { |
| 2119 base::debug::Alias(&hr); |
| 2120 // TODO(ananta) |
| 2121 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2122 // stablizes. |
| 2123 CHECK(false); |
| 2124 } |
| 2125 } else { |
| 2126 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); |
| 2127 } |
| 2103 | 2128 |
| 2104 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { | 2129 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { |
| 2105 decoder_thread_task_runner_->PostDelayedTask( | 2130 decoder_thread_task_runner_->PostDelayedTask( |
| 2106 FROM_HERE, | 2131 FROM_HERE, |
| 2107 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2132 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2108 base::Unretained(this), iterations, src_surface, | 2133 base::Unretained(this), iterations, src_surface, |
| 2109 dest_surface, picture_buffer_id, input_buffer_id), | 2134 dest_surface, picture_buffer_id, input_buffer_id), |
| 2110 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | 2135 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 2111 return; | 2136 return; |
| 2112 } | 2137 } |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2275 D3DSURFACE_DESC surface_desc; | 2300 D3DSURFACE_DESC surface_desc; |
| 2276 hr = surface->GetDesc(&surface_desc); | 2301 hr = surface->GetDesc(&surface_desc); |
| 2277 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 2302 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
| 2278 *width = surface_desc.Width; | 2303 *width = surface_desc.Width; |
| 2279 *height = surface_desc.Height; | 2304 *height = surface_desc.Height; |
| 2280 } | 2305 } |
| 2281 return true; | 2306 return true; |
| 2282 } | 2307 } |
| 2283 | 2308 |
| 2284 } // namespace content | 2309 } // namespace content |
| OLD | NEW |