Commit 0a7b7fae authored by Dale Curtis's avatar Dale Curtis Committed by Chromium LUCI CQ

Implement support for AV1 decoding through D3D11VideoDecoder.

This implements AV1 hardware decoding according to the DXVA2 spec:
https://www.microsoft.com/en-us/download/details.aspx?id=101577

Bug: 1115846
Test: Manual check of many streams. Passes all AV1 CQ tests.

Change-Id: Ic920484af92fa56fd0422f8d989692be7118cfb4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2495791
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Reviewed-by: default avatarJames Zern <jzern@google.com>
Cr-Commit-Position: refs/heads/master@{#835535}
parent 80845646
...@@ -170,6 +170,8 @@ component("gpu") { ...@@ -170,6 +170,8 @@ component("gpu") {
if (is_win) { if (is_win) {
sources += [ sources += [
"windows/av1_guids.h", "windows/av1_guids.h",
"windows/d3d11_av1_accelerator.cc",
"windows/d3d11_av1_accelerator.h",
"windows/d3d11_com_defs.h", "windows/d3d11_com_defs.h",
"windows/d3d11_copying_texture_wrapper.cc", "windows/d3d11_copying_texture_wrapper.cc",
"windows/d3d11_copying_texture_wrapper.h", "windows/d3d11_copying_texture_wrapper.h",
...@@ -309,7 +311,7 @@ source_set("common") { ...@@ -309,7 +311,7 @@ source_set("common") {
"//ui/gfx/geometry", "//ui/gfx/geometry",
] ]
if (is_ash && use_vaapi) { if ((is_ash && use_vaapi) || is_win) {
assert(use_libgav1_parser) assert(use_libgav1_parser)
sources += [ sources += [
"av1_decoder.cc", "av1_decoder.cc",
...@@ -537,7 +539,7 @@ source_set("unit_tests") { ...@@ -537,7 +539,7 @@ source_set("unit_tests") {
sources += [ "vp8_decoder_unittest.cc" ] sources += [ "vp8_decoder_unittest.cc" ]
} }
if (is_ash && use_vaapi) { if ((is_ash && use_vaapi) || is_win) {
sources += [ "av1_decoder_unittest.cc" ] sources += [ "av1_decoder_unittest.cc" ]
deps += [ "//third_party/ffmpeg" ] deps += [ "//third_party/ffmpeg" ]
} }
......
...@@ -76,7 +76,8 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) { ...@@ -76,7 +76,8 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) {
} // namespace } // namespace
AV1Decoder::AV1Decoder(std::unique_ptr<AV1Accelerator> accelerator, AV1Decoder::AV1Decoder(std::unique_ptr<AV1Accelerator> accelerator,
VideoCodecProfile profile) VideoCodecProfile profile,
const VideoColorSpace& container_color_space)
: buffer_pool_(std::make_unique<libgav1::BufferPool>( : buffer_pool_(std::make_unique<libgav1::BufferPool>(
/*on_frame_buffer_size_changed=*/nullptr, /*on_frame_buffer_size_changed=*/nullptr,
/*get_frame_buffer=*/nullptr, /*get_frame_buffer=*/nullptr,
...@@ -84,7 +85,8 @@ AV1Decoder::AV1Decoder(std::unique_ptr<AV1Accelerator> accelerator, ...@@ -84,7 +85,8 @@ AV1Decoder::AV1Decoder(std::unique_ptr<AV1Accelerator> accelerator,
/*callback_private_data=*/nullptr)), /*callback_private_data=*/nullptr)),
state_(std::make_unique<libgav1::DecoderState>()), state_(std::make_unique<libgav1::DecoderState>()),
accelerator_(std::move(accelerator)), accelerator_(std::move(accelerator)),
profile_(profile) { profile_(profile),
container_color_space_(container_color_space) {
ref_frames_.fill(nullptr); ref_frames_.fill(nullptr);
} }
...@@ -364,8 +366,21 @@ AcceleratedVideoDecoder::DecodeResult AV1Decoder::DecodeInternal() { ...@@ -364,8 +366,21 @@ AcceleratedVideoDecoder::DecodeResult AV1Decoder::DecodeInternal() {
pic->set_visible_rect(current_visible_rect); pic->set_visible_rect(current_visible_rect);
pic->set_bitstream_id(stream_id_); pic->set_bitstream_id(stream_id_);
// For AV1, prefer the frame color space over the config.
const auto& cc = current_sequence_header_->color_config;
const auto cs = VideoColorSpace(
cc.color_primary, cc.transfer_characteristics, cc.matrix_coefficients,
cc.color_range == libgav1::kColorRangeStudio
? gfx::ColorSpace::RangeID::LIMITED
: gfx::ColorSpace::RangeID::FULL);
if (cs.IsSpecified())
pic->set_colorspace(cs);
else if (container_color_space_.IsSpecified())
pic->set_colorspace(container_color_space_);
pic->frame_header = frame_header; pic->frame_header = frame_header;
// TODO(hiroh): Set color space and decrypt config. // TODO(hiroh): Set decrypt config.
if (!DecodeAndOutputPicture(std::move(pic), parser_->tile_buffers())) if (!DecodeAndOutputPicture(std::move(pic), parser_->tile_buffers()))
return kDecodeError; return kDecodeError;
} }
......
...@@ -93,7 +93,8 @@ class MEDIA_GPU_EXPORT AV1Decoder : public AcceleratedVideoDecoder { ...@@ -93,7 +93,8 @@ class MEDIA_GPU_EXPORT AV1Decoder : public AcceleratedVideoDecoder {
}; };
AV1Decoder(std::unique_ptr<AV1Accelerator> accelerator, AV1Decoder(std::unique_ptr<AV1Accelerator> accelerator,
VideoCodecProfile profile); VideoCodecProfile profile,
const VideoColorSpace& container_color_space = VideoColorSpace());
~AV1Decoder() override; ~AV1Decoder() override;
AV1Decoder(const AV1Decoder&) = delete; AV1Decoder(const AV1Decoder&) = delete;
AV1Decoder& operator=(const AV1Decoder&) = delete; AV1Decoder& operator=(const AV1Decoder&) = delete;
...@@ -138,6 +139,7 @@ class MEDIA_GPU_EXPORT AV1Decoder : public AcceleratedVideoDecoder { ...@@ -138,6 +139,7 @@ class MEDIA_GPU_EXPORT AV1Decoder : public AcceleratedVideoDecoder {
gfx::Rect visible_rect_; gfx::Rect visible_rect_;
gfx::Size frame_size_; gfx::Size frame_size_;
VideoCodecProfile profile_; VideoCodecProfile profile_;
VideoColorSpace container_color_space_;
uint8_t bit_depth_ = 0; uint8_t bit_depth_ = 0;
int32_t stream_id_ = 0; int32_t stream_id_ = 0;
......
// Copyright 2020 The Chromium Authors. All rights reserved. // Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "media/gpu/av1_decoder.h" #include "media/gpu/av1_decoder.h"
#include <string.h> #include <string.h>
...@@ -25,11 +26,6 @@ ...@@ -25,11 +26,6 @@
#include "third_party/libgav1/src/src/utils/constants.h" #include "third_party/libgav1/src/src/utils/constants.h"
#include "third_party/libgav1/src/src/utils/types.h" #include "third_party/libgav1/src/src/utils/types.h"
#if !BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
#error "This test requires Chrome OS media acceleration"
#endif
#include "media/gpu/chromeos/fourcc.h"
using ::testing::_; using ::testing::_;
using ::testing::Return; using ::testing::Return;
...@@ -139,8 +135,8 @@ class AV1DecoderTest : public ::testing::Test { ...@@ -139,8 +135,8 @@ class AV1DecoderTest : public ::testing::Test {
protected: protected:
base::FilePath GetTestFilePath(const std::string& fname) { base::FilePath GetTestFilePath(const std::string& fname) {
base::FilePath file_path(base::FilePath(base::FilePath::kCurrentDirectory) base::FilePath file_path(
.Append(base::FilePath::StringType(fname))); base::FilePath(base::FilePath::kCurrentDirectory).AppendASCII(fname));
if (base::PathExists(file_path)) { if (base::PathExists(file_path)) {
return file_path; return file_path;
} }
...@@ -198,7 +194,7 @@ std::vector<scoped_refptr<DecoderBuffer>> AV1DecoderTest::ReadIVF( ...@@ -198,7 +194,7 @@ std::vector<scoped_refptr<DecoderBuffer>> AV1DecoderTest::ReadIVF(
EXPECT_TRUE( EXPECT_TRUE(
ivf_parser.Initialize(reinterpret_cast<const uint8_t*>(ivf_data.data()), ivf_parser.Initialize(reinterpret_cast<const uint8_t*>(ivf_data.data()),
ivf_data.size(), &ivf_header)); ivf_data.size(), &ivf_header));
EXPECT_EQ(ivf_header.fourcc, ComposeFourcc('A', 'V', '0', '1')); EXPECT_EQ(ivf_header.fourcc, /*AV01=*/0x31305641u);
std::vector<scoped_refptr<DecoderBuffer>> buffers; std::vector<scoped_refptr<DecoderBuffer>> buffers;
IvfFrameHeader ivf_frame_header{}; IvfFrameHeader ivf_frame_header{};
......
This diff is collapsed.
// Copyright 2020 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.
#ifndef MEDIA_GPU_WINDOWS_D3D11_AV1_ACCELERATOR_H_
#define MEDIA_GPU_WINDOWS_D3D11_AV1_ACCELERATOR_H_
#include <d3d11_1.h>
#include <d3d9.h>
#include <dxva.h>
#include <windows.h>
#include <wrl/client.h>
#include "base/callback_helpers.h"
#include "media/base/media_log.h"
#include "media/gpu/av1_decoder.h"
#include "media/gpu/windows/d3d11_com_defs.h"
#include "media/gpu/windows/d3d11_video_context_wrapper.h"
#include "media/gpu/windows/d3d11_video_decoder_client.h"
typedef struct _DXVA_PicParams_AV1 DXVA_PicParams_AV1;
typedef struct _DXVA_Tile_AV1 DXVA_Tile_AV1;
namespace media {
class D3D11AV1Accelerator : public AV1Decoder::AV1Accelerator {
public:
D3D11AV1Accelerator(D3D11VideoDecoderClient* client,
MediaLog* media_log,
ComD3D11VideoDevice video_device,
std::unique_ptr<VideoContextWrapper> video_context);
~D3D11AV1Accelerator() override;
scoped_refptr<AV1Picture> CreateAV1Picture(bool apply_grain) override;
bool SubmitDecode(const AV1Picture& pic,
const libgav1::ObuSequenceHeader& seq_header,
const AV1ReferenceFrameVector& ref_frames,
const libgav1::Vector<libgav1::TileBuffer>& tile_buffers,
base::span<const uint8_t> data) override;
bool OutputPicture(const AV1Picture& pic) override;
private:
class ScopedDecoderBuffer;
ScopedDecoderBuffer GetBuffer(D3D11_VIDEO_DECODER_BUFFER_TYPE type);
bool SubmitDecoderBuffer(
const DXVA_PicParams_AV1& pic_params,
const libgav1::Vector<libgav1::TileBuffer>& tile_buffers);
void RecordFailure(const std::string& fail_type, const std::string& reason);
void SetVideoDecoder(ComD3D11VideoDecoder video_decoder);
void FillPicParams(size_t picture_index,
bool apply_grain,
const libgav1::ObuFrameHeader& frame_header,
const libgav1::ObuSequenceHeader& seq_header,
const AV1ReferenceFrameVector& ref_frames,
DXVA_PicParams_AV1* pp);
D3D11VideoDecoderClient* client_;
std::unique_ptr<MediaLog> media_log_;
ComD3D11VideoDecoder video_decoder_;
ComD3D11VideoDevice video_device_;
std::unique_ptr<VideoContextWrapper> video_context_;
DISALLOW_COPY_AND_ASSIGN(D3D11AV1Accelerator);
};
} // namespace media
#endif // MEDIA_GPU_WINDOWS_D3D11_AV1_ACCELERATOR_H_
...@@ -5,12 +5,15 @@ ...@@ -5,12 +5,15 @@
#include "media/gpu/windows/d3d11_decoder_configurator.h" #include "media/gpu/windows/d3d11_decoder_configurator.h"
#include <d3d11.h> #include <d3d11.h>
#include <d3d9.h>
#include <dxva2api.h>
#include "base/feature_list.h" #include "base/feature_list.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/status_codes.h" #include "media/base/status_codes.h"
#include "media/base/win/hresult_status_helper.h" #include "media/base/win/hresult_status_helper.h"
#include "media/gpu/windows/av1_guids.h"
#include "media/gpu/windows/d3d11_copying_texture_wrapper.h" #include "media/gpu/windows/d3d11_copying_texture_wrapper.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/gl/direct_composition_surface_win.h" #include "ui/gl/direct_composition_surface_win.h"
...@@ -37,25 +40,36 @@ std::unique_ptr<D3D11DecoderConfigurator> D3D11DecoderConfigurator::Create( ...@@ -37,25 +40,36 @@ std::unique_ptr<D3D11DecoderConfigurator> D3D11DecoderConfigurator::Create(
bool supports_nv12_decode_swap_chain = bool supports_nv12_decode_swap_chain =
gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported(); gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported();
DXGI_FORMAT decoder_dxgi_format = DXGI_FORMAT_NV12; // Note: All profiles of AV1 can contain 8 or 10 bit content. The professional
// profile may contain up to 12-bits. Eventually we will need a way to defer
// the output format selection until we've parsed the bitstream.
DXGI_FORMAT decoder_dxgi_format =
config.color_space_info().ToGfxColorSpace().IsHDR() ? DXGI_FORMAT_P010
: DXGI_FORMAT_NV12;
GUID decoder_guid = {}; GUID decoder_guid = {};
if (config.codec() == kCodecH264) { if (config.codec() == kCodecH264) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using h264 / NV12";
decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT; decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT;
} else if (config.profile() == VP9PROFILE_PROFILE0) { } else if (config.profile() == VP9PROFILE_PROFILE0) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using vp9p0 / NV12";
decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0; decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
} else if (config.profile() == VP9PROFILE_PROFILE2) { } else if (config.profile() == VP9PROFILE_PROFILE2) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using vp9p2 / P010"; decoder_dxgi_format = DXGI_FORMAT_P010; // Profile2 is always 10-bit.
decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2; decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
decoder_dxgi_format = DXGI_FORMAT_P010; } else if (config.profile() == AV1PROFILE_PROFILE_MAIN) {
decoder_guid = DXVA_ModeAV1_VLD_Profile0;
} else if (config.profile() == AV1PROFILE_PROFILE_HIGH) {
decoder_guid = DXVA_ModeAV1_VLD_Profile1;
} else if (config.profile() == AV1PROFILE_PROFILE_PRO) {
decoder_guid = DXVA_ModeAV1_VLD_Profile2;
} else { } else {
// TODO(tmathmeyer) support other profiles in the future.
MEDIA_LOG(INFO, media_log) MEDIA_LOG(INFO, media_log)
<< "D3D11VideoDecoder does not support codec " << config.codec(); << "D3D11VideoDecoder does not support codec " << config.codec();
return nullptr; return nullptr;
} }
MEDIA_LOG(INFO, media_log)
<< "D3D11VideoDecoder is using " << GetProfileName(config.profile())
<< " / " << (decoder_dxgi_format == DXGI_FORMAT_NV12 ? "NV12" : "P010");
return std::make_unique<D3D11DecoderConfigurator>( return std::make_unique<D3D11DecoderConfigurator>(
decoder_dxgi_format, decoder_guid, config.coded_size(), decoder_dxgi_format, decoder_guid, config.coded_size(),
config.is_encrypted(), supports_nv12_decode_swap_chain); config.is_encrypted(), supports_nv12_decode_swap_chain);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "media/base/video_util.h" #include "media/base/video_util.h"
#include "media/base/win/hresult_status_helper.h" #include "media/base/win/hresult_status_helper.h"
#include "media/gpu/windows/d3d11_av1_accelerator.h"
#include "media/gpu/windows/d3d11_picture_buffer.h" #include "media/gpu/windows/d3d11_picture_buffer.h"
#include "media/gpu/windows/d3d11_video_context_wrapper.h" #include "media/gpu/windows/d3d11_video_context_wrapper.h"
#include "media/gpu/windows/d3d11_video_decoder_impl.h" #include "media/gpu/windows/d3d11_video_decoder_impl.h"
...@@ -176,6 +177,11 @@ HRESULT D3D11VideoDecoder::InitializeAcceleratedDecoder( ...@@ -176,6 +177,11 @@ HRESULT D3D11VideoDecoder::InitializeAcceleratedDecoder(
std::make_unique<D3D11H264Accelerator>( std::make_unique<D3D11H264Accelerator>(
this, media_log_.get(), video_device_, std::move(video_context)), this, media_log_.get(), video_device_, std::move(video_context)),
profile_, config.color_space_info()); profile_, config.color_space_info());
} else if (config.codec() == kCodecAV1) {
accelerated_video_decoder_ = std::make_unique<AV1Decoder>(
std::make_unique<D3D11AV1Accelerator>(
this, media_log_.get(), video_device_, std::move(video_context)),
profile_, config.color_space_info());
} else { } else {
return E_FAIL; return E_FAIL;
} }
...@@ -241,8 +247,9 @@ D3D11VideoDecoder::CreateD3D11Decoder() { ...@@ -241,8 +247,9 @@ D3D11VideoDecoder::CreateD3D11Decoder() {
.AddCause(HresultToStatus(hr)); .AddCause(HresultToStatus(hr));
} }
if (config_.codec() == kCodecVP9 && dec_config.ConfigBitstreamRaw == 1) { if ((config_.codec() == kCodecVP9 || config_.codec() == kCodecAV1) &&
// DXVA VP9 specification mentions ConfigBitstreamRaw "shall be 1". dec_config.ConfigBitstreamRaw == 1) {
// DXVA VP9 and AV1 specifications say ConfigBitstreamRaw "shall be 1".
found = true; found = true;
break; break;
} }
...@@ -775,6 +782,13 @@ D3D11PictureBuffer* D3D11VideoDecoder::GetPicture() { ...@@ -775,6 +782,13 @@ D3D11PictureBuffer* D3D11VideoDecoder::GetPicture() {
return nullptr; return nullptr;
} }
void D3D11VideoDecoder::UpdateTimestamp(D3D11PictureBuffer* picture_buffer) {
// A picture is being reused with a different timestamp; since we've already
// generated a VideoFrame from the previous picture buffer, we can just stamp
// the new timestamp directly onto the buffer.
picture_buffer->timestamp_ = current_timestamp_;
}
bool D3D11VideoDecoder::OutputResult(const CodecPicture* picture, bool D3D11VideoDecoder::OutputResult(const CodecPicture* picture,
D3D11PictureBuffer* picture_buffer) { D3D11PictureBuffer* picture_buffer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -950,11 +964,9 @@ D3D11VideoDecoder::GetSupportedVideoDecoderConfigs( ...@@ -950,11 +964,9 @@ D3D11VideoDecoder::GetSupportedVideoDecoderConfigs(
continue; continue;
} }
// TODO(liberato): Add VP8 and AV1 support to D3D11VideoDecoder. // TODO(liberato): Add VP8 support to D3D11VideoDecoder.
if (profile == VP8PROFILE_ANY || if (profile == VP8PROFILE_ANY)
(profile >= AV1PROFILE_MIN && profile <= AV1PROFILE_MAX)) {
continue; continue;
}
const auto& resolution_range = kv.second; const auto& resolution_range = kv.second;
configs.emplace_back(profile, profile, resolution_range.min_resolution, configs.emplace_back(profile, profile, resolution_range.min_resolution,
......
...@@ -82,6 +82,7 @@ class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder, ...@@ -82,6 +82,7 @@ class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder,
// D3D11VideoDecoderClient implementation. // D3D11VideoDecoderClient implementation.
D3D11PictureBuffer* GetPicture() override; D3D11PictureBuffer* GetPicture() override;
void UpdateTimestamp(D3D11PictureBuffer* picture_buffer) override;
bool OutputResult(const CodecPicture* picture, bool OutputResult(const CodecPicture* picture,
D3D11PictureBuffer* picture_buffer) override; D3D11PictureBuffer* picture_buffer) override;
void SetDecoderCB(const SetAcceleratorDecoderCB&) override; void SetDecoderCB(const SetAcceleratorDecoderCB&) override;
......
...@@ -22,6 +22,7 @@ class D3D11VideoDecoderClient { ...@@ -22,6 +22,7 @@ class D3D11VideoDecoderClient {
base::RepeatingCallback<void(ComD3D11VideoDecoder)>; base::RepeatingCallback<void(ComD3D11VideoDecoder)>;
virtual D3D11PictureBuffer* GetPicture() = 0; virtual D3D11PictureBuffer* GetPicture() = 0;
virtual void UpdateTimestamp(D3D11PictureBuffer* picture_buffer) = 0;
virtual bool OutputResult(const CodecPicture* picture, virtual bool OutputResult(const CodecPicture* picture,
D3D11PictureBuffer* picture_buffer) = 0; D3D11PictureBuffer* picture_buffer) = 0;
......
...@@ -9,5 +9,6 @@ declare_args() { ...@@ -9,5 +9,6 @@ declare_args() {
# Enable libgav1 decoder. # Enable libgav1 decoder.
enable_libgav1_decoder = enable_libgav1_decoder =
is_ash && (target_cpu == "arm" || target_cpu == "arm64") is_ash && (target_cpu == "arm" || target_cpu == "arm64")
use_libgav1_parser = is_ash && (target_cpu == "x86" || target_cpu == "x64") use_libgav1_parser =
(is_ash || is_win) && (target_cpu == "x86" || target_cpu == "x64")
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment