Change ParseUncompressedVp9Header implementation to use BitstreamReader
Bug: None
Change-Id: I91010b0102622fd8154f8ba941e61298b0584eae
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230802
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34899}
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index b6496b2..fa50637 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -355,6 +355,7 @@
"../../api/video_codecs:video_codecs_api",
"../../common_video",
"../../modules/rtp_rtcp",
+ "../../rtc_base:bitstream_reader",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_numerics",
@@ -374,6 +375,7 @@
"../rtp_rtcp:rtp_rtcp_format",
]
absl_deps = [
+ "//third_party/abseil-cpp/absl/numeric:bits",
"//third_party/abseil-cpp/absl/strings:strings",
"//third_party/abseil-cpp/absl/types:optional",
]
diff --git a/modules/video_coding/utility/vp9_uncompressed_header_parser.cc b/modules/video_coding/utility/vp9_uncompressed_header_parser.cc
index b065069..d8f24be 100644
--- a/modules/video_coding/utility/vp9_uncompressed_header_parser.cc
+++ b/modules/video_coding/utility/vp9_uncompressed_header_parser.cc
@@ -9,30 +9,13 @@
*/
#include "modules/video_coding/utility/vp9_uncompressed_header_parser.h"
+#include "absl/numeric/bits.h"
#include "absl/strings/string_view.h"
-#include "rtc_base/bit_buffer.h"
+#include "rtc_base/bitstream_reader.h"
#include "rtc_base/logging.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
-
-// Evaluates x and returns false if false.
-#define RETURN_IF_FALSE(x) \
- if (!(x)) { \
- return false; \
- }
-
-// Evaluates x, which is intended to return an optional. If result is nullopt,
-// returns false. Else, calls fun() with the dereferenced optional as parameter.
-#define READ_OR_RETURN(x, fun) \
- do { \
- if (auto optional_val = (x)) { \
- fun(*optional_val); \
- } else { \
- return false; \
- } \
- } while (false)
-
namespace {
const size_t kVp9NumRefsPerFrame = 3;
const size_t kVp9MaxRefLFDeltas = 4;
@@ -40,169 +23,32 @@
const size_t kVp9MinTileWidthB64 = 4;
const size_t kVp9MaxTileWidthB64 = 64;
-class BitstreamReader {
- public:
- explicit BitstreamReader(rtc::BitBuffer* buffer) : buffer_(buffer) {}
-
- // Reads on bit from the input stream and:
- // * returns false if bit cannot be read
- // * calls f_true() if bit is true, returns return value of that function
- // * calls f_else() if bit is false, returns return value of that function
- bool IfNextBoolean(
- std::function<bool()> f_true,
- std::function<bool()> f_false = [] { return true; }) {
- uint32_t val;
- if (!buffer_->ReadBits(1, val)) {
- return false;
- }
- if (val != 0) {
- return f_true();
- }
- return f_false();
- }
-
- absl::optional<bool> ReadBoolean() {
- uint32_t val;
- if (!buffer_->ReadBits(1, val)) {
- return {};
- }
- return {val != 0};
- }
-
- // Reads a bit from the input stream and returns:
- // * false if bit cannot be read
- // * true if bit matches expected_val
- // * false if bit does not match expected_val - in which case `error_msg` is
- // logged as warning, if provided.
- bool VerifyNextBooleanIs(bool expected_val, absl::string_view error_msg) {
- uint32_t val;
- if (!buffer_->ReadBits(1, val)) {
- return false;
- }
- if ((val != 0) != expected_val) {
- if (!error_msg.empty()) {
- RTC_LOG(LS_WARNING) << error_msg;
- }
- return false;
- }
- return true;
- }
-
- // Reads `bits` bits from the bitstream and interprets them as an unsigned
- // integer that gets cast to the type T before returning.
- // Returns nullopt if all bits cannot be read.
- // If number of bits matches size of data type, the bits parameter may be
- // omitted. Ex:
- // ReadUnsigned<uint8_t>(2); // Returns uint8_t with 2 LSB populated.
- // ReadUnsigned<uint8_t>(); // Returns uint8_t with all 8 bits populated.
- template <typename T>
- absl::optional<T> ReadUnsigned(int bits = sizeof(T) * 8) {
- RTC_DCHECK_LE(bits, 32);
- RTC_DCHECK_LE(bits, sizeof(T) * 8);
- uint32_t val;
- if (!buffer_->ReadBits(bits, val)) {
- return {};
- }
- return (static_cast<T>(val));
- }
-
- // Helper method that reads `num_bits` from the bitstream, returns:
- // * false if bits cannot be read.
- // * true if `expected_val` matches the read bits
- // * false if `expected_val` does not match the read bits, and logs
- // `error_msg` as a warning (if provided).
- bool VerifyNextUnsignedIs(int num_bits,
- uint32_t expected_val,
- absl::string_view error_msg) {
- uint32_t val;
- if (!buffer_->ReadBits(num_bits, val)) {
- return false;
- }
- if (val != expected_val) {
- if (!error_msg.empty()) {
- RTC_LOG(LS_WARNING) << error_msg;
- }
- return false;
- }
- return true;
- }
-
- // Basically the same as ReadUnsigned() - but for signed integers.
- // Here `bits` indicates the size of the value - number of bits read from the
- // bit buffer is one higher (the sign bit). This is made to matche the spec in
- // which eg s(4) = f(1) sign-bit, plus an f(4).
- template <typename T>
- absl::optional<T> ReadSigned(int bits = sizeof(T) * 8) {
- uint32_t sign;
- if (!buffer_->ReadBits(1, sign)) {
- return {};
- }
- uint32_t val;
- if (!buffer_->ReadBits(bits, val)) {
- return {};
- }
- int64_t sign_val = val;
- if (sign != 0) {
- sign_val = -sign_val;
- }
- return {static_cast<T>(sign_val)};
- }
-
- // Reads `bits` from the bitstream, disregarding their value.
- // Returns true if full number of bits were read, false otherwise.
- bool ConsumeBits(int bits) { return buffer_->ConsumeBits(bits); }
-
- void GetPosition(size_t* out_byte_offset, size_t* out_bit_offset) const {
- buffer_->GetCurrentOffset(out_byte_offset, out_bit_offset);
- }
-
- private:
- rtc::BitBuffer* buffer_;
-};
-
-bool Vp9ReadColorConfig(BitstreamReader* br,
+void Vp9ReadColorConfig(BitstreamReader& br,
Vp9UncompressedHeader* frame_info) {
if (frame_info->profile == 2 || frame_info->profile == 3) {
- READ_OR_RETURN(br->ReadBoolean(), [frame_info](bool ten_or_twelve_bits) {
- frame_info->bit_detph =
- ten_or_twelve_bits ? Vp9BitDept::k12Bit : Vp9BitDept::k10Bit;
- });
+ frame_info->bit_detph =
+ br.Read<bool>() ? Vp9BitDept::k12Bit : Vp9BitDept::k10Bit;
} else {
frame_info->bit_detph = Vp9BitDept::k8Bit;
}
- READ_OR_RETURN(
- br->ReadUnsigned<uint8_t>(3), [frame_info](uint8_t color_space) {
- frame_info->color_space = static_cast<Vp9ColorSpace>(color_space);
- });
+ frame_info->color_space = static_cast<Vp9ColorSpace>(br.ReadBits(3));
if (frame_info->color_space != Vp9ColorSpace::CS_RGB) {
- READ_OR_RETURN(br->ReadBoolean(), [frame_info](bool color_range) {
- frame_info->color_range =
- color_range ? Vp9ColorRange::kFull : Vp9ColorRange::kStudio;
- });
+ frame_info->color_range =
+ br.Read<bool>() ? Vp9ColorRange::kFull : Vp9ColorRange::kStudio;
if (frame_info->profile == 1 || frame_info->profile == 3) {
- READ_OR_RETURN(br->ReadUnsigned<uint8_t>(2),
- [frame_info](uint8_t subsampling) {
- switch (subsampling) {
- case 0b00:
- frame_info->sub_sampling = Vp9YuvSubsampling::k444;
- break;
- case 0b01:
- frame_info->sub_sampling = Vp9YuvSubsampling::k440;
- break;
- case 0b10:
- frame_info->sub_sampling = Vp9YuvSubsampling::k422;
- break;
- case 0b11:
- frame_info->sub_sampling = Vp9YuvSubsampling::k420;
- break;
- }
- });
+ static constexpr Vp9YuvSubsampling kSubSamplings[] = {
+ Vp9YuvSubsampling::k444, Vp9YuvSubsampling::k440,
+ Vp9YuvSubsampling::k422, Vp9YuvSubsampling::k420};
+ frame_info->sub_sampling = kSubSamplings[br.ReadBits(2)];
- RETURN_IF_FALSE(br->VerifyNextBooleanIs(
- 0, "Failed to parse header. Reserved bit set."));
+ if (br.Read<bool>()) {
+ RTC_LOG(LS_WARNING) << "Failed to parse header. Reserved bit set.";
+ br.Invalidate();
+ return;
+ }
} else {
// Profile 0 or 2.
frame_info->sub_sampling = Vp9YuvSubsampling::k420;
@@ -212,206 +58,158 @@
frame_info->color_range = Vp9ColorRange::kFull;
if (frame_info->profile == 1 || frame_info->profile == 3) {
frame_info->sub_sampling = Vp9YuvSubsampling::k444;
- RETURN_IF_FALSE(br->VerifyNextBooleanIs(
- 0, "Failed to parse header. Reserved bit set."));
+ if (br.Read<bool>()) {
+ RTC_LOG(LS_WARNING) << "Failed to parse header. Reserved bit set.";
+ br.Invalidate();
+ }
} else {
RTC_LOG(LS_WARNING) << "Failed to parse header. 4:4:4 color not supported"
" in profile 0 or 2.";
- return false;
+ br.Invalidate();
}
}
-
- return true;
}
-bool ReadRefreshFrameFlags(BitstreamReader* br,
+void ReadRefreshFrameFlags(BitstreamReader& br,
Vp9UncompressedHeader* frame_info) {
// Refresh frame flags.
- READ_OR_RETURN(br->ReadUnsigned<uint8_t>(), [frame_info](uint8_t flags) {
- for (int i = 0; i < 8; ++i) {
- frame_info->updated_buffers.set(i, (flags & (0x01 << (7 - i))) != 0);
- }
- });
- return true;
+ uint8_t flags = br.Read<uint8_t>();
+ for (int i = 0; i < 8; ++i) {
+ frame_info->updated_buffers.set(i, (flags & (0x01 << (7 - i))) != 0);
+ }
}
-bool Vp9ReadFrameSize(BitstreamReader* br, Vp9UncompressedHeader* frame_info) {
+void Vp9ReadFrameSize(BitstreamReader& br, Vp9UncompressedHeader* frame_info) {
// 16 bits: frame (width|height) - 1.
- READ_OR_RETURN(br->ReadUnsigned<uint16_t>(), [frame_info](uint16_t width) {
- frame_info->frame_width = width + 1;
- });
- READ_OR_RETURN(br->ReadUnsigned<uint16_t>(), [frame_info](uint16_t height) {
- frame_info->frame_height = height + 1;
- });
- return true;
+ frame_info->frame_width = br.Read<uint16_t>() + 1;
+ frame_info->frame_height = br.Read<uint16_t>() + 1;
}
-bool Vp9ReadRenderSize(BitstreamReader* br, Vp9UncompressedHeader* frame_info) {
+void Vp9ReadRenderSize(size_t total_buffer_size_bits,
+ BitstreamReader& br,
+ Vp9UncompressedHeader* frame_info) {
// render_and_frame_size_different
- return br->IfNextBoolean(
- [&] {
- auto& pos = frame_info->render_size_position.emplace();
- br->GetPosition(&pos.byte_offset, &pos.bit_offset);
- // 16 bits: render (width|height) - 1.
- READ_OR_RETURN(br->ReadUnsigned<uint16_t>(),
- [frame_info](uint16_t width) {
- frame_info->render_width = width + 1;
- });
- READ_OR_RETURN(br->ReadUnsigned<uint16_t>(),
- [frame_info](uint16_t height) {
- frame_info->render_height = height + 1;
- });
- return true;
- },
- /*else*/
- [&] {
- frame_info->render_height = frame_info->frame_height;
- frame_info->render_width = frame_info->frame_width;
- return true;
- });
+ if (br.Read<bool>()) {
+ frame_info->render_size_offset_bits =
+ total_buffer_size_bits - br.RemainingBitCount();
+ // 16 bits: render (width|height) - 1.
+ frame_info->render_width = br.Read<uint16_t>() + 1;
+ frame_info->render_height = br.Read<uint16_t>() + 1;
+ } else {
+ frame_info->render_height = frame_info->frame_height;
+ frame_info->render_width = frame_info->frame_width;
+ }
}
-bool Vp9ReadFrameSizeFromRefs(BitstreamReader* br,
+void Vp9ReadFrameSizeFromRefs(BitstreamReader& br,
Vp9UncompressedHeader* frame_info) {
- bool found_ref = false;
- for (size_t i = 0; !found_ref && i < kVp9NumRefsPerFrame; i++) {
+ for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) {
// Size in refs.
- br->IfNextBoolean([&] {
+ if (br.Read<bool>()) {
frame_info->infer_size_from_reference = frame_info->reference_buffers[i];
- found_ref = true;
- return true;
- });
- }
-
- if (!found_ref) {
- if (!Vp9ReadFrameSize(br, frame_info)) {
- return false;
+ return;
}
}
- return Vp9ReadRenderSize(br, frame_info);
+
+ Vp9ReadFrameSize(br, frame_info);
}
-bool Vp9ReadLoopfilter(BitstreamReader* br) {
+void Vp9ReadLoopfilter(BitstreamReader& br) {
// 6 bits: filter level.
// 3 bits: sharpness level.
- RETURN_IF_FALSE(br->ConsumeBits(9));
+ br.ConsumeBits(9);
- return br->IfNextBoolean([&] { // if mode_ref_delta_enabled
- return br->IfNextBoolean([&] { // if mode_ref_delta_update
- for (size_t i = 0; i < kVp9MaxRefLFDeltas; i++) {
- RETURN_IF_FALSE(br->IfNextBoolean([&] { return br->ConsumeBits(7); }));
- }
- for (size_t i = 0; i < kVp9MaxModeLFDeltas; i++) {
- RETURN_IF_FALSE(br->IfNextBoolean([&] { return br->ConsumeBits(7); }));
- }
- return true;
- });
- });
+ if (!br.Read<bool>()) { // mode_ref_delta_enabled
+ return;
+ }
+ if (!br.Read<bool>()) { // mode_ref_delta_update
+ return;
+ }
+
+ for (size_t i = 0; i < kVp9MaxRefLFDeltas; i++) {
+ if (br.Read<bool>()) { // update_ref_delta
+ br.ConsumeBits(7);
+ }
+ }
+ for (size_t i = 0; i < kVp9MaxModeLFDeltas; i++) {
+ if (br.Read<bool>()) { // update_mode_delta
+ br.ConsumeBits(7);
+ }
+ }
}
-bool Vp9ReadQp(BitstreamReader* br, Vp9UncompressedHeader* frame_info) {
- READ_OR_RETURN(br->ReadUnsigned<uint8_t>(),
- [frame_info](uint8_t qp) { frame_info->base_qp = qp; });
+void Vp9ReadQp(BitstreamReader& br, Vp9UncompressedHeader* frame_info) {
+ frame_info->base_qp = br.Read<uint8_t>();
// yuv offsets
frame_info->is_lossless = frame_info->base_qp == 0;
for (int i = 0; i < 3; ++i) {
- RETURN_IF_FALSE(br->IfNextBoolean([&] { // if delta_coded
- READ_OR_RETURN(br->ReadUnsigned<int>(4), [&](int delta) {
- if (delta != 0) {
- frame_info->is_lossless = false;
- }
- });
- return true;
- }));
+ if (br.Read<bool>()) { // if delta_coded
+ if (br.ReadBits(4) != 0) {
+ frame_info->is_lossless = false;
+ }
+ }
}
- return true;
}
-bool Vp9ReadSegmentationParams(BitstreamReader* br,
+void Vp9ReadSegmentationParams(BitstreamReader& br,
Vp9UncompressedHeader* frame_info) {
constexpr int kSegmentationFeatureBits[kVp9SegLvlMax] = {8, 6, 2, 0};
constexpr bool kSegmentationFeatureSigned[kVp9SegLvlMax] = {1, 1, 0, 0};
- return br->IfNextBoolean([&] { // segmentation_enabled
- frame_info->segmentation_enabled = true;
- RETURN_IF_FALSE(br->IfNextBoolean([&] { // update_map
- frame_info->segmentation_tree_probs.emplace();
- for (int i = 0; i < 7; ++i) {
- RETURN_IF_FALSE(br->IfNextBoolean(
- [&] {
- READ_OR_RETURN(br->ReadUnsigned<uint8_t>(), [&](uint8_t prob) {
- (*frame_info->segmentation_tree_probs)[i] = prob;
- });
- return true;
- },
- [&] {
- (*frame_info->segmentation_tree_probs)[i] = 255;
- return true;
- }));
+ frame_info->segmentation_enabled = br.Read<bool>();
+ if (!frame_info->segmentation_enabled) {
+ return;
+ }
+
+ if (br.Read<bool>()) { // update_map
+ frame_info->segmentation_tree_probs.emplace();
+ for (int i = 0; i < 7; ++i) {
+ if (br.Read<bool>()) {
+ (*frame_info->segmentation_tree_probs)[i] = br.Read<uint8_t>();
+ } else {
+ (*frame_info->segmentation_tree_probs)[i] = 255;
}
+ }
- // temporal_update
- frame_info->segmentation_pred_prob.emplace();
- return br->IfNextBoolean(
- [&] {
- for (int i = 0; i < 3; ++i) {
- RETURN_IF_FALSE(br->IfNextBoolean(
- [&] {
- READ_OR_RETURN(
- br->ReadUnsigned<uint8_t>(), [&](uint8_t prob) {
- (*frame_info->segmentation_pred_prob)[i] = prob;
- });
- return true;
- },
- [&] {
- (*frame_info->segmentation_pred_prob)[i] = 255;
- return true;
- }));
- }
- return true;
- },
- [&] {
- frame_info->segmentation_pred_prob->fill(255);
- return true;
- });
- }));
-
- return br->IfNextBoolean([&] { // segmentation_update_data
- RETURN_IF_FALSE(br->IfNextBoolean([&] {
- frame_info->segmentation_is_delta = true;
- return true;
- }));
-
- for (size_t i = 0; i < kVp9MaxSegments; ++i) {
- for (size_t j = 0; j < kVp9SegLvlMax; ++j) {
- RETURN_IF_FALSE(br->IfNextBoolean([&] { // feature_enabled
- if (kSegmentationFeatureBits[j] == 0) {
- // No feature bits used and no sign, just mark it and return.
- frame_info->segmentation_features[i][j] = 1;
- return true;
- }
- READ_OR_RETURN(
- br->ReadUnsigned<uint8_t>(kSegmentationFeatureBits[j]),
- [&](uint8_t feature_value) {
- frame_info->segmentation_features[i][j] = feature_value;
- });
- if (kSegmentationFeatureSigned[j]) {
- RETURN_IF_FALSE(br->IfNextBoolean([&] {
- (*frame_info->segmentation_features[i][j]) *= -1;
- return true;
- }));
- }
- return true;
- }));
+ // temporal_update
+ frame_info->segmentation_pred_prob.emplace();
+ if (br.Read<bool>()) {
+ for (int i = 0; i < 3; ++i) {
+ if (br.Read<bool>()) {
+ (*frame_info->segmentation_pred_prob)[i] = br.Read<uint8_t>();
+ } else {
+ (*frame_info->segmentation_pred_prob)[i] = 255;
}
}
- return true;
- });
- });
+ } else {
+ frame_info->segmentation_pred_prob->fill(255);
+ }
+ }
+
+ if (br.Read<bool>()) { // segmentation_update_data
+ frame_info->segmentation_is_delta = br.Read<bool>();
+ for (size_t i = 0; i < kVp9MaxSegments; ++i) {
+ for (size_t j = 0; j < kVp9SegLvlMax; ++j) {
+ if (!br.Read<bool>()) { // feature_enabled
+ continue;
+ }
+ if (kSegmentationFeatureBits[j] == 0) {
+ // No feature bits used and no sign, just mark it and return.
+ frame_info->segmentation_features[i][j] = 1;
+ continue;
+ }
+ frame_info->segmentation_features[i][j] =
+ br.ReadBits(kSegmentationFeatureBits[j]);
+ if (kSegmentationFeatureSigned[j] && br.Read<bool>()) {
+ (*frame_info->segmentation_features[i][j]) *= -1;
+ }
+ }
+ }
+ }
}
-bool Vp9ReadTileInfo(BitstreamReader* br, Vp9UncompressedHeader* frame_info) {
+void Vp9ReadTileInfo(BitstreamReader& br, Vp9UncompressedHeader* frame_info) {
size_t mi_cols = (frame_info->frame_width + 7) >> 3;
size_t sb64_cols = (mi_cols + 7) >> 3;
@@ -427,27 +225,20 @@
--max_log2;
frame_info->tile_cols_log2 = min_log2;
- bool done = false;
- while (!done && frame_info->tile_cols_log2 < max_log2) {
- RETURN_IF_FALSE(br->IfNextBoolean(
- [&] {
- ++frame_info->tile_cols_log2;
- return true;
- },
- [&] {
- done = true;
- return true;
- }));
+ while (frame_info->tile_cols_log2 < max_log2) {
+ if (br.Read<bool>()) {
+ ++frame_info->tile_cols_log2;
+ } else {
+ break;
+ }
}
frame_info->tile_rows_log2 = 0;
- RETURN_IF_FALSE(br->IfNextBoolean([&] {
+ if (br.Read<bool>()) {
++frame_info->tile_rows_log2;
- return br->IfNextBoolean([&] {
+ if (br.Read<bool>()) {
++frame_info->tile_rows_log2;
- return true;
- });
- }));
- return true;
+ }
+ }
}
const Vp9InterpolationFilter kLiteralToType[4] = {
@@ -586,60 +377,49 @@
return oss.str();
}
-bool Parse(rtc::ArrayView<const uint8_t> buf,
+void Parse(BitstreamReader& br,
Vp9UncompressedHeader* frame_info,
bool qp_only) {
- rtc::BitBuffer bit_buffer(buf.data(), buf.size());
- BitstreamReader br(&bit_buffer);
+ const size_t total_buffer_size_bits = br.RemainingBitCount();
// Frame marker.
- RETURN_IF_FALSE(br.VerifyNextUnsignedIs(
- 2, 0x2, "Failed to parse header. Frame marker should be 2."));
+ if (br.ReadBits(2) != 0b10) {
+ RTC_LOG(LS_WARNING) << "Failed to parse header. Frame marker should be 2.";
+ br.Invalidate();
+ return;
+ }
// Profile has low bit first.
- READ_OR_RETURN(br.ReadBoolean(),
- [frame_info](bool low) { frame_info->profile = int{low}; });
- READ_OR_RETURN(br.ReadBoolean(), [frame_info](bool high) {
- frame_info->profile |= int{high} << 1;
- });
- if (frame_info->profile > 2) {
- RETURN_IF_FALSE(br.VerifyNextBooleanIs(
- false, "Failed to get QP. Unsupported bitstream profile."));
+ frame_info->profile = br.ReadBit();
+ frame_info->profile |= br.ReadBit() << 1;
+ if (frame_info->profile > 2 && br.Read<bool>()) {
+ RTC_LOG(LS_WARNING)
+ << "Failed to parse header. Unsupported bitstream profile.";
+ br.Invalidate();
+ return;
}
// Show existing frame.
- RETURN_IF_FALSE(br.IfNextBoolean([&] {
- READ_OR_RETURN(br.ReadUnsigned<uint8_t>(3),
- [frame_info](uint8_t frame_idx) {
- frame_info->show_existing_frame = frame_idx;
- });
- return true;
- }));
- if (frame_info->show_existing_frame.has_value()) {
- return true;
+ if (br.Read<bool>()) {
+ frame_info->show_existing_frame = br.ReadBits(3);
+ return;
}
- READ_OR_RETURN(br.ReadBoolean(), [frame_info](bool frame_type) {
- // Frame type: KEY_FRAME(0), INTER_FRAME(1).
- frame_info->is_keyframe = frame_type == 0;
- });
- READ_OR_RETURN(br.ReadBoolean(), [frame_info](bool show_frame) {
- frame_info->show_frame = show_frame;
- });
- READ_OR_RETURN(br.ReadBoolean(), [frame_info](bool error_resilient) {
- frame_info->error_resilient = error_resilient;
- });
+ // Frame type: KEY_FRAME(0), INTER_FRAME(1).
+ frame_info->is_keyframe = !br.Read<bool>();
+ frame_info->show_frame = br.Read<bool>();
+ frame_info->error_resilient = br.Read<bool>();
if (frame_info->is_keyframe) {
- RETURN_IF_FALSE(br.VerifyNextUnsignedIs(
- 24, 0x498342, "Failed to get QP. Invalid sync code."));
+ if (br.ReadBits(24) != 0x498342) {
+ RTC_LOG(LS_WARNING) << "Failed to parse header. Invalid sync code.";
+ br.Invalidate();
+ return;
+ }
- if (!Vp9ReadColorConfig(&br, frame_info))
- return false;
- if (!Vp9ReadFrameSize(&br, frame_info))
- return false;
- if (!Vp9ReadRenderSize(&br, frame_info))
- return false;
+ Vp9ReadColorConfig(br, frame_info);
+ Vp9ReadFrameSize(br, frame_info);
+ Vp9ReadRenderSize(total_buffer_size_bits, br, frame_info);
// Key-frames implicitly update all buffers.
frame_info->updated_buffers.set();
@@ -647,108 +427,86 @@
// Non-keyframe.
bool is_intra_only = false;
if (!frame_info->show_frame) {
- READ_OR_RETURN(br.ReadBoolean(),
- [&](bool intra_only) { is_intra_only = intra_only; });
+ is_intra_only = br.Read<bool>();
}
if (!frame_info->error_resilient) {
- RETURN_IF_FALSE(br.ConsumeBits(2)); // Reset frame context.
+ br.ConsumeBits(2); // Reset frame context.
}
if (is_intra_only) {
- RETURN_IF_FALSE(br.VerifyNextUnsignedIs(
- 24, 0x498342, "Failed to get QP. Invalid sync code."));
+ if (br.ReadBits(24) != 0x498342) {
+ RTC_LOG(LS_WARNING) << "Failed to parse header. Invalid sync code.";
+ br.Invalidate();
+ return;
+ }
if (frame_info->profile > 0) {
- if (!Vp9ReadColorConfig(&br, frame_info))
- return false;
+ Vp9ReadColorConfig(br, frame_info);
} else {
frame_info->color_space = Vp9ColorSpace::CS_BT_601;
frame_info->sub_sampling = Vp9YuvSubsampling::k420;
frame_info->bit_detph = Vp9BitDept::k8Bit;
}
frame_info->reference_buffers.fill(-1);
- RETURN_IF_FALSE(ReadRefreshFrameFlags(&br, frame_info));
- RETURN_IF_FALSE(Vp9ReadFrameSize(&br, frame_info));
- RETURN_IF_FALSE(Vp9ReadRenderSize(&br, frame_info));
+ ReadRefreshFrameFlags(br, frame_info);
+ Vp9ReadFrameSize(br, frame_info);
+ Vp9ReadRenderSize(total_buffer_size_bits, br, frame_info);
} else {
- RETURN_IF_FALSE(ReadRefreshFrameFlags(&br, frame_info));
+ ReadRefreshFrameFlags(br, frame_info);
frame_info->reference_buffers_sign_bias[0] = false;
for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) {
- READ_OR_RETURN(br.ReadUnsigned<uint8_t>(3), [&](uint8_t idx) {
- frame_info->reference_buffers[i] = idx;
- });
- READ_OR_RETURN(br.ReadBoolean(), [&](bool sign_bias) {
- frame_info
- ->reference_buffers_sign_bias[Vp9ReferenceFrame::kLast + i] =
- sign_bias;
- });
+ frame_info->reference_buffers[i] = br.ReadBits(3);
+ frame_info->reference_buffers_sign_bias[Vp9ReferenceFrame::kLast + i] =
+ br.Read<bool>();
}
- if (!Vp9ReadFrameSizeFromRefs(&br, frame_info))
- return false;
+ Vp9ReadFrameSizeFromRefs(br, frame_info);
+ Vp9ReadRenderSize(total_buffer_size_bits, br, frame_info);
- READ_OR_RETURN(br.ReadBoolean(), [&](bool allow_high_precision_mv) {
- frame_info->allow_high_precision_mv = allow_high_precision_mv;
- });
+ frame_info->allow_high_precision_mv = br.Read<bool>();
// Interpolation filter.
- RETURN_IF_FALSE(br.IfNextBoolean(
- [frame_info] {
- frame_info->interpolation_filter =
- Vp9InterpolationFilter::kSwitchable;
- return true;
- },
- [&] {
- READ_OR_RETURN(
- br.ReadUnsigned<uint8_t>(2), [frame_info](uint8_t filter) {
- frame_info->interpolation_filter = kLiteralToType[filter];
- });
- return true;
- }));
+ if (br.Read<bool>()) {
+ frame_info->interpolation_filter = Vp9InterpolationFilter::kSwitchable;
+ } else {
+ frame_info->interpolation_filter = kLiteralToType[br.ReadBits(2)];
+ }
}
}
if (!frame_info->error_resilient) {
// 1 bit: Refresh frame context.
// 1 bit: Frame parallel decoding mode.
- RETURN_IF_FALSE(br.ConsumeBits(2));
+ br.ConsumeBits(2);
}
// Frame context index.
- READ_OR_RETURN(br.ReadUnsigned<uint8_t>(2),
- [&](uint8_t idx) { frame_info->frame_context_idx = idx; });
+ frame_info->frame_context_idx = br.ReadBits(2);
- if (!Vp9ReadLoopfilter(&br))
- return false;
+ Vp9ReadLoopfilter(br);
// Read base QP.
- RETURN_IF_FALSE(Vp9ReadQp(&br, frame_info));
+ Vp9ReadQp(br, frame_info);
if (qp_only) {
// Not interested in the rest of the header, return early.
- return true;
+ return;
}
- RETURN_IF_FALSE(Vp9ReadSegmentationParams(&br, frame_info));
- RETURN_IF_FALSE(Vp9ReadTileInfo(&br, frame_info));
- READ_OR_RETURN(br.ReadUnsigned<uint16_t>(), [frame_info](uint16_t size) {
- frame_info->compressed_header_size = size;
- });
-
- // Trailing bits.
- RETURN_IF_FALSE(br.ConsumeBits(bit_buffer.RemainingBitCount() % 8));
+ Vp9ReadSegmentationParams(br, frame_info);
+ Vp9ReadTileInfo(br, frame_info);
+ frame_info->compressed_header_size = br.Read<uint16_t>();
frame_info->uncompressed_header_size =
- buf.size() - (bit_buffer.RemainingBitCount() / 8);
-
- return true;
+ (total_buffer_size_bits / 8) - (br.RemainingBitCount() / 8);
}
absl::optional<Vp9UncompressedHeader> ParseUncompressedVp9Header(
rtc::ArrayView<const uint8_t> buf) {
+ BitstreamReader reader(buf);
Vp9UncompressedHeader frame_info;
- if (Parse(buf, &frame_info, /*qp_only=*/false) &&
- frame_info.frame_width > 0) {
+ Parse(reader, &frame_info, /*qp_only=*/false);
+ if (reader.Ok() && frame_info.frame_width > 0) {
return frame_info;
}
return absl::nullopt;
@@ -757,8 +515,10 @@
namespace vp9 {
bool GetQp(const uint8_t* buf, size_t length, int* qp) {
+ BitstreamReader reader(rtc::MakeArrayView(buf, length));
Vp9UncompressedHeader frame_info;
- if (!Parse(rtc::MakeArrayView(buf, length), &frame_info, /*qp_only=*/true)) {
+ Parse(reader, &frame_info, /*qp_only=*/true);
+ if (!reader.Ok()) {
return false;
}
*qp = frame_info.base_qp;
diff --git a/modules/video_coding/utility/vp9_uncompressed_header_parser.h b/modules/video_coding/utility/vp9_uncompressed_header_parser.h
index 3e862bf..8d1b88c 100644
--- a/modules/video_coding/utility/vp9_uncompressed_header_parser.h
+++ b/modules/video_coding/utility/vp9_uncompressed_header_parser.h
@@ -105,11 +105,7 @@
// Width/height of the tiles used (in units of 8x8 blocks).
size_t tile_cols_log2 = 0; // tile_cols = 1 << tile_cols_log2
size_t tile_rows_log2 = 0; // tile_rows = 1 << tile_rows_log2
- struct BitstreamPosition {
- size_t byte_offset = 0;
- size_t bit_offset = 0;
- };
- absl::optional<BitstreamPosition> render_size_position;
+ absl::optional<size_t> render_size_offset_bits;
Vp9InterpolationFilter interpolation_filter =
Vp9InterpolationFilter::kEightTap;
bool allow_high_precision_mv = false;
diff --git a/modules/video_coding/utility/vp9_uncompressed_header_parser_unittest.cc b/modules/video_coding/utility/vp9_uncompressed_header_parser_unittest.cc
index 913f43e..be0a303 100644
--- a/modules/video_coding/utility/vp9_uncompressed_header_parser_unittest.cc
+++ b/modules/video_coding/utility/vp9_uncompressed_header_parser_unittest.cc
@@ -55,11 +55,7 @@
EXPECT_EQ(frame_info->updated_buffers, 0b10000000);
EXPECT_EQ(frame_info->tile_cols_log2, 0u);
EXPECT_EQ(frame_info->tile_rows_log2, 0u);
- EXPECT_THAT(
- frame_info->render_size_position,
- Optional(AllOf(
- Field(&Vp9UncompressedHeader::BitstreamPosition::byte_offset, 8u),
- Field(&Vp9UncompressedHeader::BitstreamPosition::bit_offset, 0u))));
+ EXPECT_EQ(frame_info->render_size_offset_bits, 64u);
EXPECT_EQ(frame_info->compressed_header_size, 23u);
EXPECT_EQ(frame_info->uncompressed_header_size, 37u);