mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:48:11 +00:00

This does a few things: - The decoder uses a 32- or 64-bit integer as a reservoir of the data being decoded, rather than one single byte as it was previously. - `read_bool()` only refills the reservoir (value) when the size drops below one byte. Previously, it would read out a bit-sized range from the data to completely refill the 8-bit value, doing much more work than necessary for each individual read. - VP9-specific code for reading the marker bit was moved to its own function in Context.h. - A debug flag `VPX_DEBUG` was added to optionally enable checking of the final bits in a VPX ranged arithmetic decode and ensure that it contains all zeroes. These zeroes are a bitstream requirement for VP9, and are also present for all our lossy WebP test inputs currently. This can be useful to test whether all the data present in the range has been consumed. A lot of the size of this diff comes from the removal of error handling from all the range decoder reads in LibVideo/VP9 and LibGfx/WebP (VP8), since it is now checked only at the end of the range. In a benchmark decoding `Tests/LibGfx/test-inputs/4.webp`, decode times are improved by about 22.8%, reducing average runtime from 35.5ms±1.1ms down to 27.4±1.1ms. This should cause no behavioral changes.
53 lines
1.4 KiB
C++
53 lines
1.4 KiB
C++
/*
|
|
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
|
|
* Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/BitStream.h>
|
|
#include <AK/Error.h>
|
|
#include <AK/Optional.h>
|
|
#include <AK/Types.h>
|
|
|
|
namespace Gfx {
|
|
|
|
// Can decode bitstreams encoded with VP8's and VP9's arithmetic boolean encoder.
|
|
class BooleanDecoder {
|
|
public:
|
|
static ErrorOr<BooleanDecoder> initialize(ReadonlyBytes data);
|
|
|
|
/* (9.2) */
|
|
ErrorOr<bool> read_bool(u8 probability);
|
|
ErrorOr<u8> read_literal(u8 bits);
|
|
|
|
ErrorOr<void> finish_decode();
|
|
|
|
private:
|
|
using ValueType = size_t;
|
|
static constexpr u8 reserve_bytes = sizeof(ValueType) - 1;
|
|
static constexpr u8 reserve_bits = reserve_bytes * 8;
|
|
|
|
BooleanDecoder(u8 const* data, u64 bytes_left)
|
|
: m_data(data + 1)
|
|
, m_bytes_left(bytes_left - 1)
|
|
, m_range(255)
|
|
, m_value(static_cast<ValueType>(*data) << reserve_bits)
|
|
, m_value_bits_left(8)
|
|
{
|
|
}
|
|
|
|
ErrorOr<void> fill_reservoir();
|
|
|
|
u8 const* m_data;
|
|
size_t m_bytes_left { 0 };
|
|
// This value will never exceed 255. If this is a u8, the compiler will generate a truncation in read_bool().
|
|
u32 m_range { 0 };
|
|
ValueType m_value { 0 };
|
|
// Like above, this will never exceed reserve_bits, but will truncate if it is a u8.
|
|
u32 m_value_bits_left { 0 };
|
|
};
|
|
|
|
}
|