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