From patchwork Tue Aug 1 20:10:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Heitor Schmidt X-Patchwork-Id: 43067 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:c11f:b0:130:ccc6:6c4b with SMTP id bh31csp214519pzb; Tue, 1 Aug 2023 13:10:52 -0700 (PDT) X-Google-Smtp-Source: APBJJlFC8J8BuIdNSySNG6GXx8DBmSRuh1wXBewVW9Ut9H1Agha35qQB1fbFQibbudXz38/PdtYZ X-Received: by 2002:a19:504a:0:b0:4fe:a2e:8905 with SMTP id z10-20020a19504a000000b004fe0a2e8905mr2779780lfj.44.1690920652210; Tue, 01 Aug 2023 13:10:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690920652; cv=none; d=google.com; s=arc-20160816; b=qpjCQjr1Z/cnkuOie61FTTUESHRqDQwsxji0tebVMl5ZlSQW49ruhFedmsIxEwRKZe 9qHuuw4OpnZ1w3nJJrhR2ECwgDkF0ryrflVFOVHAWi5SX4qZnSHl9nR8MNzIGA9VssK3 oqed71JWNQcB6xeUse3uUgqFgGVHA0B3Ud7jS0ruxH6dP/Dl412dEG/jQJ7u4KM6WF+o qe/O/rESF9SslRG5nvKSX+vBtxWUO5xlyDXWZATZVq7XJa94lxg4ra/y6IW1a5GUQ3fG JmRmordPOQqEfjOT/5q11Gjx/gnHprdzMlyajiXaKOSqDwjFMr7uIsb2DibVGeQCbZCe FNFw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=h6wJrN1e/FjzaCF1FrllsHKAY3T+tGMxgTa1Za62t20=; fh=JKig6YvcoVg2mcNpSIZelmNRJaU8GjIzZfzj9RsOkkQ=; b=EhmAfBjMXhEh0Kyi0zlIXomtL7WQJ8zhlewTMd0ML0Zmx2ARrxGEbz7awp/RnFivIP tmBPlksM3afQ9oriEy0M5N9CslyZ+T0uYczuZPlasjWZfYEVtQoqjlQNkQRKXJDvHnz8 j9F1bzv6/D7ULjiYjm8HhjSlzmCgpvZGJhGi6nWkbno5985HGQi6gHXu2752kDDCnSU+ 1/xhDy4yV6mpexldR95JysvPiIfCT4lD9rmS6hrkucM1S6Ijjg+Z/ewxF8w3nvHmz+lI JaMF9VEjWj6lTTo0dFNOO0DxkSe28Yb1+pyxF01nJa6OA4pLyBInX72V7aqTVkp3JSnO RzwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20221208 header.b=m76fArQF; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id x19-20020aa7d6d3000000b00522828d438dsi775274edr.32.2023.08.01.13.10.51; Tue, 01 Aug 2023 13:10:52 -0700 (PDT) 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; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20221208 header.b=m76fArQF; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id AED9368BDBB; Tue, 1 Aug 2023 23:10:48 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-oi1-f174.google.com (mail-oi1-f174.google.com [209.85.167.174]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 52EBC68BDBB for ; Tue, 1 Aug 2023 23:10:42 +0300 (EEST) Received: by mail-oi1-f174.google.com with SMTP id 5614622812f47-3a4875e65a3so4268249b6e.2 for ; Tue, 01 Aug 2023 13:10:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1690920640; x=1691525440; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=HkGiPl8mC83hOKsUuMjIqXgt5rc7+Si/H3jiUNcCJ3U=; b=m76fArQFfYYbHmGxaBZzpnGhbNo1+hD3JE3rXNbF4MhuaJbxtWs5nqZW3IGhV1ub6K hh2yRx4JKOaV2sB/OitcQQ1/nLmJlJcAFh+H/8t4cH7U6yzDyLeu7GZwHvHefRLoCBgS 5JQUS6tYWVfCykvMb8kwO4xO6HP/8MmCt5lHUfdOAuuDGEBL6hLACHZn8F0jrsDjMHUv FQJV0GMTIbVIIXwG2Oa8zHvM68jHu7bNq6Cf0CDe/ecFVTaEIYvd2ft/sDjbRIb2KeOp DC7dl88fGsqqljQ9fNqFLJ5SsbTRVQNXjF3cTyAjW1AsKPymQ+0tc+SS9arSqoyDc9kq Wp4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690920640; x=1691525440; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=HkGiPl8mC83hOKsUuMjIqXgt5rc7+Si/H3jiUNcCJ3U=; b=b7QWSWQo7wvq8Fa/DbMyMMqpAOrZT2PU/wqMJ2xlD++3MUlomkdDRQ+0/2VuFiQss8 W8lp4CIcPb6JsQhwsCzKW4Oa8QfeH+4nyGu0eVys129ZqvAt1qEa0/oXp37BxA0KAXhh u9Zo0iFgIumIm4VfB3M3JcN6iLif7wDwva6zmEJp83LK2TVnSA3BJRZguzEMJfZddQLP G/RjxzPQyH1qz1Pe97IiJcbgLOZv1DjGlhrWeKPQ5FANTcheu32UJ8n6CqBKqAaZy2Ux akZjVFO7xEODtr5Yi+EeONubp/8IAhkJtscSTnRnnJJS2a2aFPpaM6w7Xrc2HRL9HntF kxcg== X-Gm-Message-State: ABy/qLZkPga/K21S6PsCNQ/lvGdtCDV2lWIY0rgjwhwg6ht0SKjO0UnI bcfLL1niuyYX1p+57lhwAYhxFYTc/viGXw== X-Received: by 2002:a05:6808:1148:b0:3a7:4fa4:edf8 with SMTP id u8-20020a056808114800b003a74fa4edf8mr3158049oiu.33.1690920640611; Tue, 01 Aug 2023 13:10:40 -0700 (PDT) Received: from xps13.attlocal.net (99-1-221-16.lightspeed.tukrga.sbcglobal.net. [99.1.221.16]) by smtp.gmail.com with ESMTPSA id c202-20020a25c0d3000000b00d123136e2fasm3275190ybf.38.2023.08.01.13.10.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Aug 2023 13:10:40 -0700 (PDT) From: Alexandre Heitor Schmidt To: ffmpeg-devel@ffmpeg.org Date: Tue, 1 Aug 2023 16:10:25 -0400 Message-Id: <20230801201025.33541-1-alexandre.schmidt@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat/img2dec: added option -strftime_mkdir to allow directory creation if the strftime pattern include non-existing directories, similarly to how hls muxer does. X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Alexandre Heitor Schmidt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: MSIHc590YKAZ doc/demuxers.texi: Documented how to use the new parameter. Usage example: ffmpeg -i /dev/video0 -strftime 1 -strftime_mkdir 1 "/tmp/%Y/%m/%Y_%m_%d-%H_%M_%S.jpg" --- doc/muxers.texi | 13 +++++++++++++ libavformat/img2enc.c | 28 +++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index f6071484ff..1d03fef84b 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1421,6 +1421,19 @@ overwritten with new images. Default value is 0. If set to 1, expand the filename with date and time information from @code{strftime()}. Default value is 0. +@item strftime_mkdir +Used together with -strftime, if set to 1, it will create all subdirectories +which are expanded in @var{filename}. +@example +ffmpeg -i /dev/video0 -strftime 1 -strftime_mkdir 1 "/tmp/%Y/%m/%Y_%m_%d-%H_%M_%S.jpg" +@end example +This example will read all frames from /dev/video0 and save each frame into +@file{/tmp/%Y_%m/%Y_%m_%d-%H_%M_%S.jpg}, creating the necessary directory +structure if it doesn't exist. Supposing the current date at the time of the +image creation is 1978-04-27 15:01:02, the directory @file{/tmp/1978/04} +would be created - if it didn't existed - prior from saving the output file +@file{1978_04_27-15_01_02.jpg} into it. + @item atomic_writing Write output to a temporary file, which is renamed to target filename once writing is completed. Default is disabled. diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c index 9b8ec06cea..238f281467 100644 --- a/libavformat/img2enc.c +++ b/libavformat/img2enc.c @@ -44,6 +44,7 @@ typedef struct VideoMuxData { char target[4][1024]; int update; int use_strftime; + int use_strftime_mkdir; int frame_pts; const char *muxer; int use_rename; @@ -157,6 +158,22 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n"); return AVERROR(EINVAL); } + + // whether to create non-existing directory structure + if (img->use_strftime_mkdir) { + const char *dir; + char *fn_copy = av_strdup(filename); + if (!fn_copy) + return AVERROR(ENOMEM); + dir = av_dirname(fn_copy); + if (ff_mkdir_p(dir) == -1 && errno != EEXIST) { + av_log(s, AV_LOG_ERROR, "Could not create directory %s with use_strftime_mkdir\n", dir); + av_freep(&fn_copy); + return AVERROR(errno); + } + av_log(s, AV_LOG_VERBOSE, "Created directory %s\n", dir); + av_freep(&fn_copy); + } } else if (img->frame_pts) { if (av_get_frame_filename2(filename, sizeof(filename), s->url, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames."); @@ -252,12 +269,13 @@ static int query_codec(enum AVCodecID id, int std_compliance) #define OFFSET(x) offsetof(VideoMuxData, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption muxoptions[] = { - { "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, - { "start_number", "set first number in the sequence", OFFSET(start_img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC }, - { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, - { "frame_pts", "use current frame pts for filename", OFFSET(frame_pts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, + { "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, + { "start_number", "set first number in the sequence", OFFSET(start_img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC }, + { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, + { "strftime_mkdir", "create directory structure for filename, if needed", OFFSET(use_strftime_mkdir), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, + { "frame_pts", "use current frame pts for filename", OFFSET(frame_pts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "atomic_writing", "write files atomically (using temporary files and renames)", OFFSET(use_rename), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, - { "protocol_opts", "specify protocol options for the opened files", OFFSET(protocol_opts), AV_OPT_TYPE_DICT, {0}, 0, 0, ENC }, + { "protocol_opts", "specify protocol options for the opened files", OFFSET(protocol_opts), AV_OPT_TYPE_DICT, {0}, 0, 0, ENC }, { NULL }, };