From 0be130e37bfafd6022edd27833f04a0b6cee2f02 Mon Sep 17 00:00:00 2001 From: Brian Olson Date: Mon, 27 Feb 2012 10:27:17 +0100 Subject: [PATCH] img2: glob matching for image series Signed-off-by: Michael Niedermayer --- configure | 2 ++ doc/ffmpeg.texi | 6 +++- libavformat/img2dec.c | 72 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/configure b/configure index ab242e8982..6a435fd37e 100755 --- a/configure +++ b/configure @@ -1183,6 +1183,7 @@ HAVE_LIST=" GetProcessMemoryInfo GetProcessTimes getrusage + glob gnu_as ibm_asm inet_aton @@ -3075,6 +3076,7 @@ check_func_headers windows.h GetProcessAffinityMask check_func_headers windows.h GetProcessTimes check_func_headers windows.h MapViewOfFile check_func_headers windows.h VirtualAlloc +check_func_headers glob.h glob check_header dlfcn.h check_header dxva2api.h -D_WIN32_WINNT=0x0600 diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 37c941e67c..a9edad48cd 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -1077,7 +1077,11 @@ ffmpeg -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi The syntax @code{foo-%03d.jpeg} specifies to use a decimal number composed of three digits padded with zeroes to express the sequence number. It is the same syntax supported by the C printf function, but -only formats accepting a normal integer are suitable. +only formats accepting a normal integer are suitable. When importing +an image sequence, -i also accepts shell-like wildcard patterns such as +@code{foo-*.jpeg}, @code{foo-???.jpeg} or @code{foo-00[234]*.jpeg}. +It will probably be necessary to escape these patterns so they do not +get interpreted by your shell. @item You can put many streams of the same type in the output: diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c index e8b695f522..d10a7a4b6a 100644 --- a/libavformat/img2dec.c +++ b/libavformat/img2dec.c @@ -27,6 +27,25 @@ #include "libavutil/parseutils.h" #include "avformat.h" #include "internal.h" +#if HAVE_GLOB +#include + +/* Locally define as 0 (bitwise-OR no-op) any missing glob options that + are non-posix glibc/bsd extensions. */ +#ifndef GLOB_NOMAGIC +#define GLOB_NOMAGIC 0 +#endif +#ifndef GLOB_TILDE +#define GLOB_TILDE 0 +#endif +#ifndef GLOB_TILDE_CHECK +#define GLOB_TILDE_CHECK GLOB_TILDE +#endif +#ifndef GLOB_BRACE +#define GLOB_BRACE 0 +#endif + +#endif /* HAVE_GLOB */ typedef struct { const AVClass *class; /**< Class for private options. */ @@ -41,6 +60,10 @@ typedef struct { char *video_size; /**< Set by a private option. */ char *framerate; /**< Set by a private option. */ int loop; + int use_glob; +#if HAVE_GLOB + glob_t globstate; +#endif } VideoDemuxData; static const int sizes[][2] = { @@ -69,6 +92,17 @@ static int infer_size(int *width_ptr, int *height_ptr, int size) return -1; } +static int is_glob(const char *path) +{ +#if HAVE_GLOB + size_t span = strcspn(path, "*?[]{}\\"); + /* Did we hit a glob char or get to the end? */ + return path[span] != '\0'; +#else + return 0; +#endif +} + /* return -1 if no image found */ static int find_image_range(int *pfirst_index, int *plast_index, const char *path) @@ -128,6 +162,8 @@ static int read_probe(AVProbeData *p) if (p->filename && ff_guess_image2_codec(p->filename)) { if (av_filename_number_test(p->filename)) return AVPROBE_SCORE_MAX; + else if (is_glob(p->filename)) + return AVPROBE_SCORE_MAX; else return AVPROBE_SCORE_MAX/2; } @@ -183,8 +219,21 @@ static int read_header(AVFormatContext *s1) } if (!s->is_pipe) { + s->use_glob = is_glob(s->path); + if (s->use_glob) { +#if HAVE_GLOB + int gerr; + gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC|GLOB_TILDE_CHECK, NULL, &s->globstate); + if (gerr != 0) { + return AVERROR(ENOENT); + } + first_index = 0; + last_index = s->globstate.gl_pathc - 1; +#endif + } else { if (find_image_range(&first_index, &last_index, s->path) < 0) return AVERROR(ENOENT); + } s->img_first = first_index; s->img_last = last_index; s->img_number = first_index; @@ -216,7 +265,8 @@ static int read_header(AVFormatContext *s1) static int read_packet(AVFormatContext *s1, AVPacket *pkt) { VideoDemuxData *s = s1->priv_data; - char filename[1024]; + char filename_bytes[1024]; + char *filename = filename_bytes; int i; int size[3]={0}, ret[3]={0}; AVIOContext *f[3]; @@ -229,9 +279,15 @@ static int read_packet(AVFormatContext *s1, AVPacket *pkt) } if (s->img_number > s->img_last) return AVERROR_EOF; - if (av_get_frame_filename(filename, sizeof(filename), + if (s->use_glob) { +#if HAVE_GLOB + filename = s->globstate.gl_pathv[s->img_number]; +#endif + } else { + if (av_get_frame_filename(filename_bytes, sizeof(filename_bytes), s->path, s->img_number)<0 && s->img_number > 1) return AVERROR(EIO); + } for(i=0; i<3; i++){ if (avio_open2(&f[i], filename, AVIO_FLAG_READ, &s1->interrupt_callback, NULL) < 0) { @@ -281,6 +337,17 @@ static int read_packet(AVFormatContext *s1, AVPacket *pkt) } } +static int read_close(struct AVFormatContext* s1) +{ + VideoDemuxData *s = s1->priv_data; +#if HAVE_GLOB + if (s->use_glob) { + globfree(&s->globstate); + } +#endif + return 0; +} + #define OFFSET(x) offsetof(VideoDemuxData, x) #define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { @@ -305,6 +372,7 @@ AVInputFormat ff_image2_demuxer = { .read_probe = read_probe, .read_header = read_header, .read_packet = read_packet, + .read_close = read_close, .flags = AVFMT_NOFILE, .priv_class = &img2_class, };