commit d6d66ace68800dfd7cc40a42b41c8e0642cfc178
parent 0b1662e3fee888fddaa09c8fb362f05de9b5108e
Author: bsandro <[email protected]>
Date: Thu, 4 May 2023 00:13:31 +0300
Decoding frames of an animation
Diffstat:
M | src/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);
}
}