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 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
510 use_keyed_mutex_(false), | 513 use_keyed_mutex_(false), |
511 dx11_video_format_converter_media_type_needs_init_(true), | 514 dx11_video_format_converter_media_type_needs_init_(true), |
512 using_angle_device_(false), | 515 using_angle_device_(false), |
513 enable_accelerated_vpx_decode_( | 516 enable_accelerated_vpx_decode_( |
514 gpu_preferences.enable_accelerated_vpx_decode), | 517 gpu_preferences.enable_accelerated_vpx_decode), |
515 processing_config_changed_(false), | 518 processing_config_changed_(false), |
516 weak_this_factory_(this) { | 519 weak_this_factory_(this) { |
517 weak_ptr_ = weak_this_factory_.GetWeakPtr(); | 520 weak_ptr_ = weak_this_factory_.GetWeakPtr(); |
518 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 521 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
519 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 522 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
523 use_color_info_ = base::FeatureList::IsEnabled(kVideoBlitColorAccuracy); | |
520 } | 524 } |
521 | 525 |
522 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 526 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
523 client_ = NULL; | 527 client_ = NULL; |
524 } | 528 } |
525 | 529 |
526 bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, | 530 bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, |
527 Client* client) { | 531 Client* client) { |
528 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | 532 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { |
529 NOTREACHED() << "GL callbacks are required for this VDA"; | 533 NOTREACHED() << "GL callbacks are required for this VDA"; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
693 hr = device_manager_->ResetDevice(d3d9_device_ex_.get(), | 697 hr = device_manager_->ResetDevice(d3d9_device_ex_.get(), |
694 dev_manager_reset_token_); | 698 dev_manager_reset_token_); |
695 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 699 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
696 | 700 |
697 hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | 701 hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
698 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); | 702 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); |
699 // Ensure query_ API works (to avoid an infinite loop later in | 703 // Ensure query_ API works (to avoid an infinite loop later in |
700 // CopyOutputSampleDataToPictureBuffer). | 704 // CopyOutputSampleDataToPictureBuffer). |
701 hr = query_->Issue(D3DISSUE_END); | 705 hr = query_->Issue(D3DISSUE_END); |
702 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | 706 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); |
707 | |
708 CreateVideoProcessor(); | |
703 return true; | 709 return true; |
704 } | 710 } |
705 | 711 |
712 bool DXVAVideoDecodeAccelerator::CreateVideoProcessor() { | |
713 if (!use_color_info_) | |
714 return false; | |
715 | |
716 // TODO(Hubbe): Don't try again if we failed tried and failed already. | |
717 if (video_processor_service_.get()) | |
718 return true; | |
719 HRESULT hr = DXVA2CreateVideoService(d3d9_device_ex_.get(), | |
720 IID_IDirectXVideoProcessorService, | |
721 video_processor_service_.ReceiveVoid()); | |
722 RETURN_ON_HR_FAILURE(hr, "DXVA2CreateVideoService failed", false); | |
723 | |
724 // TODO(Hubbe): Use actual video settings. | |
725 DXVA2_VideoDesc inputDesc; | |
726 inputDesc.SampleWidth = 1920; | |
727 inputDesc.SampleHeight = 1080; | |
728 inputDesc.SampleFormat.VideoChromaSubsampling = | |
729 DXVA2_VideoChromaSubsampling_MPEG2; | |
730 inputDesc.SampleFormat.NominalRange = DXVA2_NominalRange_16_235; | |
731 inputDesc.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT709; | |
732 inputDesc.SampleFormat.VideoLighting = DXVA2_VideoLighting_dim; | |
733 inputDesc.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709; | |
734 inputDesc.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709; | |
735 inputDesc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame; | |
736 inputDesc.Format = (D3DFORMAT)MAKEFOURCC('N', 'V', '1', '2'); | |
737 inputDesc.InputSampleFreq.Numerator = 30; | |
738 inputDesc.InputSampleFreq.Denominator = 1; | |
739 inputDesc.OutputFrameFreq.Numerator = 30; | |
740 inputDesc.OutputFrameFreq.Denominator = 1; | |
741 | |
742 UINT guid_count = 0; | |
743 base::win::ScopedCoMem<GUID> guids; | |
744 hr = video_processor_service_->GetVideoProcessorDeviceGuids( | |
745 &inputDesc, &guid_count, &guids); | |
746 RETURN_ON_HR_FAILURE(hr, "GetVideoProcessorDeviceGuids failed", false); | |
747 | |
748 for (UINT g = 0; g < guid_count; g++) { | |
749 DXVA2_VideoProcessorCaps caps; | |
750 hr = video_processor_service_->GetVideoProcessorCaps( | |
751 guids[g], &inputDesc, D3DFMT_X8R8G8B8, &caps); | |
752 if (hr) | |
753 continue; | |
754 | |
755 if (!(caps.VideoProcessorOperations & DXVA2_VideoProcess_YUV2RGB)) | |
756 continue; | |
757 | |
758 base::win::ScopedCoMem<D3DFORMAT> formats; | |
759 UINT format_count = 0; | |
760 hr = video_processor_service_->GetVideoProcessorRenderTargets( | |
761 guids[g], &inputDesc, &format_count, &formats); | |
762 if (hr) | |
763 continue; | |
764 | |
765 UINT f; | |
766 for (f = 0; f < format_count; f++) { | |
767 if (formats[f] == D3DFMT_X8R8G8B8) { | |
768 break; | |
769 } | |
770 } | |
771 if (f == format_count) | |
772 continue; | |
773 | |
774 // Create video processor | |
775 hr = video_processor_service_->CreateVideoProcessor( | |
776 guids[g], &inputDesc, D3DFMT_X8R8G8B8, 0, processor_.Receive()); | |
777 if (hr) | |
778 continue; | |
779 | |
780 DXVA2_ValueRange range; | |
781 processor_->GetProcAmpRange(DXVA2_ProcAmp_Brightness, &range); | |
782 default_procamp_values_.Brightness = range.DefaultValue; | |
783 processor_->GetProcAmpRange(DXVA2_ProcAmp_Contrast, &range); | |
784 default_procamp_values_.Contrast = range.DefaultValue; | |
785 processor_->GetProcAmpRange(DXVA2_ProcAmp_Hue, &range); | |
786 default_procamp_values_.Hue = range.DefaultValue; | |
787 processor_->GetProcAmpRange(DXVA2_ProcAmp_Saturation, &range); | |
788 default_procamp_values_.Saturation = range.DefaultValue; | |
789 | |
790 return true; | |
791 } | |
792 return false; | |
793 } | |
794 | |
706 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { | 795 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { |
707 // The device may exist if the last state was a config change. | 796 // The device may exist if the last state was a config change. |
708 if (d3d11_device_.get()) | 797 if (d3d11_device_.get()) |
709 return true; | 798 return true; |
710 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, | 799 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, |
711 d3d11_device_manager_.Receive()); | 800 d3d11_device_manager_.Receive()); |
712 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); | 801 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); |
713 | 802 |
714 angle_device_ = | 803 angle_device_ = |
715 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); | 804 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); |
(...skipping 1038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1754 } | 1843 } |
1755 | 1844 |
1756 if (width != index->second->size().width() || | 1845 if (width != index->second->size().width() || |
1757 height != index->second->size().height()) { | 1846 height != index->second->size().height()) { |
1758 HandleResolutionChanged(width, height); | 1847 HandleResolutionChanged(width, height); |
1759 return; | 1848 return; |
1760 } | 1849 } |
1761 | 1850 |
1762 pending_sample->picture_buffer_id = index->second->id(); | 1851 pending_sample->picture_buffer_id = index->second->id(); |
1763 index->second->set_bound(); | 1852 index->second->set_bound(); |
1764 | 1853 index->second->set_color_space(pending_sample->color_space); |
1765 // We only propagate the input color space if we can give the raw YUV data | |
1766 // back to the browser process. When we cannot return the YUV data, we | |
1767 // have to do a copy to an RGBA texture, which makes proper color | |
1768 // management difficult as some fidelity is lost. Also, we currently let | |
1769 // the drivers decide how to actually do the YUV to RGB conversion, which | |
1770 // means that even if we wanted to try to color-adjust the RGB output, we | |
1771 // don't actually know exactly what color space it is in anymore. | |
1772 // TODO(hubbe): Figure out a way to always return the raw YUV data. | |
1773 if (share_nv12_textures_ || copy_nv12_textures_) { | |
1774 index->second->set_color_space(pending_sample->color_space); | |
1775 } | |
1776 | 1854 |
1777 if (share_nv12_textures_) { | 1855 if (share_nv12_textures_) { |
1778 main_thread_task_runner_->PostTask( | 1856 main_thread_task_runner_->PostTask( |
1779 FROM_HERE, | 1857 FROM_HERE, |
1780 base::Bind(&DXVAVideoDecodeAccelerator::BindPictureBufferToSample, | 1858 base::Bind(&DXVAVideoDecodeAccelerator::BindPictureBufferToSample, |
1781 weak_ptr_, pending_sample->output_sample, | 1859 weak_ptr_, pending_sample->output_sample, |
1782 pending_sample->picture_buffer_id, | 1860 pending_sample->picture_buffer_id, |
1783 pending_sample->input_buffer_id)); | 1861 pending_sample->input_buffer_id)); |
1784 continue; | 1862 continue; |
1785 } | 1863 } |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2216 decoder_thread_.init_com_with_mta(false); | 2294 decoder_thread_.init_com_with_mta(false); |
2217 decoder_thread_.Start(); | 2295 decoder_thread_.Start(); |
2218 decoder_thread_task_runner_ = decoder_thread_.task_runner(); | 2296 decoder_thread_task_runner_ = decoder_thread_.task_runner(); |
2219 } | 2297 } |
2220 | 2298 |
2221 bool DXVAVideoDecodeAccelerator::OutputSamplesPresent() { | 2299 bool DXVAVideoDecodeAccelerator::OutputSamplesPresent() { |
2222 base::AutoLock lock(decoder_lock_); | 2300 base::AutoLock lock(decoder_lock_); |
2223 return !pending_output_samples_.empty(); | 2301 return !pending_output_samples_.empty(); |
2224 } | 2302 } |
2225 | 2303 |
2226 void DXVAVideoDecodeAccelerator::CopySurface(IDirect3DSurface9* src_surface, | 2304 void DXVAVideoDecodeAccelerator::CopySurface( |
2227 IDirect3DSurface9* dest_surface, | 2305 IDirect3DSurface9* src_surface, |
2228 int picture_buffer_id, | 2306 IDirect3DSurface9* dest_surface, |
2229 int input_buffer_id) { | 2307 int picture_buffer_id, |
2308 int input_buffer_id, | |
2309 const gfx::ColorSpace& color_space) { | |
2230 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopySurface"); | 2310 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopySurface"); |
2231 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { | 2311 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { |
2232 decoder_thread_task_runner_->PostTask( | 2312 decoder_thread_task_runner_->PostTask( |
2233 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurface, | 2313 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurface, |
2234 base::Unretained(this), src_surface, dest_surface, | 2314 base::Unretained(this), src_surface, dest_surface, |
2235 picture_buffer_id, input_buffer_id)); | 2315 picture_buffer_id, input_buffer_id, color_space)); |
2236 return; | 2316 return; |
2237 } | 2317 } |
2238 | 2318 |
2239 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, | 2319 HRESULT hr; |
2240 NULL, D3DTEXF_NONE); | 2320 if (processor_) { |
2241 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", ); | 2321 D3DSURFACE_DESC src_desc; |
2322 src_surface->GetDesc(&src_desc); | |
2323 int width = src_desc.Width; | |
2324 int height = src_desc.Height; | |
2325 RECT rect = {0, 0, width, height}; | |
2326 DXVA2_VideoSample sample = {0}; | |
2327 sample.End = 1000; | |
2328 if (use_color_info_) { | |
2329 sample.SampleFormat = gfx::ColorSpaceWin::GetExtendedFormat(color_space); | |
2330 } else { | |
2331 sample.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame; | |
2332 } | |
2242 | 2333 |
2334 sample.SrcSurface = src_surface; | |
2335 sample.SrcRect = rect; | |
2336 sample.DstRect = rect; | |
2337 sample.PlanarAlpha = DXVA2_Fixed32OpaqueAlpha(); | |
2338 | |
2339 DXVA2_VideoProcessBltParams params = {0}; | |
2340 params.TargetFrame = 0; | |
2341 params.TargetRect = rect; | |
2342 params.ConstrictionSize = {width, height}; | |
2343 params.BackgroundColor = {0, 0, 0, 0xFFFF}; | |
2344 params.ProcAmpValues = default_procamp_values_; | |
2345 | |
2346 params.Alpha = DXVA2_Fixed32OpaqueAlpha(); | |
2347 | |
2348 hr = processor_->VideoProcessBlt(dest_surface, ¶ms, &sample, 1, NULL); | |
2349 if (hr != S_OK) { | |
2350 LOG(ERROR) << "VideoProcessBlt failed with code " << hr | |
2351 << " E_INVALIDARG= " << E_INVALIDARG; | |
2352 | |
2353 // Release the processor and fall back to StretchRect() | |
2354 processor_ = NULL; | |
2355 } | |
2356 } | |
2357 | |
2358 if (!processor_) { | |
2359 hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, NULL, | |
2360 D3DTEXF_NONE); | |
2361 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", ); | |
2362 } | |
2243 // Ideally, this should be done immediately before the draw call that uses | 2363 // Ideally, this should be done immediately before the draw call that uses |
2244 // the texture. Flush it once here though. | 2364 // the texture. Flush it once here though. |
2245 hr = query_->Issue(D3DISSUE_END); | 2365 hr = query_->Issue(D3DISSUE_END); |
2246 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", ); | 2366 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", ); |
2247 | 2367 |
2248 // If we are sharing the ANGLE device we don't need to wait for the Flush to | 2368 // If we are sharing the ANGLE device we don't need to wait for the Flush to |
2249 // complete. | 2369 // complete. |
2250 if (using_angle_device_) { | 2370 if (using_angle_device_) { |
2251 main_thread_task_runner_->PostTask( | 2371 main_thread_task_runner_->PostTask( |
2252 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 2372 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2289 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), | 2409 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), |
2290 "Failed to make context current", | 2410 "Failed to make context current", |
2291 PLATFORM_FAILURE, ); | 2411 PLATFORM_FAILURE, ); |
2292 | 2412 |
2293 DCHECK(!output_picture_buffers_.empty()); | 2413 DCHECK(!output_picture_buffers_.empty()); |
2294 | 2414 |
2295 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); | 2415 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); |
2296 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", | 2416 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", |
2297 PLATFORM_FAILURE, ); | 2417 PLATFORM_FAILURE, ); |
2298 | 2418 |
2299 NotifyPictureReady(picture_buffer->id(), input_buffer_id, | 2419 NotifyPictureReady( |
2300 picture_buffer->color_space()); | 2420 picture_buffer->id(), input_buffer_id, |
2421 copy_nv12_textures_ ? picture_buffer->color_space() : gfx::ColorSpace()); | |
2301 | 2422 |
2302 { | 2423 { |
2303 base::AutoLock lock(decoder_lock_); | 2424 base::AutoLock lock(decoder_lock_); |
2304 if (!pending_output_samples_.empty()) | 2425 if (!pending_output_samples_.empty()) |
2305 pending_output_samples_.pop_front(); | 2426 pending_output_samples_.pop_front(); |
2306 } | 2427 } |
2307 | 2428 |
2308 if (pending_flush_ || processing_config_changed_) { | 2429 if (pending_flush_ || processing_config_changed_) { |
2309 decoder_thread_task_runner_->PostTask( | 2430 decoder_thread_task_runner_->PostTask( |
2310 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 2431 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2369 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2490 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
2370 base::Unretained(this))); | 2491 base::Unretained(this))); |
2371 } | 2492 } |
2372 | 2493 |
2373 void DXVAVideoDecodeAccelerator::CopyTexture( | 2494 void DXVAVideoDecodeAccelerator::CopyTexture( |
2374 ID3D11Texture2D* src_texture, | 2495 ID3D11Texture2D* src_texture, |
2375 ID3D11Texture2D* dest_texture, | 2496 ID3D11Texture2D* dest_texture, |
2376 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, | 2497 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, |
2377 uint64_t keyed_mutex_value, | 2498 uint64_t keyed_mutex_value, |
2378 int picture_buffer_id, | 2499 int picture_buffer_id, |
2379 int input_buffer_id) { | 2500 int input_buffer_id, |
2501 const gfx::ColorSpace& color_space) { | |
2380 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopyTexture"); | 2502 TRACE_EVENT0("media", "DXVAVideoDecodeAccelerator::CopyTexture"); |
2381 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 2503 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
2382 | 2504 |
2383 DCHECK(use_dx11_); | 2505 DCHECK(use_dx11_); |
2384 | 2506 |
2385 // The media foundation H.264 decoder outputs YUV12 textures which we | 2507 // The media foundation H.264 decoder outputs YUV12 textures which we |
2386 // cannot copy into ANGLE as they expect ARGB textures. In D3D land | 2508 // cannot copy into ANGLE as they expect ARGB textures. In D3D land |
2387 // the StretchRect API in the IDirect3DDevice9Ex interface did the color | 2509 // the StretchRect API in the IDirect3DDevice9Ex interface did the color |
2388 // space conversion for us. Sadly in DX11 land the API does not provide | 2510 // space conversion for us. Sadly in DX11 land the API does not provide |
2389 // a straightforward way to do this. | 2511 // a straightforward way to do this. |
2390 // We use the video processor MFT. | 2512 // We use the video processor MFT. |
2391 // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx | 2513 // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx |
2392 // This object implements a media foundation transform (IMFTransform) | 2514 // This object implements a media foundation transform (IMFTransform) |
2393 // which follows the same contract as the decoder. The color space | 2515 // which follows the same contract as the decoder. The color space |
2394 // conversion as per msdn is done in the GPU. | 2516 // conversion as per msdn is done in the GPU. |
2395 | 2517 |
2396 D3D11_TEXTURE2D_DESC source_desc; | 2518 D3D11_TEXTURE2D_DESC source_desc; |
2397 src_texture->GetDesc(&source_desc); | 2519 src_texture->GetDesc(&source_desc); |
2398 | 2520 |
2399 // Set up the input and output types for the video processor MFT. | 2521 // Set up the input and output types for the video processor MFT. |
2400 if (!InitializeDX11VideoFormatConverterMediaType(source_desc.Width, | 2522 if (!InitializeDX11VideoFormatConverterMediaType( |
2401 source_desc.Height)) { | 2523 source_desc.Width, source_desc.Height, color_space)) { |
2402 RETURN_AND_NOTIFY_ON_FAILURE( | 2524 RETURN_AND_NOTIFY_ON_FAILURE( |
2403 false, "Failed to initialize media types for convesion.", | 2525 false, "Failed to initialize media types for convesion.", |
2404 PLATFORM_FAILURE, ); | 2526 PLATFORM_FAILURE, ); |
2405 } | 2527 } |
2406 | 2528 |
2407 // The input to the video processor is the output sample. | 2529 // The input to the video processor is the output sample. |
2408 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; | 2530 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; |
2409 { | 2531 { |
2410 base::AutoLock lock(decoder_lock_); | 2532 base::AutoLock lock(decoder_lock_); |
2411 PendingSampleInfo& sample_info = pending_output_samples_.front(); | 2533 PendingSampleInfo& sample_info = pending_output_samples_.front(); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2556 } | 2678 } |
2557 | 2679 |
2558 main_thread_task_runner_->PostTask( | 2680 main_thread_task_runner_->PostTask( |
2559 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 2681 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
2560 weak_ptr_, src_surface, dest_surface, | 2682 weak_ptr_, src_surface, dest_surface, |
2561 picture_buffer_id, input_buffer_id)); | 2683 picture_buffer_id, input_buffer_id)); |
2562 } | 2684 } |
2563 | 2685 |
2564 bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType( | 2686 bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType( |
2565 int width, | 2687 int width, |
2566 int height) { | 2688 int height, |
2689 const gfx::ColorSpace& color_space) { | |
2567 if (!dx11_video_format_converter_media_type_needs_init_) | 2690 if (!dx11_video_format_converter_media_type_needs_init_) |
2568 return true; | 2691 return true; |
jbauman
2016/11/22 22:16:59
We may need to reinitialize this if the color spac
hubbe
2016/11/23 21:21:26
Done.
| |
2569 | 2692 |
2570 CHECK(video_format_converter_mft_.get()); | 2693 CHECK(video_format_converter_mft_.get()); |
2571 | 2694 |
2572 HRESULT hr = video_format_converter_mft_->ProcessMessage( | 2695 HRESULT hr = video_format_converter_mft_->ProcessMessage( |
2573 MFT_MESSAGE_SET_D3D_MANAGER, | 2696 MFT_MESSAGE_SET_D3D_MANAGER, |
2574 reinterpret_cast<ULONG_PTR>(d3d11_device_manager_.get())); | 2697 reinterpret_cast<ULONG_PTR>(d3d11_device_manager_.get())); |
2575 | 2698 |
2576 if (FAILED(hr)) | 2699 if (FAILED(hr)) |
2577 DCHECK(false); | 2700 DCHECK(false); |
2578 | 2701 |
(...skipping 14 matching lines...) Expand all Loading... | |
2593 PLATFORM_FAILURE, false); | 2716 PLATFORM_FAILURE, false); |
2594 | 2717 |
2595 hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); | 2718 hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); |
2596 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type", | 2719 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type", |
2597 PLATFORM_FAILURE, false); | 2720 PLATFORM_FAILURE, false); |
2598 | 2721 |
2599 hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height); | 2722 hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height); |
2600 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes", | 2723 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes", |
2601 PLATFORM_FAILURE, false); | 2724 PLATFORM_FAILURE, false); |
2602 | 2725 |
2726 if (use_color_info_) { | |
2727 DXVA2_ExtendedFormat format = | |
2728 gfx::ColorSpaceWin::GetExtendedFormat(color_space); | |
2729 media_type->SetUINT32(MF_MT_YUV_MATRIX, format.VideoTransferMatrix); | |
2730 media_type->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, format.NominalRange); | |
2731 media_type->SetUINT32(MF_MT_VIDEO_PRIMARIES, format.VideoPrimaries); | |
2732 media_type->SetUINT32(MF_MT_TRANSFER_FUNCTION, | |
2733 format.VideoTransferFunction); | |
2734 } | |
2735 | |
2603 hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0); | 2736 hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0); |
2604 if (FAILED(hr)) | 2737 if (FAILED(hr)) |
2605 DCHECK(false); | 2738 DCHECK(false); |
2606 | 2739 |
2607 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type", | 2740 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type", |
2608 PLATFORM_FAILURE, false); | 2741 PLATFORM_FAILURE, false); |
2609 | 2742 |
2610 // It appears that we fail to set MFVideoFormat_ARGB32 as the output media | 2743 // It appears that we fail to set MFVideoFormat_ARGB32 as the output media |
2611 // type in certain configurations. Try to fallback to MFVideoFormat_RGB32 | 2744 // type in certain configurations. Try to fallback to MFVideoFormat_RGB32 |
2612 // in such cases. If both fail, then bail. | 2745 // in such cases. If both fail, then bail. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2730 SetState(kConfigChange); | 2863 SetState(kConfigChange); |
2731 Invalidate(); | 2864 Invalidate(); |
2732 Initialize(config_, client_); | 2865 Initialize(config_, client_); |
2733 decoder_thread_task_runner_->PostTask( | 2866 decoder_thread_task_runner_->PostTask( |
2734 FROM_HERE, | 2867 FROM_HERE, |
2735 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2868 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
2736 base::Unretained(this))); | 2869 base::Unretained(this))); |
2737 } | 2870 } |
2738 | 2871 |
2739 } // namespace media | 2872 } // namespace media |
OLD | NEW |