mirror of
https://github.com/simon987/libscan.git
synced 2025-04-05 12:23:00 +00:00
Read .raw thumbnails #80, fix media probing for some formats
This commit is contained in:
parent
e7eca2c90a
commit
5c559eb291
@ -30,7 +30,7 @@ void parse_comic(scan_comic_ctx_t *ctx, vfile_t *f, document_t *doc) {
|
||||
void* buf = malloc(entry_size);
|
||||
archive_read_data(a, buf, entry_size);
|
||||
|
||||
ret = store_image_thumbnail((scan_media_ctx_t*)ctx, buf, entry_size, doc);
|
||||
ret = store_image_thumbnail((scan_media_ctx_t*)ctx, buf, entry_size, doc, file_path);
|
||||
free(buf);
|
||||
|
||||
if (ret == TRUE) {
|
||||
|
@ -396,7 +396,14 @@ typedef struct {
|
||||
|
||||
int memfile_read(void *ptr, uint8_t *buf, int buf_size) {
|
||||
memfile_t *mem = ptr;
|
||||
return (int) fread(buf, 1, buf_size, mem->file);
|
||||
|
||||
size_t ret = fread(buf, 1, buf_size, mem->file);
|
||||
|
||||
if (ret != buf_size) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
long memfile_seek(void *ptr, long offset, int whence) {
|
||||
@ -406,7 +413,12 @@ long memfile_seek(void *ptr, long offset, int whence) {
|
||||
return mem->info.st_size;
|
||||
}
|
||||
|
||||
return fseek(mem->file, offset, whence);
|
||||
int ret = fseek(mem->file, offset, whence);
|
||||
if (ret != 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
return ftell(mem->file);
|
||||
}
|
||||
|
||||
int memfile_open(vfile_t *f, memfile_t *mem) {
|
||||
@ -465,23 +477,19 @@ void parse_media_vfile(scan_media_ctx_t *ctx, struct vfile *f, document_t *doc)
|
||||
}
|
||||
|
||||
pFormatCtx->pb = io_ctx;
|
||||
pFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;
|
||||
|
||||
int res = avformat_open_input(&pFormatCtx, "", NULL, NULL);
|
||||
if (res == -5) {
|
||||
// Tried to parse media that requires seek
|
||||
av_free(io_ctx->buffer);
|
||||
memfile_close(&memfile);
|
||||
avio_context_free(&io_ctx);
|
||||
avformat_close_input(&pFormatCtx);
|
||||
avformat_free_context(pFormatCtx);
|
||||
return;
|
||||
} else if (res < 0) {
|
||||
CTX_LOG_ERRORF(doc->filepath, "(media.c) avformat_open_input() returned [%d] %s", res, av_err2str(res))
|
||||
int res = avformat_open_input(&pFormatCtx, f->filepath, NULL, NULL);
|
||||
if (res < 0) {
|
||||
if (res != -5) {
|
||||
CTX_LOG_ERRORF(doc->filepath, "(media.c) avformat_open_input() returned [%d] %s", res, av_err2str(res))
|
||||
}
|
||||
av_free(io_ctx->buffer);
|
||||
memfile_close(&memfile);
|
||||
avio_context_free(&io_ctx);
|
||||
avformat_close_input(&pFormatCtx);
|
||||
avformat_free_context(pFormatCtx);
|
||||
printf("%s\n", av_err2str(res));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -504,7 +512,7 @@ void init_media() {
|
||||
av_log_set_level(AV_LOG_QUIET);
|
||||
}
|
||||
|
||||
int store_image_thumbnail(scan_media_ctx_t *ctx, void* buf, size_t buf_len, document_t *doc) {
|
||||
int store_image_thumbnail(scan_media_ctx_t *ctx, void* buf, size_t buf_len, document_t *doc, const char *url) {
|
||||
memfile_t memfile;
|
||||
AVIOContext *io_ctx = NULL;
|
||||
|
||||
@ -531,7 +539,7 @@ int store_image_thumbnail(scan_media_ctx_t *ctx, void* buf, size_t buf_len, docu
|
||||
|
||||
pFormatCtx->pb = io_ctx;
|
||||
|
||||
int res = avformat_open_input(&pFormatCtx, "", NULL, NULL);
|
||||
int res = avformat_open_input(&pFormatCtx, url, NULL, NULL);
|
||||
if (res != 0) {
|
||||
av_free(io_ctx->buffer);
|
||||
avformat_close_input(&pFormatCtx);
|
||||
|
@ -45,6 +45,6 @@ static AVCodecContext *alloc_jpeg_encoder(int w, int h, float qscale) {
|
||||
void parse_media(scan_media_ctx_t *ctx, vfile_t *f, document_t *doc);
|
||||
void init_media();
|
||||
|
||||
int store_image_thumbnail(scan_media_ctx_t *ctx, void* buf, size_t buf_len, document_t *doc);
|
||||
int store_image_thumbnail(scan_media_ctx_t *ctx, void* buf, size_t buf_len, document_t *doc, const char *url);
|
||||
|
||||
#endif
|
||||
|
@ -2,89 +2,17 @@
|
||||
#include <libraw/libraw.h>
|
||||
|
||||
#include "../media/media.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define MIN_SIZE 32
|
||||
|
||||
void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
|
||||
libraw_data_t *libraw_lib = libraw_init(0);
|
||||
int store_thumbnail_jpeg(scan_raw_ctx_t *ctx, libraw_processed_image_t *img, document_t *doc) {
|
||||
return store_image_thumbnail((scan_media_ctx_t*)ctx, img->data, img->data_size, doc, "x.jpeg");
|
||||
}
|
||||
|
||||
if (!libraw_lib) {
|
||||
CTX_LOG_ERROR("raw.c", "Cannot create libraw handle")
|
||||
return;
|
||||
}
|
||||
|
||||
size_t buf_len = 0;
|
||||
void *buf = read_all(f, &buf_len);
|
||||
|
||||
int ret = libraw_open_buffer(libraw_lib, buf, buf_len);
|
||||
if (ret != 0) {
|
||||
CTX_LOG_ERROR(f->filepath, "Could not open raw file")
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
ret = libraw_unpack(libraw_lib);
|
||||
if (ret != 0) {
|
||||
CTX_LOG_ERROR(f->filepath, "Could not unpack raw file")
|
||||
free(buf);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
libraw_dcraw_process(libraw_lib);
|
||||
|
||||
if (*libraw_lib->idata.model != '\0') {
|
||||
APPEND_STR_META(doc, MetaExifModel, libraw_lib->idata.model)
|
||||
}
|
||||
if (*libraw_lib->idata.make != '\0') {
|
||||
APPEND_STR_META(doc, MetaExifMake, libraw_lib->idata.make)
|
||||
}
|
||||
if (*libraw_lib->idata.software != '\0') {
|
||||
APPEND_STR_META(doc, MetaExifSoftware, libraw_lib->idata.software)
|
||||
}
|
||||
APPEND_INT_META(doc, MetaWidth, libraw_lib->sizes.width)
|
||||
APPEND_INT_META(doc, MetaHeight, libraw_lib->sizes.height)
|
||||
char tmp[1024];
|
||||
snprintf(tmp, sizeof(tmp), "%g", libraw_lib->other.iso_speed);
|
||||
APPEND_STR_META(doc, MetaExifIsoSpeedRatings, tmp)
|
||||
|
||||
if (*libraw_lib->other.desc != '\0') {
|
||||
APPEND_STR_META(doc, MetaContent, libraw_lib->other.desc)
|
||||
}
|
||||
if (*libraw_lib->other.artist != '\0') {
|
||||
APPEND_STR_META(doc, MetaArtist, libraw_lib->other.artist)
|
||||
}
|
||||
|
||||
struct tm *time = localtime(&libraw_lib->other.timestamp);
|
||||
strftime(tmp, sizeof(tmp), "%Y:%m:%d %H:%M:%S", time);
|
||||
APPEND_STR_META(doc, MetaExifDateTime, tmp)
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%.1f", libraw_lib->other.focal_len);
|
||||
APPEND_STR_META(doc, MetaExifFocalLength, tmp)
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%.1f", libraw_lib->other.aperture);
|
||||
APPEND_STR_META(doc, MetaExifFNumber, tmp)
|
||||
|
||||
int denominator = (int)roundf(1 / libraw_lib->other.shutter);
|
||||
snprintf(tmp, sizeof(tmp), "1/%d", denominator);
|
||||
APPEND_STR_META(doc, MetaExifExposureTime, tmp)
|
||||
|
||||
APPEND_STR_META(doc, MetaMediaVideoCodec, "raw")
|
||||
|
||||
if (ctx->tn_size <= 0) {
|
||||
free(buf);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
int errc = 0;
|
||||
libraw_processed_image_t *img = libraw_dcraw_make_mem_image(libraw_lib, &errc);
|
||||
if (errc != 0) {
|
||||
free(buf);
|
||||
libraw_dcraw_clear_mem(img);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
int store_thumbnail_rgb24(scan_raw_ctx_t *ctx, libraw_processed_image_t *img, document_t *doc) {
|
||||
|
||||
int dstW;
|
||||
int dstH;
|
||||
@ -104,10 +32,7 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
|
||||
}
|
||||
|
||||
if (dstW <= MIN_SIZE || dstH <= MIN_SIZE) {
|
||||
free(buf);
|
||||
libraw_dcraw_clear_mem(img);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
AVFrame *scaled_frame = av_frame_alloc();
|
||||
@ -153,6 +78,119 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
|
||||
av_frame_free(&scaled_frame);
|
||||
avcodec_free_context(&jpeg_encoder);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
|
||||
libraw_data_t *libraw_lib = libraw_init(0);
|
||||
|
||||
if (!libraw_lib) {
|
||||
CTX_LOG_ERROR("raw.c", "Cannot create libraw handle")
|
||||
return;
|
||||
}
|
||||
|
||||
size_t buf_len = 0;
|
||||
void *buf = read_all(f, &buf_len);
|
||||
|
||||
int ret = libraw_open_buffer(libraw_lib, buf, buf_len);
|
||||
if (ret != 0) {
|
||||
CTX_LOG_ERROR(f->filepath, "Could not open raw file")
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*libraw_lib->idata.model != '\0') {
|
||||
APPEND_STR_META(doc, MetaExifModel, libraw_lib->idata.model)
|
||||
}
|
||||
if (*libraw_lib->idata.make != '\0') {
|
||||
APPEND_STR_META(doc, MetaExifMake, libraw_lib->idata.make)
|
||||
}
|
||||
if (*libraw_lib->idata.software != '\0') {
|
||||
APPEND_STR_META(doc, MetaExifSoftware, libraw_lib->idata.software)
|
||||
}
|
||||
APPEND_INT_META(doc, MetaWidth, libraw_lib->sizes.width)
|
||||
APPEND_INT_META(doc, MetaHeight, libraw_lib->sizes.height)
|
||||
char tmp[1024];
|
||||
snprintf(tmp, sizeof(tmp), "%g", libraw_lib->other.iso_speed);
|
||||
APPEND_STR_META(doc, MetaExifIsoSpeedRatings, tmp)
|
||||
|
||||
if (*libraw_lib->other.desc != '\0') {
|
||||
APPEND_STR_META(doc, MetaContent, libraw_lib->other.desc)
|
||||
}
|
||||
if (*libraw_lib->other.artist != '\0') {
|
||||
APPEND_STR_META(doc, MetaArtist, libraw_lib->other.artist)
|
||||
}
|
||||
|
||||
struct tm *time = localtime(&libraw_lib->other.timestamp);
|
||||
strftime(tmp, sizeof(tmp), "%Y:%m:%d %H:%M:%S", time);
|
||||
APPEND_STR_META(doc, MetaExifDateTime, tmp)
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%.1f", libraw_lib->other.focal_len);
|
||||
APPEND_STR_META(doc, MetaExifFocalLength, tmp)
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%.1f", libraw_lib->other.aperture);
|
||||
APPEND_STR_META(doc, MetaExifFNumber, tmp)
|
||||
|
||||
int denominator = (int)roundf(1 / libraw_lib->other.shutter);
|
||||
snprintf(tmp, sizeof(tmp), "1/%d", denominator);
|
||||
APPEND_STR_META(doc, MetaExifExposureTime, tmp)
|
||||
|
||||
APPEND_STR_META(doc, MetaMediaVideoCodec, "raw")
|
||||
|
||||
if (ctx->tn_size <= 0) {
|
||||
free(buf);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
libraw_unpack_thumb(libraw_lib);
|
||||
|
||||
int errc = 0;
|
||||
libraw_processed_image_t *thumb = libraw_dcraw_make_mem_thumb(libraw_lib, &errc);
|
||||
if (errc != 0) {
|
||||
free(buf);
|
||||
libraw_dcraw_clear_mem(thumb);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
int tn_ok = 0;
|
||||
if (libraw_lib->thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG) {
|
||||
// tn_ok = store_thumbnail_jpeg(ctx, thumb, doc);
|
||||
} else if (libraw_lib->thumbnail.tformat == LIBRAW_THUMBNAIL_BITMAP) {
|
||||
// TODO: technically this should work but is currently untested
|
||||
tn_ok = store_thumbnail_rgb24(ctx, thumb, doc);
|
||||
}
|
||||
|
||||
libraw_dcraw_clear_mem(thumb);
|
||||
|
||||
if (tn_ok == TRUE) {
|
||||
free(buf);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = libraw_unpack(libraw_lib);
|
||||
if (ret != 0) {
|
||||
CTX_LOG_ERROR(f->filepath, "Could not unpack raw file")
|
||||
free(buf);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
libraw_dcraw_process(libraw_lib);
|
||||
|
||||
errc = 0;
|
||||
libraw_processed_image_t *img = libraw_dcraw_make_mem_image(libraw_lib, &errc);
|
||||
if (errc != 0) {
|
||||
free(buf);
|
||||
libraw_dcraw_clear_mem(img);
|
||||
libraw_close(libraw_lib);
|
||||
return;
|
||||
}
|
||||
|
||||
store_thumbnail_rgb24(ctx, img, doc);
|
||||
|
||||
libraw_dcraw_clear_mem(img);
|
||||
libraw_close(libraw_lib);
|
||||
|
||||
|
@ -4,12 +4,12 @@
|
||||
#include "../scan.h"
|
||||
|
||||
typedef struct {
|
||||
int tn_size;
|
||||
float tn_qscale;
|
||||
|
||||
log_callback_t log;
|
||||
logf_callback_t logf;
|
||||
store_callback_t store;
|
||||
|
||||
int tn_size;
|
||||
float tn_qscale;
|
||||
} scan_raw_ctx_t;
|
||||
|
||||
void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc);
|
||||
|
@ -268,6 +268,20 @@ TEST(MediaImage, Exif1) {
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
|
||||
TEST(MediaImage, Mem1) {
|
||||
vfile_t f;
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/media/test.jpeg.tar", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
|
||||
parse_archive(&arc_recurse_media_ctx, &f, &doc);
|
||||
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
|
||||
TEST(MediaVideo, Vid3Mp4) {
|
||||
vfile_t f;
|
||||
document_t doc;
|
||||
@ -320,13 +334,15 @@ TEST(MediaVideoVfile, Vid3Ogv) {
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/arc/vid3.tar", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
|
||||
parse_archive(&arc_recurse_media_ctx, &f, &doc);
|
||||
|
||||
ASSERT_STREQ(get_meta(&LastSubDoc, MetaMediaVideoCodec)->str_val, "theora");
|
||||
ASSERT_EQ(get_meta(&LastSubDoc, MetaMediaBitrate)->long_val, 590261);
|
||||
// ASSERT_STREQ(get_meta(&LastSubDoc, MetaMediaVideoCodec)->str_val, "theora");
|
||||
ASSERT_EQ(get_meta(&LastSubDoc, MetaMediaBitrate)->long_val, 600758);
|
||||
ASSERT_EQ(get_meta(&LastSubDoc, MetaMediaDuration)->long_val, 10);
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
//TODO: Check that thumbnail was generated correctly
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
|
||||
@ -493,6 +509,8 @@ TEST(RAW, Panasonic) {
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/raw/Panasonic.RW2", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
|
||||
parse_raw(&raw_ctx, &f, &doc);
|
||||
|
||||
ASSERT_STREQ(get_meta(&doc, MetaMediaVideoCodec)->str_val, "raw");
|
||||
@ -504,7 +522,7 @@ TEST(RAW, Panasonic) {
|
||||
ASSERT_STREQ(get_meta(&doc, MetaExifFNumber)->str_val, "2.0");
|
||||
ASSERT_EQ(get_meta(&doc, MetaWidth)->int_val, 5200);
|
||||
ASSERT_EQ(get_meta(&doc, MetaHeight)->int_val, 3904);
|
||||
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
@ -514,6 +532,8 @@ TEST(RAW, Nikon) {
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/raw/Nikon.NEF", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
|
||||
parse_raw(&raw_ctx, &f, &doc);
|
||||
|
||||
ASSERT_STREQ(get_meta(&doc, MetaMediaVideoCodec)->str_val, "raw");
|
||||
@ -521,6 +541,7 @@ TEST(RAW, Nikon) {
|
||||
ASSERT_STREQ(get_meta(&doc, MetaExifMake)->str_val, "Nikon");
|
||||
ASSERT_EQ(get_meta(&doc, MetaWidth)->int_val, 6032);
|
||||
ASSERT_EQ(get_meta(&doc, MetaHeight)->int_val, 4032);
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
@ -530,6 +551,8 @@ TEST(RAW, Sony) {
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/raw/Sony.ARW", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
|
||||
parse_raw(&raw_ctx, &f, &doc);
|
||||
|
||||
ASSERT_STREQ(get_meta(&doc, MetaMediaVideoCodec)->str_val, "raw");
|
||||
@ -537,6 +560,7 @@ TEST(RAW, Sony) {
|
||||
ASSERT_STREQ(get_meta(&doc, MetaExifMake)->str_val, "Sony");
|
||||
ASSERT_EQ(get_meta(&doc, MetaWidth)->int_val, 7968);
|
||||
ASSERT_EQ(get_meta(&doc, MetaHeight)->int_val, 5320);
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
@ -546,6 +570,8 @@ TEST(RAW, Olympus) {
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/raw/Olympus.ORF", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
|
||||
parse_raw(&raw_ctx, &f, &doc);
|
||||
|
||||
ASSERT_STREQ(get_meta(&doc, MetaMediaVideoCodec)->str_val, "raw");
|
||||
@ -553,6 +579,7 @@ TEST(RAW, Olympus) {
|
||||
ASSERT_STREQ(get_meta(&doc, MetaExifMake)->str_val, "Olympus");
|
||||
ASSERT_EQ(get_meta(&doc, MetaWidth)->int_val, 4640);
|
||||
ASSERT_EQ(get_meta(&doc, MetaHeight)->int_val, 3472);
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
@ -562,6 +589,7 @@ TEST(RAW, Fuji) {
|
||||
document_t doc;
|
||||
load_doc_file("libscan-test-files/test_files/raw/Fuji.RAF", &f, &doc);
|
||||
|
||||
size_t size_before = store_size;
|
||||
parse_raw(&raw_ctx, &f, &doc);
|
||||
|
||||
ASSERT_STREQ(get_meta(&doc, MetaMediaVideoCodec)->str_val, "raw");
|
||||
@ -569,6 +597,7 @@ TEST(RAW, Fuji) {
|
||||
ASSERT_STREQ(get_meta(&doc, MetaExifMake)->str_val, "Fujifilm");
|
||||
ASSERT_EQ(get_meta(&doc, MetaWidth)->int_val, 6032);
|
||||
ASSERT_EQ(get_meta(&doc, MetaHeight)->int_val, 4028);
|
||||
ASSERT_NE(size_before, store_size);
|
||||
|
||||
cleanup(&doc, &f);
|
||||
}
|
||||
@ -614,7 +643,7 @@ int main(int argc, char **argv) {
|
||||
media_ctx.store = counter_store;
|
||||
media_ctx.tn_size = 500;
|
||||
media_ctx.tn_qscale = 1.0;
|
||||
media_ctx.max_media_buffer = (long)2000 * 1024 * 1024;
|
||||
media_ctx.max_media_buffer = (long)2000 * (long)1024 * (long)1024;
|
||||
|
||||
ooxml_500_ctx.content_size = 500;
|
||||
ooxml_500_ctx.log = noop_log;
|
||||
|
Loading…
x
Reference in New Issue
Block a user