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/
From d3ba01f86900f3eae2bc4308a62d8c7c43c145c6 Mon Sep 17 00:00:00 2001 From: Georgi Chorbadzhiyski <g...@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
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel