Skip to content

Commit 0774d21

Browse files
nicolinusg
authored andcommitted
LibGfx: Parse some of WebP 'VP8 ' chunk
This is for lossy compression, in which case a WebP file is a single VP8 key frame. This only parses the 10-byte frame header, which contains image dimensions (and some other things). For now, just dbgln_if() all data. Eventually we'll want to use at least width and height.
1 parent e56e7db commit 0774d21

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

Userland/Libraries/LibGfx/WebPLoader.cpp

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,58 @@ static ErrorOr<Chunk> decode_webp_advance_chunk(WebPLoadingContext& context, Rea
147147
}
148148

149149
// https://developers.google.com/speed/webp/docs/riff_container#simple_file_format_lossy
150+
// https://datatracker.ietf.org/doc/html/rfc6386#section-19 "Annex A: Bitstream Syntax"
150151
static ErrorOr<void> decode_webp_simple_lossy(WebPLoadingContext& context, Chunk const& vp8_chunk)
151152
{
152-
// FIXME
153-
(void)context;
154-
(void)vp8_chunk;
153+
VERIFY(vp8_chunk.type == FourCC("VP8 "));
154+
155+
if (vp8_chunk.data.size() < 10)
156+
return context.error("WebPImageDecoderPlugin: 'VP8 ' chunk too small");
157+
158+
// FIXME: Eventually, this should probably call into LibVideo/VP8,
159+
// and image decoders should move into LibImageDecoders which depends on both LibGfx and LibVideo.
160+
// (LibVideo depends on LibGfx, so LibGfx can't depend on LibVideo itself.)
161+
162+
// https://datatracker.ietf.org/doc/html/rfc6386#section-4 "Overview of Compressed Data Format"
163+
// "The decoder is simply presented with a sequence of compressed frames [...]
164+
// The first frame presented to the decompressor is [...] a key frame. [...]
165+
// [E]very compressed frame has three or more pieces. It begins with an uncompressed data chunk comprising 10 bytes in the case of key frames
166+
167+
u8 const* data = vp8_chunk.data.data();
168+
169+
// https://datatracker.ietf.org/doc/html/rfc6386#section-9.1 "Uncompressed Data Chunk"
170+
u32 frame_tag = data[0] | (data[1] << 8) | (data[2] << 16);
171+
bool is_key_frame = (frame_tag & 1) == 0; // https://www.rfc-editor.org/errata/eid5534
172+
u8 version = (frame_tag & 0xe) >> 1;
173+
bool show_frame = (frame_tag & 0x10) != 0;
174+
u32 size_of_first_partition = frame_tag >> 5;
175+
176+
if (!is_key_frame)
177+
return context.error("WebPImageDecoderPlugin: 'VP8 ' chunk not a key frame");
178+
179+
// FIXME: !show_frame does not make sense in a webp file either, probably?
180+
181+
u32 start_code = data[3] | (data[4] << 8) | (data[5] << 16);
182+
if (start_code != 0x2a019d) // https://www.rfc-editor.org/errata/eid7370
183+
return context.error("WebPImageDecoderPlugin: 'VP8 ' chunk invalid start_code");
184+
185+
// "The scaling specifications for each dimension are encoded as follows.
186+
// 0 | No upscaling (the most common case).
187+
// 1 | Upscale by 5/4.
188+
// 2 | Upscale by 5/3.
189+
// 3 | Upscale by 2."
190+
// This is a display-time operation and doesn't affect decoding.
191+
u16 width_and_horizontal_scale = data[6] | (data[7] << 8);
192+
u16 width = width_and_horizontal_scale & 0x3fff;
193+
u8 horizontal_scale = width_and_horizontal_scale >> 14;
194+
195+
u16 heigth_and_vertical_scale = data[8] | (data[9] << 8);
196+
u16 height = heigth_and_vertical_scale & 0x3fff;
197+
u8 vertical_scale = heigth_and_vertical_scale >> 14;
198+
199+
dbgln_if(WEBP_DEBUG, "version {}, show_frame {}, size_of_first_partition {}, width {}, horizontal_scale {}, height {}, vertical_scale {}",
200+
version, show_frame, size_of_first_partition, width, horizontal_scale, height, vertical_scale);
201+
155202
return {};
156203
}
157204

0 commit comments

Comments
 (0)