diff options
Diffstat (limited to 'vda/vp9_bool_decoder.cc')
-rw-r--r-- | vda/vp9_bool_decoder.cc | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/vda/vp9_bool_decoder.cc b/vda/vp9_bool_decoder.cc new file mode 100644 index 0000000..bf227b2 --- /dev/null +++ b/vda/vp9_bool_decoder.cc @@ -0,0 +1,164 @@ +// Copyright 2016 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. + +#include "vp9_bool_decoder.h" + +#include <algorithm> + +#include "base/logging.h" +#include "bit_reader.h" + +namespace media { + +namespace { + +// This is an optimization lookup table for the loop in spec 9.2.2. +// while BoolRange <= 128: +// read 1 bit +// BoolRange *= 2 +// This table indicates how many iterations to run for a given BoolRange. So +// the loop could be reduced to +// read (kCountToShiftTo128[BoolRange]) bits +const int kCountToShiftTo128[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, +}; +} // namespace + +Vp9BoolDecoder::Vp9BoolDecoder() {} + +Vp9BoolDecoder::~Vp9BoolDecoder() {} + +// 9.2.1 Initialization process for Boolean decoder +bool Vp9BoolDecoder::Initialize(const uint8_t* data, size_t size) { + DCHECK(data); + if (size < 1) { + DVLOG(1) << "input size of bool decoder shall be at least 1"; + valid_ = false; + return false; + } + + reader_.reset(new BitReader(data, size)); + valid_ = true; + + bool_value_ = 0; + count_to_fill_ = 8; + bool_range_ = 255; + if (ReadLiteral(1) != 0) { + DVLOG(1) << "marker bit should be 0"; + valid_ = false; + return false; + } + return true; +} + +// Fill at least |count_to_fill_| bits and prefill remain bits of |bool_value_| +// if data is enough. +bool Vp9BoolDecoder::Fill() { + DCHECK_GE(count_to_fill_, 0); + + int bits_left = reader_->bits_available(); + if (bits_left < count_to_fill_) { + valid_ = false; + DVLOG(1) << "Vp9BoolDecoder reads beyond the end of stream"; + return false; + } + + DCHECK_LE(count_to_fill_, kBoolSize); + int max_bits_to_read = kBigBoolBitSize - kBoolSize + count_to_fill_; + int bits_to_read = std::min(max_bits_to_read, bits_left); + + BigBool data; + reader_->ReadBits(bits_to_read, &data); + bool_value_ |= data << (max_bits_to_read - bits_to_read); + count_to_fill_ -= bits_to_read; + + return true; +} + +// 9.2.2 Boolean decoding process +bool Vp9BoolDecoder::ReadBool(int prob) { + DCHECK(reader_); + + if (count_to_fill_ > 0) { + if (!Fill()) + return false; + } + + unsigned int split = (bool_range_ * prob + (256 - prob)) >> kBoolSize; + BigBool big_split = static_cast<BigBool>(split) + << (kBigBoolBitSize - kBoolSize); + + bool bit; + if (bool_value_ < big_split) { + bool_range_ = split; + bit = false; + } else { + bool_range_ -= split; + bool_value_ -= big_split; + bit = true; + } + + // Need to fill |count| bits next time in order to make |bool_range_| >= + // 128. + DCHECK_LT(bool_range_, arraysize(kCountToShiftTo128)); + DCHECK_GT(bool_range_, 0u); + int count = kCountToShiftTo128[bool_range_]; + bool_range_ <<= count; + bool_value_ <<= count; + count_to_fill_ += count; + + return bit; +} + +// 9.2.4 Parsing process for read_literal +uint8_t Vp9BoolDecoder::ReadLiteral(int bits) { + DCHECK_LT(static_cast<size_t>(bits), sizeof(uint8_t) * 8); + DCHECK(reader_); + + uint8_t x = 0; + for (int i = 0; i < bits; i++) + x = 2 * x + ReadBool(128); + + return x; +} + +bool Vp9BoolDecoder::ConsumePaddingBits() { + DCHECK(reader_); + + if (count_to_fill_ > reader_->bits_available()) { + // 9.2.2 Boolean decoding process + // Although we actually don't used the value, spec says the bitstream + // should have enough bits to fill bool range, this should never happen. + DVLOG(2) << "not enough bits in bitstream to fill bool range"; + return false; + } + + if (bool_value_ != 0) { + DVLOG(1) << "prefilled padding bits are not zero"; + return false; + } + while (reader_->bits_available() > 0) { + int data; + int size_to_read = + std::min(reader_->bits_available(), static_cast<int>(sizeof(data) * 8)); + reader_->ReadBits(size_to_read, &data); + if (data != 0) { + DVLOG(1) << "padding bits are not zero"; + return false; + } + } + return true; +} + +} // namespace media |