blob: a8bfc5575f241bfb6c1cf6fd312b9a43f7304aa1 [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"
asapersson86b01602015-10-20 23:55:26 -070013
jackychen98d8cf52015-05-21 11:12:02 -070014namespace webrtc {
15
16namespace vp8 {
asapersson86b01602015-10-20 23:55:26 -070017namespace {
18const size_t kCommonPayloadHeaderLength = 3;
19const size_t kKeyPayloadHeaderLength = 10;
20} // namespace
jackychen98d8cf52015-05-21 11:12:02 -070021
22static uint32_t BSwap32(uint32_t x) {
23 return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
24}
25
26static void VP8LoadFinalBytes(VP8BitReader* const br) {
27 // Only read 8bits at a time.
28 if (br->buf_ < br->buf_end_) {
29 br->bits_ += 8;
30 br->value_ = static_cast<uint32_t>(*br->buf_++) | (br->value_ << 8);
31 } else if (!br->eof_) {
32 br->value_ <<= 8;
33 br->bits_ += 8;
34 br->eof_ = 1;
35 }
36}
37
38static void VP8LoadNewBytes(VP8BitReader* const br) {
39 int BITS = 24;
40 // Read 'BITS' bits at a time.
41 if (br->buf_ + sizeof(uint32_t) <= br->buf_end_) {
42 uint32_t bits;
43 const uint32_t in_bits = *(const uint32_t*)(br->buf_);
44 br->buf_ += BITS >> 3;
45#if defined(WEBRTC_ARCH_BIG_ENDIAN)
philipel5908c712015-12-21 08:23:20 -080046 bits = static_cast<uint32_t>(in_bits);
47 if (BITS != 8 * sizeof(uint32_t))
48 bits >>= (8 * sizeof(uint32_t) - BITS);
jackychen98d8cf52015-05-21 11:12:02 -070049#else
philipel5908c712015-12-21 08:23:20 -080050 bits = BSwap32(in_bits);
51 bits >>= 32 - BITS;
jackychen98d8cf52015-05-21 11:12:02 -070052#endif
53 br->value_ = bits | (br->value_ << BITS);
54 br->bits_ += BITS;
55 } else {
56 VP8LoadFinalBytes(br);
57 }
58}
59
60static void VP8InitBitReader(VP8BitReader* const br,
61 const uint8_t* const start,
62 const uint8_t* const end) {
philipel5908c712015-12-21 08:23:20 -080063 br->range_ = 255 - 1;
64 br->buf_ = start;
jackychen98d8cf52015-05-21 11:12:02 -070065 br->buf_end_ = end;
philipel5908c712015-12-21 08:23:20 -080066 br->value_ = 0;
67 br->bits_ = -8; // To load the very first 8bits.
68 br->eof_ = 0;
jackychen98d8cf52015-05-21 11:12:02 -070069 VP8LoadNewBytes(br);
70}
71
72// Read a bit with proba 'prob'.
73static int VP8GetBit(VP8BitReader* const br, int prob) {
74 uint8_t range = br->range_;
75 if (br->bits_ < 0) {
76 VP8LoadNewBytes(br);
jackychen0a2c0542016-04-20 13:24:15 -070077 if (br->eof_)
78 return 0;
jackychen98d8cf52015-05-21 11:12:02 -070079 }
jackychen98d8cf52015-05-21 11:12:02 -070080 const int pos = br->bits_;
81 const uint8_t split = (range * prob) >> 8;
82 const uint8_t value = static_cast<uint8_t>(br->value_ >> pos);
83 int bit;
84 if (value > split) {
85 range -= split + 1;
86 br->value_ -= static_cast<uint32_t>(split + 1) << pos;
87 bit = 1;
88 } else {
89 range = split;
90 bit = 0;
91 }
92 if (range <= static_cast<uint8_t>(0x7e)) {
93 const int shift = kVP8Log2Range[range];
94 range = kVP8NewRange[range];
95 br->bits_ -= shift;
96 }
97 br->range_ = range;
98 return bit;
99}
100
101static uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
102 uint32_t v = 0;
103 while (bits-- > 0) {
104 v |= VP8GetBit(br, 0x80) << bits;
105 }
106 return v;
107}
108
109static uint32_t VP8Get(VP8BitReader* const br) {
110 return VP8GetValue(br, 1);
111}
112
113static int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
114 const int value = VP8GetValue(br, bits);
115 return VP8Get(br) ? -value : value;
116}
117
118static void ParseSegmentHeader(VP8BitReader* br) {
119 int use_segment = VP8Get(br);
120 if (use_segment) {
121 int update_map = VP8Get(br);
122 if (VP8Get(br)) {
123 int s;
124 VP8Get(br);
125 for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
philipel5908c712015-12-21 08:23:20 -0800126 VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
jackychen98d8cf52015-05-21 11:12:02 -0700127 }
128 for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
129 VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
130 }
131 }
132 if (update_map) {
133 int s;
134 for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
135 VP8Get(br) ? VP8GetValue(br, 8) : 255;
136 }
137 }
138 }
139}
140
141static void ParseFilterHeader(VP8BitReader* br) {
142 VP8Get(br);
143 VP8GetValue(br, 6);
144 VP8GetValue(br, 3);
145 int use_lf_delta = VP8Get(br);
146 if (use_lf_delta) {
147 if (VP8Get(br)) {
148 int i;
149 for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
150 if (VP8Get(br)) {
151 VP8GetSignedValue(br, 6);
152 }
153 }
154 for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
155 if (VP8Get(br)) {
156 VP8GetSignedValue(br, 6);
157 }
158 }
159 }
160 }
161}
162
asapersson86b01602015-10-20 23:55:26 -0700163bool GetQp(const uint8_t* buf, size_t length, int* qp) {
164 if (length < kCommonPayloadHeaderLength) {
165 LOG(LS_WARNING) << "Failed to get QP, invalid length.";
166 return false;
167 }
jackychen98d8cf52015-05-21 11:12:02 -0700168 VP8BitReader br;
169 const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
170 int key_frame = !(bits & 1);
171 // Size of first partition in bytes.
asapersson86b01602015-10-20 23:55:26 -0700172 uint32_t partition_length = (bits >> 5);
173 size_t header_length = kCommonPayloadHeaderLength;
jackychen98d8cf52015-05-21 11:12:02 -0700174 if (key_frame) {
asapersson86b01602015-10-20 23:55:26 -0700175 header_length = kKeyPayloadHeaderLength;
jackychen98d8cf52015-05-21 11:12:02 -0700176 }
asapersson86b01602015-10-20 23:55:26 -0700177 if (header_length + partition_length > length) {
178 LOG(LS_WARNING) << "Failed to get QP, invalid length: " << length;
179 return false;
180 }
181 buf += header_length;
182
jackychen98d8cf52015-05-21 11:12:02 -0700183 VP8InitBitReader(&br, buf, buf + partition_length);
184 if (key_frame) {
185 // Color space and pixel type.
186 VP8Get(&br);
187 VP8Get(&br);
188 }
189 ParseSegmentHeader(&br);
190 ParseFilterHeader(&br);
191 // Number of coefficient data partitions.
192 VP8GetValue(&br, 2);
193 // Base QP.
194 const int base_q0 = VP8GetValue(&br, 7);
asapersson86b01602015-10-20 23:55:26 -0700195 if (br.eof_ == 1) {
196 LOG(LS_WARNING) << "Failed to get QP, end of file reached.";
197 return false;
198 }
199 *qp = base_q0;
200 return true;
jackychen98d8cf52015-05-21 11:12:02 -0700201}
202
203} // namespace vp8
204
205} // namespace webrtc