xref: /aosp_15_r20/external/webrtc/modules/video_coding/utility/vp8_header_parser.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "modules/video_coding/utility/vp8_header_parser.h"
11 
12 #include "rtc_base/logging.h"
13 #include "rtc_base/system/arch.h"
14 
15 namespace webrtc {
16 
17 namespace vp8 {
18 namespace {
19 const size_t kCommonPayloadHeaderLength = 3;
20 const size_t kKeyPayloadHeaderLength = 10;
21 const int kMbFeatureTreeProbs = 3;
22 const int kNumMbSegments = 4;
23 const int kNumRefLfDeltas = 4;
24 const int kNumModeLfDeltas = 4;
25 
26 }  // namespace
27 
28 // Bitstream parser according to
29 // https://tools.ietf.org/html/rfc6386#section-7.3
VP8InitBitReader(VP8BitReader * const br,const uint8_t * start,const uint8_t * end)30 void VP8InitBitReader(VP8BitReader* const br,
31                       const uint8_t* start,
32                       const uint8_t* end) {
33   br->range_ = 255;
34   br->buf_ = start;
35   br->buf_end_ = end;
36   br->value_ = 0;
37   br->bits_ = 0;
38 
39   // Read 2 bytes.
40   int i = 0;
41   while (++i <= 2) {
42     if (br->buf_ != br->buf_end_) {
43       br->value_ = br->value_ << 8 | *br->buf_++;
44     } else {
45       br->value_ = br->value_ << 8;
46     }
47   }
48 }
49 
50 // Bit decoder according to https://tools.ietf.org/html/rfc6386#section-7.3
51 // Reads one bit from the bitstream, given that it has probability prob/256 to
52 // be 1.
Vp8BitReaderGetBool(VP8BitReader * br,int prob)53 int Vp8BitReaderGetBool(VP8BitReader* br, int prob) {
54   uint32_t split = 1 + (((br->range_ - 1) * prob) >> 8);
55   uint32_t split_hi = split << 8;
56   int retval = 0;
57   if (br->value_ >= split_hi) {
58     retval = 1;
59     br->range_ -= split;
60     br->value_ -= split_hi;
61   } else {
62     retval = 0;
63     br->range_ = split;
64   }
65 
66   while (br->range_ < 128) {
67     br->value_ <<= 1;
68     br->range_ <<= 1;
69     if (++br->bits_ == 8) {
70       br->bits_ = 0;
71       if (br->buf_ != br->buf_end_) {
72         br->value_ |= *br->buf_++;
73       }
74     }
75   }
76   return retval;
77 }
78 
VP8GetValue(VP8BitReader * br,int num_bits)79 uint32_t VP8GetValue(VP8BitReader* br, int num_bits) {
80   uint32_t v = 0;
81   while (num_bits--) {
82     // According to https://tools.ietf.org/html/rfc6386
83     // Probability 128/256 is used to encode header fields.
84     v = (v << 1) | Vp8BitReaderGetBool(br, 128);
85   }
86   return v;
87 }
88 
89 // Not a read_signed_literal() from RFC 6386!
90 // This one is used to read e.g. quantizer_update, which is written as:
91 // L(num_bits), sign-bit.
VP8GetSignedValue(VP8BitReader * br,int num_bits)92 int32_t VP8GetSignedValue(VP8BitReader* br, int num_bits) {
93   int v = VP8GetValue(br, num_bits);
94   int sign = VP8GetValue(br, 1);
95   return sign ? -v : v;
96 }
97 
ParseSegmentHeader(VP8BitReader * br)98 static void ParseSegmentHeader(VP8BitReader* br) {
99   int use_segment = VP8GetValue(br, 1);
100   if (use_segment) {
101     int update_map = VP8GetValue(br, 1);
102     if (VP8GetValue(br, 1)) {  // update_segment_feature_data.
103       VP8GetValue(br, 1);      // segment_feature_mode.
104       int s;
105       for (s = 0; s < kNumMbSegments; ++s) {
106         bool quantizer_update = VP8GetValue(br, 1);
107         if (quantizer_update) {
108           VP8GetSignedValue(br, 7);
109         }
110       }
111       for (s = 0; s < kNumMbSegments; ++s) {
112         bool loop_filter_update = VP8GetValue(br, 1);
113         if (loop_filter_update) {
114           VP8GetSignedValue(br, 6);
115         }
116       }
117     }
118     if (update_map) {
119       int s;
120       for (s = 0; s < kMbFeatureTreeProbs; ++s) {
121         bool segment_prob_update = VP8GetValue(br, 1);
122         if (segment_prob_update) {
123           VP8GetValue(br, 8);
124         }
125       }
126     }
127   }
128 }
129 
ParseFilterHeader(VP8BitReader * br)130 static void ParseFilterHeader(VP8BitReader* br) {
131   VP8GetValue(br, 1);  // filter_type.
132   VP8GetValue(br, 6);  // loop_filter_level.
133   VP8GetValue(br, 3);  // sharpness_level.
134 
135   // mb_lf_adjustments.
136   int loop_filter_adj_enable = VP8GetValue(br, 1);
137   if (loop_filter_adj_enable) {
138     int mode_ref_lf_delta_update = VP8GetValue(br, 1);
139     if (mode_ref_lf_delta_update) {
140       int i;
141       for (i = 0; i < kNumRefLfDeltas; ++i) {
142         int ref_frame_delta_update_flag = VP8GetValue(br, 1);
143         if (ref_frame_delta_update_flag) {
144           VP8GetSignedValue(br, 6);  // delta_magnitude.
145         }
146       }
147       for (i = 0; i < kNumModeLfDeltas; ++i) {
148         int mb_mode_delta_update_flag = VP8GetValue(br, 1);
149         if (mb_mode_delta_update_flag) {
150           VP8GetSignedValue(br, 6);  // delta_magnitude.
151         }
152       }
153     }
154   }
155 }
156 
GetQp(const uint8_t * buf,size_t length,int * qp)157 bool GetQp(const uint8_t* buf, size_t length, int* qp) {
158   if (length < kCommonPayloadHeaderLength) {
159     RTC_LOG(LS_WARNING) << "Failed to get QP, invalid length.";
160     return false;
161   }
162   VP8BitReader br;
163   const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
164   int key_frame = !(bits & 1);
165   // Size of first partition in bytes.
166   uint32_t partition_length = (bits >> 5);
167   size_t header_length = kCommonPayloadHeaderLength;
168   if (key_frame) {
169     header_length = kKeyPayloadHeaderLength;
170   }
171   if (header_length + partition_length > length) {
172     RTC_LOG(LS_WARNING) << "Failed to get QP, invalid length: " << length;
173     return false;
174   }
175   buf += header_length;
176 
177   VP8InitBitReader(&br, buf, buf + partition_length);
178   if (key_frame) {
179     // Color space and pixel type.
180     VP8GetValue(&br, 1);
181     VP8GetValue(&br, 1);
182   }
183   ParseSegmentHeader(&br);
184   ParseFilterHeader(&br);
185   // Parse log2_nbr_of_dct_partitions value.
186   VP8GetValue(&br, 2);
187   // Base QP.
188   const int base_q0 = VP8GetValue(&br, 7);
189   if (br.buf_ == br.buf_end_) {
190     RTC_LOG(LS_WARNING) << "Failed to get QP, bitstream is truncated or"
191                            " corrupted.";
192     return false;
193   }
194   *qp = base_q0;
195   return true;
196 }
197 
198 }  // namespace vp8
199 
200 }  // namespace webrtc
201