Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: content/common/gpu/media/dxva_video_decode_accelerator_win.cc

Issue 1851713002: Add support for detecting the maximum resolution supported by the GPU for H.264 videos. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix indentation Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/common/gpu/media/dxva_video_decode_accelerator_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 #endif 104 #endif
105 105
106 // MF_XVP_PLAYBACK_MODE 106 // MF_XVP_PLAYBACK_MODE
107 // Data type: UINT32 (treat as BOOL) 107 // Data type: UINT32 (treat as BOOL)
108 // If this attribute is TRUE, the video processor will run in playback mode 108 // If this attribute is TRUE, the video processor will run in playback mode
109 // where it allows callers to allocate output samples and allows last frame 109 // where it allows callers to allocate output samples and allows last frame
110 // regeneration (repaint). 110 // regeneration (repaint).
111 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, 111 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12,
112 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); 112 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9);
113 113
114 // Defines the GUID for the Intel H264 DXVA device.
115 static const GUID DXVA2_Intel_ModeH264_E = {
116 0x604F8E68, 0x4951, 0x4c54,{ 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6}
117 };
118
114 // Provides scoped access to the underlying buffer in an IMFMediaBuffer 119 // Provides scoped access to the underlying buffer in an IMFMediaBuffer
115 // instance. 120 // instance.
116 class MediaBufferScopedPointer { 121 class MediaBufferScopedPointer {
117 public: 122 public:
118 MediaBufferScopedPointer(IMFMediaBuffer* media_buffer) 123 MediaBufferScopedPointer(IMFMediaBuffer* media_buffer)
119 : media_buffer_(media_buffer), 124 : media_buffer_(media_buffer),
120 buffer_(nullptr), 125 buffer_(nullptr),
121 max_length_(0), 126 max_length_(0),
122 current_length_(0) { 127 current_length_(0) {
123 HRESULT hr = media_buffer_->Lock(&buffer_, &max_length_, &current_length_); 128 HRESULT hr = media_buffer_->Lock(&buffer_, &max_length_, &current_length_);
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 return hr; 315 return hr;
311 } 316 }
312 317
313 // Helper function to query the ANGLE device object. The template argument T 318 // Helper function to query the ANGLE device object. The template argument T
314 // identifies the device interface being queried. IDirect3DDevice9Ex for d3d9 319 // identifies the device interface being queried. IDirect3DDevice9Ex for d3d9
315 // and ID3D11Device for dx11. 320 // and ID3D11Device for dx11.
316 template<class T> 321 template<class T>
317 base::win::ScopedComPtr<T> QueryDeviceObjectFromANGLE(int object_type) { 322 base::win::ScopedComPtr<T> QueryDeviceObjectFromANGLE(int object_type) {
318 base::win::ScopedComPtr<T> device_object; 323 base::win::ScopedComPtr<T> device_object;
319 324
320 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 325 EGLDisplay egl_display = nullptr;
321 intptr_t egl_device = 0; 326 intptr_t egl_device = 0;
322 intptr_t device = 0; 327 intptr_t device = 0;
323 328
329 {
330 TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. GetHardwareDisplay");
331 egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
332 }
333
324 RETURN_ON_FAILURE( 334 RETURN_ON_FAILURE(
325 gfx::GLSurfaceEGL::HasEGLExtension("EGL_EXT_device_query"), 335 gfx::GLSurfaceEGL::HasEGLExtension("EGL_EXT_device_query"),
326 "EGL_EXT_device_query missing", 336 "EGL_EXT_device_query missing",
327 device_object); 337 device_object);
328 338
329 PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = 339 PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = nullptr;
330 reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(eglGetProcAddress(
331 "eglQueryDisplayAttribEXT"));
332 340
333 RETURN_ON_FAILURE( 341 {
334 QueryDisplayAttribEXT, 342 TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress");
335 "Failed to get the eglQueryDisplayAttribEXT function from ANGLE",
336 device_object);
337 343
338 PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = 344 QueryDisplayAttribEXT =
339 reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(eglGetProcAddress( 345 reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(eglGetProcAddress(
340 "eglQueryDeviceAttribEXT")); 346 "eglQueryDisplayAttribEXT"));
341 347
342 RETURN_ON_FAILURE( 348 RETURN_ON_FAILURE(
343 QueryDeviceAttribEXT, 349 QueryDisplayAttribEXT,
344 "Failed to get the eglQueryDeviceAttribEXT function from ANGLE", 350 "Failed to get the eglQueryDisplayAttribEXT function from ANGLE",
345 device_object); 351 device_object);
352 }
346 353
347 RETURN_ON_FAILURE( 354 PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = nullptr;
348 QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device), 355
349 "The eglQueryDisplayAttribEXT function failed to get the EGL device", 356 {
350 device_object); 357 TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress");
358
359 QueryDeviceAttribEXT =
360 reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(eglGetProcAddress(
361 "eglQueryDeviceAttribEXT"));
362
363 RETURN_ON_FAILURE(
364 QueryDeviceAttribEXT,
365 "Failed to get the eglQueryDeviceAttribEXT function from ANGLE",
366 device_object);
367 }
368
369 {
370 TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT");
371
372 RETURN_ON_FAILURE(
373 QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device),
374 "The eglQueryDisplayAttribEXT function failed to get the EGL device",
375 device_object);
376 }
351 377
352 RETURN_ON_FAILURE( 378 RETURN_ON_FAILURE(
353 egl_device, 379 egl_device,
354 "Failed to get the EGL device", 380 "Failed to get the EGL device",
355 device_object); 381 device_object);
356 382
357 RETURN_ON_FAILURE( 383 {
358 QueryDeviceAttribEXT( 384 TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT");
359 reinterpret_cast<EGLDeviceEXT>(egl_device), object_type, &device),
360 "The eglQueryDeviceAttribEXT function failed to get the device",
361 device_object);
362 385
363 RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object); 386 RETURN_ON_FAILURE(
387 QueryDeviceAttribEXT(
388 reinterpret_cast<EGLDeviceEXT>(egl_device), object_type, &device),
389 "The eglQueryDeviceAttribEXT function failed to get the device",
390 device_object);
391
392 RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object);
393 }
364 394
365 device_object = reinterpret_cast<T*>(device); 395 device_object = reinterpret_cast<T*>(device);
366 return device_object; 396 return device_object;
367 } 397 }
368 398
369 H264ConfigChangeDetector::H264ConfigChangeDetector() 399 H264ConfigChangeDetector::H264ConfigChangeDetector()
370 : last_sps_id_(0), 400 : last_sps_id_(0),
371 last_pps_id_(0), 401 last_pps_id_(0),
372 config_changed_(false), 402 config_changed_(false),
373 pending_config_changed_(false) { 403 pending_config_changed_(false) {
(...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 return false; 1364 return false;
1335 } 1365 }
1336 1366
1337 GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const { 1367 GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const {
1338 return GL_BGRA_EXT; 1368 return GL_BGRA_EXT;
1339 } 1369 }
1340 1370
1341 // static 1371 // static
1342 media::VideoDecodeAccelerator::SupportedProfiles 1372 media::VideoDecodeAccelerator::SupportedProfiles
1343 DXVAVideoDecodeAccelerator::GetSupportedProfiles() { 1373 DXVAVideoDecodeAccelerator::GetSupportedProfiles() {
1374 TRACE_EVENT0("gpu,startup",
1375 "DXVAVideoDecodeAccelerator::GetSupportedProfiles");
1376
1344 // TODO(henryhsu): Need to ensure the profiles are actually supported. 1377 // TODO(henryhsu): Need to ensure the profiles are actually supported.
1345 SupportedProfiles profiles; 1378 SupportedProfiles profiles;
1346 for (const auto& supported_profile : kSupportedProfiles) { 1379 for (const auto& supported_profile : kSupportedProfiles) {
1380 std::pair<int, int> min_resolution = GetMinResolution(supported_profile);
1381 std::pair<int, int> max_resolution = GetMaxResolution(supported_profile);
1382
1347 SupportedProfile profile; 1383 SupportedProfile profile;
1348 profile.profile = supported_profile; 1384 profile.profile = supported_profile;
1349 // Windows Media Foundation H.264 decoding does not support decoding videos 1385 profile.min_resolution.SetSize(min_resolution.first, min_resolution.second);
1350 // with any dimension smaller than 48 pixels: 1386 profile.max_resolution.SetSize(max_resolution.first, max_resolution.second);
1351 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815
1352 profile.min_resolution.SetSize(48, 48);
1353 // Use 1088 to account for 16x16 macroblocks.
1354 profile.max_resolution.SetSize(1920, 1088);
1355 profiles.push_back(profile); 1387 profiles.push_back(profile);
1356 } 1388 }
1357 return profiles; 1389 return profiles;
1358 } 1390 }
1359 1391
1360 // static 1392 // static
1361 void DXVAVideoDecodeAccelerator::PreSandboxInitialization() { 1393 void DXVAVideoDecodeAccelerator::PreSandboxInitialization() {
1362 ::LoadLibrary(L"MFPlat.dll"); 1394 ::LoadLibrary(L"MFPlat.dll");
1363 ::LoadLibrary(L"msmpeg2vdec.dll"); 1395 ::LoadLibrary(L"msmpeg2vdec.dll");
1364 ::LoadLibrary(L"mf.dll"); 1396 ::LoadLibrary(L"mf.dll");
1365 ::LoadLibrary(L"dxva2.dll"); 1397 ::LoadLibrary(L"dxva2.dll");
1366 1398
1367 if (base::win::GetVersion() > base::win::VERSION_WIN7) { 1399 if (base::win::GetVersion() > base::win::VERSION_WIN7) {
1368 LoadLibrary(L"msvproc.dll"); 1400 LoadLibrary(L"msvproc.dll");
1369 } else { 1401 } else {
1370 #if defined(ENABLE_DX11_FOR_WIN7) 1402 #if defined(ENABLE_DX11_FOR_WIN7)
1371 LoadLibrary(L"mshtmlmedia.dll"); 1403 LoadLibrary(L"mshtmlmedia.dll");
1372 #endif 1404 #endif
1373 } 1405 }
1374 } 1406 }
1375 1407
1408 // static
1409 std::pair<int, int> DXVAVideoDecodeAccelerator::GetMinResolution(
1410 media::VideoCodecProfile profile) {
1411 TRACE_EVENT0("gpu,startup",
1412 "DXVAVideoDecodeAccelerator::GetMinResolution");
1413 std::pair<int, int> min_resolution;
1414 if (profile >= media::H264PROFILE_BASELINE &&
1415 profile <= media::H264PROFILE_HIGH) {
1416 // Windows Media Foundation H.264 decoding does not support decoding videos
1417 // with any dimension smaller than 48 pixels:
1418 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815
1419 min_resolution = std::make_pair(48, 48);
1420 } else {
1421 // TODO(ananta)
1422 // Detect this properly for VP8/VP9 profiles.
1423 min_resolution = std::make_pair(16, 16);
1424 }
1425 return min_resolution;
1426 }
1427
1428 // static
1429 std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxResolution(
1430 const media::VideoCodecProfile profile) {
1431 TRACE_EVENT0("gpu,startup",
1432 "DXVAVideoDecodeAccelerator::GetMaxResolution");
1433 std::pair<int, int> max_resolution;
1434 if (profile >= media::H264PROFILE_BASELINE &&
1435 profile <= media::H264PROFILE_HIGH) {
1436 max_resolution = GetMaxH264Resolution();
1437 } else {
1438 // TODO(ananta)
1439 // Detect this properly for VP8/VP9 profiles.
1440 max_resolution = std::make_pair(4096, 2160);
1441 }
1442 return max_resolution;
1443 }
1444
1445 std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxH264Resolution() {
1446 TRACE_EVENT0("gpu,startup",
1447 "DXVAVideoDecodeAccelerator::GetMaxH264Resolution");
1448 // The H.264 resolution detection operation is expensive. This static flag
1449 // allows us to run the detection once.
1450 static bool resolution_detected = false;
1451 // Use 1088 to account for 16x16 macroblocks.
1452 static std::pair<int, int> max_resolution = std::make_pair(1920, 1088);
1453 if (resolution_detected)
1454 return max_resolution;
1455
1456 resolution_detected = true;
1457
1458 // On Windows 7 the maximum resolution supported by media foundation is
1459 // 1920 x 1088.
1460 if (base::win::GetVersion() == base::win::VERSION_WIN7)
1461 return max_resolution;
1462
1463 // To detect if a driver supports the desired resolutions, we try and create
1464 // a DXVA decoder instance for that resolution and profile. If that succeeds
1465 // we assume that the driver supports H/W H.264 decoding for that resolution.
1466 HRESULT hr = E_FAIL;
1467 base::win::ScopedComPtr<ID3D11Device> device;
1468
1469 {
1470 TRACE_EVENT0("gpu,startup",
1471 "GetMaxH264Resolution. QueryDeviceObjectFromANGLE");
1472
1473 device = QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE);
1474 if (!device.get())
1475 return max_resolution;
1476 }
1477
1478 base::win::ScopedComPtr<ID3D11VideoDevice> video_device;
1479 hr = device.QueryInterface(IID_ID3D11VideoDevice,
1480 video_device.ReceiveVoid());
1481 if (FAILED(hr))
1482 return max_resolution;
1483
1484 GUID decoder_guid = {};
1485
1486 {
1487 TRACE_EVENT0("gpu,startup",
1488 "GetMaxH264Resolution. H.264 guid search begin");
1489 // Enumerate supported video profiles and look for the H264 profile.
1490 bool found = false;
1491 UINT profile_count = video_device->GetVideoDecoderProfileCount();
1492 for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) {
1493 GUID profile_id = {};
1494 hr = video_device->GetVideoDecoderProfile(profile_idx, &profile_id);
1495 if (SUCCEEDED(hr) &&
1496 (profile_id == DXVA2_ModeH264_E ||
1497 profile_id == DXVA2_Intel_ModeH264_E)) {
1498 decoder_guid = profile_id;
1499 found = true;
1500 break;
1501 }
1502 }
1503 if (!found)
1504 return max_resolution;
1505 }
1506
1507 // We look for the following resolutions in the driver.
1508 // TODO(ananta)
1509 // Look into whether this list needs to be expanded.
1510 static std::pair<int, int> resolution_array[] = {
1511 // Use 1088 to account for 16x16 macroblocks.
1512 std::make_pair(1920, 1088),
1513 std::make_pair(2560, 1440),
1514 std::make_pair(3840, 2160),
1515 std::make_pair(4096, 2160),
1516 std::make_pair(4096, 2304),
1517 };
1518
1519 {
1520 TRACE_EVENT0("gpu,startup",
1521 "GetMaxH264Resolution. Resolution search begin");
1522
1523 for (size_t res_idx = 0; res_idx < arraysize(resolution_array);
1524 res_idx++) {
1525 D3D11_VIDEO_DECODER_DESC desc = {};
1526 desc.Guid = decoder_guid;
1527 desc.SampleWidth = resolution_array[res_idx].first;
1528 desc.SampleHeight = resolution_array[res_idx].second;
1529 desc.OutputFormat = DXGI_FORMAT_NV12;
1530 UINT config_count = 0;
1531 hr = video_device->GetVideoDecoderConfigCount(&desc, &config_count);
1532 if (FAILED(hr) || config_count == 0)
1533 return max_resolution;
1534
1535 D3D11_VIDEO_DECODER_CONFIG config = {};
1536 hr = video_device->GetVideoDecoderConfig(&desc, 0, &config);
1537 if (FAILED(hr))
1538 return max_resolution;
1539
1540 base::win::ScopedComPtr<ID3D11VideoDecoder> video_decoder;
1541 hr = video_device->CreateVideoDecoder(&desc, &config,
1542 video_decoder.Receive());
1543 if (!video_decoder.get())
1544 return max_resolution;
1545
1546 max_resolution = resolution_array[res_idx];
1547 }
1548 }
1549 return max_resolution;
1550 }
1551
1376 bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { 1552 bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) {
1377 HMODULE decoder_dll = NULL; 1553 HMODULE decoder_dll = NULL;
1378 1554
1379 CLSID clsid = {}; 1555 CLSID clsid = {};
1380 1556
1381 // Profile must fall within the valid range for one of the supported codecs. 1557 // Profile must fall within the valid range for one of the supported codecs.
1382 if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) { 1558 if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) {
1383 // We mimic the steps CoCreateInstance uses to instantiate the object. This 1559 // We mimic the steps CoCreateInstance uses to instantiate the object. This
1384 // was previously done because it failed inside the sandbox, and now is done 1560 // was previously done because it failed inside the sandbox, and now is done
1385 // as a more minimal approach to avoid other side-effects CCI might have (as 1561 // as a more minimal approach to avoid other side-effects CCI might have (as
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
1730 OutputBuffers::iterator index; 1906 OutputBuffers::iterator index;
1731 1907
1732 for (index = output_picture_buffers_.begin(); 1908 for (index = output_picture_buffers_.begin();
1733 index != output_picture_buffers_.end() && 1909 index != output_picture_buffers_.end() &&
1734 OutputSamplesPresent(); 1910 OutputSamplesPresent();
1735 ++index) { 1911 ++index) {
1736 if (index->second->available()) { 1912 if (index->second->available()) {
1737 PendingSampleInfo* pending_sample = NULL; 1913 PendingSampleInfo* pending_sample = NULL;
1738 { 1914 {
1739 base::AutoLock lock(decoder_lock_); 1915 base::AutoLock lock(decoder_lock_);
1740
1741 PendingSampleInfo& sample_info = pending_output_samples_.front(); 1916 PendingSampleInfo& sample_info = pending_output_samples_.front();
1742 if (sample_info.picture_buffer_id != -1) 1917 if (sample_info.picture_buffer_id != -1)
1743 continue; 1918 continue;
1744 pending_sample = &sample_info; 1919 pending_sample = &sample_info;
1745 } 1920 }
1746 1921
1747 int width = 0; 1922 int width = 0;
1748 int height = 0; 1923 int height = 0;
1749 if (!GetVideoFrameDimensions(pending_sample->output_sample.get(), 1924 if (!GetVideoFrameDimensions(pending_sample->output_sample.get(),
1750 &width, &height)) { 1925 &width, &height)) {
(...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after
2656 DismissStaleBuffers(true); 2831 DismissStaleBuffers(true);
2657 Invalidate(); 2832 Invalidate();
2658 Initialize(config_, client_); 2833 Initialize(config_, client_);
2659 decoder_thread_task_runner_->PostTask( 2834 decoder_thread_task_runner_->PostTask(
2660 FROM_HERE, 2835 FROM_HERE,
2661 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, 2836 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
2662 base::Unretained(this))); 2837 base::Unretained(this)));
2663 } 2838 }
2664 2839
2665 } // namespace content 2840 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/dxva_video_decode_accelerator_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698