diff options
Diffstat (limited to 'accel/vp8_bool_decoder.cc')
-rw-r--r-- | accel/vp8_bool_decoder.cc | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/accel/vp8_bool_decoder.cc b/accel/vp8_bool_decoder.cc new file mode 100644 index 0000000..68f06d0 --- /dev/null +++ b/accel/vp8_bool_decoder.cc @@ -0,0 +1,209 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Note: ported from Chromium commit head: 9b6f429 + +/* + * Copyright (c) 2010, The WebM Project authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google, nor the WebM Project, nor the names + * of its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file is modified from the dboolhuff.{c,h} from the WebM's libvpx +// project. (http://www.webmproject.org/code) +// It is used to decode bits from a vp8 stream. + +#include <limits.h> + +#include <algorithm> + +#include "base/numerics/safe_conversions.h" +#include "vp8_bool_decoder.h" + +namespace media { + +#define VP8_BD_VALUE_BIT \ + static_cast<int>(sizeof(Vp8BoolDecoder::value_) * CHAR_BIT) + +static const int kDefaultProbability = 0x80; // 0x80 / 256 = 0.5 + +// This is meant to be a large, positive constant that can still be efficiently +// loaded as an immediate (on platforms like ARM, for example). Even relatively +// modest values like 100 would work fine. +#define VP8_LOTS_OF_BITS (0x40000000) + +// The number of leading zeros. +static const unsigned char kVp8Norm[256] = { + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +Vp8BoolDecoder::Vp8BoolDecoder() + : user_buffer_(NULL), + user_buffer_end_(NULL), + value_(0), + count_(-8), + range_(255) { +} + +bool Vp8BoolDecoder::Initialize(const uint8_t* data, size_t size) { + if (data == NULL || size == 0) + return false; + user_buffer_start_ = data; + user_buffer_ = data; + user_buffer_end_ = data + size; + value_ = 0; + count_ = -8; + range_ = 255; + return true; +} + +void Vp8BoolDecoder::FillDecoder() { + DCHECK(user_buffer_ != NULL); + int shift = VP8_BD_VALUE_BIT - CHAR_BIT - (count_ + CHAR_BIT); + size_t bytes_left = user_buffer_end_ - user_buffer_; + size_t bits_left = bytes_left * CHAR_BIT; + int x = shift + CHAR_BIT - static_cast<int>(bits_left); + int loop_end = 0; + + if (x >= 0) { + count_ += VP8_LOTS_OF_BITS; + loop_end = x; + } + + if (x < 0 || bits_left) { + while (shift >= loop_end) { + count_ += CHAR_BIT; + value_ |= static_cast<size_t>(*user_buffer_) << shift; + ++user_buffer_; + shift -= CHAR_BIT; + } + } +} + +int Vp8BoolDecoder::ReadBit(int probability) { + int bit = 0; + size_t split = 1 + (((range_ - 1) * probability) >> 8); + if (count_ < 0) + FillDecoder(); + size_t bigsplit = static_cast<size_t>(split) << (VP8_BD_VALUE_BIT - 8); + + if (value_ >= bigsplit) { + range_ -= split; + value_ -= bigsplit; + bit = 1; + } else { + range_ = split; + } + + size_t shift = kVp8Norm[range_]; + range_ <<= shift; + value_ <<= shift; + count_ -= static_cast<int>(shift); + + DCHECK_EQ(1U, (range_ >> 7)); // In the range [128, 255]. + + return bit; +} + +bool Vp8BoolDecoder::ReadLiteral(size_t num_bits, int* out) { + DCHECK_LE(num_bits, sizeof(int) * CHAR_BIT); + *out = 0; + for (; num_bits > 0; --num_bits) + *out = (*out << 1) | ReadBit(kDefaultProbability); + return !OutOfBuffer(); +} + +bool Vp8BoolDecoder::ReadBool(bool* out, uint8_t probability) { + *out = !!ReadBit(probability); + return !OutOfBuffer(); +} + +bool Vp8BoolDecoder::ReadBool(bool* out) { + return ReadBool(out, kDefaultProbability); +} + +bool Vp8BoolDecoder::ReadLiteralWithSign(size_t num_bits, int* out) { + ReadLiteral(num_bits, out); + // Read sign. + if (ReadBit(kDefaultProbability)) + *out = -*out; + return !OutOfBuffer(); +} + +size_t Vp8BoolDecoder::BitOffset() { + int bit_count = count_ + 8; + if (bit_count > VP8_BD_VALUE_BIT) + // Capped at 0 to ignore buffer underrun. + bit_count = std::max(0, bit_count - VP8_LOTS_OF_BITS); + return (user_buffer_ - user_buffer_start_) * 8 - bit_count; +} + +uint8_t Vp8BoolDecoder::GetRange() { + return base::checked_cast<uint8_t>(range_); +} + +uint8_t Vp8BoolDecoder::GetBottom() { + if (count_ < 0) + FillDecoder(); + return static_cast<uint8_t>(value_ >> (VP8_BD_VALUE_BIT - 8)); +} + +inline bool Vp8BoolDecoder::OutOfBuffer() { + // Check if we have reached the end of the buffer. + // + // Variable |count_| stores the number of bits in the |value_| buffer, minus + // 8. The top byte is part of the algorithm and the remainder is buffered to + // be shifted into it. So, if |count_| == 8, the top 16 bits of |value_| are + // occupied, 8 for the algorithm and 8 in the buffer. + // + // When reading a byte from the user's buffer, |count_| is filled with 8 and + // one byte is filled into the |value_| buffer. When we reach the end of the + // data, |count_| is additionally filled with VP8_LOTS_OF_BITS. So when + // |count_| == VP8_LOTS_OF_BITS - 1, the user's data has been exhausted. + return (count_ > VP8_BD_VALUE_BIT) && (count_ < VP8_LOTS_OF_BITS); +} + +} // namespace media |