1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:37:35 +00:00

LibGfx/LibVideo: Read batches of multiple bytes in VPX BooleanDecoder

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.
This commit is contained in:
Zaggy1024 2023-06-02 13:52:40 -05:00 committed by Andreas Kling
parent edd847798a
commit 873b0e9470
7 changed files with 131 additions and 62 deletions

View file

@ -1141,9 +1141,7 @@ ErrorOr<void> decode_VP8_image_data(Gfx::Bitmap& bitmap, FrameHeader const& head
Vector<BooleanDecoder> streams;
for (auto data : data_partitions) {
auto memory_stream = make<FixedMemoryStream>(data);
auto bit_stream = make<BigEndianInputBitStream>(move(memory_stream));
auto decoder = TRY(BooleanDecoder::initialize(move(bit_stream), data.size() * 8));
auto decoder = TRY(BooleanDecoder::initialize(data));
TRY(streams.try_append(move(decoder)));
}
@ -1221,6 +1219,9 @@ ErrorOr<void> decode_VP8_image_data(Gfx::Bitmap& bitmap, FrameHeader const& head
}
}
for (auto& decoder : streams)
TRY(decoder.finish_decode());
return {};
}
@ -1263,9 +1264,7 @@ static ErrorOr<Vector<ReadonlyBytes>> split_data_partitions(ReadonlyBytes second
ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8_contents(VP8Header const& vp8_header, bool include_alpha_channel)
{
// The first partition stores header, per-segment state, and macroblock metadata.
FixedMemoryStream memory_stream { vp8_header.first_partition };
BigEndianInputBitStream bit_stream { MaybeOwned<Stream>(memory_stream) };
auto decoder = TRY(BooleanDecoder::initialize(MaybeOwned { bit_stream }, vp8_header.first_partition.size() * 8));
auto decoder = TRY(BooleanDecoder::initialize(vp8_header.first_partition));
auto header = TRY(decode_VP8_frame_header(decoder));
@ -1278,6 +1277,7 @@ ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8_contents(VP8Header const& v
auto macroblock_metadata = TRY(decode_VP8_macroblock_metadata(decoder, header, macroblock_width, macroblock_height));
TRY(decoder.finish_decode());
// Done with the first partition!
auto bitmap_format = include_alpha_channel ? BitmapFormat::BGRA8888 : BitmapFormat::BGRx8888;