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