[FFmpeg-devel] [patch] glob matching for image series

Brian Olson icic at bolson.org
Mon Feb 20 00:06:35 CET 2012


On Jan 31, 2012, at 1:52 AM, Brian Olson wrote:

> On Jan 29, 2012, at 1:37 PM, Nicolas George wrote:
> 
>>> +static int glob_errfunc(const char *epath, int glob_error)
>>> +{
>>> +    return 0;
>>> +}
>> 
>> According to Single Unix, passing NULL as errfunc would have the same
>> effect. Do you have any reason not to use that feature?
> 
> I guess I wrote this as a place holder in case I needed to handle glob errors and turn them into specific libavformat errors. I could delete this, or leave it as an explicit placeholder and disambiguator of the NULL parameter to glob().
> 
> I think the rest of the style things are cleaned up, making a more minimal patch without whitespace changes on a few lines where I had reindented things.

Cleaning up that one-last-thing, and rewarming the thread, here's a patch (against master branch from earlier today) that removes the excess glob error handler function and cleans up the #if statements around it.

diff --git a/configure b/configure
index 70fc016..1ead0d1 100755
--- a/configure
+++ b/configure
@@ -1186,6 +1186,7 @@ HAVE_LIST="
     GetProcessMemoryInfo
     GetProcessTimes
     getrusage
+    glob
     gnu_as
     ibm_asm
     inet_aton
@@ -3059,6 +3060,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 51a282e..32b8cf9 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1282,7 +1282,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
+ at 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/img2.c b/libavformat/img2.c
index 5776c0d..740bf82 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -29,6 +29,25 @@
 #include "avformat.h"
 #include "avio_internal.h"
 #include "internal.h"
+#if HAVE_GLOB
+#include <glob.h>
+
+/* 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. */
@@ -44,6 +63,10 @@ typedef struct {
     char *framerate;        /**< Set by a private option. */
     int loop;
     int updatefirst;
+    int use_glob;
+#if HAVE_GLOB
+    glob_t globstate;
+#endif
 } VideoData;
 
 typedef struct {
@@ -138,6 +161,17 @@ static enum CodecID av_str2id(const IdStrMap *tags, const char *str)
     return CODEC_ID_NONE;
 }
 
+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)
@@ -197,6 +231,8 @@ static int read_probe(AVProbeData *p)
     if (p->filename && av_str2id(img_tags, 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;
     }
@@ -257,8 +293,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;
@@ -290,7 +339,8 @@ static int read_header(AVFormatContext *s1)
 static int read_packet(AVFormatContext *s1, AVPacket *pkt)
 {
     VideoData *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];
@@ -303,9 +353,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) {
@@ -355,6 +411,16 @@ static int read_packet(AVFormatContext *s1, AVPacket *pkt)
     }
 }
 
+static int read_close(struct AVFormatContext* s1) {
+    VideoData *s = s1->priv_data;
+#if HAVE_GLOB
+    if (s->use_glob) {
+        globfree(&s->globstate);
+    }
+#endif
+    return 0;
+}
+
 #if CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER
 /******************************************************/
 /* image output */
@@ -488,6 +554,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,
 };

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 20120219_img_glob.diff.gz
Type: application/x-gzip
Size: 2217 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120219/0bf22729/attachment.bin>


More information about the ffmpeg-devel mailing list