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 |
11 #include <ks.h> | 11 #include <ks.h> |
12 #include <codecapi.h> | 12 #include <codecapi.h> |
13 #include <dxgi1_2.h> | |
13 #include <mfapi.h> | 14 #include <mfapi.h> |
14 #include <mferror.h> | 15 #include <mferror.h> |
15 #include <wmcodecdsp.h> | 16 #include <wmcodecdsp.h> |
16 | 17 |
17 #include "base/base_paths_win.h" | 18 #include "base/base_paths_win.h" |
18 #include "base/bind.h" | 19 #include "base/bind.h" |
19 #include "base/callback.h" | 20 #include "base/callback.h" |
20 #include "base/command_line.h" | 21 #include "base/command_line.h" |
21 #include "base/file_version_info.h" | 22 #include "base/file_version_info.h" |
22 #include "base/files/file_path.h" | 23 #include "base/files/file_path.h" |
23 #include "base/logging.h" | 24 #include "base/logging.h" |
24 #include "base/memory/scoped_ptr.h" | 25 #include "base/memory/scoped_ptr.h" |
25 #include "base/memory/shared_memory.h" | 26 #include "base/memory/shared_memory.h" |
26 #include "base/message_loop/message_loop.h" | 27 #include "base/message_loop/message_loop.h" |
27 #include "base/path_service.h" | 28 #include "base/path_service.h" |
28 #include "base/trace_event/trace_event.h" | 29 #include "base/trace_event/trace_event.h" |
29 #include "base/win/windows_version.h" | 30 #include "base/win/windows_version.h" |
30 #include "media/video/video_decode_accelerator.h" | 31 #include "media/video/video_decode_accelerator.h" |
31 #include "ui/gl/gl_bindings.h" | 32 #include "ui/gl/gl_bindings.h" |
33 #include "ui/gl/gl_context.h" | |
32 #include "ui/gl/gl_surface_egl.h" | 34 #include "ui/gl/gl_surface_egl.h" |
33 #include "ui/gl/gl_switches.h" | 35 #include "ui/gl/gl_switches.h" |
34 | 36 |
35 namespace { | 37 namespace { |
36 | 38 |
37 // Path is appended on to the PROGRAM_FILES base path. | 39 // Path is appended on to the PROGRAM_FILES base path. |
38 const wchar_t kVPXDecoderDLLPath[] = L"Intel\\Media SDK\\"; | 40 const wchar_t kVPXDecoderDLLPath[] = L"Intel\\Media SDK\\"; |
39 | 41 |
40 const wchar_t kVP8DecoderDLLName[] = | 42 const wchar_t kVP8DecoderDLLName[] = |
41 #if defined(ARCH_CPU_X86) | 43 #if defined(ARCH_CPU_X86) |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } | 78 { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } |
77 }; | 79 }; |
78 | 80 |
79 const CLSID MEDIASUBTYPE_VP90 = { | 81 const CLSID MEDIASUBTYPE_VP90 = { |
80 0x30395056, | 82 0x30395056, |
81 0x0000, | 83 0x0000, |
82 0x0010, | 84 0x0010, |
83 { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } | 85 { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } |
84 }; | 86 }; |
85 | 87 |
88 // The CLSID of the video processor media foundation transform which we use for | |
89 // texture color conversion in DX11. | |
90 DEFINE_GUID(CLSID_VideoProcessorMFT, | |
91 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, | |
92 0xc9, 0x82); | |
93 | |
94 // MF_XVP_PLAYBACK_MODE | |
95 // Data type: UINT32 (treat as BOOL) | |
96 // If this attribute is TRUE, the video processor will run in playback mode | |
97 // where it allows callers to allocate output samples and allows last frame | |
98 // regeneration (repaint). | |
99 DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, | |
100 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); | |
86 } | 101 } |
87 | 102 |
88 namespace content { | 103 namespace content { |
89 | 104 |
105 CreateDXGIDeviceManager DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ | |
106 = NULL; | |
107 | |
90 #define RETURN_ON_FAILURE(result, log, ret) \ | 108 #define RETURN_ON_FAILURE(result, log, ret) \ |
91 do { \ | 109 do { \ |
92 if (!(result)) { \ | 110 if (!(result)) { \ |
93 DLOG(ERROR) << log; \ | 111 DLOG(ERROR) << log; \ |
94 return ret; \ | 112 return ret; \ |
95 } \ | 113 } \ |
96 } while (0) | 114 } while (0) |
97 | 115 |
98 #define RETURN_ON_HR_FAILURE(result, log, ret) \ | 116 #define RETURN_ON_HR_FAILURE(result, log, ret) \ |
99 RETURN_ON_FAILURE(SUCCEEDED(result), \ | 117 RETURN_ON_FAILURE(SUCCEEDED(result), \ |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 } else { | 169 } else { |
152 hr = MFCreateAlignedMemoryBuffer(buffer_length, | 170 hr = MFCreateAlignedMemoryBuffer(buffer_length, |
153 align - 1, | 171 align - 1, |
154 buffer.Receive()); | 172 buffer.Receive()); |
155 } | 173 } |
156 RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL); | 174 RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL); |
157 | 175 |
158 hr = sample->AddBuffer(buffer.get()); | 176 hr = sample->AddBuffer(buffer.get()); |
159 RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL); | 177 RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL); |
160 | 178 |
179 buffer->SetCurrentLength(0); | |
161 return sample.Detach(); | 180 return sample.Detach(); |
162 } | 181 } |
163 | 182 |
164 // Creates a Media Foundation sample with one buffer containing a copy of the | 183 // Creates a Media Foundation sample with one buffer containing a copy of the |
165 // given Annex B stream data. | 184 // given Annex B stream data. |
166 // If duration and sample time are not known, provide 0. | 185 // If duration and sample time are not known, provide 0. |
167 // |min_size| specifies the minimum size of the buffer (might be required by | 186 // |min_size| specifies the minimum size of the buffer (might be required by |
168 // the decoder for input). If no alignment is required, provide 0. | 187 // the decoder for input). If no alignment is required, provide 0. |
169 static IMFSample* CreateInputSample(const uint8* stream, int size, | 188 static IMFSample* CreateInputSample(const uint8* stream, int size, |
170 int min_size, int alignment) { | 189 int min_size, int alignment) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 EGLConfig egl_config); | 241 EGLConfig egl_config); |
223 ~DXVAPictureBuffer(); | 242 ~DXVAPictureBuffer(); |
224 | 243 |
225 void ReusePictureBuffer(); | 244 void ReusePictureBuffer(); |
226 // Copies the output sample data to the picture buffer provided by the | 245 // Copies the output sample data to the picture buffer provided by the |
227 // client. | 246 // client. |
228 // The dest_surface parameter contains the decoded bits. | 247 // The dest_surface parameter contains the decoded bits. |
229 bool CopyOutputSampleDataToPictureBuffer( | 248 bool CopyOutputSampleDataToPictureBuffer( |
230 DXVAVideoDecodeAccelerator* decoder, | 249 DXVAVideoDecodeAccelerator* decoder, |
231 IDirect3DSurface9* dest_surface, | 250 IDirect3DSurface9* dest_surface, |
251 ID3D11Texture2D* dx11_texture, | |
232 int input_buffer_id); | 252 int input_buffer_id); |
233 | 253 |
234 bool available() const { | 254 bool available() const { |
235 return available_; | 255 return available_; |
236 } | 256 } |
237 | 257 |
238 void set_available(bool available) { | 258 void set_available(bool available) { |
239 available_ = available; | 259 available_ = available; |
240 } | 260 } |
241 | 261 |
(...skipping 10 matching lines...) Expand all Loading... | |
252 void CopySurfaceComplete(IDirect3DSurface9* src_surface, | 272 void CopySurfaceComplete(IDirect3DSurface9* src_surface, |
253 IDirect3DSurface9* dest_surface); | 273 IDirect3DSurface9* dest_surface); |
254 | 274 |
255 private: | 275 private: |
256 explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); | 276 explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); |
257 | 277 |
258 bool available_; | 278 bool available_; |
259 media::PictureBuffer picture_buffer_; | 279 media::PictureBuffer picture_buffer_; |
260 EGLSurface decoding_surface_; | 280 EGLSurface decoding_surface_; |
261 base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; | 281 base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; |
282 base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_; | |
262 | 283 |
263 // The following |IDirect3DSurface9| interface pointers are used to hold | 284 // The following |IDirect3DSurface9| interface pointers are used to hold |
264 // references on the surfaces during the course of a StretchRect operation | 285 // references on the surfaces during the course of a StretchRect operation |
265 // to copy the source surface to the target. The references are released | 286 // to copy the source surface to the target. The references are released |
266 // when the StretchRect operation i.e. the copy completes. | 287 // when the StretchRect operation i.e. the copy completes. |
267 base::win::ScopedComPtr<IDirect3DSurface9> decoder_surface_; | 288 base::win::ScopedComPtr<IDirect3DSurface9> decoder_surface_; |
268 base::win::ScopedComPtr<IDirect3DSurface9> target_surface_; | 289 base::win::ScopedComPtr<IDirect3DSurface9> target_surface_; |
269 | 290 |
291 // This ID3D11Texture2D interface pointer is used to hold a reference to the | |
292 // decoder texture during the course of a copy operation. This reference is | |
293 // released when the copy completes. | |
294 base::win::ScopedComPtr<ID3D11Texture2D> decoder_dx11_texture_; | |
295 | |
270 // Set to true if RGB is supported by the texture. | 296 // Set to true if RGB is supported by the texture. |
271 // Defaults to true. | 297 // Defaults to true. |
272 bool use_rgb_; | 298 bool use_rgb_; |
273 | 299 |
274 DISALLOW_COPY_AND_ASSIGN(DXVAPictureBuffer); | 300 DISALLOW_COPY_AND_ASSIGN(DXVAPictureBuffer); |
275 }; | 301 }; |
276 | 302 |
277 // static | 303 // static |
278 linked_ptr<DXVAVideoDecodeAccelerator::DXVAPictureBuffer> | 304 linked_ptr<DXVAVideoDecodeAccelerator::DXVAPictureBuffer> |
279 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create( | 305 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create( |
(...skipping 28 matching lines...) Expand all Loading... | |
308 EGLBoolean ret = eglQuerySurfacePointerANGLE( | 334 EGLBoolean ret = eglQuerySurfacePointerANGLE( |
309 egl_display, | 335 egl_display, |
310 picture_buffer->decoding_surface_, | 336 picture_buffer->decoding_surface_, |
311 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, | 337 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, |
312 &share_handle); | 338 &share_handle); |
313 | 339 |
314 RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, | 340 RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, |
315 "Failed to query ANGLE surface pointer", | 341 "Failed to query ANGLE surface pointer", |
316 linked_ptr<DXVAPictureBuffer>(NULL)); | 342 linked_ptr<DXVAPictureBuffer>(NULL)); |
317 | 343 |
318 // TODO(dshwang): after moving to D3D11, use RGBA surface. crbug.com/438691 | 344 HRESULT hr = E_FAIL; |
319 HRESULT hr = decoder.device_->CreateTexture( | 345 if (decoder.d3d11_device_) { |
320 buffer.size().width(), | 346 base::win::ScopedComPtr<ID3D11Resource> resource; |
321 buffer.size().height(), | 347 hr = decoder.d3d11_device_->OpenSharedResource( |
322 1, | 348 share_handle, |
323 D3DUSAGE_RENDERTARGET, | 349 __uuidof(ID3D11Resource), |
324 use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, | 350 reinterpret_cast<void**>(resource.Receive())); |
325 D3DPOOL_DEFAULT, | 351 RETURN_ON_HR_FAILURE(hr, "Failed to open shared resource", |
326 picture_buffer->decoding_texture_.Receive(), | 352 linked_ptr<DXVAPictureBuffer>(NULL)); |
327 &share_handle); | 353 hr = picture_buffer->dx11_decoding_texture_.QueryFrom(resource.get()); |
328 | 354 } else { |
355 hr = decoder.d3d9_device_ex_->CreateTexture( | |
356 buffer.size().width(), | |
357 buffer.size().height(), | |
358 1, | |
359 D3DUSAGE_RENDERTARGET, | |
360 use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, | |
361 D3DPOOL_DEFAULT, | |
362 picture_buffer->decoding_texture_.Receive(), | |
363 &share_handle); | |
364 } | |
329 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", | 365 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", |
330 linked_ptr<DXVAPictureBuffer>(NULL)); | 366 linked_ptr<DXVAPictureBuffer>(NULL)); |
331 picture_buffer->use_rgb_ = !!use_rgb; | 367 picture_buffer->use_rgb_ = !!use_rgb; |
332 return picture_buffer; | 368 return picture_buffer; |
333 } | 369 } |
334 | 370 |
335 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( | 371 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( |
336 const media::PictureBuffer& buffer) | 372 const media::PictureBuffer& buffer) |
337 : available_(true), | 373 : available_(true), |
338 picture_buffer_(buffer), | 374 picture_buffer_(buffer), |
(...skipping 19 matching lines...) Expand all Loading... | |
358 | 394 |
359 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { | 395 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { |
360 DCHECK(decoding_surface_); | 396 DCHECK(decoding_surface_); |
361 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 397 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
362 eglReleaseTexImage( | 398 eglReleaseTexImage( |
363 egl_display, | 399 egl_display, |
364 decoding_surface_, | 400 decoding_surface_, |
365 EGL_BACK_BUFFER); | 401 EGL_BACK_BUFFER); |
366 decoder_surface_.Release(); | 402 decoder_surface_.Release(); |
367 target_surface_.Release(); | 403 target_surface_.Release(); |
404 decoder_dx11_texture_.Release(); | |
368 set_available(true); | 405 set_available(true); |
369 } | 406 } |
370 | 407 |
371 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: | 408 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: |
372 CopyOutputSampleDataToPictureBuffer( | 409 CopyOutputSampleDataToPictureBuffer( |
373 DXVAVideoDecodeAccelerator* decoder, | 410 DXVAVideoDecodeAccelerator* decoder, |
374 IDirect3DSurface9* dest_surface, | 411 IDirect3DSurface9* dest_surface, |
412 ID3D11Texture2D* dx11_texture, | |
375 int input_buffer_id) { | 413 int input_buffer_id) { |
376 DCHECK(dest_surface); | 414 DCHECK(dest_surface || dx11_texture); |
377 | 415 if (dx11_texture) { |
416 // Grab a reference on the decoder texture. This reference will be released | |
417 // when we receive a notification that the copy was completed or when the | |
418 // DXVAPictureBuffer instance is destroyed. | |
419 decoder_dx11_texture_ = dx11_texture; | |
420 decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL, | |
421 id(), input_buffer_id); | |
422 return true; | |
423 } | |
378 D3DSURFACE_DESC surface_desc; | 424 D3DSURFACE_DESC surface_desc; |
379 HRESULT hr = dest_surface->GetDesc(&surface_desc); | 425 HRESULT hr = dest_surface->GetDesc(&surface_desc); |
380 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 426 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
381 | 427 |
382 D3DSURFACE_DESC texture_desc; | 428 D3DSURFACE_DESC texture_desc; |
383 decoding_texture_->GetLevelDesc(0, &texture_desc); | 429 decoding_texture_->GetLevelDesc(0, &texture_desc); |
384 | 430 |
385 if (texture_desc.Width != surface_desc.Width || | 431 if (texture_desc.Width != surface_desc.Width || |
386 texture_desc.Height != surface_desc.Height) { | 432 texture_desc.Height != surface_desc.Height) { |
387 NOTREACHED() << "Decode surface of different dimension than texture"; | 433 NOTREACHED() << "Decode surface of different dimension than texture"; |
(...skipping 29 matching lines...) Expand all Loading... | |
417 IDirect3DSurface9* dest_surface) { | 463 IDirect3DSurface9* dest_surface) { |
418 DCHECK(!available()); | 464 DCHECK(!available()); |
419 | 465 |
420 GLint current_texture = 0; | 466 GLint current_texture = 0; |
421 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); | 467 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); |
422 | 468 |
423 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); | 469 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); |
424 | 470 |
425 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
426 | 472 |
427 DCHECK_EQ(src_surface, decoder_surface_.get()); | 473 if (src_surface && dest_surface) { |
428 DCHECK_EQ(dest_surface, target_surface_.get()); | 474 DCHECK_EQ(src_surface, decoder_surface_.get()); |
429 | 475 DCHECK_EQ(dest_surface, target_surface_.get()); |
430 decoder_surface_.Release(); | 476 decoder_surface_.Release(); |
431 target_surface_.Release(); | 477 target_surface_.Release(); |
478 } else { | |
479 DCHECK(decoder_dx11_texture_.get()); | |
480 decoder_dx11_texture_.Release(); | |
481 } | |
432 | 482 |
433 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 483 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
434 eglBindTexImage( | 484 eglBindTexImage( |
435 egl_display, | 485 egl_display, |
436 decoding_surface_, | 486 decoding_surface_, |
437 EGL_BACK_BUFFER); | 487 EGL_BACK_BUFFER); |
438 | 488 |
439 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 489 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
440 glBindTexture(GL_TEXTURE_2D, current_texture); | 490 glBindTexture(GL_TEXTURE_2D, current_texture); |
441 } | 491 } |
442 | 492 |
443 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( | 493 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( |
444 int32 buffer_id, IMFSample* sample) | 494 int32 buffer_id, IMFSample* sample) |
445 : input_buffer_id(buffer_id), | 495 : input_buffer_id(buffer_id), |
446 picture_buffer_id(-1) { | 496 picture_buffer_id(-1) { |
447 output_sample.Attach(sample); | 497 output_sample.Attach(sample); |
448 } | 498 } |
449 | 499 |
450 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} | 500 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} |
451 | 501 |
452 // static | |
453 bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() { | |
454 TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager"); | |
455 | |
456 HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive()); | |
457 RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false); | |
458 | |
459 D3DPRESENT_PARAMETERS present_params = {0}; | |
460 present_params.BackBufferWidth = 1; | |
461 present_params.BackBufferHeight = 1; | |
462 present_params.BackBufferFormat = D3DFMT_UNKNOWN; | |
463 present_params.BackBufferCount = 1; | |
464 present_params.SwapEffect = D3DSWAPEFFECT_DISCARD; | |
465 present_params.hDeviceWindow = ::GetShellWindow(); | |
466 present_params.Windowed = TRUE; | |
467 present_params.Flags = D3DPRESENTFLAG_VIDEO; | |
468 present_params.FullScreen_RefreshRateInHz = 0; | |
469 present_params.PresentationInterval = 0; | |
470 | |
471 hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT, | |
472 D3DDEVTYPE_HAL, | |
473 ::GetShellWindow(), | |
474 D3DCREATE_FPU_PRESERVE | | |
475 D3DCREATE_SOFTWARE_VERTEXPROCESSING | | |
476 D3DCREATE_DISABLE_PSGP_THREADING | | |
477 D3DCREATE_MULTITHREADED, | |
478 &present_params, | |
479 NULL, | |
480 device_.Receive()); | |
481 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false); | |
482 | |
483 hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_, | |
484 device_manager_.Receive()); | |
485 RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false); | |
486 | |
487 hr = device_manager_->ResetDevice(device_.get(), dev_manager_reset_token_); | |
488 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | |
489 | |
490 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | |
491 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); | |
492 // Ensure query_ API works (to avoid an infinite loop later in | |
493 // CopyOutputSampleDataToPictureBuffer). | |
494 hr = query_->Issue(D3DISSUE_END); | |
495 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | |
496 return true; | |
497 } | |
498 | |
499 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( | 502 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
500 const base::Callback<bool(void)>& make_context_current) | 503 const base::Callback<bool(void)>& make_context_current, |
504 gfx::GLContext* gl_context) | |
501 : client_(NULL), | 505 : client_(NULL), |
502 dev_manager_reset_token_(0), | 506 dev_manager_reset_token_(0), |
507 dx11_dev_manager_reset_token_(0), | |
503 egl_config_(NULL), | 508 egl_config_(NULL), |
504 state_(kUninitialized), | 509 state_(kUninitialized), |
505 pictures_requested_(false), | 510 pictures_requested_(false), |
506 inputs_before_decode_(0), | 511 inputs_before_decode_(0), |
507 sent_drain_message_(false), | 512 sent_drain_message_(false), |
508 make_context_current_(make_context_current), | 513 make_context_current_(make_context_current), |
509 codec_(media::kUnknownVideoCodec), | 514 codec_(media::kUnknownVideoCodec), |
510 decoder_thread_("DXVAVideoDecoderThread"), | 515 decoder_thread_("DXVAVideoDecoderThread"), |
511 weak_this_factory_(this), | 516 weak_this_factory_(this), |
512 weak_ptr_(weak_this_factory_.GetWeakPtr()), | 517 weak_ptr_(weak_this_factory_.GetWeakPtr()), |
513 pending_flush_(false) { | 518 pending_flush_(false), |
519 use_dx11_(false), | |
520 dx11_video_format_converter_media_type_needs_init_(true), | |
521 gl_context_(gl_context) { | |
514 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 522 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
515 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 523 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
516 } | 524 } |
517 | 525 |
518 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 526 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
519 client_ = NULL; | 527 client_ = NULL; |
520 } | 528 } |
521 | 529 |
522 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, | 530 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
523 Client* client) { | 531 Client* client) { |
524 client_ = client; | 532 client_ = client; |
525 | 533 |
526 main_thread_task_runner_ = base::MessageLoop::current()->task_runner(); | 534 main_thread_task_runner_ = base::MessageLoop::current()->task_runner(); |
527 | 535 |
528 // Not all versions of Windows 7 and later include Media Foundation DLLs. | |
529 // Instead of crashing while delay loading the DLL when calling MFStartup() | |
530 // below, probe whether we can successfully load the DLL now. | |
531 // | |
532 // See http://crbug.com/339678 for details. | |
533 HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll"); | |
534 RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", false); | |
535 | |
536 if (profile != media::H264PROFILE_BASELINE && | 536 if (profile != media::H264PROFILE_BASELINE && |
537 profile != media::H264PROFILE_MAIN && | 537 profile != media::H264PROFILE_MAIN && |
538 profile != media::H264PROFILE_HIGH && | 538 profile != media::H264PROFILE_HIGH && |
539 profile != media::VP8PROFILE_ANY && | 539 profile != media::VP8PROFILE_ANY && |
540 profile != media::VP9PROFILE_ANY) { | 540 profile != media::VP9PROFILE_ANY) { |
541 RETURN_AND_NOTIFY_ON_FAILURE(false, | 541 RETURN_AND_NOTIFY_ON_FAILURE(false, |
542 "Unsupported h.264, vp8, or vp9 profile", PLATFORM_FAILURE, false); | 542 "Unsupported h.264, vp8, or vp9 profile", PLATFORM_FAILURE, false); |
543 } | 543 } |
544 | 544 |
545 // Not all versions of Windows 7 and later include Media Foundation DLLs. | |
546 // Instead of crashing while delay loading the DLL when calling MFStartup() | |
547 // below, probe whether we can successfully load the DLL now. | |
548 // See http://crbug.com/339678 for details. | |
549 HMODULE dxgi_manager_dll = NULL; | |
550 if ((dxgi_manager_dll = ::GetModuleHandle(L"MFPlat.dll")) == NULL) { | |
551 HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll"); | |
552 RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", | |
553 false); | |
554 // On Windows 8+ mfplat.dll provides the MFCreateDXGIDeviceManager API. | |
555 // On Windows 7 mshtmlmedia.dll provides it. | |
556 dxgi_manager_dll = mfplat_dll; | |
557 } | |
558 | |
559 // TODO(ananta) | |
560 // The code below works, as in we can create the DX11 device manager for | |
561 // Windows 7. However the IMFTransform we use for texture conversion and | |
562 // copy does not exist on Windows 7. Look into an alternate approach | |
563 // and enable the code below. | |
564 #if defined ENABLE_DX11_FOR_WIN7 | |
565 if ((base::win::GetVersion() == base::win::VERSION_WIN7) && | |
566 ((dxgi_manager_dll = ::GetModuleHandle(L"mshtmlmedia.dll")) == NULL)) { | |
567 HMODULE mshtml_media_dll = ::LoadLibrary(L"mshtmlmedia.dll"); | |
568 if (mshtml_media_dll) | |
569 dxgi_manager_dll = mshtml_media_dll; | |
570 } | |
571 #endif | |
572 // If we don't find the MFCreateDXGIDeviceManager API we fallback to D3D9 | |
573 // decoding. | |
574 if (dxgi_manager_dll && !create_dxgi_device_manager_) { | |
575 create_dxgi_device_manager_ = reinterpret_cast<CreateDXGIDeviceManager>( | |
576 ::GetProcAddress(dxgi_manager_dll, "MFCreateDXGIDeviceManager")); | |
577 } | |
578 | |
545 RETURN_AND_NOTIFY_ON_FAILURE( | 579 RETURN_AND_NOTIFY_ON_FAILURE( |
546 gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, | 580 gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, |
547 "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", | 581 "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", |
548 PLATFORM_FAILURE, | 582 PLATFORM_FAILURE, |
549 false); | 583 false); |
550 | 584 |
551 State state = GetState(); | 585 State state = GetState(); |
552 RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), | 586 RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), |
553 "Initialize: invalid state: " << state, ILLEGAL_STATE, false); | 587 "Initialize: invalid state: " << state, ILLEGAL_STATE, false); |
554 | 588 |
555 HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); | 589 HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); |
556 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE, | 590 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE, |
557 false); | 591 false); |
558 | 592 |
559 RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(), | |
560 "Failed to initialize D3D device and manager", | |
561 PLATFORM_FAILURE, | |
562 false); | |
563 | |
564 RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile), | 593 RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile), |
565 "Failed to initialize decoder", PLATFORM_FAILURE, false); | 594 "Failed to initialize decoder", PLATFORM_FAILURE, false); |
566 | 595 |
567 RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), | 596 RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), |
568 "Failed to get input/output stream info.", PLATFORM_FAILURE, false); | 597 "Failed to get input/output stream info.", PLATFORM_FAILURE, false); |
569 | 598 |
570 RETURN_AND_NOTIFY_ON_FAILURE( | 599 RETURN_AND_NOTIFY_ON_FAILURE( |
571 SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), | 600 SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), |
572 "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", | 601 "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", |
573 PLATFORM_FAILURE, false); | 602 PLATFORM_FAILURE, false); |
574 | 603 |
575 RETURN_AND_NOTIFY_ON_FAILURE( | 604 RETURN_AND_NOTIFY_ON_FAILURE( |
576 SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), | 605 SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), |
577 "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", | 606 "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", |
578 PLATFORM_FAILURE, false); | 607 PLATFORM_FAILURE, false); |
579 | 608 |
580 SetState(kNormal); | 609 SetState(kNormal); |
581 | 610 |
582 StartDecoderThread(); | 611 StartDecoderThread(); |
583 return true; | 612 return true; |
584 } | 613 } |
585 | 614 |
615 bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() { | |
616 TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager"); | |
617 | |
618 HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive()); | |
619 RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false); | |
620 | |
621 D3DPRESENT_PARAMETERS present_params = {0}; | |
622 present_params.BackBufferWidth = 1; | |
623 present_params.BackBufferHeight = 1; | |
624 present_params.BackBufferFormat = D3DFMT_UNKNOWN; | |
625 present_params.BackBufferCount = 1; | |
626 present_params.SwapEffect = D3DSWAPEFFECT_DISCARD; | |
627 present_params.hDeviceWindow = ::GetShellWindow(); | |
628 present_params.Windowed = TRUE; | |
629 present_params.Flags = D3DPRESENTFLAG_VIDEO; | |
630 present_params.FullScreen_RefreshRateInHz = 0; | |
631 present_params.PresentationInterval = 0; | |
632 | |
633 hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT, | |
634 D3DDEVTYPE_HAL, | |
635 ::GetShellWindow(), | |
636 D3DCREATE_FPU_PRESERVE | | |
637 D3DCREATE_SOFTWARE_VERTEXPROCESSING | | |
638 D3DCREATE_DISABLE_PSGP_THREADING | | |
639 D3DCREATE_MULTITHREADED, | |
640 &present_params, | |
641 NULL, | |
642 d3d9_device_ex_.Receive()); | |
643 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false); | |
644 | |
645 hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_, | |
646 device_manager_.Receive()); | |
647 RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false); | |
648 | |
649 hr = device_manager_->ResetDevice(d3d9_device_ex_.get(), | |
650 dev_manager_reset_token_); | |
651 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | |
652 | |
653 hr = d3d9_device_ex_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | |
654 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); | |
655 // Ensure query_ API works (to avoid an infinite loop later in | |
656 // CopyOutputSampleDataToPictureBuffer). | |
657 hr = query_->Issue(D3DISSUE_END); | |
658 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | |
659 return true; | |
660 } | |
661 | |
662 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { | |
663 HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, | |
664 d3d11_device_manager_.Receive()); | |
665 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); | |
666 | |
667 // This array defines the set of DirectX hardware feature levels we support. | |
668 // The ordering MUST be preserved. All applications are assumed to support | |
669 // 9.1 unless otherwise stated by the application, which is not our case. | |
670 D3D_FEATURE_LEVEL feature_levels[] = { | |
671 D3D_FEATURE_LEVEL_11_1, | |
672 D3D_FEATURE_LEVEL_11_0, | |
673 D3D_FEATURE_LEVEL_10_1, | |
674 D3D_FEATURE_LEVEL_10_0, | |
675 D3D_FEATURE_LEVEL_9_3, | |
676 D3D_FEATURE_LEVEL_9_2, | |
677 D3D_FEATURE_LEVEL_9_1 }; | |
678 | |
679 D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_0; | |
680 hr = D3D11CreateDevice(NULL, | |
681 D3D_DRIVER_TYPE_HARDWARE, | |
682 NULL, | |
683 D3D11_CREATE_DEVICE_VIDEO_SUPPORT, | |
684 feature_levels, | |
685 arraysize(feature_levels), | |
686 D3D11_SDK_VERSION, | |
687 d3d11_device_.Receive(), | |
688 &feature_level_out, | |
689 d3d11_device_context_.Receive()); | |
690 RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device", false); | |
691 | |
692 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), | |
693 dx11_dev_manager_reset_token_); | |
694 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | |
695 | |
696 hr = ::CoCreateInstance( | |
697 CLSID_VideoProcessorMFT, | |
698 NULL, | |
699 CLSCTX_INPROC_SERVER, | |
700 IID_IMFTransform, | |
701 reinterpret_cast<void**>(video_format_converter_mft_.Receive())); | |
702 if (FAILED(hr)) { | |
703 // TODO(ananta) | |
DaleCurtis
2015/02/26 22:32:22
Do you want to alias GetLastError() on the stack a
ananta
2015/02/26 23:32:57
Yes. Done.
| |
704 // Remove this CHECK when the change to use DX11 for H/W decoding | |
705 // stablizes. | |
706 CHECK(false); | |
707 } | |
708 RETURN_ON_HR_FAILURE(hr, "Failed to create video format converter", false); | |
709 return true; | |
710 } | |
711 | |
586 void DXVAVideoDecodeAccelerator::Decode( | 712 void DXVAVideoDecodeAccelerator::Decode( |
587 const media::BitstreamBuffer& bitstream_buffer) { | 713 const media::BitstreamBuffer& bitstream_buffer) { |
588 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 714 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
589 | 715 |
590 State state = GetState(); | 716 State state = GetState(); |
591 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || | 717 RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || |
592 state == kFlushing), | 718 state == kFlushing), |
593 "Invalid state: " << state, ILLEGAL_STATE,); | 719 "Invalid state: " << state, ILLEGAL_STATE,); |
594 | 720 |
595 base::win::ScopedComPtr<IMFSample> sample; | 721 base::win::ScopedComPtr<IMFSample> sample; |
(...skipping 29 matching lines...) Expand all Loading... | |
625 ++buffer_index) { | 751 ++buffer_index) { |
626 linked_ptr<DXVAPictureBuffer> picture_buffer = | 752 linked_ptr<DXVAPictureBuffer> picture_buffer = |
627 DXVAPictureBuffer::Create(*this, buffers[buffer_index], egl_config_); | 753 DXVAPictureBuffer::Create(*this, buffers[buffer_index], egl_config_); |
628 RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer.get(), | 754 RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer.get(), |
629 "Failed to allocate picture buffer", PLATFORM_FAILURE,); | 755 "Failed to allocate picture buffer", PLATFORM_FAILURE,); |
630 | 756 |
631 bool inserted = output_picture_buffers_.insert(std::make_pair( | 757 bool inserted = output_picture_buffers_.insert(std::make_pair( |
632 buffers[buffer_index].id(), picture_buffer)).second; | 758 buffers[buffer_index].id(), picture_buffer)).second; |
633 DCHECK(inserted); | 759 DCHECK(inserted); |
634 } | 760 } |
761 | |
635 ProcessPendingSamples(); | 762 ProcessPendingSamples(); |
636 if (pending_flush_) { | 763 if (pending_flush_) { |
637 decoder_thread_task_runner_->PostTask( | 764 decoder_thread_task_runner_->PostTask( |
638 FROM_HERE, | 765 FROM_HERE, |
639 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 766 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
640 base::Unretained(this))); | 767 base::Unretained(this))); |
641 } | 768 } |
642 } | 769 } |
643 | 770 |
644 void DXVAVideoDecodeAccelerator::ReusePictureBuffer( | 771 void DXVAVideoDecodeAccelerator::ReusePictureBuffer( |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
833 RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false); | 960 RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false); |
834 | 961 |
835 hr = factory->CreateInstance(NULL, | 962 hr = factory->CreateInstance(NULL, |
836 __uuidof(IMFTransform), | 963 __uuidof(IMFTransform), |
837 reinterpret_cast<void**>(decoder_.Receive())); | 964 reinterpret_cast<void**>(decoder_.Receive())); |
838 RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); | 965 RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); |
839 | 966 |
840 RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), | 967 RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), |
841 "Failed to check decoder DXVA support", false); | 968 "Failed to check decoder DXVA support", false); |
842 | 969 |
970 ULONG_PTR device_manager_to_use = NULL; | |
971 if (use_dx11_) { | |
972 CHECK(create_dxgi_device_manager_); | |
973 RETURN_AND_NOTIFY_ON_FAILURE(CreateDX11DevManager(), | |
974 "Failed to initialize DX11 device and manager", | |
975 PLATFORM_FAILURE, | |
976 false); | |
977 device_manager_to_use = reinterpret_cast<ULONG_PTR>( | |
978 d3d11_device_manager_.get()); | |
979 } else { | |
980 RETURN_AND_NOTIFY_ON_FAILURE(CreateD3DDevManager(), | |
981 "Failed to initialize D3D device and manager", | |
982 PLATFORM_FAILURE, | |
983 false); | |
984 device_manager_to_use = reinterpret_cast<ULONG_PTR>(device_manager_.get()); | |
985 } | |
986 | |
843 hr = decoder_->ProcessMessage( | 987 hr = decoder_->ProcessMessage( |
844 MFT_MESSAGE_SET_D3D_MANAGER, | 988 MFT_MESSAGE_SET_D3D_MANAGER, |
845 reinterpret_cast<ULONG_PTR>(device_manager_.get())); | 989 device_manager_to_use); |
846 RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false); | 990 if (use_dx11_) { |
991 RETURN_ON_HR_FAILURE(hr, "Failed to pass DX11 manager to decoder", false); | |
992 } else { | |
993 RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false); | |
994 } | |
847 | 995 |
848 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 996 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
849 | 997 |
850 EGLint config_attribs[] = { | 998 EGLint config_attribs[] = { |
851 EGL_BUFFER_SIZE, 32, | 999 EGL_BUFFER_SIZE, 32, |
852 EGL_RED_SIZE, 8, | 1000 EGL_RED_SIZE, 8, |
853 EGL_GREEN_SIZE, 8, | 1001 EGL_GREEN_SIZE, 8, |
854 EGL_BLUE_SIZE, 8, | 1002 EGL_BLUE_SIZE, 8, |
855 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, | 1003 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, |
856 EGL_ALPHA_SIZE, 0, | 1004 EGL_ALPHA_SIZE, 0, |
(...skipping 26 matching lines...) Expand all Loading... | |
883 hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE); | 1031 hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE); |
884 RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false); | 1032 RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false); |
885 } | 1033 } |
886 | 1034 |
887 hr = attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE); | 1035 hr = attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE); |
888 if (SUCCEEDED(hr)) { | 1036 if (SUCCEEDED(hr)) { |
889 DVLOG(1) << "Successfully set Low latency mode on decoder."; | 1037 DVLOG(1) << "Successfully set Low latency mode on decoder."; |
890 } else { | 1038 } else { |
891 DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr; | 1039 DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr; |
892 } | 1040 } |
1041 | |
1042 // The decoder should use DX11 iff | |
1043 // 1. The underlying H/W decoder supports it. | |
1044 // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for | |
1045 // this. This should always be true for Windows 8+. | |
1046 // 3. ANGLE is using DX11. | |
1047 DCHECK(gl_context_); | |
1048 if (create_dxgi_device_manager_ && | |
1049 (gl_context_->GetGLRenderer().find("Direct3D11") != | |
1050 std::string::npos)) { | |
1051 UINT32 dx11_aware = 0; | |
1052 hr = attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); | |
DaleCurtis
2015/02/26 22:32:22
Remove hr= if you're not going to use it?
ananta
2015/02/26 23:32:57
Done.
| |
1053 use_dx11_ = !!dx11_aware; | |
1054 } | |
893 return true; | 1055 return true; |
894 } | 1056 } |
895 | 1057 |
896 bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { | 1058 bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { |
897 RETURN_ON_FAILURE(SetDecoderInputMediaType(), | 1059 RETURN_ON_FAILURE(SetDecoderInputMediaType(), |
898 "Failed to set decoder input media type", false); | 1060 "Failed to set decoder input media type", false); |
899 return SetDecoderOutputMediaType(MFVideoFormat_NV12); | 1061 return SetDecoderOutputMediaType(MFVideoFormat_NV12); |
900 } | 1062 } |
901 | 1063 |
902 bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() { | 1064 bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() { |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1047 | 1209 |
1048 inputs_before_decode_ = 0; | 1210 inputs_before_decode_ = 0; |
1049 | 1211 |
1050 RETURN_AND_NOTIFY_ON_FAILURE(ProcessOutputSample(output_data_buffer.pSample), | 1212 RETURN_AND_NOTIFY_ON_FAILURE(ProcessOutputSample(output_data_buffer.pSample), |
1051 "Failed to process output sample.", PLATFORM_FAILURE,); | 1213 "Failed to process output sample.", PLATFORM_FAILURE,); |
1052 } | 1214 } |
1053 | 1215 |
1054 bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { | 1216 bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { |
1055 RETURN_ON_FAILURE(sample, "Decode succeeded with NULL output sample", false); | 1217 RETURN_ON_FAILURE(sample, "Decode succeeded with NULL output sample", false); |
1056 | 1218 |
1057 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | |
1058 HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive()); | |
1059 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false); | |
1060 | |
1061 base::win::ScopedComPtr<IDirect3DSurface9> surface; | |
1062 hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE, | |
1063 IID_PPV_ARGS(surface.Receive())); | |
1064 RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample", | |
1065 false); | |
1066 | |
1067 LONGLONG input_buffer_id = 0; | 1219 LONGLONG input_buffer_id = 0; |
1068 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), | 1220 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), |
1069 "Failed to get input buffer id associated with sample", | 1221 "Failed to get input buffer id associated with sample", |
1070 false); | 1222 false); |
1071 | 1223 |
1072 { | 1224 { |
1073 base::AutoLock lock(decoder_lock_); | 1225 base::AutoLock lock(decoder_lock_); |
1074 DCHECK(pending_output_samples_.empty()); | 1226 DCHECK(pending_output_samples_.empty()); |
1075 pending_output_samples_.push_back( | 1227 pending_output_samples_.push_back( |
1076 PendingSampleInfo(input_buffer_id, sample)); | 1228 PendingSampleInfo(input_buffer_id, sample)); |
1077 } | 1229 } |
1078 | 1230 |
1079 if (pictures_requested_) { | 1231 if (pictures_requested_) { |
1080 DVLOG(1) << "Waiting for picture slots from the client."; | 1232 DVLOG(1) << "Waiting for picture slots from the client."; |
1081 main_thread_task_runner_->PostTask( | 1233 main_thread_task_runner_->PostTask( |
1082 FROM_HERE, | 1234 FROM_HERE, |
1083 base::Bind(&DXVAVideoDecodeAccelerator::ProcessPendingSamples, | 1235 base::Bind(&DXVAVideoDecodeAccelerator::ProcessPendingSamples, |
1084 weak_this_factory_.GetWeakPtr())); | 1236 weak_this_factory_.GetWeakPtr())); |
1085 return true; | 1237 return true; |
1086 } | 1238 } |
1087 | 1239 |
1088 // We only read the surface description, which contains its width/height when | 1240 int width = 0; |
1089 // we need the picture buffers from the client. Once we have those, then they | 1241 int height = 0; |
1090 // are reused. | 1242 if (!GetVideoFrameDimensions(sample, &width, &height)) { |
1091 D3DSURFACE_DESC surface_desc; | 1243 RETURN_ON_FAILURE(false, "Failed to get D3D surface from output sample", |
1092 hr = surface->GetDesc(&surface_desc); | 1244 false); |
1093 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 1245 } |
1094 | 1246 |
1095 // Go ahead and request picture buffers. | 1247 // Go ahead and request picture buffers. |
1096 main_thread_task_runner_->PostTask( | 1248 main_thread_task_runner_->PostTask( |
1097 FROM_HERE, | 1249 FROM_HERE, |
1098 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, | 1250 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
1099 weak_this_factory_.GetWeakPtr(), | 1251 weak_this_factory_.GetWeakPtr(), |
1100 surface_desc.Width, | 1252 width, |
1101 surface_desc.Height)); | 1253 height)); |
1102 | 1254 |
1103 pictures_requested_ = true; | 1255 pictures_requested_ = true; |
1104 return true; | 1256 return true; |
1105 } | 1257 } |
1106 | 1258 |
1107 void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { | 1259 void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { |
1108 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 1260 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
1109 | 1261 |
1110 if (!output_picture_buffers_.size()) | 1262 if (!output_picture_buffers_.size()) |
1111 return; | 1263 return; |
(...skipping 11 matching lines...) Expand all Loading... | |
1123 PendingSampleInfo* pending_sample = NULL; | 1275 PendingSampleInfo* pending_sample = NULL; |
1124 { | 1276 { |
1125 base::AutoLock lock(decoder_lock_); | 1277 base::AutoLock lock(decoder_lock_); |
1126 | 1278 |
1127 PendingSampleInfo& sample_info = pending_output_samples_.front(); | 1279 PendingSampleInfo& sample_info = pending_output_samples_.front(); |
1128 if (sample_info.picture_buffer_id != -1) | 1280 if (sample_info.picture_buffer_id != -1) |
1129 continue; | 1281 continue; |
1130 pending_sample = &sample_info; | 1282 pending_sample = &sample_info; |
1131 } | 1283 } |
1132 | 1284 |
1285 int width = 0; | |
1286 int height = 0; | |
1287 if (!GetVideoFrameDimensions(pending_sample->output_sample.get(), | |
1288 &width, &height)) { | |
1289 RETURN_AND_NOTIFY_ON_FAILURE(false, | |
1290 "Failed to get D3D surface from output sample", PLATFORM_FAILURE,); | |
1291 } | |
1292 | |
1293 if (width != index->second->size().width() || | |
1294 height != index->second->size().height()) { | |
1295 HandleResolutionChanged(width, height); | |
1296 return; | |
1297 } | |
1298 | |
1133 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | 1299 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; |
1134 HRESULT hr = pending_sample->output_sample->GetBufferByIndex( | 1300 HRESULT hr = pending_sample->output_sample->GetBufferByIndex( |
1135 0, output_buffer.Receive()); | 1301 0, output_buffer.Receive()); |
1136 RETURN_AND_NOTIFY_ON_HR_FAILURE( | 1302 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
1137 hr, "Failed to get buffer from output sample", PLATFORM_FAILURE,); | 1303 "Failed to get buffer from output sample", PLATFORM_FAILURE,); |
1138 | 1304 |
1139 base::win::ScopedComPtr<IDirect3DSurface9> surface; | 1305 base::win::ScopedComPtr<IDirect3DSurface9> surface; |
1140 hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE, | 1306 base::win::ScopedComPtr<ID3D11Texture2D> d3d11_texture; |
1141 IID_PPV_ARGS(surface.Receive())); | |
1142 RETURN_AND_NOTIFY_ON_HR_FAILURE( | |
1143 hr, "Failed to get D3D surface from output sample", | |
1144 PLATFORM_FAILURE,); | |
1145 | 1307 |
1146 D3DSURFACE_DESC surface_desc; | 1308 if (use_dx11_) { |
1147 hr = surface->GetDesc(&surface_desc); | 1309 base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer; |
1148 RETURN_AND_NOTIFY_ON_HR_FAILURE( | 1310 hr = dxgi_buffer.QueryFrom(output_buffer.get()); |
1149 hr, "Failed to get surface description", PLATFORM_FAILURE,); | 1311 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
1150 | 1312 "Failed to get DXGIBuffer from output sample", PLATFORM_FAILURE,); |
1151 if (surface_desc.Width != | 1313 hr = dxgi_buffer->GetResource( |
1152 static_cast<uint32>(index->second->size().width()) || | 1314 __uuidof(ID3D11Texture2D), |
1153 surface_desc.Height != | 1315 reinterpret_cast<void**>(d3d11_texture.Receive())); |
1154 static_cast<uint32>(index->second->size().height())) { | 1316 } else { |
1155 HandleResolutionChanged(surface_desc.Width, surface_desc.Height); | 1317 hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE, |
1156 return; | 1318 IID_PPV_ARGS(surface.Receive())); |
1157 } | 1319 } |
1320 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1321 "Failed to get surface from output sample", PLATFORM_FAILURE,); | |
1158 | 1322 |
1159 pending_sample->picture_buffer_id = index->second->id(); | 1323 pending_sample->picture_buffer_id = index->second->id(); |
1160 | 1324 |
1161 RETURN_AND_NOTIFY_ON_FAILURE( | 1325 RETURN_AND_NOTIFY_ON_FAILURE( |
1162 index->second->CopyOutputSampleDataToPictureBuffer( | 1326 index->second->CopyOutputSampleDataToPictureBuffer( |
1163 this, | 1327 this, |
1164 surface.get(), | 1328 surface.get(), |
1329 d3d11_texture.get(), | |
1165 pending_sample->input_buffer_id), | 1330 pending_sample->input_buffer_id), |
1166 "Failed to copy output sample", PLATFORM_FAILURE, ); | 1331 "Failed to copy output sample", PLATFORM_FAILURE,); |
1167 | 1332 |
1168 index->second->set_available(false); | 1333 index->second->set_available(false); |
1169 } | 1334 } |
1170 } | 1335 } |
1171 } | 1336 } |
1172 | 1337 |
1173 void DXVAVideoDecodeAccelerator::StopOnError( | 1338 void DXVAVideoDecodeAccelerator::StopOnError( |
1174 media::VideoDecodeAccelerator::Error error) { | 1339 media::VideoDecodeAccelerator::Error error) { |
1175 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | 1340 if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
1176 main_thread_task_runner_->PostTask( | 1341 main_thread_task_runner_->PostTask( |
(...skipping 16 matching lines...) Expand all Loading... | |
1193 void DXVAVideoDecodeAccelerator::Invalidate() { | 1358 void DXVAVideoDecodeAccelerator::Invalidate() { |
1194 if (GetState() == kUninitialized) | 1359 if (GetState() == kUninitialized) |
1195 return; | 1360 return; |
1196 decoder_thread_.Stop(); | 1361 decoder_thread_.Stop(); |
1197 weak_this_factory_.InvalidateWeakPtrs(); | 1362 weak_this_factory_.InvalidateWeakPtrs(); |
1198 output_picture_buffers_.clear(); | 1363 output_picture_buffers_.clear(); |
1199 stale_output_picture_buffers_.clear(); | 1364 stale_output_picture_buffers_.clear(); |
1200 pending_output_samples_.clear(); | 1365 pending_output_samples_.clear(); |
1201 pending_input_buffers_.clear(); | 1366 pending_input_buffers_.clear(); |
1202 decoder_.Release(); | 1367 decoder_.Release(); |
1368 if (video_format_converter_mft_.get()) { | |
1369 video_format_converter_mft_->ProcessMessage( | |
1370 MFT_MESSAGE_NOTIFY_END_STREAMING, 0); | |
1371 video_format_converter_mft_.Release(); | |
1372 } | |
1203 MFShutdown(); | 1373 MFShutdown(); |
1374 dx11_video_format_converter_media_type_needs_init_ = true; | |
1204 SetState(kUninitialized); | 1375 SetState(kUninitialized); |
1205 } | 1376 } |
1206 | 1377 |
1207 void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { | 1378 void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { |
1208 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 1379 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
1209 if (client_) | 1380 if (client_) |
1210 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | 1381 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
1211 } | 1382 } |
1212 | 1383 |
1213 void DXVAVideoDecodeAccelerator::NotifyFlushDone() { | 1384 void DXVAVideoDecodeAccelerator::NotifyFlushDone() { |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1418 // http://code.google.com/p/chromium/issues/detail?id=150925 | 1589 // http://code.google.com/p/chromium/issues/detail?id=150925 |
1419 main_thread_task_runner_->PostTask( | 1590 main_thread_task_runner_->PostTask( |
1420 FROM_HERE, | 1591 FROM_HERE, |
1421 base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead, | 1592 base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead, |
1422 weak_this_factory_.GetWeakPtr(), | 1593 weak_this_factory_.GetWeakPtr(), |
1423 input_buffer_id)); | 1594 input_buffer_id)); |
1424 } | 1595 } |
1425 | 1596 |
1426 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, | 1597 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, |
1427 int height) { | 1598 int height) { |
1599 dx11_video_format_converter_media_type_needs_init_ = true; | |
1600 | |
1428 main_thread_task_runner_->PostTask( | 1601 main_thread_task_runner_->PostTask( |
1429 FROM_HERE, | 1602 FROM_HERE, |
1430 base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers, | 1603 base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers, |
1431 weak_this_factory_.GetWeakPtr())); | 1604 weak_this_factory_.GetWeakPtr())); |
1432 | 1605 |
1433 main_thread_task_runner_->PostTask( | 1606 main_thread_task_runner_->PostTask( |
1434 FROM_HERE, | 1607 FROM_HERE, |
1435 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, | 1608 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
1436 weak_this_factory_.GetWeakPtr(), | 1609 weak_this_factory_.GetWeakPtr(), |
1437 width, | 1610 width, |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1511 FROM_HERE, | 1684 FROM_HERE, |
1512 base::Bind(&DXVAVideoDecodeAccelerator::CopySurface, | 1685 base::Bind(&DXVAVideoDecodeAccelerator::CopySurface, |
1513 base::Unretained(this), | 1686 base::Unretained(this), |
1514 src_surface, | 1687 src_surface, |
1515 dest_surface, | 1688 dest_surface, |
1516 picture_buffer_id, | 1689 picture_buffer_id, |
1517 input_buffer_id)); | 1690 input_buffer_id)); |
1518 return; | 1691 return; |
1519 } | 1692 } |
1520 | 1693 |
1521 HRESULT hr = device_->StretchRect(src_surface, NULL, dest_surface, | 1694 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, |
1522 NULL, D3DTEXF_NONE); | 1695 NULL, D3DTEXF_NONE); |
1523 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",); | 1696 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",); |
1524 | 1697 |
1525 // Ideally, this should be done immediately before the draw call that uses | 1698 // Ideally, this should be done immediately before the draw call that uses |
1526 // the texture. Flush it once here though. | 1699 // the texture. Flush it once here though. |
1527 hr = query_->Issue(D3DISSUE_END); | 1700 hr = query_->Issue(D3DISSUE_END); |
1528 RETURN_ON_HR_FAILURE(hr, "Failed to issue END",); | 1701 RETURN_ON_HR_FAILURE(hr, "Failed to issue END",); |
1529 | 1702 |
1530 // Flush the decoder device to ensure that the decoded frame is copied to the | 1703 // Flush the decoder device to ensure that the decoded frame is copied to the |
1531 // target surface. | 1704 // target surface. |
1532 decoder_thread_task_runner_->PostDelayedTask( | 1705 decoder_thread_task_runner_->PostDelayedTask( |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1583 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 1756 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
1584 base::Unretained(this))); | 1757 base::Unretained(this))); |
1585 return; | 1758 return; |
1586 } | 1759 } |
1587 decoder_thread_task_runner_->PostTask( | 1760 decoder_thread_task_runner_->PostTask( |
1588 FROM_HERE, | 1761 FROM_HERE, |
1589 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 1762 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
1590 base::Unretained(this))); | 1763 base::Unretained(this))); |
1591 } | 1764 } |
1592 | 1765 |
1766 void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, | |
1767 ID3D11Texture2D* dest_texture, | |
1768 IMFSample* video_frame, | |
1769 int picture_buffer_id, | |
1770 int input_buffer_id) { | |
1771 HRESULT hr = E_FAIL; | |
1772 | |
1773 DCHECK(use_dx11_); | |
1774 | |
1775 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { | |
1776 // The media foundation H.264 decoder outputs YUV12 textures which we | |
1777 // cannot copy into ANGLE as they expect ARGB textures. In D3D land | |
1778 // the StretchRect API in the IDirect3DDevice9Ex interface did the color | |
1779 // space conversion for us. Sadly in DX11 land the API does not provide | |
1780 // a straightforward way to do this. | |
1781 // We use the video processor MFT. | |
1782 // https://msdn.microsoft.com/en-us/library/hh162913(v=vs.85).aspx | |
1783 // This object implements a media foundation transform (IMFTransform) | |
1784 // which follows the same contract as the decoder. The color space | |
1785 // conversion as per msdn is done in the GPU. | |
1786 | |
1787 D3D11_TEXTURE2D_DESC source_desc; | |
1788 src_texture->GetDesc(&source_desc); | |
1789 | |
1790 // Set up the input and output types for the video processor MFT. | |
1791 if (!InitializeDX11VideoFormatConverterMediaType(source_desc.Width, | |
1792 source_desc.Height)) { | |
1793 // TODO(ananta) | |
1794 // Remove this CHECK when the change to use DX11 for H/W decoding | |
1795 // stablizes. | |
1796 CHECK(false); | |
DaleCurtis
2015/02/26 22:32:22
Ditto for GetLastError alias.
ananta
2015/02/26 23:32:57
Added the alias to the InitializeDX11VideoFormatCo
| |
1797 RETURN_AND_NOTIFY_ON_FAILURE( | |
1798 false, "Failed to initialize media types for convesion.", | |
1799 PLATFORM_FAILURE,); | |
1800 } | |
1801 | |
1802 // The input to the video processor is the output sample. | |
1803 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; | |
1804 { | |
1805 base::AutoLock lock(decoder_lock_); | |
1806 PendingSampleInfo& sample_info = pending_output_samples_.front(); | |
1807 input_sample_for_conversion = sample_info.output_sample; | |
1808 } | |
1809 | |
1810 decoder_thread_task_runner_->PostTask( | |
1811 FROM_HERE, | |
1812 base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, | |
1813 base::Unretained(this), | |
1814 src_texture, | |
1815 dest_texture, | |
1816 input_sample_for_conversion.Detach(), | |
1817 picture_buffer_id, | |
1818 input_buffer_id)); | |
1819 return; | |
1820 } | |
1821 | |
1822 DCHECK(video_frame); | |
1823 | |
1824 base::win::ScopedComPtr<IMFSample> input_sample; | |
1825 input_sample.Attach(video_frame); | |
1826 | |
1827 DCHECK(video_format_converter_mft_.get()); | |
1828 | |
1829 hr = video_format_converter_mft_->ProcessInput(0, video_frame, 0); | |
1830 if (FAILED(hr)) { | |
1831 DCHECK(false); | |
1832 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1833 "Failed to convert output sample format.", PLATFORM_FAILURE,); | |
1834 } | |
1835 | |
1836 // The video processor MFT requires output samples to be allocated by the | |
1837 // caller. We create a sample with a buffer backed with the ID3D11Texture2D | |
1838 // interface exposed by ANGLE. This works nicely as this ensures that the | |
1839 // video processor coverts the color space of the output frame and copies | |
DaleCurtis
2015/02/26 22:32:22
Neat, is this more efficient than our existing cop
ananta
2015/02/26 23:32:57
The existing copy in D3D9 occurs in the GPU proces
| |
1840 // the result into the ANGLE texture. | |
1841 base::win::ScopedComPtr<IMFSample> output_sample; | |
1842 hr = MFCreateSample(output_sample.Receive()); | |
1843 if (FAILED(hr)) { | |
1844 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1845 "Failed to create output sample.", PLATFORM_FAILURE,); | |
1846 } | |
1847 | |
1848 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | |
1849 hr = MFCreateDXGISurfaceBuffer( | |
1850 __uuidof(ID3D11Texture2D), dest_texture, 0, FALSE, | |
1851 output_buffer.Receive()); | |
1852 if (FAILED(hr)) { | |
1853 // TODO(ananta) | |
1854 // Remove this CHECK when the change to use DX11 for H/W decoding | |
1855 // stablizes. | |
1856 CHECK(false); | |
1857 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1858 "Failed to create output sample.", PLATFORM_FAILURE,); | |
1859 } | |
1860 | |
1861 output_sample->AddBuffer(output_buffer.get()); | |
1862 | |
1863 DWORD status = 0; | |
1864 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; | |
1865 format_converter_output.pSample = output_sample.get(); | |
1866 hr = video_format_converter_mft_->ProcessOutput( | |
DaleCurtis
2015/02/26 22:32:22
Does this complete immediately? Unlike StretchRect
ananta
2015/02/26 23:32:57
Yes. This transform internally retrieves the bits
| |
1867 0, // No flags | |
1868 1, // # of out streams to pull from | |
1869 &format_converter_output, | |
1870 &status); | |
1871 if (FAILED(hr)) { | |
1872 // TODO(ananta) | |
1873 // Remove this CHECK when the change to use DX11 for H/W decoding | |
1874 // stablizes. | |
1875 CHECK(false); | |
1876 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1877 "Failed to convert output sample format.", PLATFORM_FAILURE,); | |
1878 } | |
1879 | |
1880 main_thread_task_runner_->PostTask( | |
1881 FROM_HERE, | |
1882 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | |
1883 weak_this_factory_.GetWeakPtr(), | |
1884 reinterpret_cast<IDirect3DSurface9*>(NULL), | |
1885 reinterpret_cast<IDirect3DSurface9*>(NULL), | |
1886 picture_buffer_id, | |
1887 input_buffer_id)); | |
1888 } | |
1889 | |
1593 void DXVAVideoDecodeAccelerator::FlushDecoder( | 1890 void DXVAVideoDecodeAccelerator::FlushDecoder( |
1594 int iterations, | 1891 int iterations, |
1595 IDirect3DSurface9* src_surface, | 1892 IDirect3DSurface9* src_surface, |
1596 IDirect3DSurface9* dest_surface, | 1893 IDirect3DSurface9* dest_surface, |
1597 int picture_buffer_id, | 1894 int picture_buffer_id, |
1598 int input_buffer_id) { | 1895 int input_buffer_id) { |
1599 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1896 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1600 | 1897 |
1601 // The DXVA decoder has its own device which it uses for decoding. ANGLE | 1898 // The DXVA decoder has its own device which it uses for decoding. ANGLE |
1602 // has its own device which we don't have access to. | 1899 // has its own device which we don't have access to. |
(...skipping 21 matching lines...) Expand all Loading... | |
1624 main_thread_task_runner_->PostTask( | 1921 main_thread_task_runner_->PostTask( |
1625 FROM_HERE, | 1922 FROM_HERE, |
1626 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | 1923 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
1627 weak_this_factory_.GetWeakPtr(), | 1924 weak_this_factory_.GetWeakPtr(), |
1628 src_surface, | 1925 src_surface, |
1629 dest_surface, | 1926 dest_surface, |
1630 picture_buffer_id, | 1927 picture_buffer_id, |
1631 input_buffer_id)); | 1928 input_buffer_id)); |
1632 } | 1929 } |
1633 | 1930 |
1931 bool DXVAVideoDecodeAccelerator::InitializeDX11VideoFormatConverterMediaType( | |
1932 int width, int height) { | |
1933 if (!dx11_video_format_converter_media_type_needs_init_) | |
1934 return true; | |
1935 | |
1936 CHECK(video_format_converter_mft_.get()); | |
1937 | |
1938 HRESULT hr = video_format_converter_mft_->ProcessMessage( | |
1939 MFT_MESSAGE_SET_D3D_MANAGER, | |
1940 reinterpret_cast<ULONG_PTR>(d3d11_device_manager_.get())); | |
1941 if (FAILED(hr)) { | |
1942 // TODO(ananta) | |
1943 // Remove this CHECK when the change to use DX11 for H/W decoding | |
1944 // stablizes. | |
1945 CHECK(false); | |
1946 } | |
1947 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1948 "Failed to initialize video format converter", PLATFORM_FAILURE, false); | |
1949 | |
1950 video_format_converter_mft_->ProcessMessage( | |
1951 MFT_MESSAGE_NOTIFY_END_STREAMING, 0); | |
1952 | |
1953 base::win::ScopedComPtr<IMFMediaType> media_type; | |
1954 hr = MFCreateMediaType(media_type.Receive()); | |
1955 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFCreateMediaType failed", | |
1956 PLATFORM_FAILURE, false); | |
1957 | |
1958 hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); | |
1959 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set major input type", | |
1960 PLATFORM_FAILURE, false); | |
1961 | |
1962 hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); | |
1963 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type", | |
1964 PLATFORM_FAILURE, false); | |
1965 | |
1966 hr = media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); | |
1967 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1968 "Failed to set attributes on media type", PLATFORM_FAILURE, false); | |
1969 | |
1970 hr = media_type->SetUINT32(MF_MT_INTERLACE_MODE, | |
1971 MFVideoInterlace_Progressive); | |
1972 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
1973 "Failed to set attributes on media type", PLATFORM_FAILURE, false); | |
1974 | |
1975 base::win::ScopedComPtr<IMFAttributes> converter_attributes; | |
1976 hr = video_format_converter_mft_->GetAttributes( | |
1977 converter_attributes.Receive()); | |
1978 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get converter attributes", | |
1979 PLATFORM_FAILURE, false); | |
1980 | |
1981 hr = converter_attributes->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE); | |
1982 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes", | |
1983 PLATFORM_FAILURE, false); | |
1984 | |
1985 hr = converter_attributes->SetUINT32(MF_LOW_LATENCY, FALSE); | |
1986 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes", | |
1987 PLATFORM_FAILURE, false); | |
1988 | |
1989 hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height); | |
1990 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes", | |
1991 PLATFORM_FAILURE, false); | |
1992 | |
1993 hr = video_format_converter_mft_->SetInputType(0, media_type.get(), 0); | |
1994 if (FAILED(hr)) { | |
1995 // TODO(ananta) | |
1996 // Remove this CHECK when the change to use DX11 for H/W decoding | |
1997 // stablizes. | |
1998 CHECK(false); | |
1999 } | |
2000 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type", | |
2001 PLATFORM_FAILURE, false); | |
2002 | |
2003 base::win::ScopedComPtr<IMFMediaType> out_media_type; | |
2004 | |
2005 for (uint32 i = 0; | |
2006 SUCCEEDED(video_format_converter_mft_->GetOutputAvailableType(0, i, | |
2007 out_media_type.Receive())); | |
2008 ++i) { | |
2009 GUID out_subtype = {0}; | |
2010 hr = out_media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype); | |
2011 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get output major type", | |
2012 PLATFORM_FAILURE, false); | |
2013 | |
2014 if (out_subtype == MFVideoFormat_ARGB32) { | |
2015 hr = out_media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); | |
2016 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
2017 "Failed to set attributes on media type", PLATFORM_FAILURE, false); | |
2018 | |
2019 hr = out_media_type->SetUINT32(MF_MT_INTERLACE_MODE, | |
2020 MFVideoInterlace_Progressive); | |
2021 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
2022 "Failed to set attributes on media type", PLATFORM_FAILURE, false); | |
2023 | |
2024 hr = MFSetAttributeSize(out_media_type.get(), MF_MT_FRAME_SIZE, width, | |
2025 height); | |
2026 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
2027 "Failed to set media type attributes", PLATFORM_FAILURE, false); | |
2028 | |
2029 hr = video_format_converter_mft_->SetOutputType( | |
2030 0, out_media_type.get(), 0); // No flags | |
2031 if (FAILED(hr)) { | |
2032 // TODO(ananta) | |
2033 // Remove this CHECK when the change to use DX11 for H/W decoding | |
2034 // stablizes. | |
2035 CHECK(false); | |
2036 } | |
2037 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | |
2038 "Failed to set converter output type", PLATFORM_FAILURE, false); | |
2039 | |
2040 hr = video_format_converter_mft_->ProcessMessage( | |
2041 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); | |
2042 if (FAILED(hr)) { | |
2043 // TODO(ananta) | |
2044 // Remove this CHECK when the change to use DX11 for H/W decoding | |
2045 // stablizes. | |
2046 RETURN_AND_NOTIFY_ON_FAILURE( | |
2047 false, "Failed to initialize video converter.", PLATFORM_FAILURE, | |
2048 false); | |
2049 } | |
2050 dx11_video_format_converter_media_type_needs_init_ = false; | |
2051 return true; | |
2052 } | |
2053 out_media_type.Release(); | |
2054 } | |
2055 return false; | |
2056 } | |
2057 | |
2058 bool DXVAVideoDecodeAccelerator::GetVideoFrameDimensions( | |
2059 IMFSample* sample, | |
2060 int* width, | |
2061 int* height) { | |
2062 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | |
2063 HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive()); | |
2064 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false); | |
2065 | |
2066 if (use_dx11_) { | |
2067 base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer; | |
2068 base::win::ScopedComPtr<ID3D11Texture2D> d3d11_texture; | |
2069 hr = dxgi_buffer.QueryFrom(output_buffer.get()); | |
2070 RETURN_ON_HR_FAILURE(hr, "Failed to get DXGIBuffer from output sample", | |
2071 false); | |
2072 hr = dxgi_buffer->GetResource( | |
2073 __uuidof(ID3D11Texture2D), | |
2074 reinterpret_cast<void**>(d3d11_texture.Receive())); | |
2075 RETURN_ON_HR_FAILURE(hr, "Failed to get D3D11Texture from output buffer", | |
2076 false); | |
2077 D3D11_TEXTURE2D_DESC d3d11_texture_desc; | |
2078 d3d11_texture->GetDesc(&d3d11_texture_desc); | |
2079 *width = d3d11_texture_desc.Width; | |
2080 *height = d3d11_texture_desc.Height; | |
2081 } else { | |
2082 base::win::ScopedComPtr<IDirect3DSurface9> surface; | |
2083 hr = MFGetService(output_buffer.get(), MR_BUFFER_SERVICE, | |
2084 IID_PPV_ARGS(surface.Receive())); | |
2085 RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample", | |
2086 false); | |
2087 D3DSURFACE_DESC surface_desc; | |
2088 hr = surface->GetDesc(&surface_desc); | |
2089 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | |
2090 *width = surface_desc.Width; | |
2091 *height = surface_desc.Height; | |
2092 } | |
2093 return true; | |
2094 } | |
2095 | |
1634 } // namespace content | 2096 } // namespace content |
OLD | NEW |