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

Unified Diff: media/gpu/d3d11_video_decode_accelerator_win.cc

Issue 2534313004: Add prototype D3D11VideoDecodeAccelerator. (Closed)
Patch Set: rename d3d11_video_decoder.cc and other changes Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/gpu/d3d11_video_decode_accelerator_win.h ('k') | media/gpu/gpu_video_decode_accelerator_factory.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/gpu/d3d11_video_decode_accelerator_win.cc
diff --git a/media/gpu/d3d11_video_decode_accelerator_win.cc b/media/gpu/d3d11_video_decode_accelerator_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..63e77143cec85ee66bdd9dd43af87f85fb531cc2
--- /dev/null
+++ b/media/gpu/d3d11_video_decode_accelerator_win.cc
@@ -0,0 +1,327 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is defined here to ensure the D3D11, D3D9, and DXVA includes through
+// this header have their GUIDs intialized.
+#define INITGUID
+#include "media/gpu/d3d11_video_decode_accelerator_win.h"
+#undef INITGUID
+
+#include <d3d11.h>
+
+#include "base/bits.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "base/win/scoped_comptr.h"
+#include "media/gpu/d3d11_h264_accelerator.h"
+#include "media/gpu/h264_decoder.h"
+#include "media/gpu/h264_dpb.h"
+#include "third_party/angle/include/EGL/egl.h"
+#include "third_party/angle/include/EGL/eglext.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface_egl.h"
+
+namespace media {
+
+#define RETURN_ON_FAILURE(result, log, ret) \
+ do { \
+ if (!(result)) { \
+ DLOG(ERROR) << log; \
+ return ret; \
+ } \
+ } while (0)
+
+// Helper function to query the ANGLE device object. The template argument T
+// identifies the device interface being queried. IDirect3DDevice9Ex for d3d9
+// and ID3D11Device for dx11.
+template <class T>
+base::win::ScopedComPtr<T> QueryDeviceObjectFromANGLE(int object_type) {
+ base::win::ScopedComPtr<T> device_object;
+
+ EGLDisplay egl_display = nullptr;
+ intptr_t egl_device = 0;
+ intptr_t device = 0;
+
+ {
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. GetHardwareDisplay");
+ egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+ }
+
+ RETURN_ON_FAILURE(gl::GLSurfaceEGL::HasEGLExtension("EGL_EXT_device_query"),
+ "EGL_EXT_device_query missing", device_object);
+
+ PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = nullptr;
+
+ {
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress");
+
+ QueryDisplayAttribEXT = reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
+ eglGetProcAddress("eglQueryDisplayAttribEXT"));
+
+ RETURN_ON_FAILURE(
+ QueryDisplayAttribEXT,
+ "Failed to get the eglQueryDisplayAttribEXT function from ANGLE",
+ device_object);
+ }
+
+ PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = nullptr;
+
+ {
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress");
+
+ QueryDeviceAttribEXT = reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(
+ eglGetProcAddress("eglQueryDeviceAttribEXT"));
+
+ RETURN_ON_FAILURE(
+ QueryDeviceAttribEXT,
+ "Failed to get the eglQueryDeviceAttribEXT function from ANGLE",
+ device_object);
+ }
+
+ {
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT");
+
+ RETURN_ON_FAILURE(
+ QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device),
+ "The eglQueryDisplayAttribEXT function failed to get the EGL device",
+ device_object);
+ }
+
+ RETURN_ON_FAILURE(egl_device, "Failed to get the EGL device", device_object);
+
+ {
+ TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT");
+
+ RETURN_ON_FAILURE(
+ QueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(egl_device),
+ object_type, &device),
+ "The eglQueryDeviceAttribEXT function failed to get the device",
+ device_object);
+
+ RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object);
+ }
+
+ device_object = reinterpret_cast<T*>(device);
+ return device_object;
+}
+
+D3D11VideoDecodeAccelerator::D3D11VideoDecodeAccelerator(
+ const GetGLContextCallback& get_gl_context_cb,
+ const MakeGLContextCurrentCallback& make_context_current_cb)
+ : get_gl_context_cb_(get_gl_context_cb),
+ make_context_current_cb_(make_context_current_cb) {}
+
+D3D11VideoDecodeAccelerator::~D3D11VideoDecodeAccelerator() {}
+
+bool D3D11VideoDecodeAccelerator::Initialize(const Config& config,
+ Client* client) {
+ client_ = client;
+ make_context_current_cb_.Run();
+
+ device_ = QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE);
+ device_->GetImmediateContext(device_context_.Receive());
+
+ HRESULT hr = device_context_.QueryInterface(video_context_.Receive());
+ CHECK(SUCCEEDED(hr));
+
+ hr = device_.QueryInterface(video_device_.Receive());
+ CHECK(SUCCEEDED(hr));
+
+ bool is_h264 =
+ config.profile >= H264PROFILE_MIN && config.profile <= H264PROFILE_MAX;
+ if (!is_h264)
+ return false;
+
+ GUID needed_guid;
+ memcpy(&needed_guid, &D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
+ sizeof(needed_guid));
+ GUID decoder_guid = {};
+
+ {
+ // Enumerate supported video profiles and look for the H264 profile.
+ bool found = false;
+ UINT profile_count = video_device_->GetVideoDecoderProfileCount();
+ for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) {
+ GUID profile_id = {};
+ hr = video_device_->GetVideoDecoderProfile(profile_idx, &profile_id);
+ if (SUCCEEDED(hr) && (profile_id == needed_guid)) {
+ decoder_guid = profile_id;
+ found = true;
+ break;
+ }
+ }
+ CHECK(found);
+ }
+
+ D3D11_VIDEO_DECODER_DESC desc = {};
+ desc.Guid = decoder_guid;
+ desc.SampleWidth = 1920;
+ desc.SampleHeight = 1088;
+ desc.OutputFormat = DXGI_FORMAT_NV12;
+ UINT config_count = 0;
+ hr = video_device_->GetVideoDecoderConfigCount(&desc, &config_count);
+ if (FAILED(hr) || config_count == 0)
+ CHECK(false);
+
+ D3D11_VIDEO_DECODER_CONFIG dec_config = {};
+ for (UINT i = 0; i < config_count; i++) {
+ hr = video_device_->GetVideoDecoderConfig(&desc, i, &dec_config);
+ if (FAILED(hr))
+ CHECK(false);
+ if (dec_config.ConfigBitstreamRaw == 2)
+ break;
+ }
+ memcpy(&decoder_guid_, &decoder_guid, sizeof decoder_guid_);
+
+ base::win::ScopedComPtr<ID3D11VideoDecoder> video_decoder;
+ hr = video_device_->CreateVideoDecoder(&desc, &dec_config,
+ video_decoder.Receive());
+ CHECK(video_decoder.get());
+
+ h264_accelerator_.reset(new D3D11H264Accelerator(
+ this, video_decoder, video_device_, video_context_));
+ decoder_.reset(new media::H264Decoder(h264_accelerator_.get()));
+
+ return true;
+}
+
+void D3D11VideoDecodeAccelerator::Decode(
+ const BitstreamBuffer& bitstream_buffer) {
+ input_buffer_queue_.push_back(bitstream_buffer);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&D3D11VideoDecodeAccelerator::DoDecode,
+ base::Unretained(this)));
+}
+
+void D3D11VideoDecodeAccelerator::DoDecode() {
+ if (!bitstream_buffer_) {
+ if (input_buffer_queue_.empty())
+ return;
+ BitstreamBuffer buffer = input_buffer_queue_.front();
+ bitstream_buffer_ =
+ base::MakeUnique<base::SharedMemory>(buffer.handle(), true);
+ bitstream_buffer_->Map(buffer.size());
+ bitstream_buffer_size_ = buffer.size();
+ input_buffer_id_ = buffer.id();
+ input_buffer_queue_.pop_front();
+ decoder_->SetStream((const uint8_t*)bitstream_buffer_->memory(),
+ bitstream_buffer_size_);
+ }
+
+ while (true) {
+ media::AcceleratedVideoDecoder::DecodeResult result = decoder_->Decode();
+ if (result == media::AcceleratedVideoDecoder::kRanOutOfStreamData) {
+ client_->NotifyEndOfBitstreamBuffer(input_buffer_id_);
+ bitstream_buffer_.reset();
+ break;
+ }
+ if (result == media::AcceleratedVideoDecoder::kRanOutOfSurfaces) {
+ return;
+ }
+ if (result == media::AcceleratedVideoDecoder::kAllocateNewSurfaces) {
+ client_->ProvidePictureBuffers(20, PIXEL_FORMAT_NV12, 2,
+ decoder_->GetPicSize(),
+ GL_TEXTURE_EXTERNAL_OES);
+ return;
+
+ } else {
+ LOG(ERROR) << "VDA Error " << result;
+ CHECK(false);
+ }
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&D3D11VideoDecodeAccelerator::DoDecode,
+ base::Unretained(this)));
+}
+
+void D3D11VideoDecodeAccelerator::AssignPictureBuffers(
+ const std::vector<PictureBuffer>& buffers) {
+ D3D11_TEXTURE2D_DESC texture_desc = {};
+ texture_desc.Width = decoder_->GetPicSize().width();
+ texture_desc.Height = decoder_->GetPicSize().height();
+ texture_desc.MipLevels = 1;
+ texture_desc.ArraySize = buffers.size();
+ texture_desc.Format = DXGI_FORMAT_NV12;
+ texture_desc.SampleDesc.Count = 1;
+ texture_desc.Usage = D3D11_USAGE_DEFAULT;
+ texture_desc.BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
+ texture_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+
+ base::win::ScopedComPtr<ID3D11Texture2D> out_texture;
+ HRESULT hr =
+ device_->CreateTexture2D(&texture_desc, nullptr, out_texture.Receive());
+ CHECK(SUCCEEDED(hr));
+
+ make_context_current_cb_.Run();
+ picture_buffers_.clear();
+
+ for (size_t i = 0; i < buffers.size(); i++) {
+ picture_buffers_.push_back(
+ base::MakeUnique<D3D11PictureBuffer>(buffers[i], i));
+ picture_buffers_[i]->Init(video_device_, out_texture, decoder_guid_);
+ }
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&D3D11VideoDecodeAccelerator::DoDecode,
+ base::Unretained(this)));
+}
+
+void D3D11VideoDecodeAccelerator::ReusePictureBuffer(
+ int32_t picture_buffer_id) {
+ make_context_current_cb_.Run();
+ for (auto& buffer : picture_buffers_) {
+ if (buffer->picture_buffer().id() == picture_buffer_id) {
+ buffer->set_in_client_use(false);
+
+ break;
+ }
+ }
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&D3D11VideoDecodeAccelerator::DoDecode,
+ base::Unretained(this)));
+}
+
+D3D11PictureBuffer* D3D11VideoDecodeAccelerator::GetPicture() {
+ for (auto& buffer : picture_buffers_)
+ if (!buffer->in_client_use() && !buffer->in_picture_use()) {
+ return buffer.get();
+ }
+ return nullptr;
+}
+
+void D3D11VideoDecodeAccelerator::Flush() {
+ client_->NotifyFlushDone();
+}
+
+void D3D11VideoDecodeAccelerator::Reset() {
+ client_->NotifyResetDone();
+}
+void D3D11VideoDecodeAccelerator::Destroy() {}
+
+bool D3D11VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
+ const base::WeakPtr<Client>& decode_client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
+ return false;
+}
+
+GLenum D3D11VideoDecodeAccelerator::GetSurfaceInternalFormat() const {
+ return GL_BGRA_EXT;
+}
+
+size_t D3D11VideoDecodeAccelerator::input_buffer_id() const {
+ return input_buffer_id_;
+}
+
+void D3D11VideoDecodeAccelerator::OutputResult(D3D11PictureBuffer* buffer,
+ size_t input_buffer_id) {
+ buffer->set_in_client_use(true);
+ Picture picture(buffer->picture_buffer().id(), input_buffer_id,
+ gfx::Rect(0, 0), gfx::ColorSpace(), false);
+ client_->PictureReady(picture);
+}
+} // namespace media
« no previous file with comments | « media/gpu/d3d11_video_decode_accelerator_win.h ('k') | media/gpu/gpu_video_decode_accelerator_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698