static pixmap_t * fa_image_from_video(const char *url0, const image_meta_t *im, char *errbuf, size_t errlen, int *cache_control, cancellable_t *c) { static char *stated_url; static fa_stat_t fs; time_t stattime = 0; time_t mtime = 0; pixmap_t *pm = NULL; char cacheid[512]; char *url = mystrdupa(url0); char *tim = strchr(url, '#'); const char *siz; *tim++ = 0; int secs = atoi(tim); hts_mutex_lock(&image_from_video_mutex[0]); if(strcmp(url, stated_url ?: "")) { free(stated_url); stated_url = NULL; if(fa_stat(url, &fs, errbuf, errlen)) { hts_mutex_unlock(&image_from_video_mutex[0]); return NULL; } stated_url = strdup(url); } stattime = fs.fs_mtime; hts_mutex_unlock(&image_from_video_mutex[0]); if(im->im_req_width < 100 && im->im_req_height < 100) { siz = "min"; } else if(im->im_req_width < 200 && im->im_req_height < 200) { siz = "mid"; } else { siz = "max"; } snprintf(cacheid, sizeof(cacheid), "%s-%s", url0, siz); buf_t *b = blobcache_get(cacheid, "videothumb", 0, 0, NULL, &mtime); if(b != NULL && mtime == stattime) { pm = pixmap_alloc_coded(b->b_ptr, b->b_size, PIXMAP_JPEG); buf_release(b); return pm; } buf_release(b); if(ONLY_CACHED(cache_control)) { snprintf(errbuf, errlen, "Not cached"); return NULL; } hts_mutex_lock(&image_from_video_mutex[1]); pm = fa_image_from_video2(url, im, cacheid, errbuf, errlen, secs, stattime, c); hts_mutex_unlock(&image_from_video_mutex[1]); return pm; }
static pixmap_t * fa_image_from_video(const char *url0, const image_meta_t *im, char *errbuf, size_t errlen, int *cache_control, fa_load_cb_t *cb, void *opaque) { static char *stated_url; static fa_stat_t fs; time_t stattime = 0; time_t mtime = 0; pixmap_t *pm = NULL; char cacheid[512]; void *data; size_t datasize; char *url = mystrdupa(url0); char *tim = strchr(url, '#'); *tim++ = 0; int secs = atoi(tim); hts_mutex_lock(&image_from_video_mutex); if(strcmp(url, stated_url ?: "")) { free(stated_url); stated_url = NULL; if(fa_stat(url, &fs, errbuf, errlen)) { hts_mutex_unlock(&image_from_video_mutex); return NULL; } stated_url = strdup(url); } stattime = fs.fs_mtime; hts_mutex_unlock(&image_from_video_mutex); snprintf(cacheid, sizeof(cacheid), "%s-%d-%d-3", url0, im->im_req_width, im->im_req_height); data = blobcache_get(cacheid, "videothumb", &datasize, 0, 0, NULL, &mtime); if(data != NULL && mtime == stattime) { pm = pixmap_alloc_coded(data, datasize, PIXMAP_PNG); free(data); return pm; } if(ONLY_CACHED(cache_control)) { snprintf(errbuf, errlen, "Not cached"); return NULL; } hts_mutex_lock(&image_from_video_mutex); pm = fa_image_from_video2(url, im, cacheid, errbuf, errlen, secs, stattime, cb, opaque); hts_mutex_unlock(&image_from_video_mutex); return pm; }
pixmap_t * fa_imageloader(const char *url, const struct image_meta *im, const char **vpaths, char *errbuf, size_t errlen, int *cache_control, cancellable_t *c) { uint8_t p[16]; int r; int width = -1, height = -1, orientation = 0; fa_handle_t *fh; pixmap_t *pm; pixmap_type_t fmt; #if ENABLE_LIBAV if(strchr(url, '#')) return fa_image_from_video(url, im, errbuf, errlen, cache_control, c); #endif if(!im->im_want_thumb) return fa_imageloader2(url, vpaths, errbuf, errlen, cache_control, c); fa_open_extra_t foe = { .foe_c = c }; if((fh = fa_open_vpaths(url, vpaths, errbuf, errlen, FA_BUFFERED_SMALL, &foe)) == NULL) return NULL; if(ONLY_CACHED(cache_control)) { snprintf(errbuf, errlen, "Not cached"); return NULL; } if(fa_read(fh, p, sizeof(p)) != sizeof(p)) { snprintf(errbuf, errlen, "File too short"); fa_close(fh); return NULL; } /* Probe format */ if((p[6] == 'J' && p[7] == 'F' && p[8] == 'I' && p[9] == 'F') || (p[6] == 'E' && p[7] == 'x' && p[8] == 'i' && p[9] == 'f')) { jpeginfo_t ji; if(jpeg_info(&ji, jpeginfo_reader, fh, JPEG_INFO_DIMENSIONS | JPEG_INFO_ORIENTATION | (im->im_want_thumb ? JPEG_INFO_THUMBNAIL : 0), p, sizeof(p), errbuf, errlen)) { fa_close(fh); return NULL; } if(im->im_want_thumb && ji.ji_thumbnail) { pixmap_t *pm = pixmap_dup(ji.ji_thumbnail); fa_close(fh); jpeg_info_clear(&ji); return pm; } fmt = PIXMAP_JPEG; width = ji.ji_width; height = ji.ji_height; orientation = ji.ji_orientation; jpeg_info_clear(&ji); } else if(!memcmp(pngsig, p, 8)) { fmt = PIXMAP_PNG; } else if(!memcmp(gif87sig, p, sizeof(gif87sig)) || !memcmp(gif89sig, p, sizeof(gif89sig))) { fmt = PIXMAP_GIF; } else if(!memcmp(svgsig1, p, sizeof(svgsig1)) || !memcmp(svgsig2, p, sizeof(svgsig2))) { fmt = PIXMAP_SVG; } else { snprintf(errbuf, errlen, "Unknown format"); fa_close(fh); return NULL; } int64_t s = fa_fsize(fh); if(s < 0) { snprintf(errbuf, errlen, "Can't read from non-seekable file"); fa_close(fh); return NULL; } pm = pixmap_alloc_coded(NULL, s, fmt); if(pm == NULL) { snprintf(errbuf, errlen, "Out of memory"); fa_close(fh); return NULL; } pm->pm_width = width; pm->pm_height = height; pm->pm_orientation = orientation; fa_seek(fh, SEEK_SET, 0); r = fa_read(fh, pm->pm_data, pm->pm_size); fa_close(fh); if(r != pm->pm_size) { pixmap_release(pm); snprintf(errbuf, errlen, "Read error"); return NULL; } return pm; }
static image_t * fa_image_from_video(const char *url0, const image_meta_t *im, char *errbuf, size_t errlen, int *cache_control, cancellable_t *c) { static char *stated_url; static fa_stat_t fs; time_t stattime = 0; time_t mtime = 0; image_t *img = NULL; char cacheid[512]; char *url = mystrdupa(url0); char *tim = strchr(url, '#'); const char *siz; *tim++ = 0; int secs; if(!strcmp(tim, "cover")) secs = -1; else secs = atoi(tim); hts_mutex_lock(&image_from_video_mutex[0]); if(strcmp(url, stated_url ?: "")) { free(stated_url); stated_url = NULL; if(fa_stat(url, &fs, errbuf, errlen)) { hts_mutex_unlock(&image_from_video_mutex[0]); return NULL; } stated_url = strdup(url); } stattime = fs.fs_mtime; hts_mutex_unlock(&image_from_video_mutex[0]); if(im->im_req_width < 100 && im->im_req_height < 100) { siz = "min"; } else if(im->im_req_width < 200 && im->im_req_height < 200) { siz = "mid"; } else { siz = "max"; } snprintf(cacheid, sizeof(cacheid), "%s-%s", url0, siz); buf_t *b = blobcache_get(cacheid, "videothumb", 0, 0, NULL, &mtime); if(b != NULL && mtime == stattime) { img = image_coded_create_from_buf(b, IMAGE_JPEG); buf_release(b); return img; } buf_release(b); if(ONLY_CACHED(cache_control)) { snprintf(errbuf, errlen, "Not cached"); return NULL; } hts_mutex_lock(&image_from_video_mutex[1]); img = fa_image_from_video2(url, im, cacheid, errbuf, errlen, secs, stattime, c); hts_mutex_unlock(&image_from_video_mutex[1]); if(img != NULL) img->im_flags |= IMAGE_ADAPTED; return img; }
image_t * fa_imageloader(const char *url, const struct image_meta *im, const char **vpaths, char *errbuf, size_t errlen, int *cache_control, cancellable_t *c) { uint8_t p[16]; int r; int width = -1, height = -1, orientation = 0; fa_handle_t *fh; image_t *img; image_coded_type_t fmt; #if ENABLE_LIBAV if(strchr(url, '#')) return fa_image_from_video(url, im, errbuf, errlen, cache_control, c); #endif if(!im->im_want_thumb) return fa_imageloader2(url, vpaths, errbuf, errlen, cache_control, c); fa_open_extra_t foe = { .foe_cancellable = c }; if((fh = fa_open_vpaths(url, vpaths, errbuf, errlen, FA_BUFFERED_SMALL, &foe)) == NULL) return NULL; if(ONLY_CACHED(cache_control)) { snprintf(errbuf, errlen, "Not cached"); return NULL; } if(fa_read(fh, p, sizeof(p)) != sizeof(p)) { snprintf(errbuf, errlen, "File too short"); fa_close(fh); return NULL; } /* Probe format */ if(p[0] == 0xff && p[1] == 0xd8 && p[2] == 0xff) { jpeginfo_t ji; if(jpeg_info(&ji, jpeginfo_reader, fh, JPEG_INFO_DIMENSIONS | JPEG_INFO_ORIENTATION | (im->im_want_thumb ? JPEG_INFO_THUMBNAIL : 0), p, sizeof(p), errbuf, errlen)) { fa_close(fh); return NULL; } if(im->im_want_thumb && ji.ji_thumbnail) { image_t *im = image_retain(ji.ji_thumbnail); fa_close(fh); jpeg_info_clear(&ji); im->im_flags |= IMAGE_ADAPTED; return im; } fmt = IMAGE_JPEG; width = ji.ji_width; height = ji.ji_height; orientation = ji.ji_orientation; jpeg_info_clear(&ji); } else if(!memcmp(pngsig, p, 8)) { fmt = IMAGE_PNG; } else if(!memcmp(gif87sig, p, sizeof(gif87sig)) || !memcmp(gif89sig, p, sizeof(gif89sig))) { fmt = IMAGE_GIF; } else if(p[0] == 'B' && p[1] == 'M') { fmt = IMAGE_BMP; } else if(!memcmp(svgsig1, p, sizeof(svgsig1)) || !memcmp(svgsig2, p, sizeof(svgsig2))) { fmt = IMAGE_SVG; } else { snprintf(errbuf, errlen, "Unknown format"); fa_close(fh); return NULL; } int64_t s = fa_fsize(fh); if(s < 0) { snprintf(errbuf, errlen, "Can't read from non-seekable file"); fa_close(fh); return NULL; } void *ptr; img = image_coded_alloc(&ptr, s, fmt); if(img == NULL) { snprintf(errbuf, errlen, "Out of memory"); fa_close(fh); return NULL; } img->im_width = width; img->im_height = height; img->im_orientation = orientation; fa_seek(fh, SEEK_SET, 0); r = fa_read(fh, ptr, s); fa_close(fh); if(r != s) { image_release(img); snprintf(errbuf, errlen, "Read error"); return NULL; } return img; }