animation.c (3504B)
1 #define _GNU_SOURCE 2 3 #include "animation.h" 4 #include "fileops.h" 5 #include <libgen.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <assert.h> 9 #include <string.h> 10 #include <strings.h> 11 #include "webp/decode.h" 12 #include "webp/demux.h" 13 14 #ifdef __OpenBSD__ 15 #include <sys/syslimits.h> 16 #endif 17 18 #ifdef __linux__ 19 #include <linux/limits.h> 20 #endif 21 22 Animation * ImageLoad(const char *path) { 23 Animation *img = malloc(sizeof(Animation)); 24 assert(img!=NULL); 25 bzero(img, sizeof(Animation)); 26 img->path = realpath(path, NULL); 27 assert(img->path!=NULL); 28 printf("img->path: %s\n", img->path); 29 int r = WebpRead(img->path, img); 30 assert(r==0); 31 32 char *name_copy = strndup(img->path, PATH_MAX); 33 char *path_copy = strndup(img->path, PATH_MAX); 34 img->filename = strndup(basename(name_copy), NAME_MAX); 35 img->dirname = strndup(dirname(path_copy), PATH_MAX); 36 free(name_copy); 37 free(path_copy); 38 39 //printf("[%s/%s]\ncols: %d\ndimensions: %dx%dpx\nframes: %d\n", img->dirname, img->filename, cols, img->width, img->height, img->frame_count); 40 41 return img; 42 } 43 44 void ImageUnload(Animation **img) { 45 free((*img)->path); 46 free((*img)->dirname); 47 free((*img)->filename); 48 free(*img); 49 *img = NULL; 50 } 51 52 int WebpRead(const char *filename, Animation *anim) { 53 printf("WebpRead(%s)\n", filename); 54 55 WebPData webp_data; 56 WebPDataInit(&webp_data); 57 58 if (FileRead(filename, &webp_data.bytes, &webp_data.size) == -1) { 59 fprintf(stderr, "FileRead() error\n"); 60 return -1; 61 } 62 63 if (!WebPGetInfo(webp_data.bytes, webp_data.size, NULL, NULL)) { 64 fprintf(stderr, "invalid webp\n"); 65 WebPDataClear(&webp_data); 66 return -1; 67 } 68 69 WebPAnimDecoder *dec = WebPAnimDecoderNew(&webp_data, NULL); 70 assert(dec != NULL); 71 72 WebPAnimInfo anim_info; 73 if (!WebPAnimDecoderGetInfo(dec, &anim_info)) { 74 fprintf(stderr, "error decoding animation info\n"); 75 // @todo cleanup 76 return -1; 77 } 78 79 anim->width = anim_info.canvas_width; 80 anim->height = anim_info.canvas_height; 81 anim->loop_count = anim_info.loop_count; 82 anim->bgcolor = anim_info.bgcolor; 83 AnimationCreate(anim, anim_info.frame_count); 84 85 uint32_t frame_index = 0; 86 int prev_ts = 0; 87 while (WebPAnimDecoderHasMoreFrames(dec)) { 88 Frame *frame; 89 uint8_t *curr_rgba, *frame_rgba; 90 int ts; 91 if (!WebPAnimDecoderGetNext(dec, &frame_rgba, &ts)) { 92 fprintf(stderr, "error decoding frame %d\n", frame_index); 93 return -1; 94 } 95 assert(frame_index < anim_info.frame_count); 96 frame = &anim->frames[frame_index]; 97 curr_rgba = frame->rgba; 98 frame->duration = ts - prev_ts; 99 memcpy(curr_rgba, frame_rgba, anim->width * anim->height * NUM_CHANNELS); 100 // ... <- nani kore? 101 ++frame_index; 102 prev_ts = ts; 103 } 104 105 WebPDataClear(&webp_data); 106 WebPAnimDecoderDelete(dec); 107 return 0; 108 } 109 110 void AnimationCreate(Animation *img, uint32_t frame_count) { 111 assert(frame_count > 0); 112 uint8_t *mem = NULL; 113 Frame *frames = NULL; 114 const uint64_t rgba_size = img->width * img->height * NUM_CHANNELS; 115 const uint64_t img_size = frame_count * rgba_size * sizeof(uint8_t); 116 const uint64_t frames_size = frame_count * sizeof(Frame); 117 118 assert(img_size == (size_t)img_size); 119 assert(frames_size == (size_t)frames_size); 120 121 printf("img mem: %" PRIu64 "\nframes mem: %" PRIu64 "\n", img_size, frames_size); 122 123 mem = malloc(img_size); 124 frames = malloc(frames_size); 125 assert(mem != NULL); 126 assert(frames != NULL); 127 128 for (uint32_t i=0; i<frame_count; ++i) { 129 frames[i].rgba = mem+i*rgba_size; 130 frames[i].duration = 0; 131 frames[i].is_key = false; 132 } 133 img->frame_count = frame_count; 134 img->frames = frames; 135 img->raw_mem = mem; 136 }