diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 939b153479..fd03ffe723 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -369,7 +369,10 @@ rtc_library("video_coding_utility") { "../../system_wrappers:field_trial", "../rtp_rtcp:rtp_rtcp_format", ] - absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", + ] } rtc_library("webrtc_h264") { diff --git a/modules/video_coding/utility/vp9_uncompressed_header_parser.cc b/modules/video_coding/utility/vp9_uncompressed_header_parser.cc index f8ddd4db41..20862d4939 100644 --- a/modules/video_coding/utility/vp9_uncompressed_header_parser.cc +++ b/modules/video_coding/utility/vp9_uncompressed_header_parser.cc @@ -9,90 +9,195 @@ */ #include "modules/video_coding/utility/vp9_uncompressed_header_parser.h" +#include "absl/strings/string_view.h" #include "rtc_base/bit_buffer.h" #include "rtc_base/logging.h" namespace webrtc { -#define RETURN_FALSE_IF_ERROR(x) \ - if (!(x)) { \ - return false; \ +// 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 vp9 { namespace { const size_t kVp9NumRefsPerFrame = 3; const size_t kVp9MaxRefLFDeltas = 4; const size_t kVp9MaxModeLFDeltas = 2; +const size_t kVp9MinTileWidthB64 = 4; +const size_t kVp9MaxTileWidthB64 = 64; -bool Vp9ReadProfile(rtc::BitBuffer* br, uint8_t* profile) { - uint32_t high_bit; - uint32_t low_bit; - RETURN_FALSE_IF_ERROR(br->ReadBits(&low_bit, 1)); - RETURN_FALSE_IF_ERROR(br->ReadBits(&high_bit, 1)); - *profile = (high_bit << 1) + low_bit; - if (*profile > 2) { - uint32_t reserved_bit; - RETURN_FALSE_IF_ERROR(br->ReadBits(&reserved_bit, 1)); - if (reserved_bit) { - RTC_LOG(LS_WARNING) << "Failed to get QP. Unsupported bitstream profile."; +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(&val, 1)) { return false; } + if (val != 0) { + return f_true(); + } + return f_false(); } - return true; -} -bool Vp9ReadSyncCode(rtc::BitBuffer* br) { - uint32_t sync_code; - RETURN_FALSE_IF_ERROR(br->ReadBits(&sync_code, 24)); - if (sync_code != 0x498342) { - RTC_LOG(LS_WARNING) << "Failed to get QP. Invalid sync code."; - return false; + absl::optional ReadBoolean() { + uint32_t val; + if (!buffer_->ReadBits(&val, 1)) { + return {}; + } + return {val != 0}; } - return true; -} -bool Vp9ReadColorConfig(rtc::BitBuffer* br, - uint8_t profile, - FrameInfo* frame_info) { - if (profile == 0 || profile == 1) { + // 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(&val, 1)) { + 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(&val, bits)) { + 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(&val, num_bits)) { + 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(&sign, 1)) { + return {}; + } + uint32_t val; + if (!buffer_->ReadBits(&val, bits)) { + 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); } + + private: + rtc::BitBuffer* buffer_; +}; + +bool Vp9ReadColorConfig(BitstreamReader* br, FrameInfo* 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 ? BitDept::k12Bit : BitDept::k10Bit; + }); + } else { frame_info->bit_detph = BitDept::k8Bit; - } else if (profile == 2 || profile == 3) { - uint32_t ten_or_twelve_bits; - RETURN_FALSE_IF_ERROR(br->ReadBits(&ten_or_twelve_bits, 1)); - frame_info->bit_detph = - ten_or_twelve_bits ? BitDept::k12Bit : BitDept::k10Bit; } - uint32_t color_space; - RETURN_FALSE_IF_ERROR(br->ReadBits(&color_space, 3)); - frame_info->color_space = static_cast(color_space); - // SRGB is 7. - if (color_space != 7) { - uint32_t color_range; - RETURN_FALSE_IF_ERROR(br->ReadBits(&color_range, 1)); - frame_info->color_range = - color_range ? ColorRange::kFull : ColorRange::kStudio; + READ_OR_RETURN( + br->ReadUnsigned(3), [frame_info](uint8_t color_space) { + frame_info->color_space = static_cast(color_space); + }); - if (profile == 1 || profile == 3) { - uint32_t subsampling_x; - uint32_t subsampling_y; - RETURN_FALSE_IF_ERROR(br->ReadBits(&subsampling_x, 1)); - RETURN_FALSE_IF_ERROR(br->ReadBits(&subsampling_y, 1)); - if (subsampling_x) { - frame_info->sub_sampling = - subsampling_y ? YuvSubsampling::k420 : YuvSubsampling::k422; - } else { - frame_info->sub_sampling = - subsampling_y ? YuvSubsampling::k440 : YuvSubsampling::k444; - } + if (frame_info->color_space != ColorSpace::CS_RGB) { + READ_OR_RETURN(br->ReadBoolean(), [frame_info](bool color_range) { + frame_info->color_range = + color_range ? ColorRange::kFull : ColorRange::kStudio; + }); - uint32_t reserved_bit; - RETURN_FALSE_IF_ERROR(br->ReadBits(&reserved_bit, 1)); - if (reserved_bit) { - RTC_LOG(LS_WARNING) << "Failed to parse header. Reserved bit set."; - return false; - } + 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 = YuvSubsampling::k444; + break; + case 0b01: + frame_info->sub_sampling = YuvSubsampling::k440; + break; + case 0b10: + frame_info->sub_sampling = YuvSubsampling::k422; + break; + case 0b11: + frame_info->sub_sampling = YuvSubsampling::k420; + break; + } + }); + + RETURN_IF_FALSE(br->VerifyNextBooleanIs( + 0, "Failed to parse header. Reserved bit set.")); } else { // Profile 0 or 2. frame_info->sub_sampling = YuvSubsampling::k420; @@ -100,14 +205,10 @@ bool Vp9ReadColorConfig(rtc::BitBuffer* br, } else { // SRGB frame_info->color_range = ColorRange::kFull; - if (profile == 1 || profile == 3) { + if (frame_info->profile == 1 || frame_info->profile == 3) { frame_info->sub_sampling = YuvSubsampling::k444; - uint32_t reserved_bit; - RETURN_FALSE_IF_ERROR(br->ReadBits(&reserved_bit, 1)); - if (reserved_bit) { - RTC_LOG(LS_WARNING) << "Failed to parse header. Reserved bit set."; - return false; - } + RETURN_IF_FALSE(br->VerifyNextBooleanIs( + 0, "Failed to parse header. Reserved bit set.")); } else { RTC_LOG(LS_WARNING) << "Failed to parse header. 4:4:4 color not supported" " in profile 0 or 2."; @@ -118,44 +219,45 @@ bool Vp9ReadColorConfig(rtc::BitBuffer* br, return true; } -bool Vp9ReadFrameSize(rtc::BitBuffer* br, FrameInfo* frame_info) { - // 16 bits: frame width - 1. - uint16_t frame_width_minus_one; - RETURN_FALSE_IF_ERROR(br->ReadUInt16(&frame_width_minus_one)); - // 16 bits: frame height - 1. - uint16_t frame_height_minus_one; - RETURN_FALSE_IF_ERROR(br->ReadUInt16(&frame_height_minus_one)); - frame_info->frame_width = frame_width_minus_one + 1; - frame_info->frame_height = frame_height_minus_one + 1; +bool Vp9ReadFrameSize(BitstreamReader* br, FrameInfo* 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; } -bool Vp9ReadRenderSize(rtc::BitBuffer* br, FrameInfo* frame_info) { - uint32_t render_and_frame_size_different; - RETURN_FALSE_IF_ERROR(br->ReadBits(&render_and_frame_size_different, 1)); - if (render_and_frame_size_different) { - // 16 bits: render width - 1. - uint16_t render_width_minus_one; - RETURN_FALSE_IF_ERROR(br->ReadUInt16(&render_width_minus_one)); - // 16 bits: render height - 1. - uint16_t render_height_minus_one; - RETURN_FALSE_IF_ERROR(br->ReadUInt16(&render_height_minus_one)); - frame_info->render_width = render_width_minus_one + 1; - frame_info->render_height = render_height_minus_one + 1; - } else { - frame_info->render_width = frame_info->frame_width; - frame_info->render_height = frame_info->frame_height; - } - return true; +bool Vp9ReadRenderSize(BitstreamReader* br, FrameInfo* frame_info) { + // render_and_frame_size_different + return br->IfNextBoolean( + [&] { + // 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; + }); } -bool Vp9ReadFrameSizeFromRefs(rtc::BitBuffer* br, FrameInfo* frame_info) { - uint32_t found_ref = 0; - for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { +bool Vp9ReadFrameSizeFromRefs(BitstreamReader* br, FrameInfo* frame_info) { + bool found_ref = false; + for (size_t i = 0; !found_ref && i < kVp9NumRefsPerFrame; i++) { // Size in refs. - RETURN_FALSE_IF_ERROR(br->ReadBits(&found_ref, 1)); - if (found_ref) - break; + READ_OR_RETURN(br->ReadBoolean(), [&](bool ref) { found_ref = ref; }); } if (!found_ref) { @@ -166,83 +268,156 @@ bool Vp9ReadFrameSizeFromRefs(rtc::BitBuffer* br, FrameInfo* frame_info) { return Vp9ReadRenderSize(br, frame_info); } -bool Vp9ReadInterpolationFilter(rtc::BitBuffer* br) { - uint32_t bit; - RETURN_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); - if (bit) - return true; - - return br->ConsumeBits(2); -} - -bool Vp9ReadLoopfilter(rtc::BitBuffer* br) { +bool Vp9ReadLoopfilter(BitstreamReader* br) { // 6 bits: filter level. // 3 bits: sharpness level. - RETURN_FALSE_IF_ERROR(br->ConsumeBits(9)); + RETURN_IF_FALSE(br->ConsumeBits(9)); - uint32_t mode_ref_delta_enabled; - RETURN_FALSE_IF_ERROR(br->ReadBits(&mode_ref_delta_enabled, 1)); - if (mode_ref_delta_enabled) { - uint32_t mode_ref_delta_update; - RETURN_FALSE_IF_ERROR(br->ReadBits(&mode_ref_delta_update, 1)); - if (mode_ref_delta_update) { - uint32_t bit; + 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_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); - if (bit) { - RETURN_FALSE_IF_ERROR(br->ConsumeBits(7)); - } + RETURN_IF_FALSE(br->IfNextBoolean([&] { return br->ConsumeBits(7); })); } for (size_t i = 0; i < kVp9MaxModeLFDeltas; i++) { - RETURN_FALSE_IF_ERROR(br->ReadBits(&bit, 1)); - if (bit) { - RETURN_FALSE_IF_ERROR(br->ConsumeBits(7)); - } + RETURN_IF_FALSE(br->IfNextBoolean([&] { return br->ConsumeBits(7); })); } - } + return true; + }); + }); +} + +bool Vp9ReadQp(BitstreamReader* br, FrameInfo* frame_info) { + READ_OR_RETURN(br->ReadUnsigned(), + [frame_info](uint8_t qp) { frame_info->base_qp = qp; }); + + // yuv offsets + for (int i = 0; i < 3; ++i) { + RETURN_IF_FALSE(br->IfNextBoolean([br] { // if delta_coded + return br->ConsumeBits(5); + })); } return true; } -} // namespace -bool Parse(const uint8_t* buf, size_t length, int* qp, FrameInfo* frame_info) { - rtc::BitBuffer br(buf, length); +bool Vp9ReadSegmentationParams(BitstreamReader* br) { + constexpr int kVp9MaxSegments = 8; + constexpr int kVp9SegLvlMax = 4; + constexpr int kSegmentationFeatureBits[kVp9SegLvlMax] = {8, 6, 2, 0}; + constexpr bool kSegmentationFeatureSigned[kVp9SegLvlMax] = {1, 1, 0, 0}; - // Frame marker. - uint32_t frame_marker; - RETURN_FALSE_IF_ERROR(br.ReadBits(&frame_marker, 2)); - if (frame_marker != 0x2) { - RTC_LOG(LS_WARNING) << "Failed to parse header. Frame marker should be 2."; - return false; + return br->IfNextBoolean([&] { // segmentation_enabled + return br->IfNextBoolean([&] { // update_map + // Consume probs. + for (int i = 0; i < 7; ++i) { + RETURN_IF_FALSE(br->IfNextBoolean([br] { return br->ConsumeBits(7); })); + } + + return br->IfNextBoolean([&] { // temporal_update + // Consume probs. + for (int i = 0; i < 3; ++i) { + RETURN_IF_FALSE( + br->IfNextBoolean([br] { return br->ConsumeBits(7); })); + } + return true; + }); + }); + }); + + return br->IfNextBoolean([&] { + RETURN_IF_FALSE(br->ConsumeBits(1)); // abs_or_delta + for (int i = 0; i < kVp9MaxSegments; ++i) { + for (int j = 0; j < kVp9SegLvlMax; ++j) { + RETURN_IF_FALSE(br->IfNextBoolean([&] { // feature_enabled + return br->ConsumeBits(kSegmentationFeatureBits[j] + + kSegmentationFeatureSigned[j]); + })); + } + } + return true; + }); +} + +bool Vp9ReadTileInfo(BitstreamReader* br, FrameInfo* frame_info) { + size_t mi_cols = (frame_info->frame_width + 7) >> 3; + size_t sb64_cols = (mi_cols + 7) >> 3; + + size_t min_log2 = 0; + while ((kVp9MaxTileWidthB64 << min_log2) < sb64_cols) { + ++min_log2; } - // Profile. - uint8_t profile; - if (!Vp9ReadProfile(&br, &profile)) - return false; - frame_info->profile = profile; + size_t max_log2 = 1; + while ((sb64_cols >> max_log2) >= kVp9MinTileWidthB64) { + ++max_log2; + } + --max_log2; + + size_t cols_log2 = min_log2; + bool done = false; + while (!done && cols_log2 < max_log2) { + RETURN_IF_FALSE(br->IfNextBoolean( + [&] { + ++cols_log2; + return true; + }, + [&] { + done = true; + return true; + })); + } + + // rows_log2; + return br->IfNextBoolean([&] { return br->ConsumeBits(1); }); +} +} // namespace + +bool Parse(const uint8_t* buf, size_t length, FrameInfo* frame_info) { + rtc::BitBuffer bit_buffer(buf, length); + BitstreamReader br(&bit_buffer); + + // Frame marker. + RETURN_IF_FALSE(br.VerifyNextUnsignedIs( + 2, 0x2, "Failed to parse header. Frame marker should be 2.")); + + // 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.")); + } // Show existing frame. - uint32_t show_existing_frame; - RETURN_FALSE_IF_ERROR(br.ReadBits(&show_existing_frame, 1)); - if (show_existing_frame) - return false; + 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; + } - // Frame type: KEY_FRAME(0), INTER_FRAME(1). - uint32_t frame_type; - uint32_t show_frame; - uint32_t error_resilient; - RETURN_FALSE_IF_ERROR(br.ReadBits(&frame_type, 1)); - RETURN_FALSE_IF_ERROR(br.ReadBits(&show_frame, 1)); - RETURN_FALSE_IF_ERROR(br.ReadBits(&error_resilient, 1)); - frame_info->show_frame = show_frame; - frame_info->error_resilient = error_resilient; + 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; + }); - if (frame_type == 0) { - // Key-frame. - if (!Vp9ReadSyncCode(&br)) - return false; - if (!Vp9ReadColorConfig(&br, profile, frame_info)) + if (frame_info->is_keyframe) { + RETURN_IF_FALSE(br.VerifyNextUnsignedIs( + 24, 0x498342, "Failed to get QP. Invalid sync code.")); + + if (!Vp9ReadColorConfig(&br, frame_info)) return false; if (!Vp9ReadFrameSize(&br, frame_info)) return false; @@ -250,76 +425,92 @@ bool Parse(const uint8_t* buf, size_t length, int* qp, FrameInfo* frame_info) { return false; } else { // Non-keyframe. - uint32_t intra_only = 0; - if (!show_frame) - RETURN_FALSE_IF_ERROR(br.ReadBits(&intra_only, 1)); - if (!error_resilient) - RETURN_FALSE_IF_ERROR(br.ConsumeBits(2)); // Reset frame context. + bool is_intra_only = false; + if (!frame_info->show_frame) { + READ_OR_RETURN(br.ReadBoolean(), + [&](bool intra_only) { is_intra_only = intra_only; }); + } + if (!frame_info->error_resilient) { + RETURN_IF_FALSE(br.ConsumeBits(2)); // Reset frame context. + } - if (intra_only) { - if (!Vp9ReadSyncCode(&br)) - return false; + if (is_intra_only) { + RETURN_IF_FALSE(br.VerifyNextUnsignedIs( + 24, 0x498342, "Failed to get QP. Invalid sync code.")); - if (profile > 0) { - if (!Vp9ReadColorConfig(&br, profile, frame_info)) + if (frame_info->profile > 0) { + if (!Vp9ReadColorConfig(&br, frame_info)) return false; } // Refresh frame flags. - RETURN_FALSE_IF_ERROR(br.ConsumeBits(8)); + RETURN_IF_FALSE(br.ConsumeBits(8)); if (!Vp9ReadFrameSize(&br, frame_info)) return false; if (!Vp9ReadRenderSize(&br, frame_info)) return false; } else { // Refresh frame flags. - RETURN_FALSE_IF_ERROR(br.ConsumeBits(8)); + RETURN_IF_FALSE(br.ConsumeBits(8)); for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { // 3 bits: Ref frame index. // 1 bit: Ref frame sign biases. - RETURN_FALSE_IF_ERROR(br.ConsumeBits(4)); + RETURN_IF_FALSE(br.ConsumeBits(4)); } if (!Vp9ReadFrameSizeFromRefs(&br, frame_info)) return false; // Allow high precision mv. - RETURN_FALSE_IF_ERROR(br.ConsumeBits(1)); + RETURN_IF_FALSE(br.ConsumeBits(1)); // Interpolation filter. - if (!Vp9ReadInterpolationFilter(&br)) - return false; + RETURN_IF_FALSE(br.IfNextBoolean([] { return true; }, + [&br] { return br.ConsumeBits(2); })); } } - if (!error_resilient) { + if (!frame_info->error_resilient) { // 1 bit: Refresh frame context. // 1 bit: Frame parallel decoding mode. - RETURN_FALSE_IF_ERROR(br.ConsumeBits(2)); + RETURN_IF_FALSE(br.ConsumeBits(2)); } // Frame context index. - RETURN_FALSE_IF_ERROR(br.ConsumeBits(2)); + RETURN_IF_FALSE(br.ConsumeBits(2)); if (!Vp9ReadLoopfilter(&br)) return false; - // Base QP. - uint8_t base_q0; - RETURN_FALSE_IF_ERROR(br.ReadUInt8(&base_q0)); - *qp = base_q0; + // Read base QP. + RETURN_IF_FALSE(Vp9ReadQp(&br, frame_info)); + + const bool kParseFullHeader = false; + if (kParseFullHeader) { + // Currently not used, but will be needed when parsing beyond the + // uncompressed header. + RETURN_IF_FALSE(Vp9ReadSegmentationParams(&br)); + + RETURN_IF_FALSE(Vp9ReadTileInfo(&br, frame_info)); + + RETURN_IF_FALSE(br.ConsumeBits(16)); // header_size_in_bytes + } + return true; } bool GetQp(const uint8_t* buf, size_t length, int* qp) { FrameInfo frame_info; - return Parse(buf, length, qp, &frame_info); + if (!Parse(buf, length, &frame_info)) { + return false; + } + *qp = frame_info.base_qp; + return true; } absl::optional ParseIntraFrameInfo(const uint8_t* buf, size_t length) { - int qp = 0; FrameInfo frame_info; - if (Parse(buf, length, &qp, &frame_info) && frame_info.frame_width > 0) { + if (Parse(buf, length, &frame_info) && frame_info.frame_width > 0) { return frame_info; } return absl::nullopt; diff --git a/modules/video_coding/utility/vp9_uncompressed_header_parser.h b/modules/video_coding/utility/vp9_uncompressed_header_parser.h index a7f04670d2..7a5e2c058b 100644 --- a/modules/video_coding/utility/vp9_uncompressed_header_parser.h +++ b/modules/video_coding/utility/vp9_uncompressed_header_parser.h @@ -65,6 +65,8 @@ enum class YuvSubsampling { struct FrameInfo { int profile = 0; // Profile 0-3 are valid. + absl::optional show_existing_frame; + bool is_keyframe = false; bool show_frame = false; bool error_resilient = false; BitDept bit_detph = BitDept::k8Bit; @@ -75,6 +77,7 @@ struct FrameInfo { int frame_height = 0; int render_width = 0; int render_height = 0; + int base_qp = 0; }; // Parses frame information for a VP9 key-frame or all-intra frame from a