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

Brian Olson icic at bolson.org
Mon Jan 9 02:17:06 CET 2012


To make a singular net diff, here's the output of `git diff master mybranch` (also attached if that's easier to parse):

diff --git a/configure b/configure
index 43b63bb..47146d8 100755
--- a/configure
+++ b/configure
@@ -1179,6 +1179,7 @@ HAVE_LIST="
   GetProcessMemoryInfo
   GetProcessTimes
   getrusage
+    glob
   gnu_as
   ibm_asm
   inet_aton
@@ -3021,6 +3022,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 83a45a8..ded3098 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1226,7 +1226,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 bc35591..7f94a1f 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -29,6 +29,9 @@
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
+#if HAVE_GLOB
+#include <glob.h>
+#endif

typedef struct {
   const AVClass *class;  /**< Class for private options. */
@@ -44,6 +47,10 @@ typedef struct {
   char *framerate;        /**< Set by a private option. */
   int loop;
   int updatefirst;
+#if HAVE_GLOB
+    int use_glob;
+    glob_t globstate;
+#endif
} VideoData;

typedef struct {
@@ -133,6 +140,38 @@ static enum CodecID av_str2id(const IdStrMap *tags, const char *str)
   return CODEC_ID_NONE;
}

+#if HAVE_GLOB
+static int glob_errfunc(const char* epath, int glob_error) {
+	return 0;
+}
+static int is_glob(const char* path) {
+    while (*path != '\0') {
+        switch (*path) {
+        case '*':
+        case '?':
+        case '[':
+        case ']':
+        case '{':
+        case '}':
+        case '\\':
+            return 1;
+        }
+        path++;
+    }
+    return 0;
+}
+static int use_glob(VideoData *s) {
+    return s->use_glob;
+}
+#else
+static int is_glob(const char* path) {
+    return 0;
+}
+static int use_glob(VideoData *s) {
+    return 0;
+}
+#endif
+
/* return -1 if no image found */
static int find_image_range(int *pfirst_index, int *plast_index,
                           const char *path)
@@ -192,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;
   }
@@ -263,10 +304,42 @@ static int read_header(AVFormatContext *s1, AVFormatParameters *ap)
   }

   if (!s->is_pipe) {
-        if (find_image_range(&first_index, &last_index, s->path) < 0)
-            return AVERROR(ENOENT);
-        s->img_first = first_index;
-        s->img_last = last_index;
+        if (is_glob(s->path)) {
+#if HAVE_GLOB
+            int gerr;
+            s->use_glob = 1;
+/* 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
+            gerr = glob(
+			    s->path,
+				GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC|GLOB_TILDE_CHECK,
+				glob_errfunc,
+				&s->globstate);
+            if (gerr != 0) {
+                return AVERROR(ENOENT);
+            }
+            s->img_first = 0;
+            s->img_last = 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;
       /* compute duration */
       st->start_time = 0;
@@ -296,7 +369,8 @@ static int read_header(AVFormatContext *s1, AVFormatParameters *ap)
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];
@@ -309,9 +383,17 @@ 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),
-                                  s->path, s->img_number)<0 && s->img_number > 1)
-            return AVERROR(EIO);
+        if (use_glob(s)) {
+#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) {
@@ -361,6 +443,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 */
@@ -494,6 +586,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,
};




On Jan 8, 2012, at 12:50 PM, Nicolas George wrote:

> The preferred way for external contributors (and most internal ones too, in
> fact) is to use git send-email, or the equivalent using git format-patch.
> You will probably need to squash your patches together into a single one.
> The patch then gets reviewed inline.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: glob20120108.diff.gz
Type: application/x-gzip
Size: 2356 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120108/77061885/attachment.bin>


More information about the ffmpeg-devel mailing list