* [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.
@ 2023-08-01 20:10 Alexandre Heitor Schmidt
2023-08-02 14:35 ` Nicolas George
0 siblings, 1 reply; 2+ messages in thread
From: Alexandre Heitor Schmidt @ 2023-08-01 20:10 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Alexandre Heitor Schmidt
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 },
};
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [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.
2023-08-01 20:10 [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 Alexandre Heitor Schmidt
@ 2023-08-02 14:35 ` Nicolas George
0 siblings, 0 replies; 2+ messages in thread
From: Nicolas George @ 2023-08-02 14:35 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Alexandre Heitor Schmidt
Alexandre Heitor Schmidt (12023-08-01):
> 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(-)
Hi.
Thanks for the patch. See my remark below.
>
> 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);
> + }
This is copied from hlsenc.c. Please factor it instead.
As far as I can see, ff_mkdir_p() is used exactly twice now and will be
thrice with this patch. And every time, it is invoked after
av_dirname(), so I suggest to turn it into ff_mkdir_p_parent(). That
would also fix the missing error checks in format_name().
> + 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 },
> };
>
Regards,
--
Nicolas George
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-08-02 14:35 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-01 20:10 [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 Alexandre Heitor Schmidt
2023-08-02 14:35 ` Nicolas George
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git