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