OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/gpu/dxva_picture_buffer_win.h" | 5 #include "media/gpu/dxva_picture_buffer_win.h" |
6 | 6 |
7 #include "media/gpu/dxva_video_decode_accelerator_win.h" | 7 #include "media/gpu/dxva_video_decode_accelerator_win.h" |
8 #include "third_party/angle/include/EGL/egl.h" | 8 #include "third_party/angle/include/EGL/egl.h" |
9 #include "third_party/angle/include/EGL/eglext.h" | 9 #include "third_party/angle/include/EGL/eglext.h" |
10 #include "ui/gl/gl_bindings.h" | 10 #include "ui/gl/gl_bindings.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 // These GLImage subclasses are just used to hold references to the underlying | 26 // These GLImage subclasses are just used to hold references to the underlying |
27 // image content so it can be destroyed when the textures are. | 27 // image content so it can be destroyed when the textures are. |
28 class DummyGLImage : public gl::GLImage { | 28 class DummyGLImage : public gl::GLImage { |
29 public: | 29 public: |
30 DummyGLImage(const gfx::Size& size) : size_(size) {} | 30 DummyGLImage(const gfx::Size& size) : size_(size) {} |
31 | 31 |
32 // gl::GLImage implementation. | 32 // gl::GLImage implementation. |
33 gfx::Size GetSize() override { return size_; } | 33 gfx::Size GetSize() override { return size_; } |
34 unsigned GetInternalFormat() override { return GL_BGRA_EXT; } | 34 unsigned GetInternalFormat() override { return GL_BGRA_EXT; } |
35 bool BindTexImage(unsigned target) override { return false; } | 35 // PbufferPictureBuffer::CopySurfaceComplete does the actual binding, so |
| 36 // this doesn't do anything and always succeeds. |
| 37 bool BindTexImage(unsigned target) override { return true; } |
36 void ReleaseTexImage(unsigned target) override {} | 38 void ReleaseTexImage(unsigned target) override {} |
37 bool CopyTexImage(unsigned target) override { return false; } | 39 bool CopyTexImage(unsigned target) override { return false; } |
38 bool CopyTexSubImage(unsigned target, | 40 bool CopyTexSubImage(unsigned target, |
39 const gfx::Point& offset, | 41 const gfx::Point& offset, |
40 const gfx::Rect& rect) override { | 42 const gfx::Rect& rect) override { |
41 return false; | 43 return false; |
42 } | 44 } |
43 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, | 45 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, |
44 int z_order, | 46 int z_order, |
45 gfx::OverlayTransform transform, | 47 gfx::OverlayTransform transform, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 // The keyed mutex should always be released before the other thread | 97 // The keyed mutex should always be released before the other thread |
96 // attempts to acquire it, so AcquireSync should always return immediately. | 98 // attempts to acquire it, so AcquireSync should always return immediately. |
97 kAcquireSyncWaitMs = 0, | 99 kAcquireSyncWaitMs = 0, |
98 }; | 100 }; |
99 | 101 |
100 // static | 102 // static |
101 linked_ptr<DXVAPictureBuffer> DXVAPictureBuffer::Create( | 103 linked_ptr<DXVAPictureBuffer> DXVAPictureBuffer::Create( |
102 const DXVAVideoDecodeAccelerator& decoder, | 104 const DXVAVideoDecodeAccelerator& decoder, |
103 const PictureBuffer& buffer, | 105 const PictureBuffer& buffer, |
104 EGLConfig egl_config) { | 106 EGLConfig egl_config) { |
105 if (decoder.share_nv12_textures_) { | 107 switch (decoder.GetPictureBufferMechanism()) { |
106 linked_ptr<EGLStreamPictureBuffer> picture_buffer( | 108 case DXVAVideoDecodeAccelerator::PictureBufferMechanism::BIND: { |
107 new EGLStreamPictureBuffer(buffer)); | 109 linked_ptr<EGLStreamPictureBuffer> picture_buffer( |
108 if (!picture_buffer->Initialize()) | 110 new EGLStreamPictureBuffer(buffer)); |
109 return linked_ptr<DXVAPictureBuffer>(nullptr); | 111 if (!picture_buffer->Initialize()) |
| 112 return linked_ptr<DXVAPictureBuffer>(nullptr); |
110 | 113 |
111 return picture_buffer; | 114 return picture_buffer; |
| 115 } |
| 116 case DXVAVideoDecodeAccelerator::PictureBufferMechanism:: |
| 117 DELAYED_COPY_TO_NV12: { |
| 118 linked_ptr<EGLStreamDelayedCopyPictureBuffer> picture_buffer( |
| 119 new EGLStreamDelayedCopyPictureBuffer(buffer)); |
| 120 if (!picture_buffer->Initialize(decoder)) |
| 121 return linked_ptr<DXVAPictureBuffer>(nullptr); |
| 122 |
| 123 return picture_buffer; |
| 124 } |
| 125 case DXVAVideoDecodeAccelerator::PictureBufferMechanism::COPY_TO_NV12: { |
| 126 linked_ptr<EGLStreamCopyPictureBuffer> picture_buffer( |
| 127 new EGLStreamCopyPictureBuffer(buffer)); |
| 128 if (!picture_buffer->Initialize(decoder)) |
| 129 return linked_ptr<DXVAPictureBuffer>(nullptr); |
| 130 |
| 131 return picture_buffer; |
| 132 } |
| 133 case DXVAVideoDecodeAccelerator::PictureBufferMechanism::COPY_TO_RGB: { |
| 134 linked_ptr<PbufferPictureBuffer> picture_buffer( |
| 135 new PbufferPictureBuffer(buffer)); |
| 136 |
| 137 if (!picture_buffer->Initialize(decoder, egl_config)) |
| 138 return linked_ptr<DXVAPictureBuffer>(nullptr); |
| 139 |
| 140 return picture_buffer; |
| 141 } |
112 } | 142 } |
113 if (decoder.copy_nv12_textures_) { | 143 NOTREACHED(); |
114 linked_ptr<EGLStreamCopyPictureBuffer> picture_buffer( | 144 return linked_ptr<DXVAPictureBuffer>(nullptr); |
115 new EGLStreamCopyPictureBuffer(buffer)); | |
116 if (!picture_buffer->Initialize(decoder)) | |
117 return linked_ptr<DXVAPictureBuffer>(nullptr); | |
118 | |
119 return picture_buffer; | |
120 } | |
121 linked_ptr<PbufferPictureBuffer> picture_buffer( | |
122 new PbufferPictureBuffer(buffer)); | |
123 | |
124 if (!picture_buffer->Initialize(decoder, egl_config)) | |
125 return linked_ptr<DXVAPictureBuffer>(nullptr); | |
126 | |
127 return picture_buffer; | |
128 } | 145 } |
129 | 146 |
130 DXVAPictureBuffer::~DXVAPictureBuffer() {} | 147 DXVAPictureBuffer::~DXVAPictureBuffer() {} |
131 | 148 |
132 void DXVAPictureBuffer::ResetReuseFence() { | 149 void DXVAPictureBuffer::ResetReuseFence() { |
133 NOTREACHED(); | 150 NOTREACHED(); |
134 } | 151 } |
135 | 152 |
136 bool DXVAPictureBuffer::CopyOutputSampleDataToPictureBuffer( | 153 bool DXVAPictureBuffer::CopyOutputSampleDataToPictureBuffer( |
137 DXVAVideoDecodeAccelerator* decoder, | 154 DXVAVideoDecodeAccelerator* decoder, |
(...skipping 16 matching lines...) Expand all Loading... |
154 bool DXVAPictureBuffer::CopySurfaceComplete(IDirect3DSurface9* src_surface, | 171 bool DXVAPictureBuffer::CopySurfaceComplete(IDirect3DSurface9* src_surface, |
155 IDirect3DSurface9* dest_surface) { | 172 IDirect3DSurface9* dest_surface) { |
156 NOTREACHED(); | 173 NOTREACHED(); |
157 return false; | 174 return false; |
158 } | 175 } |
159 | 176 |
160 DXVAPictureBuffer::DXVAPictureBuffer(const PictureBuffer& buffer) | 177 DXVAPictureBuffer::DXVAPictureBuffer(const PictureBuffer& buffer) |
161 : picture_buffer_(buffer) {} | 178 : picture_buffer_(buffer) {} |
162 | 179 |
163 bool DXVAPictureBuffer::BindSampleToTexture( | 180 bool DXVAPictureBuffer::BindSampleToTexture( |
| 181 DXVAVideoDecodeAccelerator* decoder, |
164 base::win::ScopedComPtr<IMFSample> sample) { | 182 base::win::ScopedComPtr<IMFSample> sample) { |
165 NOTREACHED(); | 183 NOTREACHED(); |
166 return false; | 184 return false; |
167 } | 185 } |
168 | 186 |
169 bool PbufferPictureBuffer::Initialize(const DXVAVideoDecodeAccelerator& decoder, | 187 bool PbufferPictureBuffer::Initialize(const DXVAVideoDecodeAccelerator& decoder, |
170 EGLConfig egl_config) { | 188 EGLConfig egl_config) { |
171 RETURN_ON_FAILURE(!picture_buffer_.service_texture_ids().empty(), | 189 RETURN_ON_FAILURE(!picture_buffer_.service_texture_ids().empty(), |
172 "No service texture ids provided", false); | 190 "No service texture ids provided", false); |
173 | 191 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 | 386 |
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 387 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
370 glBindTexture(GL_TEXTURE_2D, current_texture); | 388 glBindTexture(GL_TEXTURE_2D, current_texture); |
371 return true; | 389 return true; |
372 } | 390 } |
373 | 391 |
374 bool PbufferPictureBuffer::AllowOverlay() const { | 392 bool PbufferPictureBuffer::AllowOverlay() const { |
375 return false; | 393 return false; |
376 } | 394 } |
377 | 395 |
| 396 bool PbufferPictureBuffer::CanBindSamples() const { |
| 397 return false; |
| 398 } |
| 399 |
378 PbufferPictureBuffer::PbufferPictureBuffer(const PictureBuffer& buffer) | 400 PbufferPictureBuffer::PbufferPictureBuffer(const PictureBuffer& buffer) |
379 : DXVAPictureBuffer(buffer), | 401 : DXVAPictureBuffer(buffer), |
380 decoding_surface_(NULL), | 402 decoding_surface_(NULL), |
381 texture_share_handle_(nullptr), | 403 texture_share_handle_(nullptr), |
382 keyed_mutex_value_(0), | 404 keyed_mutex_value_(0), |
383 use_rgb_(true) {} | 405 use_rgb_(true) {} |
384 | 406 |
385 PbufferPictureBuffer::~PbufferPictureBuffer() { | 407 PbufferPictureBuffer::~PbufferPictureBuffer() { |
386 // decoding_surface_ will be deleted by gl_image_. | 408 // decoding_surface_ will be deleted by gl_image_. |
387 } | 409 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 } | 489 } |
468 if (current_d3d_sample_) { | 490 if (current_d3d_sample_) { |
469 dx11_decoding_texture_.Reset(); | 491 dx11_decoding_texture_.Reset(); |
470 current_d3d_sample_.Reset(); | 492 current_d3d_sample_.Reset(); |
471 } | 493 } |
472 state_ = UNUSED; | 494 state_ = UNUSED; |
473 return true; | 495 return true; |
474 } | 496 } |
475 | 497 |
476 bool EGLStreamPictureBuffer::BindSampleToTexture( | 498 bool EGLStreamPictureBuffer::BindSampleToTexture( |
| 499 DXVAVideoDecodeAccelerator* decoder, |
477 base::win::ScopedComPtr<IMFSample> sample) { | 500 base::win::ScopedComPtr<IMFSample> sample) { |
478 DCHECK_EQ(BOUND, state_); | 501 DCHECK_EQ(BOUND, state_); |
479 state_ = IN_CLIENT; | 502 state_ = IN_CLIENT; |
480 | 503 |
481 current_d3d_sample_ = sample; | 504 current_d3d_sample_ = sample; |
482 EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay(); | 505 EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay(); |
483 | 506 |
484 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | 507 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; |
485 HRESULT hr = | 508 HRESULT hr = |
486 current_d3d_sample_->GetBufferByIndex(0, output_buffer.GetAddressOf()); | 509 current_d3d_sample_->GetBufferByIndex(0, output_buffer.GetAddressOf()); |
(...skipping 24 matching lines...) Expand all Loading... |
511 DCHECK(gl_image_dxgi); | 534 DCHECK(gl_image_dxgi); |
512 | 535 |
513 gl_image_dxgi->SetTexture(dx11_decoding_texture_, subresource); | 536 gl_image_dxgi->SetTexture(dx11_decoding_texture_, subresource); |
514 return true; | 537 return true; |
515 } | 538 } |
516 | 539 |
517 bool EGLStreamPictureBuffer::AllowOverlay() const { | 540 bool EGLStreamPictureBuffer::AllowOverlay() const { |
518 return true; | 541 return true; |
519 } | 542 } |
520 | 543 |
| 544 bool EGLStreamPictureBuffer::CanBindSamples() const { |
| 545 return true; |
| 546 } |
| 547 |
| 548 EGLStreamDelayedCopyPictureBuffer::EGLStreamDelayedCopyPictureBuffer( |
| 549 const PictureBuffer& buffer) |
| 550 : DXVAPictureBuffer(buffer), stream_(nullptr) {} |
| 551 |
| 552 EGLStreamDelayedCopyPictureBuffer::~EGLStreamDelayedCopyPictureBuffer() { |
| 553 // stream_ will be deleted by gl_image_. |
| 554 } |
| 555 |
| 556 bool EGLStreamDelayedCopyPictureBuffer::Initialize( |
| 557 const DXVAVideoDecodeAccelerator& decoder) { |
| 558 RETURN_ON_FAILURE(picture_buffer_.service_texture_ids().size() >= 2, |
| 559 "Not enough texture ids provided", false); |
| 560 |
| 561 EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay(); |
| 562 const EGLint stream_attributes[] = { |
| 563 EGL_CONSUMER_LATENCY_USEC_KHR, |
| 564 0, |
| 565 EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, |
| 566 0, |
| 567 EGL_NONE, |
| 568 }; |
| 569 stream_ = eglCreateStreamKHR(egl_display, stream_attributes); |
| 570 RETURN_ON_FAILURE(!!stream_, "Could not create stream", false); |
| 571 gl::ScopedActiveTexture texture0(GL_TEXTURE0); |
| 572 gl::ScopedTextureBinder texture0_binder( |
| 573 GL_TEXTURE_EXTERNAL_OES, picture_buffer_.service_texture_ids()[0]); |
| 574 gl::ScopedActiveTexture texture1(GL_TEXTURE1); |
| 575 gl::ScopedTextureBinder texture1_binder( |
| 576 GL_TEXTURE_EXTERNAL_OES, picture_buffer_.service_texture_ids()[1]); |
| 577 |
| 578 EGLAttrib consumer_attributes[] = { |
| 579 EGL_COLOR_BUFFER_TYPE, |
| 580 EGL_YUV_BUFFER_EXT, |
| 581 EGL_YUV_NUMBER_OF_PLANES_EXT, |
| 582 2, |
| 583 EGL_YUV_PLANE0_TEXTURE_UNIT_NV, |
| 584 0, |
| 585 EGL_YUV_PLANE1_TEXTURE_UNIT_NV, |
| 586 1, |
| 587 EGL_NONE, |
| 588 }; |
| 589 EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV( |
| 590 egl_display, stream_, consumer_attributes); |
| 591 RETURN_ON_FAILURE(result, "Could not set stream consumer", false); |
| 592 |
| 593 EGLAttrib producer_attributes[] = { |
| 594 EGL_NONE, |
| 595 }; |
| 596 |
| 597 result = eglCreateStreamProducerD3DTextureNV12ANGLE(egl_display, stream_, |
| 598 producer_attributes); |
| 599 RETURN_ON_FAILURE(result, "Could not create stream producer", false); |
| 600 scoped_refptr<gl::CopyingGLImageDXGI> copying_image_ = |
| 601 make_scoped_refptr(new gl::CopyingGLImageDXGI( |
| 602 base::win::ScopedComPtr<ID3D11Device>(decoder.D3D11Device()), size(), |
| 603 stream_)); |
| 604 gl_image_ = copying_image_; |
| 605 return copying_image_->Initialize(); |
| 606 } |
| 607 |
| 608 bool EGLStreamDelayedCopyPictureBuffer::ReusePictureBuffer() { |
| 609 DCHECK_NE(UNUSED, state_); |
| 610 |
| 611 static_cast<gl::CopyingGLImageDXGI*>(gl_image_.get())->UnbindFromTexture(); |
| 612 if (current_d3d_sample_) { |
| 613 dx11_decoding_texture_.Reset(); |
| 614 current_d3d_sample_.Reset(); |
| 615 } |
| 616 state_ = UNUSED; |
| 617 return true; |
| 618 } |
| 619 |
| 620 bool EGLStreamDelayedCopyPictureBuffer::BindSampleToTexture( |
| 621 DXVAVideoDecodeAccelerator* decoder, |
| 622 base::win::ScopedComPtr<IMFSample> sample) { |
| 623 DCHECK_EQ(BOUND, state_); |
| 624 state_ = IN_CLIENT; |
| 625 |
| 626 current_d3d_sample_ = sample; |
| 627 |
| 628 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; |
| 629 HRESULT hr = |
| 630 current_d3d_sample_->GetBufferByIndex(0, output_buffer.GetAddressOf()); |
| 631 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false); |
| 632 |
| 633 base::win::ScopedComPtr<IMFDXGIBuffer> dxgi_buffer; |
| 634 hr = output_buffer.CopyTo(dxgi_buffer.GetAddressOf()); |
| 635 RETURN_ON_HR_FAILURE(hr, "Failed to get DXGIBuffer from output sample", |
| 636 false); |
| 637 hr = dxgi_buffer->GetResource( |
| 638 IID_PPV_ARGS(dx11_decoding_texture_.GetAddressOf())); |
| 639 RETURN_ON_HR_FAILURE(hr, "Failed to get texture from output sample", false); |
| 640 UINT subresource; |
| 641 dxgi_buffer->GetSubresourceIndex(&subresource); |
| 642 if (!decoder->InitializeID3D11VideoProcessor(size().width(), size().height(), |
| 643 color_space_)) |
| 644 return false; |
| 645 |
| 646 DCHECK(decoder->d3d11_processor_); |
| 647 DCHECK(decoder->enumerator_); |
| 648 |
| 649 gl::GLImageDXGI* gl_image_dxgi = |
| 650 gl::GLImageDXGI::FromGLImage(gl_image_.get()); |
| 651 DCHECK(gl_image_dxgi); |
| 652 |
| 653 gl_image_dxgi->SetTexture(dx11_decoding_texture_, subresource); |
| 654 return static_cast<gl::CopyingGLImageDXGI*>(gl_image_dxgi) |
| 655 ->InitializeVideoProcessor(decoder->d3d11_processor_, |
| 656 decoder->enumerator_); |
| 657 } |
| 658 |
| 659 bool EGLStreamDelayedCopyPictureBuffer::AllowOverlay() const { |
| 660 return true; |
| 661 } |
| 662 |
| 663 bool EGLStreamDelayedCopyPictureBuffer::CanBindSamples() const { |
| 664 return true; |
| 665 } |
| 666 |
521 EGLStreamCopyPictureBuffer::EGLStreamCopyPictureBuffer( | 667 EGLStreamCopyPictureBuffer::EGLStreamCopyPictureBuffer( |
522 const PictureBuffer& buffer) | 668 const PictureBuffer& buffer) |
523 : DXVAPictureBuffer(buffer), stream_(nullptr) {} | 669 : DXVAPictureBuffer(buffer), stream_(nullptr) {} |
524 | 670 |
525 EGLStreamCopyPictureBuffer::~EGLStreamCopyPictureBuffer() { | 671 EGLStreamCopyPictureBuffer::~EGLStreamCopyPictureBuffer() { |
526 // stream_ will be deleted by gl_image_. | 672 // stream_ will be deleted by gl_image_. |
527 } | 673 } |
528 | 674 |
529 bool EGLStreamCopyPictureBuffer::Initialize( | 675 bool EGLStreamCopyPictureBuffer::Initialize( |
530 const DXVAVideoDecodeAccelerator& decoder) { | 676 const DXVAVideoDecodeAccelerator& decoder) { |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 EGLBoolean result = eglStreamConsumerReleaseKHR(egl_display, stream_); | 824 EGLBoolean result = eglStreamConsumerReleaseKHR(egl_display, stream_); |
679 RETURN_ON_FAILURE(result, "Could not release stream", false); | 825 RETURN_ON_FAILURE(result, "Could not release stream", false); |
680 } | 826 } |
681 return true; | 827 return true; |
682 } | 828 } |
683 | 829 |
684 bool EGLStreamCopyPictureBuffer::AllowOverlay() const { | 830 bool EGLStreamCopyPictureBuffer::AllowOverlay() const { |
685 return true; | 831 return true; |
686 } | 832 } |
687 | 833 |
| 834 bool EGLStreamCopyPictureBuffer::CanBindSamples() const { |
| 835 return false; |
| 836 } |
| 837 |
688 } // namespace media | 838 } // namespace media |
OLD | NEW |