blob: be6df00bd1979fc04a445b76c5e413d5f57a63e5 [file] [log] [blame]
// 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 "cobalt/media/filters/vp9_bool_decoder.h"
#include <algorithm>
#include "base/logging.h"
#include "cobalt/media/base/bit_reader.h"
namespace cobalt {
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
} // namespace cobalt