Chromium Code Reviews| 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 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 pictures_requested_(false), | 614 pictures_requested_(false), |
| 615 inputs_before_decode_(0), | 615 inputs_before_decode_(0), |
| 616 sent_drain_message_(false), | 616 sent_drain_message_(false), |
| 617 make_context_current_(make_context_current), | 617 make_context_current_(make_context_current), |
| 618 codec_(media::kUnknownVideoCodec), | 618 codec_(media::kUnknownVideoCodec), |
| 619 decoder_thread_("DXVAVideoDecoderThread"), | 619 decoder_thread_("DXVAVideoDecoderThread"), |
| 620 pending_flush_(false), | 620 pending_flush_(false), |
| 621 use_dx11_(false), | 621 use_dx11_(false), |
| 622 dx11_video_format_converter_media_type_needs_init_(true), | 622 dx11_video_format_converter_media_type_needs_init_(true), |
| 623 gl_context_(gl_context), | 623 gl_context_(gl_context), |
| 624 dx11_device_locked_(false), | |
| 624 weak_this_factory_(this) { | 625 weak_this_factory_(this) { |
| 625 weak_ptr_ = weak_this_factory_.GetWeakPtr(); | 626 weak_ptr_ = weak_this_factory_.GetWeakPtr(); |
| 626 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 627 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
| 627 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 628 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
| 628 } | 629 } |
| 629 | 630 |
| 630 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 631 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
| 631 client_ = NULL; | 632 client_ = NULL; |
| 632 } | 633 } |
| 633 | 634 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 797 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); | 798 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); |
| 798 RETURN_ON_FAILURE( | 799 RETURN_ON_FAILURE( |
| 799 d3d11_device_context_.get(), | 800 d3d11_device_context_.get(), |
| 800 "Failed to query DX11 device context from ANGLE device", | 801 "Failed to query DX11 device context from ANGLE device", |
| 801 false); | 802 false); |
| 802 | 803 |
| 803 // Enable multithreaded mode on the context. This ensures that accesses to | 804 // Enable multithreaded mode on the context. This ensures that accesses to |
| 804 // context are synchronized across threads. We have multiple threads | 805 // context are synchronized across threads. We have multiple threads |
| 805 // accessing the context, the media foundation decoder threads and the | 806 // accessing the context, the media foundation decoder threads and the |
| 806 // decoder thread via the video format conversion transform. | 807 // decoder thread via the video format conversion transform. |
| 807 base::win::ScopedComPtr<ID3D10Multithread> multi_threaded; | 808 hr = multi_threaded_.QueryFrom(d3d11_device_context_.get()); |
| 808 hr = multi_threaded.QueryFrom(d3d11_device_context_.get()); | |
| 809 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); | 809 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); |
| 810 multi_threaded->SetMultithreadProtected(TRUE); | 810 multi_threaded_->SetMultithreadProtected(TRUE); |
| 811 | 811 |
| 812 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), | 812 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), |
| 813 dx11_dev_manager_reset_token_); | 813 dx11_dev_manager_reset_token_); |
| 814 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 814 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 815 | 815 |
| 816 D3D11_QUERY_DESC query_desc; | 816 D3D11_QUERY_DESC query_desc; |
| 817 query_desc.Query = D3D11_QUERY_EVENT; | 817 query_desc.Query = D3D11_QUERY_EVENT; |
| 818 query_desc.MiscFlags = 0; | 818 query_desc.MiscFlags = 0; |
| 819 hr = d3d11_device_->CreateQuery( | 819 hr = d3d11_device_->CreateQuery( |
| 820 &query_desc, | 820 &query_desc, |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 961 | 961 |
| 962 void DXVAVideoDecodeAccelerator::Reset() { | 962 void DXVAVideoDecodeAccelerator::Reset() { |
| 963 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 963 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
| 964 | 964 |
| 965 DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset"; | 965 DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset"; |
| 966 | 966 |
| 967 State state = GetState(); | 967 State state = GetState(); |
| 968 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped), | 968 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped), |
| 969 "Reset: invalid state: " << state, ILLEGAL_STATE,); | 969 "Reset: invalid state: " << state, ILLEGAL_STATE,); |
| 970 | 970 |
| 971 decoder_thread_.Stop(); | 971 StopDecoderThread(); |
| 972 | 972 |
| 973 SetState(kResetting); | 973 SetState(kResetting); |
| 974 | 974 |
| 975 // If we have pending output frames waiting for display then we drop those | 975 // If we have pending output frames waiting for display then we drop those |
| 976 // frames and set the corresponding picture buffer as available. | 976 // frames and set the corresponding picture buffer as available. |
| 977 PendingOutputSamples::iterator index; | 977 PendingOutputSamples::iterator index; |
| 978 for (index = pending_output_samples_.begin(); | 978 for (index = pending_output_samples_.begin(); |
| 979 index != pending_output_samples_.end(); | 979 index != pending_output_samples_.end(); |
| 980 ++index) { | 980 ++index) { |
| 981 if (index->picture_buffer_id != -1) { | 981 if (index->picture_buffer_id != -1) { |
| (...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1491 client_ = NULL; | 1491 client_ = NULL; |
| 1492 | 1492 |
| 1493 if (GetState() != kUninitialized) { | 1493 if (GetState() != kUninitialized) { |
| 1494 Invalidate(); | 1494 Invalidate(); |
| 1495 } | 1495 } |
| 1496 } | 1496 } |
| 1497 | 1497 |
| 1498 void DXVAVideoDecodeAccelerator::Invalidate() { | 1498 void DXVAVideoDecodeAccelerator::Invalidate() { |
| 1499 if (GetState() == kUninitialized) | 1499 if (GetState() == kUninitialized) |
| 1500 return; | 1500 return; |
| 1501 decoder_thread_.Stop(); | 1501 StopDecoderThread(); |
| 1502 weak_this_factory_.InvalidateWeakPtrs(); | 1502 weak_this_factory_.InvalidateWeakPtrs(); |
| 1503 output_picture_buffers_.clear(); | 1503 output_picture_buffers_.clear(); |
| 1504 stale_output_picture_buffers_.clear(); | 1504 stale_output_picture_buffers_.clear(); |
| 1505 pending_output_samples_.clear(); | 1505 pending_output_samples_.clear(); |
| 1506 pending_input_buffers_.clear(); | 1506 pending_input_buffers_.clear(); |
| 1507 decoder_.Release(); | 1507 decoder_.Release(); |
| 1508 | 1508 |
| 1509 if (use_dx11_) { | 1509 if (use_dx11_) { |
| 1510 if (video_format_converter_mft_.get()) { | 1510 if (video_format_converter_mft_.get()) { |
| 1511 video_format_converter_mft_->ProcessMessage( | 1511 video_format_converter_mft_->ProcessMessage( |
| (...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2004 // TODO(ananta) | 2004 // TODO(ananta) |
| 2005 // Remove this CHECK when the change to use DX11 for H/W decoding | 2005 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2006 // stablizes. | 2006 // stablizes. |
| 2007 CHECK(false); | 2007 CHECK(false); |
| 2008 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2008 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2009 "Failed to create output sample.", PLATFORM_FAILURE,); | 2009 "Failed to create output sample.", PLATFORM_FAILURE,); |
| 2010 } | 2010 } |
| 2011 | 2011 |
| 2012 output_sample->AddBuffer(output_buffer.get()); | 2012 output_sample->AddBuffer(output_buffer.get()); |
| 2013 | 2013 |
| 2014 // Lock the device here as we are accessing the destination texture created | |
| 2015 // on the main thread. | |
| 2016 CHECK(!dx11_device_locked_); | |
| 2017 dx11_device_locked_ = true; | |
| 2018 multi_threaded_->Enter(); | |
| 2019 | |
| 2014 DWORD status = 0; | 2020 DWORD status = 0; |
| 2015 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; | 2021 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; |
| 2016 format_converter_output.pSample = output_sample.get(); | 2022 format_converter_output.pSample = output_sample.get(); |
| 2017 hr = video_format_converter_mft_->ProcessOutput( | 2023 hr = video_format_converter_mft_->ProcessOutput( |
| 2018 0, // No flags | 2024 0, // No flags |
| 2019 1, // # of out streams to pull from | 2025 1, // # of out streams to pull from |
| 2020 &format_converter_output, | 2026 &format_converter_output, |
| 2021 &status); | 2027 &status); |
| 2022 | 2028 |
| 2023 d3d11_device_context_->Flush(); | 2029 d3d11_device_context_->Flush(); |
| 2024 d3d11_device_context_->End(d3d11_query_.get()); | 2030 d3d11_device_context_->End(d3d11_query_.get()); |
| 2025 | 2031 |
| 2026 if (FAILED(hr)) { | 2032 if (FAILED(hr)) { |
| 2027 base::debug::Alias(&hr); | 2033 base::debug::Alias(&hr); |
| 2028 // TODO(ananta) | 2034 // TODO(ananta) |
| 2029 // Remove this CHECK when the change to use DX11 for H/W decoding | 2035 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2030 // stablizes. | 2036 // stablizes. |
| 2031 CHECK(false); | 2037 CHECK(false); |
| 2032 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2038 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2033 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2039 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2034 } | 2040 } |
| 2035 | 2041 |
| 2036 decoder_thread_task_runner_->PostDelayedTask( | 2042 decoder_thread_task_runner_->PostDelayedTask( |
|
jbauman
2015/11/02 20:50:42
I think you should do the Leave here - it should b
ananta
2015/11/02 22:17:56
We don't need to wait anymore for the flush based
| |
| 2037 FROM_HERE, | 2043 FROM_HERE, |
| 2038 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2044 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2039 base::Unretained(this), 0, | 2045 base::Unretained(this), 0, |
| 2040 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2046 reinterpret_cast<IDirect3DSurface9*>(NULL), |
| 2041 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2047 reinterpret_cast<IDirect3DSurface9*>(NULL), |
| 2042 picture_buffer_id, input_buffer_id), | 2048 picture_buffer_id, input_buffer_id), |
| 2043 base::TimeDelta::FromMilliseconds( | 2049 base::TimeDelta::FromMilliseconds( |
| 2044 kFlushDecoderSurfaceTimeoutMs)); | 2050 kFlushDecoderSurfaceTimeoutMs)); |
| 2045 } | 2051 } |
| 2046 | 2052 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 2062 // We need to do this in a loop and call flush multiple times. | 2068 // We need to do this in a loop and call flush multiple times. |
| 2063 // We have seen the GetData call for flushing the command buffer fail to | 2069 // We have seen the GetData call for flushing the command buffer fail to |
| 2064 // return success occassionally on multi core machines, leading to an | 2070 // return success occassionally on multi core machines, leading to an |
| 2065 // infinite loop. | 2071 // infinite loop. |
| 2066 // Workaround is to have an upper limit of 4 on the number of iterations to | 2072 // Workaround is to have an upper limit of 4 on the number of iterations to |
| 2067 // wait for the Flush to finish. | 2073 // wait for the Flush to finish. |
| 2068 HRESULT hr = E_FAIL; | 2074 HRESULT hr = E_FAIL; |
| 2069 | 2075 |
| 2070 if (use_dx11_) { | 2076 if (use_dx11_) { |
| 2071 BOOL query_data = 0; | 2077 BOOL query_data = 0; |
| 2072 hr = d3d11_device_context_->GetData(d3d11_query_.get(), &query_data, | 2078 hr = d3d11_device_context_->GetData(d3d11_query_.get(), &query_data, |
|
jbauman
2015/11/02 20:50:42
You could maybe do an Enter() and Leave() just aro
ananta
2015/11/02 22:17:56
Ditto
| |
| 2073 sizeof(BOOL), 0); | 2079 sizeof(BOOL), 0); |
| 2074 if (FAILED(hr)) { | 2080 if (FAILED(hr)) { |
| 2075 base::debug::Alias(&hr); | 2081 base::debug::Alias(&hr); |
| 2076 // TODO(ananta) | 2082 // TODO(ananta) |
| 2077 // Remove this CHECK when the change to use DX11 for H/W decoding | 2083 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2078 // stablizes. | 2084 // stablizes. |
| 2079 CHECK(false); | 2085 CHECK(false); |
| 2080 } | 2086 } |
| 2081 } else { | 2087 } else { |
| 2082 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); | 2088 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); |
| 2083 } | 2089 } |
| 2084 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { | 2090 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { |
| 2085 decoder_thread_task_runner_->PostDelayedTask( | 2091 decoder_thread_task_runner_->PostDelayedTask( |
| 2086 FROM_HERE, | 2092 FROM_HERE, |
| 2087 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2093 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2088 base::Unretained(this), iterations, src_surface, | 2094 base::Unretained(this), iterations, src_surface, |
| 2089 dest_surface, picture_buffer_id, input_buffer_id), | 2095 dest_surface, picture_buffer_id, input_buffer_id), |
| 2090 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | 2096 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 2091 return; | 2097 return; |
| 2092 } | 2098 } |
| 2093 | 2099 |
| 2100 dx11_device_locked_ = false; | |
| 2101 multi_threaded_->Leave(); | |
| 2102 | |
| 2094 main_thread_task_runner_->PostTask( | 2103 main_thread_task_runner_->PostTask( |
| 2095 FROM_HERE, | 2104 FROM_HERE, |
| 2096 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 2105 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
| 2097 weak_this_factory_.GetWeakPtr(), | 2106 weak_this_factory_.GetWeakPtr(), |
| 2098 src_surface, | 2107 src_surface, |
| 2099 dest_surface, | 2108 dest_surface, |
| 2100 picture_buffer_id, | 2109 picture_buffer_id, |
| 2101 input_buffer_id)); | 2110 input_buffer_id)); |
| 2102 } | 2111 } |
| 2103 | 2112 |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2264 false); | 2273 false); |
| 2265 D3DSURFACE_DESC surface_desc; | 2274 D3DSURFACE_DESC surface_desc; |
| 2266 hr = surface->GetDesc(&surface_desc); | 2275 hr = surface->GetDesc(&surface_desc); |
| 2267 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 2276 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
| 2268 *width = surface_desc.Width; | 2277 *width = surface_desc.Width; |
| 2269 *height = surface_desc.Height; | 2278 *height = surface_desc.Height; |
| 2270 } | 2279 } |
| 2271 return true; | 2280 return true; |
| 2272 } | 2281 } |
| 2273 | 2282 |
| 2283 void DXVAVideoDecodeAccelerator::StopDecoderThread() { | |
| 2284 if (main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 2285 if (decoder_thread_.IsRunning()) { | |
| 2286 decoder_thread_task_runner_->PostTask( | |
| 2287 FROM_HERE, | |
| 2288 base::Bind(&DXVAVideoDecodeAccelerator::StopDecoderThread, | |
| 2289 base::Unretained(this))); | |
| 2290 } | |
| 2291 decoder_thread_.Stop(); | |
| 2292 return; | |
| 2293 } | |
| 2294 | |
| 2295 if (dx11_device_locked_) { | |
| 2296 dx11_device_locked_ = false; | |
| 2297 multi_threaded_->Leave(); | |
| 2298 } | |
| 2299 } | |
| 2300 | |
| 2274 } // namespace content | 2301 } // namespace content |
| OLD | NEW |