Skip to content

Commit

Permalink
Add decoding support for HEVC range extension profile on Windows.
Browse files Browse the repository at this point in the history
This enables range extension support for 420/422/444 8-12 bits on Intel
platforms that support HW decoding of those HEVC profiles.

Bug: 1345568
Change-Id: I23fcab13056404b1ab4974605442504879826381
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3779371
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Jeffrey Kardatzke <jkardatzke@google.com>
Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com>
Cr-Commit-Position: refs/heads/main@{#1029606}
  • Loading branch information
taste1981 authored and Chromium LUCI CQ committed Jul 29, 2022
1 parent 7132e3a commit a790b3d
Show file tree
Hide file tree
Showing 38 changed files with 573 additions and 82 deletions.
15 changes: 15 additions & 0 deletions media/base/video_types.cc
Expand Up @@ -90,6 +90,21 @@ std::string VideoPixelFormatToString(VideoPixelFormat format) {
return "";
}

std::string VideoChromaSamplingToString(VideoChromaSampling chroma_sampling) {
switch (chroma_sampling) {
case VideoChromaSampling::kUnknown:
return "unknown chroma sampling";
case VideoChromaSampling::k400:
return "4:0:0";
case VideoChromaSampling::k420:
return "4:2:0";
case VideoChromaSampling::k444:
return "4:4:4";
case VideoChromaSampling::k422:
return "4:2:2";
}
}

std::ostream& operator<<(std::ostream& os, VideoPixelFormat format) {
os << VideoPixelFormatToString(format);
return os;
Expand Down
13 changes: 13 additions & 0 deletions media/base/video_types.h
Expand Up @@ -93,6 +93,19 @@ enum VideoPixelFormat {
PIXEL_FORMAT_YUV444AP10, // Must always be equal to largest entry logged.
};

// Chroma sampling formats
enum class VideoChromaSampling : uint8_t {
kUnknown = 0,
k420, // 4:2:0 chroma channel has 1/2 height/width of luma channel.
k422, // 4:2:2 chroma channel has same height & 1/2 width of luma channel.
k444, // 4:4:4 chroma channel has same height/width of luma channel.
k400, // 4:0:0 monochrome without chroma subsampling..
};

// Return the name of chroma sampling format as a string.
MEDIA_SHMEM_EXPORT std::string VideoChromaSamplingToString(
VideoChromaSampling chroma_sampling);

// Returns the name of a Format as a string.
MEDIA_SHMEM_EXPORT std::string VideoPixelFormatToString(
VideoPixelFormat format);
Expand Down
11 changes: 7 additions & 4 deletions media/gpu/accelerated_video_decoder.h
Expand Up @@ -10,6 +10,7 @@

#include "media/base/decoder_buffer.h"
#include "media/base/video_codecs.h"
#include "media/base/video_types.h"
#include "media/gpu/media_gpu_export.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
Expand Down Expand Up @@ -72,14 +73,16 @@ class MEDIA_GPU_EXPORT AcceleratedVideoDecoder {
// we need a new set of them, or when an error occurs.
[[nodiscard]] virtual DecodeResult Decode() = 0;

// Return dimensions/visible rectangle/profile/bit depth/required number of
// pictures that client should be ready to provide for the decoder to function
// properly (of which up to GetNumReferenceFrames() might be needed for
// internal decoding). To be used after Decode() returns kConfigChange.
// Return dimensions/visible rectangle/profile/bit depth/chroma sampling
// format/required number of pictures that client should be ready to provide
// for the decoder to function properly (of which up to
// GetNumReferenceFrames() might be needed for internal decoding). To be used
// after Decode() returns kConfigChange.
virtual gfx::Size GetPicSize() const = 0;
virtual gfx::Rect GetVisibleRect() const = 0;
virtual VideoCodecProfile GetProfile() const = 0;
virtual uint8_t GetBitDepth() const = 0;
virtual VideoChromaSampling GetChromaSampling() const = 0;
virtual size_t GetRequiredNumOfPictures() const = 0;
virtual size_t GetNumReferenceFrames() const = 0;

Expand Down
6 changes: 6 additions & 0 deletions media/gpu/av1_decoder.cc
Expand Up @@ -510,6 +510,12 @@ uint8_t AV1Decoder::GetBitDepth() const {
return bit_depth_;
}

VideoChromaSampling AV1Decoder::GetChromaSampling() const {
// AV1 decoder does not rely on chroma sampling format for creating or
// reconfiguring decoder, so return an unknown format.
return VideoChromaSampling::kUnknown;
}

size_t AV1Decoder::GetRequiredNumOfPictures() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
Expand Down
1 change: 1 addition & 0 deletions media/gpu/av1_decoder.h
Expand Up @@ -124,6 +124,7 @@ class MEDIA_GPU_EXPORT AV1Decoder : public AcceleratedVideoDecoder {
gfx::Rect GetVisibleRect() const override;
VideoCodecProfile GetProfile() const override;
uint8_t GetBitDepth() const override;
VideoChromaSampling GetChromaSampling() const override;
size_t GetRequiredNumOfPictures() const override;
size_t GetNumReferenceFrames() const override;

Expand Down
6 changes: 6 additions & 0 deletions media/gpu/h264_decoder.cc
Expand Up @@ -1668,6 +1668,12 @@ uint8_t H264Decoder::GetBitDepth() const {
return bit_depth_;
}

VideoChromaSampling H264Decoder::GetChromaSampling() const {
// H264 decoder does not rely on chroma sampling format for creating
// or reconfiguring decoder, so return an unknown format.
return VideoChromaSampling::kUnknown;
}

size_t H264Decoder::GetRequiredNumOfPictures() const {
constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
return GetNumReferenceFrames() + kPicsInPipeline;
Expand Down
1 change: 1 addition & 0 deletions media/gpu/h264_decoder.h
Expand Up @@ -191,6 +191,7 @@ class MEDIA_GPU_EXPORT H264Decoder : public AcceleratedVideoDecoder {
gfx::Rect GetVisibleRect() const override;
VideoCodecProfile GetProfile() const override;
uint8_t GetBitDepth() const override;
VideoChromaSampling GetChromaSampling() const override;
size_t GetRequiredNumOfPictures() const override;
size_t GetNumReferenceFrames() const override;

Expand Down
22 changes: 14 additions & 8 deletions media/gpu/h265_decoder.cc
Expand Up @@ -72,11 +72,6 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) {
return false;
}
}

bool IsYUV420Sequence(const H265SPS& sps) {
// Spec 6.2
return sps.chroma_format_idc == 1;
}
} // namespace

H265Decoder::H265Accelerator::H265Accelerator() = default;
Expand Down Expand Up @@ -392,6 +387,10 @@ uint8_t H265Decoder::GetBitDepth() const {
return bit_depth_;
}

VideoChromaSampling H265Decoder::GetChromaSampling() const {
return chroma_sampling_;
}

size_t H265Decoder::GetRequiredNumOfPictures() const {
constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
return GetNumReferenceFrames() + kPicsInPipeline;
Expand Down Expand Up @@ -422,7 +421,9 @@ bool H265Decoder::ProcessPPS(int pps_id, bool* need_new_buffers) {
DVLOG(2) << "New visible rect: " << new_visible_rect.ToString();
visible_rect_ = new_visible_rect;
}
if (!IsYUV420Sequence(*sps)) {

VideoChromaSampling new_chroma_sampling = sps->GetChromaSampling();
if (!accelerator_->IsChromaSamplingSupported(new_chroma_sampling)) {
DVLOG(1) << "Only YUV 4:2:0 is supported";
return false;
}
Expand All @@ -441,18 +442,23 @@ bool H265Decoder::ProcessPPS(int pps_id, bool* need_new_buffers) {
<< ", profile=" << GetProfileName(new_profile);
return false;
}

if (pic_size_ != new_pic_size || dpb_.max_num_pics() != sps->max_dpb_size ||
profile_ != new_profile || bit_depth_ != new_bit_depth) {
profile_ != new_profile || bit_depth_ != new_bit_depth ||
chroma_sampling_ != new_chroma_sampling) {
if (!Flush())
return false;
DVLOG(1) << "Codec profile: " << GetProfileName(new_profile)
<< ", level(x30): " << sps->profile_tier_level.general_level_idc
<< ", DPB size: " << sps->max_dpb_size
<< ", Picture size: " << new_pic_size.ToString()
<< ", bit_depth: " << base::strict_cast<int>(new_bit_depth);
<< ", bit_depth: " << base::strict_cast<int>(new_bit_depth)
<< ", chroma_sampling_format: "
<< VideoChromaSamplingToString(new_chroma_sampling);
profile_ = new_profile;
bit_depth_ = new_bit_depth;
pic_size_ = new_pic_size;
chroma_sampling_ = new_chroma_sampling;
dpb_.set_max_num_pics(sps->max_dpb_size);
if (need_new_buffers)
*need_new_buffers = true;
Expand Down
7 changes: 7 additions & 0 deletions media/gpu/h265_decoder.h
Expand Up @@ -150,6 +150,10 @@ class MEDIA_GPU_EXPORT H265Decoder final : public AcceleratedVideoDecoder {
// kNotSupported.
virtual Status SetStream(base::span<const uint8_t> stream,
const DecryptConfig* decrypt_config);

// Indicates whether the accelerator supports bitstreams with
// specific chroma subsampling format.
virtual bool IsChromaSamplingSupported(VideoChromaSampling format) = 0;
};

H265Decoder(std::unique_ptr<H265Accelerator> accelerator,
Expand All @@ -170,6 +174,7 @@ class MEDIA_GPU_EXPORT H265Decoder final : public AcceleratedVideoDecoder {
gfx::Rect GetVisibleRect() const override;
VideoCodecProfile GetProfile() const override;
uint8_t GetBitDepth() const override;
VideoChromaSampling GetChromaSampling() const override;
size_t GetRequiredNumOfPictures() const override;
size_t GetNumReferenceFrames() const override;

Expand Down Expand Up @@ -329,6 +334,8 @@ class MEDIA_GPU_EXPORT H265Decoder final : public AcceleratedVideoDecoder {
VideoCodecProfile profile_;
// Bit depth of input bitstream.
uint8_t bit_depth_ = 0;
// Chroma sampling format of input bitstream
VideoChromaSampling chroma_sampling_ = VideoChromaSampling::kUnknown;

const std::unique_ptr<H265Accelerator> accelerator_;
};
Expand Down
4 changes: 4 additions & 0 deletions media/gpu/h265_decoder_fuzzertest.cc
Expand Up @@ -7,6 +7,7 @@
#include "base/numerics/safe_conversions.h"
#include "media/base/decoder_buffer.h"
#include "media/base/video_codecs.h"
#include "media/base/video_types.h"
#include "media/gpu/h265_decoder.h"

namespace {
Expand Down Expand Up @@ -58,6 +59,9 @@ class FakeH265Accelerator : public media::H265Decoder::H265Accelerator {
const media::DecryptConfig* decrypt_config) override {
return Status::kOk;
}
bool IsChromaSamplingSupported(media::VideoChromaSampling format) override {
return format == media::VideoChromaSampling::k420;
}
};

} // namespace
Expand Down
4 changes: 3 additions & 1 deletion media/gpu/h265_decoder_unittest.cc
Expand Up @@ -118,7 +118,9 @@ class MockH265Accelerator : public H265Decoder::H265Accelerator {
MOCK_METHOD2(SetStream,
Status(base::span<const uint8_t> stream,
const DecryptConfig* decrypt_config));

bool IsChromaSamplingSupported(VideoChromaSampling format) override {
return format == VideoChromaSampling::k420;
}
void Reset() override {}
};

Expand Down
5 changes: 5 additions & 0 deletions media/gpu/vaapi/h265_vaapi_video_decoder_delegate.cc
Expand Up @@ -59,6 +59,11 @@ scoped_refptr<H265Picture> H265VaapiVideoDecoderDelegate::CreateH265Picture() {
return new VaapiH265Picture(std::move(va_surface));
}

bool H265VaapiVideoDecoderDelegate::IsChromaSamplingSupported(
VideoChromaSampling chroma_sampling) {
return chroma_sampling == VideoChromaSampling::k420;
}

DecodeStatus H265VaapiVideoDecoderDelegate::SubmitFrameMetadata(
const H265SPS* sps,
const H265PPS* pps,
Expand Down
1 change: 1 addition & 0 deletions media/gpu/vaapi/h265_vaapi_video_decoder_delegate.h
Expand Up @@ -62,6 +62,7 @@ class H265VaapiVideoDecoderDelegate : public H265Decoder::H265Accelerator,
void Reset() override;
Status SetStream(base::span<const uint8_t> stream,
const DecryptConfig* decrypt_config) override;
bool IsChromaSamplingSupported(VideoChromaSampling chroma_sampling) override;

private:
void FillVAPicture(VAPictureHEVC* va_pic, scoped_refptr<H265Picture> pic);
Expand Down
1 change: 1 addition & 0 deletions media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
Expand Up @@ -64,6 +64,7 @@ class MockAcceleratedVideoDecoder : public AcceleratedVideoDecoder {
MOCK_CONST_METHOD0(GetPicSize, gfx::Size());
MOCK_CONST_METHOD0(GetProfile, VideoCodecProfile());
MOCK_CONST_METHOD0(GetBitDepth, uint8_t());
MOCK_CONST_METHOD0(GetChromaSampling, VideoChromaSampling());
MOCK_CONST_METHOD0(GetVisibleRect, gfx::Rect());
MOCK_CONST_METHOD0(GetRequiredNumOfPictures, size_t());
MOCK_CONST_METHOD0(GetNumReferenceFrames, size_t());
Expand Down
6 changes: 6 additions & 0 deletions media/gpu/vp8_decoder.cc
Expand Up @@ -186,6 +186,12 @@ uint8_t VP8Decoder::GetBitDepth() const {
return 8u;
}

VideoChromaSampling VP8Decoder::GetChromaSampling() const {
// VP8 decoder currently does not rely on chroma sampling format for
// creating/reconfiguring decoder, so return an unknown format.
return VideoChromaSampling::kUnknown;
}

size_t VP8Decoder::GetRequiredNumOfPictures() const {
constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
return kNumVp8ReferenceBuffers + kPicsInPipeline;
Expand Down
1 change: 1 addition & 0 deletions media/gpu/vp8_decoder.h
Expand Up @@ -77,6 +77,7 @@ class MEDIA_GPU_EXPORT VP8Decoder : public AcceleratedVideoDecoder {
gfx::Rect GetVisibleRect() const override;
VideoCodecProfile GetProfile() const override;
uint8_t GetBitDepth() const override;
VideoChromaSampling GetChromaSampling() const override;
size_t GetRequiredNumOfPictures() const override;
size_t GetNumReferenceFrames() const override;

Expand Down
6 changes: 6 additions & 0 deletions media/gpu/vp9_decoder.cc
Expand Up @@ -408,6 +408,12 @@ uint8_t VP9Decoder::GetBitDepth() const {
return bit_depth_;
}

VideoChromaSampling VP9Decoder::GetChromaSampling() const {
// VP9 decoder currently does not rely on chroma sampling format for
// creating/reconfiguring decoder, so return an unknown format.
return VideoChromaSampling::kUnknown;
}

size_t VP9Decoder::GetRequiredNumOfPictures() const {
constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
return kPicsInPipeline + GetNumReferenceFrames();
Expand Down
1 change: 1 addition & 0 deletions media/gpu/vp9_decoder.h
Expand Up @@ -134,6 +134,7 @@ class MEDIA_GPU_EXPORT VP9Decoder : public AcceleratedVideoDecoder {
gfx::Rect GetVisibleRect() const override;
VideoCodecProfile GetProfile() const override;
uint8_t GetBitDepth() const override;
VideoChromaSampling GetChromaSampling() const override;
size_t GetRequiredNumOfPictures() const override;
size_t GetNumReferenceFrames() const override;

Expand Down

0 comments on commit a790b3d

Please sign in to comment.