blob: 6b65fad4007fb80affabe9fda22348d48e8c3104 [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;
21} // namespace
jackychen98d8cf52015-05-21 11:12:02 -070022
23static uint32_t BSwap32(uint32_t x) {
24 return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
25}
26
27static void VP8LoadFinalBytes(VP8BitReader* const br) {
28 // Only read 8bits at a time.
29 if (br->buf_ < br->buf_end_) {
30 br->bits_ += 8;
31 br->value_ = static_cast<uint32_t>(*br->buf_++) | (br->value_ << 8);
32 } else if (!br->eof_) {
33 br->value_ <<= 8;
34 br->bits_ += 8;
35 br->eof_ = 1;
36 }
37}
38
39static void VP8LoadNewBytes(VP8BitReader* const br) {
40 int BITS = 24;
41 // Read 'BITS' bits at a time.
42 if (br->buf_ + sizeof(uint32_t) <= br->buf_end_) {
43 uint32_t bits;
44 const uint32_t in_bits = *(const uint32_t*)(br->buf_);
45 br->buf_ += BITS >> 3;
46#if defined(WEBRTC_ARCH_BIG_ENDIAN)
philipel5908c712015-12-21 08:23:20 -080047 bits = static_cast<uint32_t>(in_bits);
48 if (BITS != 8 * sizeof(uint32_t))
49 bits >>= (8 * sizeof(uint32_t) - BITS);
jackychen98d8cf52015-05-21 11:12:02 -070050#else
philipel5908c712015-12-21 08:23:20 -080051 bits = BSwap32(in_bits);
52 bits >>= 32 - BITS;
jackychen98d8cf52015-05-21 11:12:02 -070053#endif
54 br->value_ = bits | (br->value_ << BITS);
55 br->bits_ += BITS;
56 } else {
57 VP8LoadFinalBytes(br);
58 }
59}
60
61static void VP8InitBitReader(VP8BitReader* const br,
62 const uint8_t* const start,
63 const uint8_t* const end) {
philipel5908c712015-12-21 08:23:20 -080064 br->range_ = 255 - 1;
65 br->buf_ = start;
jackychen98d8cf52015-05-21 11:12:02 -070066 br->buf_end_ = end;
philipel5908c712015-12-21 08:23:20 -080067 br->value_ = 0;
68 br->bits_ = -8; // To load the very first 8bits.
69 br->eof_ = 0;
jackychen98d8cf52015-05-21 11:12:02 -070070 VP8LoadNewBytes(br);
71}
72
73// Read a bit with proba 'prob'.
74static int VP8GetBit(VP8BitReader* const br, int prob) {
75 uint8_t range = br->range_;
76 if (br->bits_ < 0) {
77 VP8LoadNewBytes(br);
jackychen0a2c0542016-04-20 13:24:15 -070078 if (br->eof_)
79 return 0;
jackychen98d8cf52015-05-21 11:12:02 -070080 }
jackychen98d8cf52015-05-21 11:12:02 -070081 const int pos = br->bits_;
82 const uint8_t split = (range * prob) >> 8;
83 const uint8_t value = static_cast<uint8_t>(br->value_ >> pos);
84 int bit;
85 if (value > split) {
86 range -= split + 1;
87 br->value_ -= static_cast<uint32_t>(split + 1) << pos;
88 bit = 1;
89 } else {
90 range = split;
91 bit = 0;
92 }
93 if (range <= static_cast<uint8_t>(0x7e)) {
94 const int shift = kVP8Log2Range[range];
95 range = kVP8NewRange[range];
96 br->bits_ -= shift;
97 }
98 br->range_ = range;
99 return bit;
100}
101
102static uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
103 uint32_t v = 0;
104 while (bits-- > 0) {
105 v |= VP8GetBit(br, 0x80) << bits;
106 }
107 return v;
108}
109
110static uint32_t VP8Get(VP8BitReader* const br) {
111 return VP8GetValue(br, 1);
112}
113
114static int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
115 const int value = VP8GetValue(br, bits);
116 return VP8Get(br) ? -value : value;
117}
118
119static void ParseSegmentHeader(VP8BitReader* br) {
120 int use_segment = VP8Get(br);
121 if (use_segment) {
122 int update_map = VP8Get(br);
123 if (VP8Get(br)) {
124 int s;
125 VP8Get(br);
126 for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
philipel5908c712015-12-21 08:23:20 -0800127 VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
jackychen98d8cf52015-05-21 11:12:02 -0700128 }
129 for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
130 VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
131 }
132 }
133 if (update_map) {
134 int s;
135 for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
136 VP8Get(br) ? VP8GetValue(br, 8) : 255;
137 }
138 }
139 }
140}
141
142static void ParseFilterHeader(VP8BitReader* br) {
143 VP8Get(br);
144 VP8GetValue(br, 6);
145 VP8GetValue(br, 3);
146 int use_lf_delta = VP8Get(br);
147 if (use_lf_delta) {
148 if (VP8Get(br)) {
149 int i;
150 for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
151 if (VP8Get(br)) {
152 VP8GetSignedValue(br, 6);
153 }
154 }
155 for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
156 if (VP8Get(br)) {
157 VP8GetSignedValue(br, 6);
158 }
159 }
160 }
161 }
162}
163
asapersson86b01602015-10-20 23:55:26 -0700164bool GetQp(const uint8_t* buf, size_t length, int* qp) {
165 if (length < kCommonPayloadHeaderLength) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100166 RTC_LOG(LS_WARNING) << "Failed to get QP, invalid length.";
asapersson86b01602015-10-20 23:55:26 -0700167 return false;
168 }
jackychen98d8cf52015-05-21 11:12:02 -0700169 VP8BitReader br;
170 const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
171 int key_frame = !(bits & 1);
172 // Size of first partition in bytes.
asapersson86b01602015-10-20 23:55:26 -0700173 uint32_t partition_length = (bits >> 5);
174 size_t header_length = kCommonPayloadHeaderLength;
jackychen98d8cf52015-05-21 11:12:02 -0700175 if (key_frame) {
asapersson86b01602015-10-20 23:55:26 -0700176 header_length = kKeyPayloadHeaderLength;
jackychen98d8cf52015-05-21 11:12:02 -0700177 }
asapersson86b01602015-10-20 23:55:26 -0700178 if (header_length + partition_length > length) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100179 RTC_LOG(LS_WARNING) << "Failed to get QP, invalid length: " << length;
asapersson86b01602015-10-20 23:55:26 -0700180 return false;
181 }
182 buf += header_length;
183
jackychen98d8cf52015-05-21 11:12:02 -0700184 VP8InitBitReader(&br, buf, buf + partition_length);
185 if (key_frame) {
186 // Color space and pixel type.
187 VP8Get(&br);
188 VP8Get(&br);
189 }
190 ParseSegmentHeader(&br);
191 ParseFilterHeader(&br);
192 // Number of coefficient data partitions.
193 VP8GetValue(&br, 2);
194 // Base QP.
195 const int base_q0 = VP8GetValue(&br, 7);
asapersson86b01602015-10-20 23:55:26 -0700196 if (br.eof_ == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100197 RTC_LOG(LS_WARNING) << "Failed to get QP, end of file reached.";
asapersson86b01602015-10-20 23:55:26 -0700198 return false;
199 }
200 *qp = base_q0;
201 return true;
jackychen98d8cf52015-05-21 11:12:02 -0700202}
203
204} // namespace vp8
205
206} // namespace webrtc