I find this patch very useful. Here is a version against master as recommended by Ricardo.
Works well for me. Thanks Georgi. Le 20/02/2018 à 12:17, Georgi Chorbadzhiyski a écrit : > 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 -- Julien GAULMIN <julien.gaul...@4g-technology.eu>
diff --git a/libavformat/segment.c b/libavformat/segment.c index 7fb4dc7d21..f6b9ea8b89 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -26,6 +26,7 @@ #include <float.h> #include <time.h> +#include <unistd.h> #include "avformat.h" #include "avio_internal.h" @@ -230,6 +231,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; @@ -251,6 +295,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->url)) < 0) + return err; + if ((err = s->io_open(s, &oc->pb, oc->url, AVIO_FLAG_WRITE, NULL)) < 0) { av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->url); return err; @@ -281,6 +328,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); @@ -750,6 +801,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->url)) < 0) + return ret; + if ((ret = s->io_open(s, &oc->pb, seg->header_filename ? seg->header_filename : oc->url, AVIO_FLAG_WRITE, NULL)) < 0) {
signature.asc
Description: OpenPGP digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel