@@ -147,11 +147,58 @@ static ErrorOr<Chunk> decode_webp_advance_chunk(WebPLoadingContext& context, Rea
147
147
}
148
148
149
149
// 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"
150
151
static ErrorOr<void > decode_webp_simple_lossy (WebPLoadingContext& context, Chunk const & vp8_chunk)
151
152
{
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
+
155
202
return {};
156
203
}
157
204
0 commit comments