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
14namespace webrtc {
15
16namespace vp8 {
17namespace {
18const size_t kCommonPayloadHeaderLength = 3;
19const size_t kKeyPayloadHeaderLength = 10;
20}  // namespace
21
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)
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    bits = BSwap32(in_bits);
51    bits >>= 32 - BITS;
52#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) {
63  br->range_ = 255 - 1;
64  br->buf_ = start;
65  br->buf_end_ = end;
66  br->value_ = 0;
67  br->bits_ = -8;  // To load the very first 8bits.
68  br->eof_ = 0;
69  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);
77  }
78
79  const int pos = br->bits_;
80  const uint8_t split = (range * prob) >> 8;
81  const uint8_t value = static_cast<uint8_t>(br->value_ >> pos);
82  int bit;
83  if (value > split) {
84    range -= split + 1;
85    br->value_ -= static_cast<uint32_t>(split + 1) << pos;
86    bit = 1;
87  } else {
88    range = split;
89    bit = 0;
90  }
91  if (range <= static_cast<uint8_t>(0x7e)) {
92    const int shift = kVP8Log2Range[range];
93    range = kVP8NewRange[range];
94    br->bits_ -= shift;
95  }
96  br->range_ = range;
97  return bit;
98}
99
100static uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
101  uint32_t v = 0;
102  while (bits-- > 0) {
103    v |= VP8GetBit(br, 0x80) << bits;
104  }
105  return v;
106}
107
108static uint32_t VP8Get(VP8BitReader* const br) {
109  return VP8GetValue(br, 1);
110}
111
112static int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
113  const int value = VP8GetValue(br, bits);
114  return VP8Get(br) ? -value : value;
115}
116
117static void ParseSegmentHeader(VP8BitReader* br) {
118  int use_segment = VP8Get(br);
119  if (use_segment) {
120    int update_map = VP8Get(br);
121    if (VP8Get(br)) {
122      int s;
123      VP8Get(br);
124      for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
125        VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
126      }
127      for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
128        VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
129      }
130    }
131    if (update_map) {
132      int s;
133      for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
134        VP8Get(br) ? VP8GetValue(br, 8) : 255;
135      }
136    }
137  }
138}
139
140static void ParseFilterHeader(VP8BitReader* br) {
141  VP8Get(br);
142  VP8GetValue(br, 6);
143  VP8GetValue(br, 3);
144  int use_lf_delta = VP8Get(br);
145  if (use_lf_delta) {
146    if (VP8Get(br)) {
147      int i;
148      for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
149        if (VP8Get(br)) {
150          VP8GetSignedValue(br, 6);
151        }
152      }
153      for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
154        if (VP8Get(br)) {
155          VP8GetSignedValue(br, 6);
156        }
157      }
158    }
159  }
160}
161
162bool GetQp(const uint8_t* buf, size_t length, int* qp) {
163  if (length < kCommonPayloadHeaderLength) {
164    LOG(LS_WARNING) << "Failed to get QP, invalid length.";
165    return false;
166  }
167  VP8BitReader br;
168  const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
169  int key_frame = !(bits & 1);
170  // Size of first partition in bytes.
171  uint32_t partition_length = (bits >> 5);
172  size_t header_length = kCommonPayloadHeaderLength;
173  if (key_frame) {
174    header_length = kKeyPayloadHeaderLength;
175  }
176  if (header_length + partition_length > length) {
177    LOG(LS_WARNING) << "Failed to get QP, invalid length: " << length;
178    return false;
179  }
180  buf += header_length;
181
182  VP8InitBitReader(&br, buf, buf + partition_length);
183  if (key_frame) {
184    // Color space and pixel type.
185    VP8Get(&br);
186    VP8Get(&br);
187  }
188  ParseSegmentHeader(&br);
189  ParseFilterHeader(&br);
190  // Number of coefficient data partitions.
191  VP8GetValue(&br, 2);
192  // Base QP.
193  const int base_q0 = VP8GetValue(&br, 7);
194  if (br.eof_ == 1) {
195    LOG(LS_WARNING) << "Failed to get QP, end of file reached.";
196    return false;
197  }
198  *qp = base_q0;
199  return true;
200}
201
202}  // namespace vp8
203
204}  // namespace webrtc
205