Skip to content

Commit

Permalink
VVC parser implementation: VPS parser.
Browse files Browse the repository at this point in the history
This is splitted from the VVC prototyping CL:4303858. This CL enables
VVC VPS parser.

Bug: 1417910
Change-Id: I110837a1163e4a145fca70bcbbffc5406afb632c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4454527
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com>
Cr-Commit-Position: refs/heads/main@{#1137520}
  • Loading branch information
taste1981 authored and Chromium LUCI CQ committed Apr 29, 2023
1 parent 00b0e45 commit ef642ac
Show file tree
Hide file tree
Showing 14 changed files with 1,243 additions and 145 deletions.
5 changes: 5 additions & 0 deletions media/test/data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ ffmpeg -i bbb.y4m -vf scale=480x360 bbb_480x360.yuv
vvencapp --preset medium -i bbb_480x360.yuv -s 480x360 -r 15 -b 1000000 -p 2 -f 60 -o bbb_360p.vvc
```

#### basketball_2_layers.vvc
2 spatial layer VVC video with layer 0 at 208x120 and layer 1 at 832x480.
Used for vvc parser test. Once vvencapp supports multi-layer encoding, the
creation command needs to be provided.

### AV1

Unless noted otherwise, the codec string is `av01.0.04M.08` for 8-bit files,
Expand Down
Binary file added media/test/data/basketball_2_layers.vvc
Binary file not shown.
1 change: 1 addition & 0 deletions media/test/media_bundle_data.filelist
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ data/av1-monochrome-I-frame-320x240-8bpp
data/av1-show_existing_frame.ivf
data/av1-svc-L2T2.ivf
data/bali_640x360_P420.yuv
data/basketball_2_layers.vvc
data/bbb-320x240-2video-2audio.mp4
data/bbb.hevc
data/bbb_360p.vvc
Expand Down
1 change: 1 addition & 0 deletions media/unit_tests_bundle_data.filelist
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
//media/test/data/av1-show_existing_frame.ivf
//media/test/data/av1-svc-L2T2.ivf
//media/test/data/bali_640x360_P420.yuv
//media/test/data/basketball_2_layers.vvc
//media/test/data/bbb-320x240-2video-2audio.mp4
//media/test/data/bbb.hevc
//media/test/data/bbb_360p.vvc
Expand Down
17 changes: 16 additions & 1 deletion media/video/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ source_set("video") {
sources += [
"h266_nalu_parser.cc",
"h266_nalu_parser.h",
"h266_parser.cc",
"h266_parser.h",
]
}

Expand Down Expand Up @@ -169,7 +171,10 @@ source_set("unit_tests") {
}
}
if (enable_platform_vvc) {
sources += [ "h266_nalu_parser_unittest.cc" ]
sources += [
"h266_nalu_parser_unittest.cc",
"h266_parser_unittest.cc",
]
}

configs += [ "//media:media_config" ]
Expand Down Expand Up @@ -207,3 +212,13 @@ if (enable_hevc_parser_and_hw_decoder) {
]
}
}

if (enable_platform_vvc) {
fuzzer_test("media_h266_parser_fuzzer") {
sources = [ "h266_parser_fuzzertest.cc" ]
deps = [
"//base",
"//media",
]
}
}
97 changes: 77 additions & 20 deletions media/video/bit_reader_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,63 @@
*out = _out != 0; \
} while (0)

#define READ_UE_OR_RETURN(out) \
do { \
if (ReadUE(out, nullptr) != kOk) { \
DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
return kInvalidStream; \
} \
// Exp-Golomb code parsing as specified in H.26x specifications.
// Read one unsigned exp-Golomb code from the stream and return in |*out|
// with total bits read return in |*bits_read|.
#define READ_UE_WITH_BITS_READ_OR_RETURN(out, bits_read) \
do { \
int _bit = 0; \
int _num_bits_processed = -1; \
do { \
READ_BITS_OR_RETURN(1, &_bit); \
_num_bits_processed++; \
} while (_bit == 0); \
if (_num_bits_processed > 31) { \
return kInvalidStream; \
} \
*out = (1u << _num_bits_processed) - 1u; \
*bits_read = 1 + _num_bits_processed * 2; \
int _rest; \
if (_num_bits_processed == 31) { \
READ_BITS_OR_RETURN(_num_bits_processed, &_rest); \
if (_rest == 0) { \
break; \
} else { \
DVLOG(1) \
<< "Error in stream: invalid value while trying to read " #out; \
return kInvalidStream; \
} \
} \
if (_num_bits_processed > 0) { \
READ_BITS_OR_RETURN(_num_bits_processed, &_rest); \
*out += _rest; \
} \
} while (0)

#define READ_UE_AND_MINUS_BITS_READ_OR_RETURN(out, num_bits_remain) \
do { \
int num_bits_read; \
if (ReadUE(out, &num_bits_read) != kOk) { \
DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
return kInvalidStream; \
} \
*num_bits_remain -= num_bits_read; \
#define READ_UE_OR_RETURN(out) \
do { \
int _bits_read = -1; \
READ_UE_WITH_BITS_READ_OR_RETURN(out, &_bits_read); \
} while (0)

#define READ_SE_OR_RETURN(out) \
do { \
if (ReadSE(out, nullptr) != kOk) { \
DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
return kInvalidStream; \
} \
#define READ_UE_AND_MINUS_BITS_READ_OR_RETURN(out, num_bits_remain) \
do { \
int num_bits_read = -1; \
READ_UE_WITH_BITS_READ_OR_RETURN(out, &num_bits_read); \
*num_bits_remain -= num_bits_read; \
} while (0)

// Read one signed exp-Golomb code from the stream and return in |*out|.
#define READ_SE_OR_RETURN(out) \
do { \
int _bits_read = -1; \
int ue = 0; \
READ_UE_WITH_BITS_READ_OR_RETURN(&ue, &_bits_read); \
if (ue % 2 == 0) { \
*out = -(ue / 2); \
} else { \
*out = ue / 2 + 1; \
} \
} while (0)

#define IN_RANGE_OR_RETURN(val, min, max) \
Expand Down Expand Up @@ -120,4 +153,28 @@
} \
} while (0)

#define GT_OR_RETURN(val1, val2) \
do { \
if ((val1) <= (val2)) { \
DVLOG(1) << "Error in stream, " #val1 " is smaller than " #val2; \
return kInvalidStream; \
} \
} while (0)

#define LE_OR_RETURN(val1, val2) \
do { \
if ((val1) > (val2)) { \
DVLOG(1) << "Error in stream, " #val1 " is larger than " #val2; \
return kInvalidStream; \
} \
} while (0)

#define BYTE_ALIGNMENT() \
do { \
int bits_left_to_align = br_.NumBitsLeft() % 8; \
if (bits_left_to_align) { \
SKIP_BITS_OR_RETURN(bits_left_to_align); \
} \
} while (0)

#endif // MEDIA_VIDEO_BIT_READER_MACROS_H_
54 changes: 0 additions & 54 deletions media/video/h264_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -501,60 +501,6 @@ bool H264Parser::ParseNALUs(const uint8_t* stream,
return false;
}

H264Parser::Result H264Parser::ReadUE(int* val, int* num_bits_read) {
int num_bits = -1;
int bit;
int rest;

// Count the number of contiguous zero bits.
do {
READ_BITS_OR_RETURN(1, &bit);
num_bits++;
} while (bit == 0);

if (num_bits > 31)
return kInvalidStream;

// Calculate exp-Golomb code value of size num_bits.
// Special case for |num_bits| == 31 to avoid integer overflow. The only
// valid representation as an int is 2^31 - 1, so the remaining bits must
// be 0 or else the number is too large.
*val = (1u << num_bits) - 1u;

// Calculate the total read bits count.
if (num_bits_read)
*num_bits_read = 1 + num_bits * 2;

if (num_bits == 31) {
READ_BITS_OR_RETURN(num_bits, &rest);
return (rest == 0) ? kOk : kInvalidStream;
}

if (num_bits > 0) {
READ_BITS_OR_RETURN(num_bits, &rest);
*val += rest;
}

return kOk;
}

H264Parser::Result H264Parser::ReadSE(int* val, int* num_bits_read) {
int ue;
Result res;

// See Chapter 9 in the spec.
res = ReadUE(&ue, num_bits_read);
if (res != kOk)
return res;

if (ue % 2 == 0)
*val = -(ue / 2);
else
*val = ue / 2 + 1;

return kOk;
}

H264Parser::Result H264Parser::AdvanceToNextNALU(H264NALU* nalu) {
off_t start_code_size;
off_t nalu_size_with_start_code;
Expand Down
9 changes: 0 additions & 9 deletions media/video/h264_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,15 +552,6 @@ class MEDIA_EXPORT H264Parser {
// - the size in bytes of the start code is returned in |*start_code_size|.
bool LocateNALU(off_t* nalu_size, off_t* start_code_size);

// Exp-Golomb code parsing as specified in chapter 9.1 of the spec.
// Read one unsigned exp-Golomb code from the stream and return in |*val|
// with total bits read return in |*num_bits_read|.
Result ReadUE(int* val, int* num_bits_read);

// Read one signed exp-Golomb code from the stream and return in |*val|
// with total bits read return in |*num_bits_read|.
Result ReadSE(int* val, int* num_bits_read);

// Parse scaling lists (see spec).
Result ParseScalingList(int size, uint8_t* scaling_list, bool* use_default);
Result ParseSPSScalingLists(H264SPS* sps);
Expand Down
52 changes: 0 additions & 52 deletions media/video/h265_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -230,58 +230,6 @@ bool H265SliceHeader::IsBSlice() const {
return slice_type == kSliceTypeB;
}

H265Parser::Result H265Parser::ReadUE(int* val, int* num_bits_read) {
// Count the number of contiguous zero bits.
int bit;
int num_bits = -1;
do {
READ_BITS_OR_RETURN(1, &bit);
num_bits++;
} while (bit == 0);

if (num_bits > 31)
return kInvalidStream;

// Calculate exp-Golomb code value of size num_bits.
// Special case for |num_bits| == 31 to avoid integer overflow. The only
// valid representation as an int is 2^31 - 1, so the remaining bits must
// be 0 or else the number is too large.
*val = (1u << num_bits) - 1u;

// Calculate the total read bits count.
if (num_bits_read)
*num_bits_read = 1 + num_bits * 2;

int rest;
if (num_bits == 31) {
READ_BITS_OR_RETURN(num_bits, &rest);
return (rest == 0) ? kOk : kInvalidStream;
}

if (num_bits > 0) {
READ_BITS_OR_RETURN(num_bits, &rest);
*val += rest;
}

return kOk;
}

H265Parser::Result H265Parser::ReadSE(int* val, int* num_bits_read) {
// See Chapter 9 in the spec.
int ue;
Result res;
res = ReadUE(&ue, num_bits_read);
if (res != kOk)
return res;

if (ue % 2 == 0)
*val = -(ue / 2);
else
*val = ue / 2 + 1;

return kOk;
}

H265Parser::Result H265Parser::ParseVPS(int* vps_id) {
DVLOG(4) << "Parsing VPS";
Result res = kOk;
Expand Down
9 changes: 0 additions & 9 deletions media/video/h265_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -541,15 +541,6 @@ class MEDIA_EXPORT H265Parser : public H265NaluParser {
static VideoCodecProfile ProfileIDCToVideoCodecProfile(int profile_idc);

private:
// Exp-Golomb code parsing as specified in chapter 9.2 of the spec.
// Read one unsigned exp-Golomb code from the stream and return in |*val|
// with total bits read return in |*num_bits_read|.
Result ReadUE(int* val, int* num_bits_read);

// Read one signed exp-Golomb code from the stream and return in |*val|
// with total bits read return in |*num_bits_read|.
Result ReadSE(int* val, int* num_bits_read);

Result ParseProfileTierLevel(bool profile_present,
int max_num_sub_layers_minus1,
H265ProfileTierLevel* profile_tier_level);
Expand Down
Loading

0 comments on commit ef642ac

Please sign in to comment.