blob: 80026f9a0f404d7089aac1fabb33a6c32ad284c0 [file] [log] [blame]
jackychen98d8cf52015-05-21 11:12:02 -07001/*
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 */
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020010#include "modules/video_coding/utility/vp8_header_parser.h"
jackychen98d8cf52015-05-21 11:12:02 -070011
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020012#include "rtc_base/logging.h"
Niels Möllera12c42a2018-07-25 16:05:48 +020013#include "rtc_base/system/arch.h"
asapersson86b01602015-10-20 23:55:26 -070014
jackychen98d8cf52015-05-21 11:12:02 -070015namespace webrtc {
16
17namespace vp8 {
asapersson86b01602015-10-20 23:55:26 -070018namespace {
19const size_t kCommonPayloadHeaderLength = 3;
20const size_t kKeyPayloadHeaderLength = 10;
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010021const int kMbFeatureTreeProbs = 3;
22const int kNumMbSegments = 4;
23const int kNumRefLfDeltas = 4;
24const int kNumModeLfDeltas = 4;
25
asapersson86b01602015-10-20 23:55:26 -070026} // namespace
jackychen98d8cf52015-05-21 11:12:02 -070027
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010028// Bitstream parser according to
29// https://tools.ietf.org/html/rfc6386#section-7.3
30void VP8InitBitReader(VP8BitReader* const br,
31 const uint8_t* start,
32 const uint8_t* end) {
33 br->range_ = 255;
philipel5908c712015-12-21 08:23:20 -080034 br->buf_ = start;
jackychen98d8cf52015-05-21 11:12:02 -070035 br->buf_end_ = end;
philipel5908c712015-12-21 08:23:20 -080036 br->value_ = 0;
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010037 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 }
jackychen98d8cf52015-05-21 11:12:02 -070048}
49
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010050// 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.
53int 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;
jackychen98d8cf52015-05-21 11:12:02 -070061 } else {
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010062 retval = 0;
63 br->range_ = split;
jackychen98d8cf52015-05-21 11:12:02 -070064 }
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010065
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 }
jackychen98d8cf52015-05-21 11:12:02 -070075 }
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010076 return retval;
jackychen98d8cf52015-05-21 11:12:02 -070077}
78
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010079uint32_t VP8GetValue(VP8BitReader* br, int num_bits) {
jackychen98d8cf52015-05-21 11:12:02 -070080 uint32_t v = 0;
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010081 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);
jackychen98d8cf52015-05-21 11:12:02 -070085 }
86 return v;
87}
88
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010089// 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.
92int32_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;
jackychen98d8cf52015-05-21 11:12:02 -070096}
97
98static void ParseSegmentHeader(VP8BitReader* br) {
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +010099 int use_segment = VP8GetValue(br, 1);
jackychen98d8cf52015-05-21 11:12:02 -0700100 if (use_segment) {
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100101 int update_map = VP8GetValue(br, 1);
102 if (VP8GetValue(br, 1)) { // update_segment_feature_data.
103 VP8GetValue(br, 1); // segment_feature_mode.
jackychen98d8cf52015-05-21 11:12:02 -0700104 int s;
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100105 for (s = 0; s < kNumMbSegments; ++s) {
106 bool quantizer_update = VP8GetValue(br, 1);
107 if (quantizer_update) {
108 VP8GetSignedValue(br, 7);
109 }
jackychen98d8cf52015-05-21 11:12:02 -0700110 }
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100111 for (s = 0; s < kNumMbSegments; ++s) {
112 bool loop_filter_update = VP8GetValue(br, 1);
113 if (loop_filter_update) {
114 VP8GetSignedValue(br, 6);
115 }
jackychen98d8cf52015-05-21 11:12:02 -0700116 }
117 }
118 if (update_map) {
119 int s;
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100120 for (s = 0; s < kMbFeatureTreeProbs; ++s) {
121 bool segment_prob_update = VP8GetValue(br, 1);
122 if (segment_prob_update) {
123 VP8GetValue(br, 8);
124 }
jackychen98d8cf52015-05-21 11:12:02 -0700125 }
126 }
127 }
128}
129
130static void ParseFilterHeader(VP8BitReader* br) {
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100131 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) {
jackychen98d8cf52015-05-21 11:12:02 -0700140 int i;
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100141 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.
jackychen98d8cf52015-05-21 11:12:02 -0700145 }
146 }
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100147 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.
jackychen98d8cf52015-05-21 11:12:02 -0700151 }
152 }
153 }
154 }
155}
156
asapersson86b01602015-10-20 23:55:26 -0700157bool GetQp(const uint8_t* buf, size_t length, int* qp) {
158 if (length < kCommonPayloadHeaderLength) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100159 RTC_LOG(LS_WARNING) << "Failed to get QP, invalid length.";
asapersson86b01602015-10-20 23:55:26 -0700160 return false;
161 }
jackychen98d8cf52015-05-21 11:12:02 -0700162 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.
asapersson86b01602015-10-20 23:55:26 -0700166 uint32_t partition_length = (bits >> 5);
167 size_t header_length = kCommonPayloadHeaderLength;
jackychen98d8cf52015-05-21 11:12:02 -0700168 if (key_frame) {
asapersson86b01602015-10-20 23:55:26 -0700169 header_length = kKeyPayloadHeaderLength;
jackychen98d8cf52015-05-21 11:12:02 -0700170 }
asapersson86b01602015-10-20 23:55:26 -0700171 if (header_length + partition_length > length) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100172 RTC_LOG(LS_WARNING) << "Failed to get QP, invalid length: " << length;
asapersson86b01602015-10-20 23:55:26 -0700173 return false;
174 }
175 buf += header_length;
176
jackychen98d8cf52015-05-21 11:12:02 -0700177 VP8InitBitReader(&br, buf, buf + partition_length);
178 if (key_frame) {
179 // Color space and pixel type.
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100180 VP8GetValue(&br, 1);
181 VP8GetValue(&br, 1);
jackychen98d8cf52015-05-21 11:12:02 -0700182 }
183 ParseSegmentHeader(&br);
184 ParseFilterHeader(&br);
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100185 // Parse log2_nbr_of_dct_partitions value.
jackychen98d8cf52015-05-21 11:12:02 -0700186 VP8GetValue(&br, 2);
187 // Base QP.
188 const int base_q0 = VP8GetValue(&br, 7);
Ilya Nikolaevskiyae922442020-03-02 15:04:55 +0100189 if (br.buf_ == br.buf_end_) {
190 RTC_LOG(LS_WARNING) << "Failed to get QP, bitstream is truncated or"
191 " corrupted.";
asapersson86b01602015-10-20 23:55:26 -0700192 return false;
193 }
194 *qp = base_q0;
195 return true;
jackychen98d8cf52015-05-21 11:12:02 -0700196}
197
198} // namespace vp8
199
200} // namespace webrtc