blob: e0631d877ec8530720aeef8cd87a76f8bcb9e110 [file] [log] [blame]
// 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/windows/d3d11_h264_accelerator.h"
#include <windows.h>
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
#include "media/base/media_log.h"
#include "media/base/win/mf_helpers.h"
#include "media/gpu/h264_decoder.h"
#include "media/gpu/h264_dpb.h"
#include "media/gpu/windows/d3d11_picture_buffer.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_image_dxgi.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/scoped_binders.h"
namespace media {
using DecoderStatus = H264Decoder::H264Accelerator::Status;
namespace {
// Converts SubsampleEntry to D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK.
void AppendSubsamples(
const std::vector<SubsampleEntry>& from,
std::vector<D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK>* to) {
for (const auto& from_entry : from) {
D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK subsample = {};
subsample.ClearSize = from_entry.clear_bytes;
subsample.EncryptedSize = from_entry.cypher_bytes;
to->push_back(subsample);
}
}
} // namespace
class D3D11H264Picture : public H264Picture {
public:
D3D11H264Picture(D3D11PictureBuffer* picture)
: picture(picture), picture_index_(picture->picture_index()) {
picture->set_in_picture_use(true);
}
D3D11PictureBuffer* picture;
size_t picture_index_;
D3D11H264Picture* AsD3D11H264Picture() override { return this; }
protected:
~D3D11H264Picture() override;
};
D3D11H264Picture::~D3D11H264Picture() {
picture->set_in_picture_use(false);
}
D3D11H264Accelerator::D3D11H264Accelerator(
D3D11VideoDecoderClient* client,
MediaLog* media_log,
ComD3D11VideoDevice video_device,
std::unique_ptr<VideoContextWrapper> video_context)
: client_(client),
media_log_(media_log),
video_device_(video_device),
video_context_(std::move(video_context)) {
DCHECK(client);
DCHECK(media_log_);
client->SetDecoderCB(base::BindRepeating(
&D3D11H264Accelerator::SetVideoDecoder, base::Unretained(this)));
}
D3D11H264Accelerator::~D3D11H264Accelerator() {}
scoped_refptr<H264Picture> D3D11H264Accelerator::CreateH264Picture() {
D3D11PictureBuffer* picture = client_->GetPicture();
if (!picture) {
return nullptr;
}
return base::MakeRefCounted<D3D11H264Picture>(picture);
}
DecoderStatus 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,
scoped_refptr<H264Picture> pic) {
const bool is_encrypted = pic->decrypt_config();
if (is_encrypted) {
RecordFailure("Cannot find decrypt context for the frame.",
StatusCode::kCryptoConfigFailed);
return DecoderStatus::kFail;
}
HRESULT hr;
for (;;) {
D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture();
if (!d3d11_pic)
return DecoderStatus::kFail;
ID3D11VideoDecoderOutputView* output_view = nullptr;
auto result = d3d11_pic->picture->AcquireOutputView();
if (result.has_value()) {
output_view = std::move(result).value();
} else {
RecordFailure(std::move(result).error());
return DecoderStatus::kFail;
}
hr = video_context_->DecoderBeginFrame(video_decoder_.Get(), output_view, 0,
nullptr);
if (hr == E_PENDING || hr == D3DERR_WASSTILLDRAWING) {
// Hardware is busy. We should make the call again.
// TODO(liberato): For now, just busy wait.
;
} else if (!SUCCEEDED(hr)) {
RecordFailure("DecoderBeginFrame failed",
StatusCode::kDecoderBeginFrameFailed, hr);
return DecoderStatus::kFail;
} else {
break;
}
}
sps_ = *sps;
for (size_t i = 0; i < media::kRefFrameMaxCount; 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;
// TODO(liberato): this is similar to H264Accelerator. can they share code?
int i = 0;
for (auto it = dpb.begin(); it != dpb.end(); i++, it++) {
// The DPB is supposed to have a maximum of 16 pictures in it, but there's
// nothing actually stopping it from having more. If we run into this case,
// something is clearly wrong, and we should just fail decoding rather than
// try to sort out which pictures really shouldn't be included.
if (i >= media::kRefFrameMaxCount)
return DecoderStatus::kFail;
D3D11H264Picture* our_ref_pic = it->get()->AsD3D11H264Picture();
// How does a non-d3d11 picture get here you might ask? The decoder
// inserts blank H264Picture objects that we can't use as part of filling
// gaps in frame numbers. If we see one, it's not a reference picture
// anyway, so skip it.
if (!our_ref_pic || !our_ref_pic->ref)
continue;
ref_frame_list_[i].Index7Bits = our_ref_pic->picture_index_;
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->frame_num;
unsigned ref = 3;
used_for_reference_flags_ |= ref << (2 * i);
non_existing_frame_flags_ |= (our_ref_pic->nonexisting) << i;
}
slice_info_.clear();
return RetrieveBitstreamBuffer() ? DecoderStatus::kOk : DecoderStatus::kFail;
}
bool D3D11H264Accelerator::RetrieveBitstreamBuffer() {
DCHECK(!bitstream_buffer_bytes_);
DCHECK(!bitstream_buffer_size_);
current_offset_ = 0;
void* buffer;
UINT buffer_size;
HRESULT hr = video_context_->GetDecoderBuffer(
video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &buffer_size,
&buffer);
if (!SUCCEEDED(hr)) {
RecordFailure("GetDecoderBuffer (Bitstream) failed",
StatusCode::kGetBitstreamBufferFailed, hr);
return false;
}
bitstream_buffer_bytes_ = (uint8_t*)buffer;
bitstream_buffer_size_ = buffer_size;
return true;
}
void D3D11H264Accelerator::FillPicParamsWithConstants(
DXVA_PicParams_H264* pic) {
// From "DirectX Video Acceleration Specification for H.264/AVC Decoding":
// "The value shall be 1 unless the restricted-mode profile in use
// explicitly supports the value 0."
pic->MbsConsecutiveFlag = 1;
// The latest DXVA decoding guide says to set this to 3 if the software
// decoder (this class) is following the guide.
pic->Reserved16Bits = 3;
// |ContinuationFlag| indicates that we've filled in the remaining fields.
pic->ContinuationFlag = 1;
// Must be zero unless bit 13 of ConfigDecoderSpecific is set.
pic->Reserved8BitsA = 0;
// Unused, should always be zero.
pic->Reserved8BitsB = 0;
// Should always be 1.
pic->StatusReportFeedbackNumber = 1;
// UNUSED: slice_group_map_type (undocumented)
// UNUSED: slice_group_change_rate (undocumented)
}
#define ARG_SEL(_1, _2, NAME, ...) NAME
#define SPS_TO_PP1(a) pic_param->a = sps->a;
#define SPS_TO_PP2(a, b) pic_param->a = sps->b;
#define SPS_TO_PP(...) ARG_SEL(__VA_ARGS__, SPS_TO_PP2, SPS_TO_PP1)(__VA_ARGS__)
void D3D11H264Accelerator::PicParamsFromSPS(DXVA_PicParams_H264* pic_param,
const H264SPS* sps,
bool field_pic) {
// The H.264 specification now calls this |max_num_ref_frames|, while
// DXVA_PicParams_H264 continues to use the old name, |num_ref_frames|.
// See DirectX Video Acceleration for H.264/MPEG-4 AVC Decoding (4.2).
SPS_TO_PP(num_ref_frames, max_num_ref_frames);
SPS_TO_PP(wFrameWidthInMbsMinus1, pic_width_in_mbs_minus1);
SPS_TO_PP(wFrameHeightInMbsMinus1, pic_height_in_map_units_minus1);
SPS_TO_PP(residual_colour_transform_flag, separate_colour_plane_flag);
SPS_TO_PP(chroma_format_idc);
SPS_TO_PP(frame_mbs_only_flag);
SPS_TO_PP(bit_depth_luma_minus8);
SPS_TO_PP(bit_depth_chroma_minus8);
SPS_TO_PP(log2_max_frame_num_minus4);
SPS_TO_PP(pic_order_cnt_type);
SPS_TO_PP(log2_max_pic_order_cnt_lsb_minus4);
SPS_TO_PP(delta_pic_order_always_zero_flag);
SPS_TO_PP(direct_8x8_inference_flag);
pic_param->MbaffFrameFlag = sps->mb_adaptive_frame_field_flag && field_pic;
pic_param->field_pic_flag = field_pic;
pic_param->MinLumaBipredSize8x8Flag = sps->level_idc >= 31;
}
#undef SPS_TO_PP
#undef SPS_TO_PP2
#undef SPS_TO_PP1
#define PPS_TO_PP1(a) pic_param->a = pps->a;
#define PPS_TO_PP2(a, b) pic_param->a = pps->b;
#define PPS_TO_PP(...) ARG_SEL(__VA_ARGS__, PPS_TO_PP2, PPS_TO_PP1)(__VA_ARGS__)
bool D3D11H264Accelerator::PicParamsFromPPS(DXVA_PicParams_H264* pic_param,
const H264PPS* pps) {
PPS_TO_PP(constrained_intra_pred_flag);
PPS_TO_PP(weighted_pred_flag);
PPS_TO_PP(weighted_bipred_idc);
PPS_TO_PP(transform_8x8_mode_flag);
PPS_TO_PP(pic_init_qs_minus26);
PPS_TO_PP(chroma_qp_index_offset);
PPS_TO_PP(second_chroma_qp_index_offset);
PPS_TO_PP(pic_init_qp_minus26);
PPS_TO_PP(num_ref_idx_l0_active_minus1, num_ref_idx_l0_default_active_minus1);
PPS_TO_PP(num_ref_idx_l1_active_minus1, num_ref_idx_l1_default_active_minus1);
PPS_TO_PP(entropy_coding_mode_flag);
PPS_TO_PP(pic_order_present_flag,
bottom_field_pic_order_in_frame_present_flag);
PPS_TO_PP(deblocking_filter_control_present_flag);
PPS_TO_PP(redundant_pic_cnt_present_flag);
PPS_TO_PP(num_slice_groups_minus1);
if (pic_param->num_slice_groups_minus1) {
// TODO(liberato): UMA?
// TODO(liberato): media log?
LOG(ERROR) << "num_slice_groups_minus1 == "
<< pic_param->num_slice_groups_minus1;
return false;
}
return true;
}
#undef PPS_TO_PP
#undef PPS_TO_PP2
#undef PPS_TO_PP1
#undef ARG_SEL
void D3D11H264Accelerator::PicParamsFromSliceHeader(
DXVA_PicParams_H264* pic_param,
const H264SliceHeader* slice_hdr) {
pic_param->sp_for_switch_flag = slice_hdr->sp_for_switch_flag;
pic_param->field_pic_flag = slice_hdr->field_pic_flag;
pic_param->CurrPic.AssociatedFlag = slice_hdr->bottom_field_flag;
pic_param->IntraPicFlag = slice_hdr->IsISlice();
}
void D3D11H264Accelerator::PicParamsFromPic(DXVA_PicParams_H264* pic_param,
D3D11H264Picture* pic) {
pic_param->CurrPic.Index7Bits = pic->picture_index_;
pic_param->RefPicFlag = pic->ref;
pic_param->frame_num = pic->frame_num;
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;
}
}
DecoderStatus D3D11H264Accelerator::SubmitSlice(
const H264PPS* pps,
const H264SliceHeader* slice_hdr,
const H264Picture::Vector& ref_pic_list0,
const H264Picture::Vector& ref_pic_list1,
scoped_refptr<H264Picture> pic,
const uint8_t* data,
size_t size,
const std::vector<SubsampleEntry>& subsamples) {
const bool is_encrypted = pic->decrypt_config();
DXVA_PicParams_H264 pic_param = {};
FillPicParamsWithConstants(&pic_param);
PicParamsFromSPS(&pic_param, &sps_, slice_hdr->field_pic_flag);
if (!PicParamsFromPPS(&pic_param, pps))
return DecoderStatus::kFail;
PicParamsFromSliceHeader(&pic_param, slice_hdr);
D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture();
if (!d3d11_pic)
return DecoderStatus::kFail;
PicParamsFromPic(&pic_param, d3d11_pic);
memcpy(pic_param.RefFrameList, ref_frame_list_,
sizeof pic_param.RefFrameList);
memcpy(pic_param.FieldOrderCntList, field_order_cnt_list_,
sizeof pic_param.FieldOrderCntList);
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_;
UINT buffer_size;
void* buffer;
HRESULT hr = video_context_->GetDecoderBuffer(
video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS,
&buffer_size, &buffer);
if (!SUCCEEDED(hr)) {
RecordFailure("GetDecoderBuffer (PictureParams) failed",
StatusCode::kGetPicParamBufferFailed, hr);
return DecoderStatus::kFail;
}
memcpy(buffer, &pic_param, sizeof(pic_param));
hr = video_context_->ReleaseDecoderBuffer(
video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS);
if (!SUCCEEDED(hr)) {
RecordFailure("ReleaseDecoderBuffer (PictureParams) failed",
StatusCode::kReleasePicParamBufferFailed, hr);
return DecoderStatus::kFail;
}
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);
if (!SUCCEEDED(hr)) {
RecordFailure("GetDecoderBuffer (QuantMatrix) failed",
StatusCode::kGetQuantBufferFailed, hr);
return DecoderStatus::kFail;
}
memcpy(buffer, &iq_matrix_buf, sizeof(iq_matrix_buf));
hr = video_context_->ReleaseDecoderBuffer(
video_decoder_.Get(),
D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX);
if (!SUCCEEDED(hr)) {
RecordFailure("ReleaseDecoderBuffer (QuantMatrix) failed",
StatusCode::kReleaseQuantBufferFailed, hr);
return DecoderStatus::kFail;
}
// 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;
if (is_encrypted) {
// For now, the entire frame has to fit into the bitstream buffer. This way
// the subsample ClearSize adjustment below should work.
if (bitstream_buffer_size_ < remaining_bitstream) {
RecordFailure("Input slice NALU (" + std::to_string(remaining_bitstream) +
") too big to fit in the bistream buffer (" +
base::NumberToString(bitstream_buffer_size_) + ").",
StatusCode::kBitstreamBufferSliceTooBig);
return DecoderStatus::kFail;
}
AppendSubsamples(subsamples, &subsamples_);
if (!subsamples.empty()) {
// 3 added to clear bytes because a start code is prepended to the slice
// NALU.
// TODO(rkuroiwa): This should be done right after the start code is
// written to the buffer, but currently the start code is written in the
// loop (which is not the right place, there's only one slice NALU passed
// into this function) and it's not easy to identify where the subsample
// starts in the buffer.
subsamples_[subsamples_.size() - subsamples.size()].ClearSize += 3;
}
}
while (remaining_bitstream > 0) {
if (bitstream_buffer_size_ < remaining_bitstream &&
slice_info_.size() > 0) {
if (!SubmitSliceData())
return DecoderStatus::kFail;
if (!RetrieveBitstreamBuffer())
return DecoderStatus::kFail;
}
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 DecoderStatus::kOk;
}
bool D3D11H264Accelerator::SubmitSliceData() {
CHECK(slice_info_.size() > 0);
UINT buffer_size;
void* buffer;
// TODO(liberato): Should we release the other buffers on failure?
HRESULT hr = video_context_->GetDecoderBuffer(
video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL,
&buffer_size, &buffer);
if (!SUCCEEDED(hr)) {
RecordFailure("GetDecoderBuffer (SliceControl) failed",
StatusCode::kGetSliceControlBufferFailed, hr);
return false;
}
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);
if (!SUCCEEDED(hr)) {
RecordFailure("ReleaseDecoderBuffer (SliceControl) failed",
StatusCode::kReleaseSliceControlBufferFailed, hr);
return false;
}
hr = video_context_->ReleaseDecoderBuffer(
video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM);
if (!SUCCEEDED(hr)) {
RecordFailure("ReleaseDecoderBuffer (BitStream) failed",
StatusCode::kReleaseBitstreamBufferFailed, hr);
return false;
}
VideoContextWrapper::VideoBufferWrapper 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 = sizeof(slice_info_[0]) * slice_info_.size();
buffers[3].BufferType = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM;
buffers[3].DataOffset = 0;
buffers[3].DataSize = current_offset_;
if (!frame_iv_.empty()) {
buffers[3].pIV = frame_iv_.data();
buffers[3].IVSize = frame_iv_.size();
// Subsmaples matter iff there is IV, for decryption.
if (!subsamples_.empty()) {
buffers[3].pSubSampleMappingBlock = subsamples_.data();
buffers[3].SubSampleMappingCount = subsamples_.size();
}
}
hr = video_context_->SubmitDecoderBuffers(video_decoder_.Get(),
base::size(buffers), buffers);
current_offset_ = 0;
slice_info_.clear();
bitstream_buffer_bytes_ = nullptr;
bitstream_buffer_size_ = 0;
frame_iv_.clear();
subsamples_.clear();
if (!SUCCEEDED(hr)) {
RecordFailure("SubmitDecoderBuffers failed",
StatusCode::kSubmitDecoderBuffersFailed, hr);
return false;
}
return true;
}
DecoderStatus D3D11H264Accelerator::SubmitDecode(
scoped_refptr<H264Picture> pic) {
if (!SubmitSliceData())
return DecoderStatus::kFail;
HRESULT hr = video_context_->DecoderEndFrame(video_decoder_.Get());
if (!SUCCEEDED(hr)) {
RecordFailure("DecoderEndFrame failed", StatusCode::kDecoderEndFrameFailed,
hr);
return DecoderStatus::kFail;
}
return DecoderStatus::kOk;
}
void D3D11H264Accelerator::Reset() {
if (!bitstream_buffer_bytes_)
return;
HRESULT hr = video_context_->ReleaseDecoderBuffer(
video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM);
bitstream_buffer_bytes_ = nullptr;
bitstream_buffer_size_ = 0;
current_offset_ = 0;
CHECK(SUCCEEDED(hr));
}
bool D3D11H264Accelerator::OutputPicture(scoped_refptr<H264Picture> pic) {
D3D11H264Picture* our_pic = pic->AsD3D11H264Picture();
return our_pic && client_->OutputResult(our_pic, our_pic->picture);
}
void D3D11H264Accelerator::RecordFailure(const std::string& reason,
StatusCode code,
HRESULT hr) const {
std::string hr_string;
if (!SUCCEEDED(hr))
hr_string = ": " + logging::SystemErrorCodeToString(hr);
DLOG(ERROR) << reason << hr_string;
MEDIA_LOG(ERROR, media_log_) << hr_string << ": " << reason;
base::UmaHistogramSparse("Media.D3D11.H264Status", static_cast<int>(code));
}
void D3D11H264Accelerator::RecordFailure(media::Status error) const {
RecordFailure(error.message(), error.code());
}
void D3D11H264Accelerator::SetVideoDecoder(ComD3D11VideoDecoder video_decoder) {
video_decoder_ = std::move(video_decoder);
}
} // namespace media