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

Unified Diff: media/gpu/d3d11_h264_accelerator.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_h264_accelerator.h ('k') | media/gpu/d3d11_video_decode_accelerator_win.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/gpu/d3d11_h264_accelerator.cc
diff --git a/media/gpu/d3d11_h264_accelerator.cc b/media/gpu/d3d11_h264_accelerator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..49aaab34bd14785e1958384918cffb1bb8ed7288
--- /dev/null
+++ b/media/gpu/d3d11_h264_accelerator.cc
@@ -0,0 +1,455 @@
+// 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.
+
+#include "media/gpu/d3d11_h264_accelerator.h"
+
+#include <d3d11.h>
+#include <dxva.h>
+#include <windows.h>
+
+#include "base/memory/ptr_util.h"
+#include "base/trace_event/trace_event.h"
+#include "base/win/scoped_comptr.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"
+#include "ui/gl/scoped_binders.h"
+
+namespace media {
+
+#define RETURN_ON_FAILURE(result, log, ret) \
+ do { \
+ if (!(result)) { \
+ DLOG(ERROR) << log; \
+ return ret; \
+ } \
+ } while (0)
+
+D3D11PictureBuffer::D3D11PictureBuffer(PictureBuffer picture_buffer,
+ size_t level)
+ : picture_buffer_(picture_buffer), level_(level) {}
+
+D3D11PictureBuffer::~D3D11PictureBuffer() {}
+
+bool D3D11PictureBuffer::Init(
+ base::win::ScopedComPtr<ID3D11VideoDevice> video_device,
+ base::win::ScopedComPtr<ID3D11Texture2D> texture,
+ const GUID& decoder_guid) {
+ texture_ = texture;
+ D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = {};
+ view_desc.DecodeProfile = decoder_guid;
+ view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
+ view_desc.Texture2D.ArraySlice = (UINT)level_;
+
+ HRESULT hr = video_device->CreateVideoDecoderOutputView(
+ texture.get(), &view_desc, output_view_.Receive());
+
+ CHECK(SUCCEEDED(hr));
+ EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+ const EGLint stream_attributes[] = {
+ EGL_CONSUMER_LATENCY_USEC_KHR,
+ 0,
+ EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR,
+ 0,
+ EGL_NONE,
+ };
+ stream_ = eglCreateStreamKHR(egl_display, stream_attributes);
+ RETURN_ON_FAILURE(!!stream_, "Could not create stream", false);
+ gl::ScopedActiveTexture texture0(GL_TEXTURE0);
+ gl::ScopedTextureBinder texture0_binder(
+ GL_TEXTURE_EXTERNAL_OES, picture_buffer_.service_texture_ids()[0]);
+ gl::ScopedActiveTexture texture1(GL_TEXTURE1);
+ gl::ScopedTextureBinder texture1_binder(
+ GL_TEXTURE_EXTERNAL_OES, picture_buffer_.service_texture_ids()[1]);
+
+ EGLAttrib consumer_attributes[] = {
+ EGL_COLOR_BUFFER_TYPE,
+ EGL_YUV_BUFFER_EXT,
+ EGL_YUV_NUMBER_OF_PLANES_EXT,
+ 2,
+ EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
+ 0,
+ EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
+ 1,
+ EGL_NONE,
+ };
+ EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV(
+ egl_display, stream_, consumer_attributes);
+ RETURN_ON_FAILURE(result, "Could not set stream consumer", false);
+
+ EGLAttrib producer_attributes[] = {
+ EGL_NONE,
+ };
+
+ result = eglCreateStreamProducerD3DTextureNV12ANGLE(egl_display, stream_,
+ producer_attributes);
+
+ EGLAttrib frame_attributes[] = {
+ EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, level_, EGL_NONE,
+ };
+
+ result = eglStreamPostD3DTextureNV12ANGLE(egl_display, stream_,
+ static_cast<void*>(texture.get()),
+ frame_attributes);
+ RETURN_ON_FAILURE(result, "Could not post texture", false);
+ result = eglStreamConsumerAcquireKHR(egl_display, stream_);
+ RETURN_ON_FAILURE(result, "Could not post acquire stream", false);
+ return true;
+}
+
+class D3D11H264Picture : public H264Picture {
+ public:
+ D3D11H264Picture(D3D11PictureBuffer* picture, size_t input_buffer_id)
+ : picture(picture),
+ level_(picture->level()),
+ input_buffer_id_(input_buffer_id) {}
+
+ D3D11PictureBuffer* picture;
+ size_t level_;
+ size_t input_buffer_id_;
+
+ protected:
+ ~D3D11H264Picture() override;
+};
+
+D3D11H264Accelerator::D3D11H264Accelerator(
+ D3D11VideoDecoderClient* client,
+ base::win::ScopedComPtr<ID3D11VideoDecoder> video_decoder,
+ base::win::ScopedComPtr<ID3D11VideoDevice> video_device,
+ base::win::ScopedComPtr<ID3D11VideoContext> video_context)
+ : client_(client),
+ video_decoder_(video_decoder),
+ video_device_(video_device),
+ video_context_(video_context) {}
+
+D3D11H264Accelerator::~D3D11H264Accelerator() {}
+
+scoped_refptr<H264Picture> D3D11H264Accelerator::CreateH264Picture() {
+ D3D11PictureBuffer* picture = client_->GetPicture();
+ if (!picture) {
+ return nullptr;
+ }
+ picture->set_in_picture_use(true);
+ return make_scoped_refptr(
+ new D3D11H264Picture(picture, client_->input_buffer_id()));
+}
+
+bool D3D11H264Accelerator::SubmitFrameMetadata(
+ const H264SPS* sps,
+ const H264PPS* pps,
+ const H264DPB& dpb,
+ const H264Picture::Vector& ref_pic_listp0,
+ const H264Picture::Vector& ref_pic_listb0,
+ const H264Picture::Vector& ref_pic_listb1,
+ const scoped_refptr<H264Picture>& pic) {
+ scoped_refptr<D3D11H264Picture> our_pic(
+ static_cast<D3D11H264Picture*>(pic.get()));
+
+ HRESULT hr;
+ hr = video_context_->DecoderBeginFrame(
+ video_decoder_.get(), our_pic->picture->output_view_.get(), 0, nullptr);
+ CHECK(SUCCEEDED(hr));
+
+ sps_ = *sps;
+ for (size_t i = 0; i < 16; i++) {
+ ref_frame_list_[i].bPicEntry = 0xFF;
+ field_order_cnt_list_[i][0] = 0;
+ field_order_cnt_list_[i][1] = 0;
+ frame_num_list_[i] = 0;
+ }
+ used_for_reference_flags_ = 0;
+ non_existing_frame_flags_ = 0;
+
+ int i = 0;
+
+ for (auto it = dpb.begin(); it != dpb.end(); it++) {
+ scoped_refptr<D3D11H264Picture> our_ref_pic(
+ static_cast<D3D11H264Picture*>(it->get()));
+ if (!our_ref_pic->ref) {
+ i++;
+ continue;
+ }
+ ref_frame_list_[i].Index7Bits = our_ref_pic->level_;
+ ref_frame_list_[i].AssociatedFlag = our_ref_pic->long_term;
+ field_order_cnt_list_[i][0] = our_ref_pic->top_field_order_cnt;
+ field_order_cnt_list_[i][1] = our_ref_pic->bottom_field_order_cnt;
+ frame_num_list_[i] = ref_frame_list_[i].AssociatedFlag
+ ? our_ref_pic->long_term_pic_num
+ : our_ref_pic->pic_num;
+ int ref = 3;
+ used_for_reference_flags_ |= ref << (2 * i);
+ non_existing_frame_flags_ |= (our_ref_pic->nonexisting) << i;
+ i++;
+ }
+ slice_info_.clear();
+ RetrieveBitstreamBuffer();
+ return true;
+}
+
+void D3D11H264Accelerator::RetrieveBitstreamBuffer() {
+ current_offset_ = 0;
+ void* buffer;
+ UINT buffer_size;
+ HRESULT hr = video_context_->GetDecoderBuffer(
+ video_decoder_.get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &buffer_size,
+ &buffer);
+ bitstream_buffer_bytes_ = (uint8_t*)buffer;
+ bitstream_buffer_size_ = buffer_size;
+ CHECK(SUCCEEDED(hr));
+}
+
+bool D3D11H264Accelerator::SubmitSlice(const H264PPS* pps,
+ const H264SliceHeader* slice_hdr,
+ const H264Picture::Vector& ref_pic_list0,
+ const H264Picture::Vector& ref_pic_list1,
+ const scoped_refptr<H264Picture>& pic,
+ const uint8_t* data,
+ size_t size) {
+ scoped_refptr<D3D11H264Picture> our_pic(
+ static_cast<D3D11H264Picture*>(pic.get()));
+
+ DXVA_PicParams_H264 pic_param = {};
+
+#define FROM_SPS_TO_PP(a) pic_param.a = sps_.a
+#define FROM_SPS_TO_PP2(a, b) pic_param.a = sps_.b
+#define FROM_PPS_TO_PP(a) pic_param.a = pps->a
+#define FROM_PPS_TO_PP2(a, b) pic_param.a = pps->b
+#define FROM_SLICE_TO_PP(a) pic_param.a = slice_hdr->a
+#define FROM_SLICE_TO_PP2(a, b) pic_param.a = slice_hdr->b
+ FROM_SPS_TO_PP2(wFrameWidthInMbsMinus1, pic_width_in_mbs_minus1);
+ FROM_SPS_TO_PP2(wFrameHeightInMbsMinus1, pic_height_in_map_units_minus1);
+ pic_param.CurrPic.Index7Bits = our_pic->level_;
+ // UNUSED: pic_param.CurrPic.AssociatedFlag = slide_hdr->field_pic_flag
+ FROM_SPS_TO_PP2(num_ref_frames, max_num_ref_frames);
+
+ FROM_SLICE_TO_PP(field_pic_flag);
+ pic_param.MbaffFrameFlag =
+ sps_.mb_adaptive_frame_field_flag && pic_param.field_pic_flag;
+ FROM_SPS_TO_PP2(residual_colour_transform_flag, separate_colour_plane_flag);
+ FROM_SLICE_TO_PP(sp_for_switch_flag);
+ FROM_SPS_TO_PP(chroma_format_idc);
+ pic_param.RefPicFlag = pic->ref;
+ FROM_PPS_TO_PP(constrained_intra_pred_flag);
+ FROM_PPS_TO_PP(weighted_pred_flag);
+ FROM_PPS_TO_PP(weighted_bipred_idc);
+ pic_param.MbsConsecutiveFlag = 1;
+ FROM_SPS_TO_PP(frame_mbs_only_flag);
+ FROM_PPS_TO_PP(transform_8x8_mode_flag);
+ // UNUSED: Minlumabipredsize
+ // UNUSED: pic_param.IntraPicFlag = slice_hdr->IsISlice();
+ FROM_SPS_TO_PP(bit_depth_luma_minus8);
+ FROM_SPS_TO_PP(bit_depth_chroma_minus8);
+ memcpy(pic_param.RefFrameList, ref_frame_list_,
+ sizeof pic_param.RefFrameList);
+ if (pic_param.field_pic_flag && pic_param.CurrPic.AssociatedFlag) {
+ pic_param.CurrFieldOrderCnt[1] = pic->bottom_field_order_cnt;
+ pic_param.CurrFieldOrderCnt[0] = 0;
+ } else if (pic_param.field_pic_flag && !pic_param.CurrPic.AssociatedFlag) {
+ pic_param.CurrFieldOrderCnt[0] = pic->top_field_order_cnt;
+ pic_param.CurrFieldOrderCnt[1] = 0;
+ } else {
+ pic_param.CurrFieldOrderCnt[0] = pic->top_field_order_cnt;
+ pic_param.CurrFieldOrderCnt[1] = pic->bottom_field_order_cnt;
+ }
+ memcpy(pic_param.FieldOrderCntList, field_order_cnt_list_,
+ sizeof pic_param.FieldOrderCntList);
+ FROM_PPS_TO_PP(pic_init_qs_minus26);
+ FROM_PPS_TO_PP(chroma_qp_index_offset);
+ FROM_PPS_TO_PP(second_chroma_qp_index_offset);
+ pic_param.ContinuationFlag = 1;
+ FROM_PPS_TO_PP(pic_init_qp_minus26);
+ FROM_PPS_TO_PP2(num_ref_idx_l0_active_minus1,
+ num_ref_idx_l0_default_active_minus1);
+ FROM_PPS_TO_PP2(num_ref_idx_l1_active_minus1,
+ num_ref_idx_l1_default_active_minus1);
+ // UNUSED: Reserved8BitsA
+ memcpy(pic_param.FrameNumList, frame_num_list_,
+ sizeof pic_param.FrameNumList);
+ pic_param.UsedForReferenceFlags = used_for_reference_flags_;
+ pic_param.NonExistingFrameFlags = non_existing_frame_flags_;
+ pic_param.frame_num = pic->frame_num;
+ FROM_SPS_TO_PP(log2_max_frame_num_minus4);
+ FROM_SPS_TO_PP(pic_order_cnt_type);
+ FROM_SPS_TO_PP(log2_max_pic_order_cnt_lsb_minus4);
+ FROM_SPS_TO_PP(delta_pic_order_always_zero_flag);
+ FROM_SPS_TO_PP(direct_8x8_inference_flag);
+ FROM_PPS_TO_PP(entropy_coding_mode_flag);
+ FROM_PPS_TO_PP2(pic_order_present_flag,
+ bottom_field_pic_order_in_frame_present_flag);
+ FROM_PPS_TO_PP(num_slice_groups_minus1);
+ CHECK_EQ(0u, pic_param.num_slice_groups_minus1);
+ // UNUSED: slice_group_map_type
+ FROM_PPS_TO_PP(deblocking_filter_control_present_flag);
+ FROM_PPS_TO_PP(redundant_pic_cnt_present_flag);
+ // UNUSED: Reserved8BitsB
+ // UNUSED: slice_group_change_rate
+ //
+ //
+ //
+
+ pic_param.StatusReportFeedbackNumber = 1;
+
+ UINT buffer_size;
+ void* buffer;
+ HRESULT hr = video_context_->GetDecoderBuffer(
+ video_decoder_.get(), D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS,
+ &buffer_size, &buffer);
+ CHECK(SUCCEEDED(hr));
+
+ memcpy(buffer, &pic_param, sizeof(pic_param));
+ hr = video_context_->ReleaseDecoderBuffer(
+ video_decoder_.get(), D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS);
+ CHECK(SUCCEEDED(hr));
+
+ DXVA_Qmatrix_H264 iq_matrix_buf = {};
+
+ if (pps->pic_scaling_matrix_present_flag) {
+ for (int i = 0; i < 6; ++i) {
+ for (int j = 0; j < 16; ++j)
+ iq_matrix_buf.bScalingLists4x4[i][j] = pps->scaling_list4x4[i][j];
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 64; ++j)
+ iq_matrix_buf.bScalingLists8x8[i][j] = pps->scaling_list8x8[i][j];
+ }
+ } else {
+ for (int i = 0; i < 6; ++i) {
+ for (int j = 0; j < 16; ++j)
+ iq_matrix_buf.bScalingLists4x4[i][j] = sps_.scaling_list4x4[i][j];
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 64; ++j)
+ iq_matrix_buf.bScalingLists8x8[i][j] = sps_.scaling_list8x8[i][j];
+ }
+ }
+ hr = video_context_->GetDecoderBuffer(
+ video_decoder_.get(),
+ D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX, &buffer_size,
+ &buffer);
+ CHECK(SUCCEEDED(hr));
+ memcpy(buffer, &iq_matrix_buf, sizeof(iq_matrix_buf));
+ hr = video_context_->ReleaseDecoderBuffer(
+ video_decoder_.get(),
+ D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX);
+
+ // Ideally all slices in a frame are put in the same bitstream buffer.
+ // However the bitstream buffer may not fit all the data, so split on the
+ // necessary boundaries.
+
+ size_t out_bitstream_size = size + 3;
+
+ size_t remaining_bitstream = out_bitstream_size;
+ size_t start_location = 0;
+
+ while (remaining_bitstream > 0) {
+ if (bitstream_buffer_size_ < remaining_bitstream &&
+ slice_info_.size() > 0) {
+ SubmitSliceData();
+ RetrieveBitstreamBuffer();
+ }
+
+ size_t bytes_to_copy = remaining_bitstream;
+ bool contains_end = true;
+ if (bytes_to_copy > bitstream_buffer_size_) {
+ bytes_to_copy = bitstream_buffer_size_;
+ contains_end = false;
+ }
+ size_t real_bytes_to_copy = bytes_to_copy;
+ // TODO(jbauman): fix hack
+ uint8_t* out_start = bitstream_buffer_bytes_;
+ if (bytes_to_copy >= 3 && start_location == 0) {
+ *(out_start++) = 0;
+ *(out_start++) = 0;
+ *(out_start++) = 1;
+ real_bytes_to_copy -= 3;
+ }
+ memcpy(out_start, data + start_location, real_bytes_to_copy);
+
+ DXVA_Slice_H264_Short slice_info = {};
+ slice_info.BSNALunitDataLocation = (UINT)current_offset_;
+ slice_info.SliceBytesInBuffer = (UINT)bytes_to_copy;
+ if (contains_end && start_location == 0)
+ slice_info.wBadSliceChopping = 0;
+ else if (!contains_end && start_location == 0)
+ slice_info.wBadSliceChopping = 1;
+ else if (contains_end && start_location != 0)
+ slice_info.wBadSliceChopping = 2;
+ else
+ slice_info.wBadSliceChopping = 3;
+
+ slice_info_.push_back(slice_info);
+ bitstream_buffer_size_ -= bytes_to_copy;
+ current_offset_ += bytes_to_copy;
+ start_location += bytes_to_copy;
+ remaining_bitstream -= bytes_to_copy;
+ bitstream_buffer_bytes_ += bytes_to_copy;
+ }
+
+ return true;
+}
+
+void D3D11H264Accelerator::SubmitSliceData() {
+ CHECK(slice_info_.size() > 0);
+ UINT buffer_size;
+ void* buffer;
+ HRESULT hr = video_context_->GetDecoderBuffer(
+ video_decoder_.get(), D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL,
+ &buffer_size, &buffer);
+ CHECK(SUCCEEDED(hr));
+ CHECK_LE(sizeof(slice_info_[0]) * slice_info_.size(), buffer_size);
+ memcpy(buffer, &slice_info_[0], sizeof(slice_info_[0]) * slice_info_.size());
+ hr = video_context_->ReleaseDecoderBuffer(
+ video_decoder_.get(), D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL);
+
+ hr = video_context_->ReleaseDecoderBuffer(
+ video_decoder_.get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM);
+ D3D11_VIDEO_DECODER_BUFFER_DESC buffers[4] = {};
+ buffers[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
+ buffers[0].DataOffset = 0;
+ buffers[0].DataSize = sizeof(DXVA_PicParams_H264);
+ buffers[1].BufferType =
+ D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
+ buffers[1].DataOffset = 0;
+ buffers[1].DataSize = sizeof(DXVA_Qmatrix_H264);
+ buffers[2].BufferType = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL;
+ buffers[2].DataOffset = 0;
+ buffers[2].DataSize = (UINT)(sizeof(slice_info_[0]) * slice_info_.size());
+ buffers[3].BufferType = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM;
+ buffers[3].DataOffset = 0;
+ buffers[3].DataSize = (UINT)current_offset_;
+
+ hr = video_context_->SubmitDecoderBuffers(video_decoder_.get(), 4, buffers);
+ current_offset_ = 0;
+ slice_info_.clear();
+}
+
+bool D3D11H264Accelerator::SubmitDecode(const scoped_refptr<H264Picture>& pic) {
+ SubmitSliceData();
+
+ HRESULT hr = video_context_->DecoderEndFrame(video_decoder_.get());
+ CHECK(SUCCEEDED(hr));
+
+ return true;
+}
+
+bool D3D11H264Accelerator::OutputPicture(
+ const scoped_refptr<H264Picture>& pic) {
+ scoped_refptr<D3D11H264Picture> our_pic(
+ static_cast<D3D11H264Picture*>(pic.get()));
+ client_->OutputResult(our_pic->picture, our_pic->input_buffer_id_);
+ return true;
+}
+
+D3D11H264Picture::~D3D11H264Picture() {
+ picture->set_in_picture_use(false);
+}
+
+} // namespace media
« no previous file with comments | « media/gpu/d3d11_h264_accelerator.h ('k') | media/gpu/d3d11_video_decode_accelerator_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698