diff mbox

[FFmpeg-devel] Adding mkdir option for img2enc

Message ID be814673-f6fe-80e3-15a0-67a79fb14eb6@escribe.co.uk
State New
Headers show

Commit Message

Dr Alan Barclay Dec. 17, 2017, 10:41 p.m. UTC
Hi All,

Please would someone with an interest in img2enc take a look at my minor 
feature addition and consider committing it to the main line for me.

Example:
ffmpeg -i ~/trailer.mp4 -strftime 1 -mkdir 1 %Y/%m/%d/out_%H-%M-%S.jpg

Without the new mkdir option, this command will fail if the directory 
hierarchy for the jpg files does not already exist, which can be 
difficult to predict for time-stamped directories.

This patch adds a mkdir option to img2enc which invites it to make 
whatever directory hierarchy is necessary for each output file. When 
used in conjunction with the strftime then the jpg files will be located 
in a newly created (time-stamped) directory as processing progresses.

My typical usage scenario is capturing a long-running live video feed 
(perhaps time-lapsed) and storing the resulting images in a time-stamped 
directory hierarchy fashion, rather than as a numbered sequence of files 
in a single directory.

If you look at the code you will see that only a half dozen lines of 
code were required in img2enc. The function for creating directories 
already existed in hlsenc.c but I've moved into utils.c as I presumed 
that was a more generic location for it.

All comments appreciated.

Thanks ad Regards,
Alan.

Comments

Carl Eugen Hoyos Dec. 17, 2017, 10:46 p.m. UTC | #1
2017-12-17 23:41 GMT+01:00 Dr Alan Barclay <alan@escribe.co.uk>:

> Please would someone with an interest in img2enc take a look
> at my minor feature addition and consider committing it to the
> main line for me.

To be acceptable, the patch has to be split in two and please
move the definition into internal.h

Carl Eugen
diff mbox

Patch

From 666ba7be8878a401c1e7fedd6dd7f56c9e049e14 Mon Sep 17 00:00:00 2001
From: "Dr. Alan Barclay" <alan@escribe.co.uk>
Date: Sun, 17 Dec 2017 19:24:44 +0000
Subject: [PATCH] Adding mkdir option for img2enc.

---
 libavformat/avformat.h |  7 +++++++
 libavformat/hlsenc.c   | 33 ---------------------------------
 libavformat/img2enc.c  |  8 ++++++++
 libavformat/utils.c    | 33 +++++++++++++++++++++++++++++++++
 4 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 4f2798a871..8e76fb3349 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2990,6 +2990,13 @@  int avformat_transfer_internal_stream_timing_info(const AVOutputFormat *ofmt,
 AVRational av_stream_get_codec_timebase(const AVStream *st);
 
 /**
+ * Make the specified directory.
+ *
+ * @param path  path for directory
+ */
+int mkdir_p(const char *path);
+
+/**
  * @}
  */
 
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index dd09739651..8523916d98 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -205,39 +205,6 @@  typedef struct HLSContext {
     int http_persistent;
 } HLSContext;
 
-static int mkdir_p(const char *path) {
-    int ret = 0;
-    char *temp = av_strdup(path);
-    char *pos = temp;
-    char tmp_ch = '\0';
-
-    if (!path || !temp) {
-        return -1;
-    }
-
-    if (!strncmp(temp, "/", 1) || !strncmp(temp, "\\", 1)) {
-        pos++;
-    } else if (!strncmp(temp, "./", 2) || !strncmp(temp, ".\\", 2)) {
-        pos += 2;
-    }
-
-    for ( ; *pos != '\0'; ++pos) {
-        if (*pos == '/' || *pos == '\\') {
-            tmp_ch = *pos;
-            *pos = '\0';
-            ret = mkdir(temp, 0755);
-            *pos = tmp_ch;
-        }
-    }
-
-    if ((*(pos - 1) != '/') || (*(pos - 1) != '\\')) {
-        ret = mkdir(temp, 0755);
-    }
-
-    av_free(temp);
-    return ret;
-}
-
 static int is_http_proto(char *filename) {
     const char *proto = avio_find_protocol_name(filename);
     return proto ? (!av_strcasecmp(proto, "http") || !av_strcasecmp(proto, "https")) : 0;
diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c
index b680676bff..d037719ca1 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -42,6 +42,7 @@  typedef struct VideoMuxData {
     char target[4][1024];
     int update;
     int use_strftime;
+    int use_mkdir;
     int frame_pts;
     const char *muxer;
     int use_rename;
@@ -114,6 +115,12 @@  static int write_packet(AVFormatContext *s, AVPacket *pkt)
                    img->img_number, img->path);
             return AVERROR(EINVAL);
         }
+        if (img->use_mkdir) {
+            char *temp_filename = av_strdup(filename);
+            const char *temp_path = av_dirname(temp_filename);
+            mkdir_p(temp_path);
+            av_free(temp_filename);
+        }
         for (i = 0; i < 4; i++) {
             snprintf(img->tmp[i], sizeof(img->tmp[i]), "%s.tmp", filename);
             av_strlcpy(img->target[i], filename, sizeof(img->target[i]));
@@ -212,6 +219,7 @@  static const AVOption muxoptions[] = {
     { "update",       "continuously overwrite one file", OFFSET(update),  AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0,       1, ENC },
     { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT,  { .i64 = 1 }, 0, INT_MAX, ENC },
     { "strftime",     "use strftime for filename", OFFSET(use_strftime),  AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
+    { "mkdir",        "make sub-dirs as required", OFFSET(use_mkdir),  AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
     { "frame_pts",    "use current frame pts for filename", OFFSET(frame_pts),  AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
     { "atomic_writing", "write files atomically (using temporary files and renames)", OFFSET(use_rename), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
     { NULL },
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 84e49208b8..3f32cc9e18 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -5606,3 +5606,36 @@  FF_ENABLE_DEPRECATION_WARNINGS
     return st->internal->avctx->time_base;
 #endif
 }
+
+int mkdir_p(const char *path) {
+    int ret = 0;
+    char *temp = av_strdup(path);
+    char *pos = temp;
+    char tmp_ch = '\0';
+
+    if (!path || !temp) {
+        return -1;
+    }
+
+    if (!strncmp(temp, "/", 1) || !strncmp(temp, "\\", 1)) {
+        pos++;
+    } else if (!strncmp(temp, "./", 2) || !strncmp(temp, ".\\", 2)) {
+        pos += 2;
+    }
+
+    for ( ; *pos != '\0'; ++pos) {
+        if (*pos == '/' || *pos == '\\') {
+            tmp_ch = *pos;
+            *pos = '\0';
+            ret = mkdir(temp, 0755);
+            *pos = tmp_ch;
+        }
+    }
+
+    if ((*(pos - 1) != '/') || (*(pos - 1) != '\\')) {
+        ret = mkdir(temp, 0755);
+    }
+
+    av_free(temp);
+    return ret;
+}
-- 
2.11.0