This basically adds the line
u8 token = TRY(
tree_decode(decoder, COEFFICIENT_TREE,
header.coefficient_probabilities[plane][band][tricky],
last_decoded_value == DCT_0 ? 2 : 0));
and calls it once for the 16 coefficients of a discrete cosine transform
that covers a 4x4 pixel subblock.
And then it does this 24 or 25 times per macroblock, for the 4x4 Y
subblocks and the 2x2 each U and V subblocks (plus an optional Y2 block
for some macroblocks).
It then adds a whole bunch of machinery to be able to compute `plane`,
`band`, and in particular `tricky` (which depends on if the
corresponding left or above subblock has non-zero coefficients).
(It also does dequantization, and does an inverse Walsh-Hadamard
transform when needed, to end up with complete DCT coefficients
in all cases.)
Also add `vp8_short_inv_walsh4x4_c()` from the spec for the inverse
Walsh-Hadamard transform. The YUV output data must bitwise match the
behavior of the spec, so there isn't a ton of flexibility of how to
do this particular function.
This will contain several of the fixed data tables from the VP8 spec.
For starters, it contains the tables needed to read the frame header
in the first partition. These tables are needed to read the
probabilities of the metablock predicition modes, which in turn will
be needed to read the metablock predicition modes themselves.
...and keep a forwarding header around in VP9, so we don't have to
update all references to the class there.
In time, we probably want to merge LibGfx/ImageDecoders and LibVideo
into LibMedia, but for now I need just this class for the lossy
webp decoder. So move just it over.
No behvior change.
Pixels will leave the lossy decoder with alpha set to 255.
The old code would be a no-op in that case.
No observable behavior change yet, since there still is no
decoder for lossy webp.
In practice, it looks like e.g. the animaged webp file on
https://mathiasbynens.be/demo/animated-webp has the header flag set,
because 2 of the frames have alpha, but they're composited on top of
the final bitmap, but the final bitmap isn't transparent there. So
that image still gets a useless alpha channel. Oh well.
This is done by adding an intermediate buffer and flush it at the end of
every row. This makes the `add_pixels` method to drop from 50% to 7% in
profiles.
As we directly write to the stream, we don't need to store a copy of the
entire image in memory. However, writing to a stream is heavier on the
CPU than to a ByteBuffer. This commit unfortunately makes `add_pixels`
two times slower.
This is done by two distinct things:
- Allowing 12 bits AC and DC coefficients
- Adjusting coefficients in the IDCT
While this patch allows to display them we still don't correctly do
the color transformation and ultimately only truncating coefficients to
8 bits.
More precisely, it allows the decoder to try `SOF1` images. There are
still some sub-kind of this kind of JPEG that we don't support. In a
nutshell `SOF1` images allow more Huffman and quantization tables, 12
bits precision and arithmetic encoding. This patch only brings support
for the "more tables" part.
Please note that `SOF2` images are also allowed to have more tables, so
we gave the decoder the ability to handle these in the same time.
Pure code move (except of removing `static` on the two public functions
in the new header), not behavior change.
There isn't a lot of lossy decoder yet, but it'll make implementing it
more convenient.
No behavior change.
Namely:
* Store compressed data in VP8Header
* Make the functions just take ReadonlyBytes instead of a Chunk
Having a function that takes a header and does decoding of the data
after the header isn't really necessary for VP8. For VP8L, it's needed
because the ALPH chunk stores VP8L data without the VP8L header.
But it's nice to make the functions consistent, and it's kind of a
nice structure.
No behavior change.
decode_webp_chunk_VP8() itself will only ever decode RGB data from a
lossy webp stream, but a separate ALPH chunk could add alpha data
later on. Let the function know if that will happen, so that it can
return a bitmap with an alpha channel if appropriate.
Since lossy decoding isn't implemented yet, no behavior change. But it
makes it a bit easier to implement lossy decoding in the future.
The one caller checked the chunk type, so the VERIFY() for that did
nothing.
The VERIFY() for vp8l data only being in files that start with
VP8L or VP8X chunks wasn't completely useless, but also not very
useful.
Remove the now-unused context parameter of decode_webp_image_data().
Most places used to call `context.error()` to report an error,
which would set the context's state to `Error` and then return an
`Error::from_string_literal()`.
This is somewhat elegant, but it doesn't work: Some functions this
code calls returns ErrorOr<>s that aren't created by `context.error()`,
and for these we wouldn't enter the error state.
Instead, manually check error-ness at the leaf entry functions of the
class:
1. Add a set_error() helper for functions returning bool
2. In the two functions returning ErrorOr<>, awkwardly check the error
manually. If this becomes a very common pattern, maybe we can add
a `TRY_WITH_HANDLER(expr, error_lambda)` which would invoke a
lambda on error. We could use that here to set the error code.
No real behavior change (except we enter the error state more often
when something goes wrong).
Instead of ImageData having an Optional<Chunk> for the image data,
have it have a Chunk, and give the context an Optional<ImageData>.
This allows sharing a single code path for checking that either the
main image or an animation frame has a main image data chunk, and
that an alpha chunk is only present with a lossy main image data
chunk.
No behavior change.
Instead of testing all possible code to find the good symbol, we use a
lookup table to directly find the expected symbol. This method is used
by most Huffman decoder (gzip or libjpeg-turbo).
In order to use the correct key when peeking a constant number of bits
from the stream, we generate duplicates in the table. As an example, for
the code 110, all entries with that pattern 110***** will be set to
110's symbol. So, when you read this code plus garbage from following
codes, you still find the correct symbol.
Advantages of encapsulation are really obvious here:
- Put related code together
- Prevent external functions to modify the object
- Abstract the implementation
No functional changes intended.
A compressed ALPH chunk is a lossless webp bitstream, but without
the 5 byte "header" that stores width, height, is-alpha-channel-used
(it never is for an ALPH chunk since the ALPH chunk gets the alpha
data out of the lossless webp's green channel), and version fields.
For that reason, this cuts decode_webp_chunk_VP8L() into the
header-reading part and the remaining part, so that the remaining
part can be called by the ALPH reading routine.
Lossy webp files with a (losslessly) compressed alpha channel can
be found in the wild. Since we can't decode lossy webp data yet,
change the `#if 0` in decode_webp_chunk_VP8() to `#if 1` to test this.