Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" |
| 6 | 6 |
| 7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
| 8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
| 9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
| 10 | 10 |
| 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 |