diff mbox

[FFmpeg-devel] segment: Create missing directories

Message ID 21754b81-89e9-a6e1-6f01-78d4acd0b8e6@unixsol.org
State New
Headers show

Commit Message

Georgi Chorbadzhiyski Feb. 20, 2018, 11:17 a.m. UTC
The attached patch allows segment muxer to be used for file archiving by
allowing it to automatically create the output directories. For example the
following should work as expected:

ffmpeg
  ...input_params...
  -f segment \
     -segment_atclocktime 1 \
     -segment_time 5 \
     -write_empty_segments 1 \
     -segment_format_options movflags=+faststart \
     -strftime 1 output_directory/mychannel/%Y/%m/%d/%H/%M/mychannel-%s-%Y%m%d-%H%M%S.mp4

The patch is against ffmpeg-3.3.6

Comments

Ricardo Constantino Feb. 20, 2018, 11:22 a.m. UTC | #1
On 20 February 2018 at 11:17, Georgi Chorbadzhiyski <gf@unixsol.org> wrote:

> The attached patch allows segment muxer to be used for file archiving by
> allowing it to automatically create the output directories. For example the
> following should work as expected:
>
> ffmpeg
>   ...input_params...
>   -f segment \
>      -segment_atclocktime 1 \
>      -segment_time 5 \
>      -write_empty_segments 1 \
>      -segment_format_options movflags=+faststart \
>      -strftime 1 output_directory/mychannel/%Y/
> %m/%d/%H/%M/mychannel-%s-%Y%m%d-%H%M%S.mp4
>
> The patch is against ffmpeg-3.3.6
>
>
Patches should be made for git master, not old releases.
diff mbox

Patch

diff --git a/libavformat/segment.c b/libavformat/segment.c
index 8ec3653..2d90ef2 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -28,6 +28,7 @@ 
 
 #include <float.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "avformat.h"
 #include "avio_internal.h"
@@ -226,6 +227,49 @@  static int set_segment_filename(AVFormatContext *s)
     return 0;
 }
 
+/* Note: This modifies *dir */
+static int create_dir(char *dir, mode_t mode) {
+    int ret = 0;
+    unsigned int i, dlen;
+    /* Shortcut, there are no deep directories */
+    if (strchr(dir, '/') == NULL)
+        return mkdir(dir, mode);
+    dlen = strlen(dir);
+    /* Skip first char (it can be /) */
+    for (i = 1; i < dlen; i++) {
+        if (dir[i] != '/')
+            continue;
+        dir[i] = '\0';
+        ret = mkdir(dir, mode);
+        dir[i] = '/';
+        if (ret < 0 && errno != EEXIST)
+            goto OUT;
+    }
+    ret = mkdir(dir, mode);
+OUT:
+    return ret;
+}
+
+static int segment_create_directory(AVFormatContext *oc, char *filename) {
+    char *dir, *fname;
+    /* Do nothing when the filename is URL */
+    if (strstr(filename, "://") != NULL)
+        return 0;
+    fname = av_strdup(filename);
+    if (!fname)
+        return AVERROR(ENOMEM);
+    dir = (char *)av_dirname(fname);
+    if (access(dir, W_OK) != F_OK)
+        av_log(oc, AV_LOG_INFO, "Create directory %s\n", dir);
+    if (create_dir(dir, 0777) == -1 && errno != EEXIST) {
+        av_log(oc, AV_LOG_ERROR, "Could not create directory %s\n", dir);
+        av_free(fname);
+        return AVERROR(errno);
+    }
+    av_free(fname);
+    return 0;
+}
+
 static int segment_start(AVFormatContext *s, int write_header)
 {
     SegmentContext *seg = s->priv_data;
@@ -247,6 +291,9 @@  static int segment_start(AVFormatContext *s, int write_header)
     if ((err = set_segment_filename(s)) < 0)
         return err;
 
+    if ((err = segment_create_directory(s, oc->filename)) < 0)
+        return err;
+
     if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0) {
         av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
         return err;
@@ -277,6 +324,10 @@  static int segment_list_open(AVFormatContext *s)
     int ret;
 
     snprintf(seg->temp_list_filename, sizeof(seg->temp_list_filename), seg->use_rename ? "%s.tmp" : "%s", seg->list);
+
+    if ((ret = segment_create_directory(s, seg->temp_list_filename)) < 0)
+        return ret;
+
     ret = s->io_open(s, &seg->list_pb, seg->temp_list_filename, AVIO_FLAG_WRITE, NULL);
     if (ret < 0) {
         av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list);
@@ -746,6 +797,9 @@  static int seg_init(AVFormatContext *s)
     oc = seg->avf;
 
     if (seg->write_header_trailer) {
+        if ((ret = segment_create_directory(s, seg->header_filename ? seg->header_filename : oc->filename)) < 0)
+            return ret;
+
         if ((ret = s->io_open(s, &oc->pb,
                               seg->header_filename ? seg->header_filename : oc->filename,
                               AVIO_FLAG_WRITE, NULL)) < 0) {