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 "media/gpu/dxva_video_decode_accelerator_win.h" | 5 #include "media/gpu/dxva_video_decode_accelerator_win.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #if !defined(OS_WIN) | 9 #if !defined(OS_WIN) |
| 10 #error This file should only be built on Windows. | 10 #error This file should only be built on Windows. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 #include "base/files/file_path.h" | 28 #include "base/files/file_path.h" |
| 29 #include "base/location.h" | 29 #include "base/location.h" |
| 30 #include "base/logging.h" | 30 #include "base/logging.h" |
| 31 #include "base/macros.h" | 31 #include "base/macros.h" |
| 32 #include "base/memory/shared_memory.h" | 32 #include "base/memory/shared_memory.h" |
| 33 #include "base/path_service.h" | 33 #include "base/path_service.h" |
| 34 #include "base/single_thread_task_runner.h" | 34 #include "base/single_thread_task_runner.h" |
| 35 #include "base/stl_util.h" | 35 #include "base/stl_util.h" |
| 36 #include "base/threading/thread_task_runner_handle.h" | 36 #include "base/threading/thread_task_runner_handle.h" |
| 37 #include "base/trace_event/trace_event.h" | 37 #include "base/trace_event/trace_event.h" |
| 38 #include "base/win/scoped_co_mem.h" | |
| 38 #include "base/win/windows_version.h" | 39 #include "base/win/windows_version.h" |
| 39 #include "build/build_config.h" | 40 #include "build/build_config.h" |
| 40 #include "gpu/command_buffer/service/gpu_preferences.h" | 41 #include "gpu/command_buffer/service/gpu_preferences.h" |
| 41 #include "gpu/config/gpu_driver_bug_workarounds.h" | 42 #include "gpu/config/gpu_driver_bug_workarounds.h" |
| 43 #include "media/base/media_switches.h" | |
| 42 #include "media/base/win/mf_helpers.h" | 44 #include "media/base/win/mf_helpers.h" |
| 43 #include "media/base/win/mf_initializer.h" | 45 #include "media/base/win/mf_initializer.h" |
| 44 #include "media/gpu/dxva_picture_buffer_win.h" | 46 #include "media/gpu/dxva_picture_buffer_win.h" |
| 45 #include "media/video/video_decode_accelerator.h" | 47 #include "media/video/video_decode_accelerator.h" |
| 46 #include "third_party/angle/include/EGL/egl.h" | 48 #include "third_party/angle/include/EGL/egl.h" |
| 47 #include "third_party/angle/include/EGL/eglext.h" | 49 #include "third_party/angle/include/EGL/eglext.h" |
| 50 #include "ui/gfx/color_space_win.h" | |
| 48 #include "ui/gl/gl_bindings.h" | 51 #include "ui/gl/gl_bindings.h" |
| 49 #include "ui/gl/gl_context.h" | 52 #include "ui/gl/gl_context.h" |
| 50 #include "ui/gl/gl_fence.h" | 53 #include "ui/gl/gl_fence.h" |
| 51 #include "ui/gl/gl_surface_egl.h" | 54 #include "ui/gl/gl_surface_egl.h" |
| 52 | 55 |
| 53 namespace { | 56 namespace { |
| 54 | 57 |
| 55 // AMD | 58 // AMD |
| 56 // Path is appended on to the PROGRAM_FILES base path. | 59 // Path is appended on to the PROGRAM_FILES base path. |
| 57 const wchar_t kAMDVPXDecoderDLLPath[] = | 60 const wchar_t kAMDVPXDecoderDLLPath[] = |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 512 use_keyed_mutex_(false), | 515 use_keyed_mutex_(false), |
| 513 dx11_video_format_converter_media_type_needs_init_(true), | 516 dx11_video_format_converter_media_type_needs_init_(true), |
| 514 using_angle_device_(false), | 517 using_angle_device_(false), |
| 515 enable_accelerated_vpx_decode_( | 518 enable_accelerated_vpx_decode_( |
| 516 gpu_preferences.enable_accelerated_vpx_decode), | 519 gpu_preferences.enable_accelerated_vpx_decode), |
| 517 processing_config_changed_(false), | 520 processing_config_changed_(false), |
| 518 weak_this_factory_(this) { | 521 weak_this_factory_(this) { |
| 519 weak_ptr_ = weak_this_factory_.GetWeakPtr(); | 522 weak_ptr_ = weak_this_factory_.GetWeakPtr(); |
| 520 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 523 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
| 521 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 524 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
| 525 use_color_info_ = base::FeatureList::IsEnabled(kVideoBlitColorAccuracy); | |
| 522 } | 526 } |
| 523 | 527 |
| 524 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 528 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
| 525 client_ = NULL; | 529 client_ = NULL; |
| 526 } | 530 } |
| 527 | 531 |
| 528 bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, | 532 bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, |
| 529 Client* client) { | 533 Client* client) { |
| 530 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | 534 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { |
| 531 NOTREACHED() << "GL callbacks are required for this VDA"; | 535 NOTREACHED() << "GL callbacks are required for this VDA"; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 hr = device_manager_->ResetDevice(d3d9_device_ex_.get(), | 699 hr = device_manager_->ResetDevice(d3d9_device_ex_.get(), |
| 696 dev_manager_reset_token_); | 700 dev_manager_reset_token_); |
| 697 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 701 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 698 | 702 |
| 699 hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | 703 hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
| 700 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); | 704 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); |
| 701 // Ensure query_ API works (to avoid an infinite loop later in | 705 // Ensure query_ API works (to avoid an infinite loop later in |
| 702 // CopyOutputSampleDataToPictureBuffer). | 706 // CopyOutputSampleDataToPictureBuffer). |
| 703 hr = query_->Issue(D3DISSUE_END); | 707 hr = query_->Issue(D3DISSUE_END); |
| 704 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | 708 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); |
| 709 | |
| 710 CreateVideoProcessor(); | |
| 705 return true; | 711 return true; |
| 706 } | 712 } |
| 707 | 713 |
| 714 bool DXVAVideoDecodeAccelerator::CreateVideoProcessor() { | |
| 715 if (!use_color_info_) | |
| 716 return false; | |
| 717 | |
| 718 // TODO(Hubbe): Don't try again if we tried and failed already. | |
| 719 if (video_processor_service_.get()) | |
| 720 return true; | |
| 721 HRESULT hr = DXVA2CreateVideoService(d3d9_device_ex_.get(), | |
| 722 IID_IDirectXVideoProcessorService, | |
| 723 video_processor_service_.ReceiveVoid()); | |
| 724 RETURN_ON_HR_FAILURE(hr, "DXVA2CreateVideoService failed", false); | |
| 725 | |
| 726 // TODO(Hubbe): Use actual video settings. | |
| 727 DXVA2_VideoDesc inputDesc; | |
| 728 inputDesc.SampleWidth = 1920; | |
| 729 inputDesc.SampleHeight = 1080; | |
| 730 inputDesc.SampleFormat.VideoChromaSubsampling = | |
| 731 DXVA2_VideoChromaSubsampling_MPEG2; | |
| 732 inputDesc.SampleFormat.NominalRange = DXVA2_NominalRange_16_235; | |
| 733 inputDesc.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT709; | |
| 734 inputDesc.SampleFormat.VideoLighting = DXVA2_VideoLighting_dim; | |
| 735 inputDesc.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709; | |
| 736 inputDesc.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709; | |
| 737 inputDesc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame; | |
| 738 inputDesc.Format = (D3DFORMAT)MAKEFOURCC('N', 'V', '1', '2'); | |
| 739 inputDesc.InputSampleFreq.Numerator = 30; | |
| 740 inputDesc.InputSampleFreq.Denominator = 1; | |
| 741 inputDesc.OutputFrameFreq.Numerator = 30; | |
| 742 inputDesc.OutputFrameFreq.Denominator = 1; | |
| 743 | |
| 744 UINT guid_count = 0; | |
| 745 base::win::ScopedCoMem<GUID> guids; | |
| 746 hr = video_processor_service_->GetVideoProcessorDeviceGuids( | |
| 747 &inputDesc, &guid_count, &guids); | |
| 748 RETURN_ON_HR_FAILURE(hr, "GetVideoProcessorDeviceGuids failed", false); | |
| 749 | |
| 750 for (UINT g = 0; g < guid_count; g++) { | |
| 751 DXVA2_VideoProcessorCaps caps; | |
| 752 hr = video_processor_service_->GetVideoProcessorCaps( | |
| 753 guids[g], &inputDesc, D3DFMT_X8R8G8B8, &caps); | |
| 754 if (hr) | |
| 755 continue; | |
| 756 | |
| 757 if (!(caps.VideoProcessorOperations & DXVA2_VideoProcess_YUV2RGB)) | |
| 758 continue; | |
| 759 | |
| 760 base::win::ScopedCoMem<D3DFORMAT> formats; | |
| 761 UINT format_count = 0; | |
| 762 hr = video_processor_service_->GetVideoProcessorRenderTargets( | |
| 763 guids[g], &inputDesc, &format_count, &formats); | |
| 764 if (hr) | |
| 765 continue; | |
| 766 | |
| 767 UINT f; | |
| 768 for (f = 0; f < format_count; f++) { | |
| 769 if (formats[f] == D3DFMT_X8R8G8B8) { | |
| 770 break; | |
| 771 } | |
| 772 } | |
| 773 if (f == format_count) | |
| 774 continue; | |
| 775 | |
| 776 // Create video processor | |
| 777 hr = video_processor_service_->CreateVideoProcessor( | |
| 778 guids[g], &inputDesc, D3DFMT_X8R8G8B8, 0, processor_.Receive()); | |
| 779 if (hr) | |
| 780 continue; | |
| 781 | |
| 782 DXVA2_ValueRange range; | |
| 783 processor_->GetProcAmpRange(DXVA2_ProcAmp_Brightness, &range); | |
| 784 default_procamp_values_.Brightness = range.DefaultValue; | |
| 785 processor_->GetProcAmpRange(DXVA2_ProcAmp_Contrast, &range); | |
| 786 default_procamp_values_.Contrast = range.DefaultValue; | |
| 787 processor_->GetProcAmpRange(DXVA2_ProcAmp_Hue, &range); | |
| 788 default_procamp_values_.Hue = range.DefaultValue; | |
| 789 processor_->GetProcAmpRange(DXVA2_ProcAmp_Saturation, &range); | |
| 790 default_procamp_values_.Saturation = range.DefaultValue; | |
| 791 | |
| 792 return true; | |
| 793 } | |
| 794 return false; | |
| 795 } | |
| 796 | |
| 708 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { | 797 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { |
| 709 // The device may exist if the last state was a config change. | 798 // The device may exist if the last state was a config change. |
| 710 if (d3d11_device_.get()) | 799 if (d3d11_device_.get()) |
| 711 return true; | 800 return true; |
| 712 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, | 801 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, |
| 713 d3d11_device_manager_.Receive()); | 802 d3d11_device_manager_.Receive()); |
| 714 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); | 803 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); |
| 715 | 804 |
| 716 angle_device_ = | 805 angle_device_ = |
| 717 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); | 806 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); |
| (...skipping 1060 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1778 } | 1867 } |
| 1779 | 1868 |
| 1780 if (width != index->second->size().width() || | 1869 if (width != index->second->size().width() || |
| 1781 height != index->second->size().height()) { | 1870 height != index->second->size().height()) { |
| 1782 HandleResolutionChanged(width, height); | 1871 HandleResolutionChanged(width, height); |
| 1783 return; | 1872 return; |
| 1784 } | 1873 } |
| 1785 | 1874 |
| 1786 pending_sample->picture_buffer_id = index->second->id(); | 1875 pending_sample->picture_buffer_id = index->second->id(); |
| 1787 index->second->set_bound(); | 1876 index->second->set_bound(); |
| 1788 | 1877 index->second->set_color_space(pending_sample->color_space); |
| 1789 // We only propagate the input color space if we can give the raw YUV data | |
| 1790 // back to the browser process. When we cannot return the YUV data, we | |
| 1791 // have to do a copy to an RGBA texture, which makes proper color | |
| 1792 // management difficult as some fidelity is lost. Also, we currently let | |
| 1793 // the drivers decide how to actually do the YUV to RGB conversion, which | |
| 1794 // means that even if we wanted to try to color-adjust the RGB output, we | |
| 1795 // don't actually know exactly what color space it is in anymore. | |
| 1796 // TODO(hubbe): Figure out a way to always return the raw YUV data. | |
| 1797 if (share_nv12_textures_ || copy_nv12_textures_) { | |
| 1798 index->second->set_color_space(pending_sample->color_space); | |
| 1799 } | |
| 1800 | 1878 |
| 1801 if (share_nv12_textures_) { | 1879 if (share_nv12_textures_) { |
| 1802 main_thread_task_runner_->PostTask( | 1880 main_thread_task_runner_->PostTask( |
| 1803 FROM_HERE, | 1881 FROM_HERE, |
| 1804 base::Bind(&DXVAVideoDecodeAccelerator::BindPictureBufferToSample, | 1882 base::Bind(&DXVAVideoDecodeAccelerator::BindPictureBufferToSample, |
| 1805 weak_ptr_, pending_sample->output_sample, | 1883 weak_ptr_, pending_sample->output_sample, |
| 1806 pending_sample->picture_buffer_id, | 1884 pending_sample->picture_buffer_id, |
| 1807 pending_sample->input_buffer_id)); | 1885 pending_sample->input_buffer_id)); |
| 1808 continue; | 1886 continue; |
| 1809 } | 1887 } |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2240 decoder_thread_.init_com_with_mta(true); | 2318 decoder_thread_.init_com_with_mta(true); |
| 2241 decoder_thread_.Start(); | 2319 decoder_thread_.Start(); |
| 2242 decoder_thread_task_runner_ = decoder_thread_.task_runner(); | 2320 decoder_thread_task_runner_ = decoder_thread_.task_runner(); |
| 2243 } | 2321 } |
| 2244 | 2322 |
| 2245 bool DXVAVideoDecodeAccelerator::OutputSamplesPresent() { | 2323 bool DXVAVideoDecodeAccelerator::OutputSamplesPresent() { |
| 2246 base::AutoLock lock(decoder_lock_); | 2324 base::AutoLock lock(decoder_lock_); |
| 2247 return !pending_output_samples_.empty(); | 2325 return !pending_output_samples_.empty(); |
| 2248 } | 2326 } |
| 2249 | 2327 |
| 2250 void DXVAVideoDecodeAccelerator::CopySurface(IDirect3DSurface9* src_surface, | 2328 void DXVAVideoDecodeAccelerator::CopySurface( |
| 2251 IDirect3DSurface9* dest_surface, | 2329 IDirect3DSurface9* src_surface, |
| 2252 int picture_buffer_id, | 2330 IDirect3DSurface9* dest_surface, |
| 2253 int input_buffer_id) { | 2331 int picture_buffer_id, |
| 2332 int input_buffer_id, | |
| 2333 const gfx::ColorSpace& color_space) { | |
| 2254 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopySurface"); | 2334 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopySurface"); |
| 2255 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { | 2335 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { |
| 2256 decoder_thread_task_runner_->PostTask( | 2336 decoder_thread_task_runner_->PostTask( |
| 2257 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurface, | 2337 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurface, |
| 2258 base::Unretained(this), src_surface, dest_surface, | 2338 base::Unretained(this), src_surface, dest_surface, |
| 2259 picture_buffer_id, input_buffer_id)); | 2339 picture_buffer_id, input_buffer_id, color_space)); |
| 2260 return; | 2340 return; |
| 2261 } | 2341 } |
| 2262 | 2342 |
| 2263 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, | 2343 HRESULT hr; |
| 2264 NULL, D3DTEXF_NONE); | 2344 if (processor_) { |
| 2265 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", ); | 2345 D3DSURFACE_DESC src_desc; |
| 2346 src_surface->GetDesc(&src_desc); | |
| 2347 int width = src_desc.Width; | |
| 2348 int height = src_desc.Height; | |
| 2349 RECT rect = {0, 0, width, height}; | |
| 2350 DXVA2_VideoSample sample = {0}; | |
| 2351 sample.End = 1000; | |
| 2352 if (use_color_info_) { | |
| 2353 sample.SampleFormat = gfx::ColorSpaceWin::GetExtendedFormat(color_space); | |
| 2354 } else { | |
| 2355 sample.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame; | |
| 2356 } | |
| 2266 | 2357 |
| 2358 sample.SrcSurface = src_surface; | |
| 2359 sample.SrcRect = rect; | |
| 2360 sample.DstRect = rect; | |
| 2361 sample.PlanarAlpha = DXVA2_Fixed32OpaqueAlpha(); | |
| 2362 | |
| 2363 DXVA2_VideoProcessBltParams params = {0}; | |
| 2364 params.TargetFrame = 0; | |
| 2365 params.TargetRect = rect; | |
| 2366 params.ConstrictionSize = {width, height}; | |
| 2367 params.BackgroundColor = {0, 0, 0, 0xFFFF}; | |
| 2368 params.ProcAmpValues = default_procamp_values_; | |
| 2369 | |
| 2370 params.Alpha = DXVA2_Fixed32OpaqueAlpha(); | |
| 2371 | |
| 2372 hr = processor_->VideoProcessBlt(dest_surface, ¶ms, &sample, 1, NULL); | |
| 2373 if (hr != S_OK) { | |
| 2374 LOG(ERROR) << "VideoProcessBlt failed with code " << hr | |
| 2375 << " E_INVALIDARG= " << E_INVALIDARG; | |
| 2376 | |
| 2377 // Release the processor and fall back to StretchRect() | |
| 2378 processor_ = NULL; | |
| 2379 } | |
| 2380 } | |
| 2381 | |
| 2382 if (!processor_) { | |
| 2383 hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, NULL, | |
| 2384 D3DTEXF_NONE); | |
| 2385 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", ); | |
| 2386 } | |
| 2267 // Ideally, this should be done immediately before the draw call that uses | 2387 // Ideally, this should be done immediately before the draw call that uses |
| 2268 // the texture. Flush it once here though. | 2388 // the texture. Flush it once here though. |
| 2269 hr = query_->Issue(D3DISSUE_END); | 2389 hr = query_->Issue(D3DISSUE_END); |
| 2270 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", ); | 2390 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", ); |
| 2271 | 2391 |
| 2272 // If we are sharing the ANGLE device we don't need to wait for the Flush to | 2392 // If we are sharing the ANGLE device we don't need to wait for the Flush to |
| 2273 // complete. | 2393 // complete. |
| 2274 if (using_angle_device_) { | 2394 if (using_angle_device_) { |
| 2275 main_thread_task_runner_->PostTask( | 2395 main_thread_task_runner_->PostTask( |
| 2276 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 2396 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2313 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), | 2433 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), |
| 2314 "Failed to make context current", | 2434 "Failed to make context current", |
| 2315 PLATFORM_FAILURE, ); | 2435 PLATFORM_FAILURE, ); |
| 2316 | 2436 |
| 2317 DCHECK(!output_picture_buffers_.empty()); | 2437 DCHECK(!output_picture_buffers_.empty()); |
| 2318 | 2438 |
| 2319 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); | 2439 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); |
| 2320 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", | 2440 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", |
| 2321 PLATFORM_FAILURE, ); | 2441 PLATFORM_FAILURE, ); |
| 2322 | 2442 |
| 2323 NotifyPictureReady(picture_buffer->id(), input_buffer_id, | 2443 NotifyPictureReady( |
| 2324 picture_buffer->color_space()); | 2444 picture_buffer->id(), input_buffer_id, |
| 2445 copy_nv12_textures_ ? picture_buffer->color_space() : gfx::ColorSpace()); | |
| 2325 | 2446 |
| 2326 { | 2447 { |
| 2327 base::AutoLock lock(decoder_lock_); | 2448 base::AutoLock lock(decoder_lock_); |
| 2328 if (!pending_output_samples_.empty()) | 2449 if (!pending_output_samples_.empty()) |
| 2329 pending_output_samples_.pop_front(); | 2450 pending_output_samples_.pop_front(); |
| 2330 } | 2451 } |
| 2331 | 2452 |
| 2332 if (pending_flush_ || processing_config_changed_) { | 2453 if (pending_flush_ || processing_config_changed_) { |
| 2333 decoder_thread_task_runner_->PostTask( | 2454 decoder_thread_task_runner_->PostTask( |
| 2334 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 2455 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2393 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2514 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
| 2394 base::Unretained(this))); | 2515 base::Unretained(this))); |
| 2395 } | 2516 } |
| 2396 | 2517 |
| 2397 void DXVAVideoDecodeAccelerator::CopyTexture( | 2518 void DXVAVideoDecodeAccelerator::CopyTexture( |
| 2398 ID3D11Texture2D* src_texture, | 2519 ID3D11Texture2D* src_texture, |
| 2399 ID3D11Texture2D* dest_texture, | 2520 ID3D11Texture2D* dest_texture, |
| 2400 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, | 2521 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, |
| 2401 uint64_t keyed_mutex_value, | 2522 uint64_t keyed_mutex_value, |
| 2402 int picture_buffer_id, | 2523 int picture_buffer_id, |
| 2403 int input_buffer_id) { | 2524 int input_buffer_id, |
| 2525 const gfx::ColorSpace& color_space) { | |
| 2404 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopyTexture"); | 2526 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopyTexture"); |
| 2405 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 2527 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
| 2406 | 2528 |
| 2407 DCHECK(use_dx11_); | 2529 DCHECK(use_dx11_); |
| 2408 | 2530 |
| 2409 // The media foundation H.264 decoder outputs YUV12 textures which we | 2531 // The media foundation H.264 decoder outputs YUV12 textures which we |
| 2410 // cannot copy into ANGLE as they expect ARGB textures. In D3D land | 2532 // cannot copy into ANGLE as they expect ARGB textures. In D3D land |
| 2411 // the StretchRect API in the IDirect3DDevice9Ex interface did the color | 2533 // the StretchRect API in the IDirect3DDevice9Ex interface did the color |
| 2412 // space conversion for us. Sadly in DX11 land the API does not provide | 2534 // space conversion for us. Sadly in DX11 land the API does not provide |
| 2413 // a straightforward way to do this. | 2535 // a straightforward way to do this. |
| 2414 // We use the video processor MFT. | 2536 // We use the video processor MFT. |
| 2415 // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx | 2537 // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx |
| 2416 // This object implements a media foundation transform (IMFTransform) | 2538 // This object implements a media foundation transform (IMFTransform) |
| 2417 // which follows the same contract as the decoder. The color space | 2539 // which follows the same contract as the decoder. The color space |
| 2418 // conversion as per msdn is done in the GPU. | 2540 // conversion as per msdn is done in the GPU. |
| 2419 | 2541 |
| 2420 D3D11_TEXTURE2D_DESC source_desc; | 2542 D3D11_TEXTURE2D_DESC source_desc; |
| 2421 src_texture->GetDesc(&source_desc); | 2543 src_texture->GetDesc(&source_desc); |
| 2422 | 2544 |
| 2423 // Set up the input and output types for the video processor MFT. | 2545 // Set up the input and output types for the video processor MFT. |
| 2424 if (!InitializeDX11VideoFormatConverterMediaType(source_desc.Width, | 2546 if (!InitializeDX11VideoFormatConverterMediaType( |
| 2425 source_desc.Height)) { | 2547 source_desc.Width, source_desc.Height, color_space)) { |
| 2426 RETURN_AND_NOTIFY_ON_FAILURE( | 2548 RETURN_AND_NOTIFY_ON_FAILURE( |
| 2427 false, "Failed to initialize media types for convesion.", | 2549 false, "Failed to initialize media types for convesion.", |
| 2428 PLATFORM_FAILURE, ); | 2550 PLATFORM_FAILURE, ); |
| 2429 } | 2551 } |
| 2430 | 2552 |
| 2431 // The input to the video processor is the output sample. | 2553 // The input to the video processor is the output sample. |
| 2432 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; | 2554 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; |
| 2433 { | 2555 { |
| 2434 base::AutoLock lock(decoder_lock_); | 2556 base::AutoLock lock(decoder_lock_); |
| 2435 PendingSampleInfo& sample_info = pending_output_samples_.front(); | 2557 PendingSampleInfo& sample_info = pending_output_samples_.front(); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2580 } | 2702 } |
| 2581 | 2703 |
| 2582 main_thread_task_runner_->PostTask( | 2704 main_thread_task_runner_->PostTask( |
| 2583 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 2705 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
| 2584 weak_ptr_, src_surface, dest_surface, | 2706 weak_ptr_, src_surface, dest_surface, |
| 2585 picture_buffer_id, input_buffer_id)); | 2707 picture_buffer_id, input_buffer_id)); |
| 2586 } | 2708 } |
| 2587 | 2709 |
| 2588 bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType( | 2710 bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType( |
| 2589 int width, | 2711 int width, |
| 2590 int height) { | 2712 int height, |
| 2591 if (!dx11_video_format_converter_media_type_needs_init_) | 2713 const gfx::ColorSpace& color_space) { |
| 2592 return true; | 2714 if (!dx11_video_format_converter_media_type_needs_init_) { |
| 2715 if (use_color_info_ && color_space != dx11_converter_color_space_) { | |
| 2716 // Free the convert and re-initialize it because the color space | |
| 2717 // has changed. | |
| 2718 video_format_converter_mft_ = NULL; | |
|
jbauman
2016/11/23 22:20:14
You can't set this to NULL as the check below will
hubbe
2016/11/23 23:59:21
Ops, I read that backwards.
Fixed.
| |
| 2719 } else { | |
| 2720 return true; | |
| 2721 } | |
| 2722 } | |
| 2593 | 2723 |
| 2594 CHECK(video_format_converter_mft_.get()); | 2724 CHECK(video_format_converter_mft_.get()); |
| 2595 | 2725 |
| 2596 HRESULT hr = video_format_converter_mft_->ProcessMessage( | 2726 HRESULT hr = video_format_converter_mft_->ProcessMessage( |
| 2597 MFT_MESSAGE_SET_D3D_MANAGER, | 2727 MFT_MESSAGE_SET_D3D_MANAGER, |
| 2598 reinterpret_cast<ULONG_PTR>(d3d11_device_manager_.get())); | 2728 reinterpret_cast<ULONG_PTR>(d3d11_device_manager_.get())); |
| 2599 | 2729 |
| 2600 if (FAILED(hr)) | 2730 if (FAILED(hr)) |
| 2601 DCHECK(false); | 2731 DCHECK(false); |
| 2602 | 2732 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2617 PLATFORM_FAILURE, false); | 2747 PLATFORM_FAILURE, false); |
| 2618 | 2748 |
| 2619 hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); | 2749 hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); |
| 2620 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type", | 2750 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type", |
| 2621 PLATFORM_FAILURE, false); | 2751 PLATFORM_FAILURE, false); |
| 2622 | 2752 |
| 2623 hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height); | 2753 hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height); |
| 2624 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes", | 2754 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes", |
| 2625 PLATFORM_FAILURE, false); | 2755 PLATFORM_FAILURE, false); |
| 2626 | 2756 |
| 2757 if (use_color_info_) { | |
| 2758 DXVA2_ExtendedFormat format = | |
| 2759 gfx::ColorSpaceWin::GetExtendedFormat(color_space); | |
| 2760 media_type->SetUINT32(MF_MT_YUV_MATRIX, format.VideoTransferMatrix); | |
| 2761 media_type->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, format.NominalRange); | |
| 2762 media_type->SetUINT32(MF_MT_VIDEO_PRIMARIES, format.VideoPrimaries); | |
| 2763 media_type->SetUINT32(MF_MT_TRANSFER_FUNCTION, | |
| 2764 format.VideoTransferFunction); | |
| 2765 dx11_converter_color_space_ = color_space; | |
| 2766 } | |
| 2767 | |
| 2627 hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0); | 2768 hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0); |
| 2628 if (FAILED(hr)) | 2769 if (FAILED(hr)) |
| 2629 DCHECK(false); | 2770 DCHECK(false); |
| 2630 | 2771 |
| 2631 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type", | 2772 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type", |
| 2632 PLATFORM_FAILURE, false); | 2773 PLATFORM_FAILURE, false); |
| 2633 | 2774 |
| 2634 // It appears that we fail to set MFVideoFormat_ARGB32 as the output media | 2775 // It appears that we fail to set MFVideoFormat_ARGB32 as the output media |
| 2635 // type in certain configurations. Try to fallback to MFVideoFormat_RGB32 | 2776 // type in certain configurations. Try to fallback to MFVideoFormat_RGB32 |
| 2636 // in such cases. If both fail, then bail. | 2777 // in such cases. If both fail, then bail. |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2759 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2900 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
| 2760 base::Unretained(this))); | 2901 base::Unretained(this))); |
| 2761 } | 2902 } |
| 2762 | 2903 |
| 2763 uint32_t DXVAVideoDecodeAccelerator::GetTextureTarget() const { | 2904 uint32_t DXVAVideoDecodeAccelerator::GetTextureTarget() const { |
| 2764 bool provide_nv12_textures = share_nv12_textures_ || copy_nv12_textures_; | 2905 bool provide_nv12_textures = share_nv12_textures_ || copy_nv12_textures_; |
| 2765 return provide_nv12_textures ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; | 2906 return provide_nv12_textures ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; |
| 2766 } | 2907 } |
| 2767 | 2908 |
| 2768 } // namespace media | 2909 } // namespace media |
| OLD | NEW |