/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // Derived from Stagefright's ABitReader. #include "BitReader.h" namespace mozilla { BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer) : BitReader(aBuffer->Elements(), aBuffer->Length() * 8) { } BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer, size_t aBits) : BitReader(aBuffer->Elements(), aBits) { } BitReader::BitReader(const uint8_t* aBuffer, size_t aBits) : mData(aBuffer) , mOriginalBitSize(aBits) , mTotalBitsLeft(aBits) , mSize((aBits + 7) / 8) , mReservoir(0) , mNumBitsLeft(0) { } BitReader::~BitReader() { } uint32_t BitReader::ReadBits(size_t aNum) { MOZ_ASSERT(aNum <= 32); if (mTotalBitsLeft < aNum) { NS_ASSERTION(false, "Reading past end of buffer"); return 0; } uint32_t result = 0; while (aNum > 0) { if (mNumBitsLeft == 0) { FillReservoir(); } size_t m = aNum; if (m > mNumBitsLeft) { m = mNumBitsLeft; } result = (result << m) | (mReservoir >> (32 - m)); mReservoir <<= m; mNumBitsLeft -= m; mTotalBitsLeft -= m; aNum -= m; } return result; } // Read unsigned integer Exp-Golomb-coded. uint32_t BitReader::ReadUE() { uint32_t i = 0; while (ReadBit() == 0 && i < 32) { i++; } if (i == 32) { // This can happen if the data is invalid, or if it's // short, since ReadBit() will return 0 when it runs // off the end of the buffer. NS_WARNING("Invalid H.264 data"); return 0; } uint32_t r = ReadBits(i); r += (1 << i) - 1; return r; } // Read signed integer Exp-Golomb-coded. int32_t BitReader::ReadSE() { int32_t r = ReadUE(); if (r & 1) { return (r+1) / 2; } else { return -r / 2; } } uint64_t BitReader::ReadU64() { uint64_t hi = ReadU32(); uint32_t lo = ReadU32(); return (hi << 32) | lo; } uint64_t BitReader::ReadUTF8() { int64_t val = ReadBits(8); uint32_t top = (val & 0x80) >> 1; if ((val & 0xc0) == 0x80 || val >= 0xFE) { // error. return -1; } while (val & top) { int tmp = ReadBits(8) - 128; if (tmp >> 6) { // error. return -1; } val = (val << 6) + tmp; top <<= 5; } val &= (top << 1) - 1; return val; } size_t BitReader::BitCount() const { return mOriginalBitSize - mTotalBitsLeft; } size_t BitReader::BitsLeft() const { return mTotalBitsLeft; } void BitReader::FillReservoir() { if (mSize == 0) { NS_ASSERTION(false, "Attempting to fill reservoir from past end of data"); return; } mReservoir = 0; size_t i; for (i = 0; mSize > 0 && i < 4; i++) { mReservoir = (mReservoir << 8) | *mData; mData++; mSize--; } mNumBitsLeft = 8 * i; mReservoir <<= 32 - mNumBitsLeft; } } // namespace mozilla