From patchwork Tue Feb 20 11:17:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georgi Chorbadzhiyski X-Patchwork-Id: 7677 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.150.33 with SMTP id c30csp2591397jai; Tue, 20 Feb 2018 03:17:28 -0800 (PST) X-Google-Smtp-Source: AH8x226WyK//CnnI0crDc6IF5in9SDNmYo59TlsMKck1VAq+x7Mccjnf/bh2JX/eKAD1uEj2nhCp X-Received: by 10.28.247.25 with SMTP id v25mr14502146wmh.10.1519125448126; Tue, 20 Feb 2018 03:17:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519125448; cv=none; d=google.com; s=arc-20160816; b=JJ1fTYIFtXKHty4x81nFyN8V3f/ZFhlR4lCnj6FrwgPU4t4MEdOPdEX6hs+eAwJ0Ui 0+x/YaI6JZtWOlYmbIyuQQCahUJLvlebuRM6qMT6EW7dAPZTqre61ao8YFdclRkfd9Wl HvCSV2mJJlgDlUKP+ufQSULDPkDBPCY6skNQC4Npy8u62/d6pPPYMZKXZWHqVtvh3ZRr +SgMwwi/2gEn3M1sezfXDOMpFrPpgoYEo6yyfl2aAA+98FV9OaKLXnS3JuqvecMlx+wq 7qHXfbPrXX6wRgt1+KujgfUJHZuk91j4CcDC/VfwCrYni5jZm9bQpQe10yuw0FpSgoPN w6wg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject :content-language:mime-version:user-agent:date:message-id:from:to :delivered-to:arc-authentication-results; bh=r16ARpDS9ifOBVHGlnd0yqyB+3zk7lHCsK1bT+IsD8w=; b=dEZhQI2JosNFkcwF9V4WjOzSkh4OcI+99AmazVe3ExBOndciEeEuq59X0KSU+v59ne dl4Men5AODpxzcLZRsbPh4cPRngv7OLbmks6u1X+kRPxF5pq8CvRK+YgL2jeZseWkTyx 96TDI1Ks3A1jPcPLFhFr16lz15sEuqn+go0l6O6zlB08NU0hdtCkWBtJsWckX3OUZgdM CpKlRc33AGIU85PBv4R7nX71sJPgKXw4vd4329d3LKNdZHm3FH9yNe2pAfTpxxH/fR/I dP9F3Xvid3hx0hY3E0ElqLiwYNT6ALtPEj3OK2ebj9CdGUWM+wwUIA9xencijF+HJAlZ POcg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id g78si15481058wmc.244.2018.02.20.03.17.27; Tue, 20 Feb 2018 03:17:28 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id EC3F668A29A; Tue, 20 Feb 2018 13:17:24 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from ns.unixsol.org (ns.unixsol.org [193.110.159.2]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 80AA968A25F for ; Tue, 20 Feb 2018 13:17:18 +0200 (EET) Received: from gwork.local ([::ffff:82.118.240.130]) (AUTH: CRAM-MD5 gf, SSL: TLSv1/SSLv3,128bits,AES128-SHA) by ns.unixsol.org with ESMTPSA; Tue, 20 Feb 2018 13:17:19 +0200 id 0000000000560188.000000005A8C03BF.000045BE To: ffmpeg-devel@ffmpeg.org From: Georgi Chorbadzhiyski Message-ID: <21754b81-89e9-a6e1-6f01-78d4acd0b8e6@unixsol.org> Date: Tue, 20 Feb 2018 13:17:19 +0200 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Thunderbird/52.6.0 Mime-Version: 1.0 Content-Language: en-US Subject: [FFmpeg-devel] [PATCH] segment: Create missing directories X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 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 #include +#include #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) {