From faba0fa1c7efa238ff32412c4d76e435829f8071 Mon Sep 17 00:00:00 2001 From: Danil Chapovalov Date: Wed, 1 Sep 2021 16:27:04 +0200 Subject: [PATCH] Change ParseUncompressedVp9Header implementation to use BitstreamReader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: None Change-Id: I91010b0102622fd8154f8ba941e61298b0584eae Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230802 Commit-Queue: Danil Chapovalov Reviewed-by: Erik Språng Cr-Commit-Position: refs/heads/main@{#34899} --- modules/video_coding/BUILD.gn | 2 + .../utility/vp9_uncompressed_header_parser.cc | 640 ++++++------------ .../utility/vp9_uncompressed_header_parser.h | 6 +- ...vp9_uncompressed_header_parser_unittest.cc | 6 +- 4 files changed, 204 insertions(+), 450 deletions(-) diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index b6496b29ae..fa50637871 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -355,6 +355,7 @@ rtc_library("video_coding_utility") { "../../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 @@ rtc_library("video_coding_utility") { "../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 b0650694ec..d8f24be0dc 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 kVp9MaxModeLFDeltas = 2; 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 f_true, - std::function 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 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(2); // Returns uint8_t with 2 LSB populated. - // ReadUnsigned(); // Returns uint8_t with all 8 bits populated. - template - absl::optional 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(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 - absl::optional 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(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() ? Vp9BitDept::k12Bit : Vp9BitDept::k10Bit; } else { frame_info->bit_detph = Vp9BitDept::k8Bit; } - READ_OR_RETURN( - br->ReadUnsigned(3), [frame_info](uint8_t color_space) { - frame_info->color_space = static_cast(color_space); - }); + frame_info->color_space = static_cast(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() ? Vp9ColorRange::kFull : Vp9ColorRange::kStudio; if (frame_info->profile == 1 || frame_info->profile == 3) { - READ_OR_RETURN(br->ReadUnsigned(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()) { + 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 @@ bool Vp9ReadColorConfig(BitstreamReader* br, 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()) { + 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(), [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(); + 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(), [frame_info](uint16_t width) { - frame_info->frame_width = width + 1; - }); - READ_OR_RETURN(br->ReadUnsigned(), [frame_info](uint16_t height) { - frame_info->frame_height = height + 1; - }); - return true; + frame_info->frame_width = br.Read() + 1; + frame_info->frame_height = br.Read() + 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(), - [frame_info](uint16_t width) { - frame_info->render_width = width + 1; - }); - READ_OR_RETURN(br->ReadUnsigned(), - [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()) { + frame_info->render_size_offset_bits = + total_buffer_size_bits - br.RemainingBitCount(); + // 16 bits: render (width|height) - 1. + frame_info->render_width = br.Read() + 1; + frame_info->render_height = br.Read() + 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()) { 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()) { // mode_ref_delta_enabled + return; + } + if (!br.Read()) { // mode_ref_delta_update + return; + } + + for (size_t i = 0; i < kVp9MaxRefLFDeltas; i++) { + if (br.Read()) { // update_ref_delta + br.ConsumeBits(7); + } + } + for (size_t i = 0; i < kVp9MaxModeLFDeltas; i++) { + if (br.Read()) { // update_mode_delta + br.ConsumeBits(7); + } + } } -bool Vp9ReadQp(BitstreamReader* br, Vp9UncompressedHeader* frame_info) { - READ_OR_RETURN(br->ReadUnsigned(), - [frame_info](uint8_t qp) { frame_info->base_qp = qp; }); +void Vp9ReadQp(BitstreamReader& br, Vp9UncompressedHeader* frame_info) { + frame_info->base_qp = br.Read(); // 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(4), [&](int delta) { - if (delta != 0) { - frame_info->is_lossless = false; - } - }); - return true; - })); + if (br.Read()) { // 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 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(); + if (!frame_info->segmentation_enabled) { + return; + } + + if (br.Read()) { // update_map + frame_info->segmentation_tree_probs.emplace(); + for (int i = 0; i < 7; ++i) { + if (br.Read()) { + (*frame_info->segmentation_tree_probs)[i] = br.Read(); + } 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 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(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()) { + for (int i = 0; i < 3; ++i) { + if (br.Read()) { + (*frame_info->segmentation_pred_prob)[i] = br.Read(); + } else { + (*frame_info->segmentation_pred_prob)[i] = 255; } } - return true; - }); - }); + } else { + frame_info->segmentation_pred_prob->fill(255); + } + } + + if (br.Read()) { // segmentation_update_data + frame_info->segmentation_is_delta = br.Read(); + for (size_t i = 0; i < kVp9MaxSegments; ++i) { + for (size_t j = 0; j < kVp9SegLvlMax; ++j) { + if (!br.Read()) { // 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()) { + (*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 @@ bool Vp9ReadTileInfo(BitstreamReader* br, Vp9UncompressedHeader* frame_info) { --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()) { + ++frame_info->tile_cols_log2; + } else { + break; + } } frame_info->tile_rows_log2 = 0; - RETURN_IF_FALSE(br->IfNextBoolean([&] { + if (br.Read()) { ++frame_info->tile_rows_log2; - return br->IfNextBoolean([&] { + if (br.Read()) { ++frame_info->tile_rows_log2; - return true; - }); - })); - return true; + } + } } const Vp9InterpolationFilter kLiteralToType[4] = { @@ -586,60 +377,49 @@ std::string Vp9UncompressedHeader::ToString() const { return oss.str(); } -bool Parse(rtc::ArrayView 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()) { + 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(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()) { + 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(); + frame_info->show_frame = br.Read(); + frame_info->error_resilient = br.Read(); 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 @@ bool Parse(rtc::ArrayView buf, // 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(); } 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(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(); } - 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(); // Interpolation filter. - RETURN_IF_FALSE(br.IfNextBoolean( - [frame_info] { - frame_info->interpolation_filter = - Vp9InterpolationFilter::kSwitchable; - return true; - }, - [&] { - READ_OR_RETURN( - br.ReadUnsigned(2), [frame_info](uint8_t filter) { - frame_info->interpolation_filter = kLiteralToType[filter]; - }); - return true; - })); + if (br.Read()) { + 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(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(), [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(); frame_info->uncompressed_header_size = - buf.size() - (bit_buffer.RemainingBitCount() / 8); - - return true; + (total_buffer_size_bits / 8) - (br.RemainingBitCount() / 8); } absl::optional ParseUncompressedVp9Header( rtc::ArrayView 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 @@ absl::optional ParseUncompressedVp9Header( 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 3e862bf71d..8d1b88c3d3 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 @@ struct Vp9UncompressedHeader { // 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 render_size_position; + absl::optional 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 913f43eba7..be0a303708 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 @@ TEST(Vp9UncompressedHeaderParserTest, FrameWithSegmentation) { 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);