webpdec.h: single-file WebP decoder
libwebp 1.6.0's decode + demux path (lossy VP8, lossless VP8L, VP8X container, ALPH alpha, and the WebPDemux/WebPAnimDecoder animation API) amalgamated into one stb-style header, built as portable C99 with all SIMD, threads and host file I/O disabled. amalgamate.py regenerates webpdec.h from a pinned, auto-cloned libwebp checkout; tests/run.sh checks decode output bit-exactly against reference libwebp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/* exercises the demux + animation API folded into the single header */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WEBPDEC_IMPLEMENTATION
|
||||
#include "webpdec.h"
|
||||
|
||||
static unsigned char* slurp(const char* p, size_t* n){
|
||||
FILE* f=fopen(p,"rb"); if(!f) return 0;
|
||||
fseek(f,0,SEEK_END); long L=ftell(f); fseek(f,0,SEEK_SET);
|
||||
unsigned char* b=malloc(L); if(fread(b,1,L,f)!=(size_t)L){} fclose(f); *n=L; return b;
|
||||
}
|
||||
|
||||
int main(int argc,char**argv){
|
||||
size_t n; unsigned char* buf=slurp(argv[1],&n);
|
||||
if(!buf){ printf("no file\n"); return 1; }
|
||||
|
||||
WebPData data = { buf, n };
|
||||
|
||||
/* --- demux: report canvas + frame/loop count --- */
|
||||
WebPDemuxer* dmux = WebPDemux(&data);
|
||||
if(!dmux){ printf("WebPDemux failed\n"); return 1; }
|
||||
unsigned cw = WebPDemuxGetI(dmux, WEBP_FF_CANVAS_WIDTH);
|
||||
unsigned ch = WebPDemuxGetI(dmux, WEBP_FF_CANVAS_HEIGHT);
|
||||
unsigned nf = WebPDemuxGetI(dmux, WEBP_FF_FRAME_COUNT);
|
||||
unsigned lp = WebPDemuxGetI(dmux, WEBP_FF_LOOP_COUNT);
|
||||
unsigned fl = WebPDemuxGetI(dmux, WEBP_FF_FORMAT_FLAGS);
|
||||
printf("demux: canvas=%ux%u frames=%u loop=%u flags=0x%x\n", cw,ch,nf,lp,fl);
|
||||
WebPDemuxDelete(dmux);
|
||||
|
||||
/* --- animation: decode every frame via WebPAnimDecoder --- */
|
||||
WebPAnimDecoderOptions opt;
|
||||
WebPAnimDecoderOptionsInit(&opt);
|
||||
opt.color_mode = MODE_RGBA;
|
||||
WebPAnimDecoder* adec = WebPAnimDecoderNew(&data, &opt);
|
||||
if(!adec){ printf("WebPAnimDecoderNew failed\n"); return 1; }
|
||||
WebPAnimInfo info;
|
||||
WebPAnimDecoderGetInfo(adec, &info);
|
||||
printf("anim: %ux%u frames=%u loops=%u bgcolor=0x%08x\n",
|
||||
info.canvas_width, info.canvas_height, info.frame_count,
|
||||
info.loop_count, info.bgcolor);
|
||||
int prev = 0, got = 0;
|
||||
while (WebPAnimDecoderHasMoreFrames(adec)) {
|
||||
uint8_t* frgba; int ts;
|
||||
if (!WebPAnimDecoderGetNext(adec, &frgba, &ts)) { printf("GetNext failed\n"); break; }
|
||||
long c = ((long)info.canvas_height/2*info.canvas_width + info.canvas_width/2)*4;
|
||||
printf(" frame %d ts=%dms (+%dms) centerRGBA=%d,%d,%d,%d\n",
|
||||
got, ts, ts-prev, frgba[c],frgba[c+1],frgba[c+2],frgba[c+3]);
|
||||
prev = ts; got++;
|
||||
}
|
||||
printf("decoded %d/%u frames -> %s\n", got, info.frame_count,
|
||||
(got==(int)info.frame_count)?"OK":"MISMATCH");
|
||||
WebPAnimDecoderDelete(adec);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user