[FFmpeg-devel] [PATCH] segment: Create missing directories
Georgi Chorbadzhiyski
gf at unixsol.org
Tue Feb 20 13:17:19 EET 2018
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
--
Georgi Chorbadzhiyski | http://georgi.unixsol.org/ | http://github.com/gfto/
-------------- next part --------------
From d3ba01f86900f3eae2bc4308a62d8c7c43c145c6 Mon Sep 17 00:00:00 2001
From: Georgi Chorbadzhiyski <gf at unixsol.org>
Date: Sun, 18 Feb 2018 18:10:33 +0200
Subject: [PATCH] segment: Create missing directories
---
libavformat/segment.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
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) {
--
2.9.0
More information about the ffmpeg-devel
mailing list