emote2ss

Animated webp to spritesheets converting tool
git clone git://bsandro.tech/emote2ss
Log | Files | Refs

commit d6d66ace68800dfd7cc40a42b41c8e0642cfc178
parent 0b1662e3fee888fddaa09c8fb362f05de9b5108e
Author: bsandro <email@bsandro.tech>
Date:   Thu,  4 May 2023 00:13:31 +0300

Decoding frames of an animation

Diffstat:
Msrc/main.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 67 insertions(+), 22 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -1,8 +1,15 @@ +/** + * Based on the libwebp example program "anim_dump" + */ + #include <stdio.h> #include "webp/decode.h" #include "webp/demux.h" #include <stdbool.h> #include <stdlib.h> +#include <assert.h> + +#define NUM_CHANNELS 4 static void print_webp_version() { int dec_ver = WebPGetDecoderVersion(); @@ -21,30 +28,52 @@ typedef struct { typedef struct { int width, height, bgcolor, loop_count; DecodedFrame *frames; - uint32_t frames_count; + uint32_t frame_count; void *raw_mem; } AnimatedImage; +void alloc_image(AnimatedImage *img, uint32_t frame_count) { + uint8_t *mem = NULL; + DecodedFrame *frames = NULL; + const uint64_t rgba_size = img->width * img->height * NUM_CHANNELS; + const uint64_t img_size = frame_count * rgba_size * sizeof(uint8_t); + const uint64_t frames_size = frame_count * sizeof(DecodedFrame); + + assert(img_size == (size_t)img_size); + assert(frames_size == (size_t)frames_size); + + printf("img mem: %lu\nframes mem: %lu\n", img_size, frames_size); + + mem = malloc(img_size); + frames = malloc(frames_size); + assert(mem != NULL); + assert(frames != NULL); + + for (uint32_t i=0; i<frame_count; ++i) { + frames[i].rgba = mem+i*rgba_size; + frames[i].duration = 0; + frames[i].is_key = false; + } + img->frame_count = frame_count; + img->frames = frames; + img->raw_mem = mem; +} + int read_file(const char *fname, const uint8_t **data, size_t *size) { - if (data == NULL || size == NULL) return -1; + assert(data != NULL); + assert(size != NULL); + *data = NULL; *size = 0; FILE *infile = fopen(fname, "rb"); - if (infile == NULL) { - fprintf(stderr, "cannot open file %s\n", fname); - return -1; - } + assert(infile != NULL); fseek(infile, 0, SEEK_END); size_t fsize = ftell(infile); printf("%s: %zu bytes\n", fname, fsize); fseek(infile, 0, SEEK_SET); uint8_t *fdata = malloc(fsize+1); - if (fdata == NULL) { - fclose(infile); - fprintf(stderr, "malloc failed\n"); - return -1; - } + assert(fdata != NULL); fdata[fsize] = '\0'; int ok = (fread(fdata, fsize, 1, infile)==1); fclose(infile); @@ -54,10 +83,8 @@ int read_file(const char *fname, const uint8_t **data, size_t *size) { free(fdata); return -1; } - *data = fdata; *size = fsize; - return 0; } @@ -79,11 +106,7 @@ int read_webp(const char *fname, AnimatedImage *anim) { } WebPAnimDecoder *dec = WebPAnimDecoderNew(&webp_data, NULL); - if (dec == NULL) { - fprintf(stderr, "decoder error\n"); - // @todo cleanup - return -1; - } + assert(dec != NULL); WebPAnimInfo anim_info; if (!WebPAnimDecoderGetInfo(dec, &anim_info)) { @@ -91,13 +114,35 @@ int read_webp(const char *fname, AnimatedImage *anim) { // @todo cleanup return -1; } - anim->frames_count = anim_info.frame_count; + + alloc_image(anim, anim_info.frame_count); anim->width = anim_info.canvas_width; anim->height = anim_info.canvas_height; anim->loop_count = anim_info.loop_count; anim->bgcolor = anim_info.bgcolor; + uint32_t frame_index = 0; + int prev_ts = 0; + while (WebPAnimDecoderHasMoreFrames(dec)) { + DecodedFrame *frame; + uint8_t *curr_rgba, *frame_rgba; + int ts; + if (!WebPAnimDecoderGetNext(dec, &frame_rgba, &ts)) { + fprintf(stderr, "error decoding frame %d\n", frame_index); + return -1; + } + assert(frame_index < anim_info.frame_count); + frame = &anim->frames[frame_index]; + curr_rgba = frame->rgba; + frame->duration = ts - prev_ts; + memcpy(curr_rgba, frame_rgba, anim->width * anim->height * NUM_CHANNELS); + // ... + ++frame_index; + prev_ts = ts; + } + WebPDataClear(&webp_data); + WebPAnimDecoderDelete(dec); return 0; } @@ -106,9 +151,9 @@ int main(int argc, const char **argv) { if (argc >= 1) { for (int i=1; i<argc; ++i) { - AnimatedImage anim = {0}; - read_webp(argv[i], &anim); - printf("dimensions: %dx%d\nframes: %d\n", anim.width, anim.height, anim.frames_count); + AnimatedImage img = {0}; + assert(read_webp(argv[i], &img) == 0); + printf("dimensions: %dx%d\nframes: %d\n", img.width, img.height, img.frame_count); } }