|
diff -Nurp orig-ffmpeg-5.1.2/doc/muxers.texi ffmpeg-5.1.2/doc/muxers.texi |
|
--- orig-ffmpeg-5.1.2/doc/muxers.texi 2022-10-26 20:41:23.448158621 -0500 |
|
+++ ffmpeg-5.1.2/doc/muxers.texi 2022-10-26 20:43:33.992821906 -0500 |
|
@@ -1392,6 +1392,9 @@ If the pattern contains "%d" or "%0@var{ |
|
the file list specified will contain the number 1, all the following |
|
numbers will be sequential. |
|
|
|
+The pattern can also contain "%t" which writes out the timestamp of the |
|
+frame in the format "HH.mm.ss.fff" |
|
+ |
|
The pattern may contain a suffix which is used to automatically |
|
determine the format of the image files to write. |
|
|
|
diff -Nurp orig-ffmpeg-5.1.2/libavformat/avformat.h ffmpeg-5.1.2/libavformat/avformat.h |
|
--- orig-ffmpeg-5.1.2/libavformat/avformat.h 2022-10-26 20:41:22.344119243 -0500 |
|
+++ ffmpeg-5.1.2/libavformat/avformat.h 2022-10-26 20:45:29.792968466 -0500 |
|
@@ -2733,10 +2733,11 @@ void av_dump_format(AVFormatContext *ic, |
|
* @param path numbered sequence string |
|
* @param number frame number |
|
* @param flags AV_FRAME_FILENAME_FLAGS_* |
|
+ * @param ts frame timestamp in seconds |
|
* @return 0 if OK, -1 on format error |
|
*/ |
|
int av_get_frame_filename2(char *buf, int buf_size, |
|
- const char *path, int number, int flags); |
|
+ const char *path, int number, int flags, int64_t t); |
|
|
|
int av_get_frame_filename(char *buf, int buf_size, |
|
const char *path, int number); |
|
diff -Nurp orig-ffmpeg-5.1.2/libavformat/img2enc.c ffmpeg-5.1.2/libavformat/img2enc.c |
|
--- orig-ffmpeg-5.1.2/libavformat/img2enc.c 2022-10-26 20:41:22.400121240 -0500 |
|
+++ ffmpeg-5.1.2/libavformat/img2enc.c 2022-10-26 21:04:27.033262565 -0500 |
|
@@ -140,9 +140,11 @@ static int write_packet(AVFormatContext |
|
AVIOContext *pb[4] = {0}; |
|
char filename[1024]; |
|
AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; |
|
+ AVStream *stream = s->streams[pkt->stream_index]; |
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(par->format); |
|
int ret, i; |
|
int nb_renames = 0; |
|
+ int64_t ts = av_rescale_q(pkt->pts, stream->time_base, AV_TIME_BASE_Q); |
|
AVDictionary *options = NULL; |
|
|
|
if (img->update) { |
|
@@ -157,13 +159,14 @@ static int write_packet(AVFormatContext |
|
return AVERROR(EINVAL); |
|
} |
|
} else if (img->frame_pts) { |
|
- if (av_get_frame_filename2(filename, sizeof(filename), s->url, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { |
|
+ if (av_get_frame_filename2(filename, sizeof(filename), s->url, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) { |
|
av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames."); |
|
return AVERROR(EINVAL); |
|
} |
|
} else if (av_get_frame_filename2(filename, sizeof(filename), s->url, |
|
img->img_number, |
|
- AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { |
|
+ AV_FRAME_FILENAME_FLAGS_MULTIPLE, |
|
+ ts) < 0) { |
|
if (img->img_number == img->start_img_number) { |
|
av_log(s, AV_LOG_WARNING, "The specified filename '%s' does not contain an image sequence pattern or a pattern is invalid.\n", s->url); |
|
av_log(s, AV_LOG_WARNING, |
|
diff -Nurp orig-ffmpeg-5.1.2/libavformat/utils.c ffmpeg-5.1.2/libavformat/utils.c |
|
--- orig-ffmpeg-5.1.2/libavformat/utils.c 2022-10-26 20:41:22.348119385 -0500 |
|
+++ ffmpeg-5.1.2/libavformat/utils.c 2022-10-26 21:02:46.913755214 -0500 |
|
@@ -291,15 +291,17 @@ uint64_t ff_parse_ntp_time(uint64_t ntp_ |
|
return (sec * 1000000) + usec; |
|
} |
|
|
|
-int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number, int flags) |
|
+int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number, int flags, int64_t ts) |
|
{ |
|
const char *p; |
|
char *q, buf1[20], c; |
|
- int nd, len, percentd_found; |
|
+ int nd, len, percentd_found, percentt_found; |
|
+ int hours, mins, secs, ms; |
|
|
|
q = buf; |
|
p = path; |
|
percentd_found = 0; |
|
+ percentt_found = 0; |
|
for (;;) { |
|
c = *p++; |
|
if (c == '\0') |
|
@@ -331,6 +333,26 @@ int av_get_frame_filename2(char *buf, in |
|
memcpy(q, buf1, len); |
|
q += len; |
|
break; |
|
+ case 't': |
|
+ if (percentd_found) |
|
+ goto fail; |
|
+ if (ts < 0) |
|
+ goto fail; |
|
+ percentt_found = 1; |
|
+ ms = (ts/1000)%1000; |
|
+ ts /= AV_TIME_BASE; |
|
+ secs = ts % 60; |
|
+ ts /= 60; |
|
+ mins = ts % 60; |
|
+ ts /= 60; |
|
+ hours = ts; |
|
+ snprintf(buf1, sizeof(buf1), "%02d.%02d.%02d.%03d", hours, mins, secs, ms); |
|
+ len = strlen(buf1); |
|
+ if ((q - buf + len) > buf_size - 1) |
|
+ goto fail; |
|
+ memcpy(q, buf1, len); |
|
+ q += len; |
|
+ break; |
|
default: |
|
goto fail; |
|
} |
|
@@ -340,7 +362,7 @@ addchar: |
|
*q++ = c; |
|
} |
|
} |
|
- if (!percentd_found) |
|
+ if (!(percentd_found || percentt_found)) |
|
goto fail; |
|
*q = '\0'; |
|
return 0; |
|
@@ -351,7 +373,7 @@ fail: |
|
|
|
int av_get_frame_filename(char *buf, int buf_size, const char *path, int number) |
|
{ |
|
- return av_get_frame_filename2(buf, buf_size, path, number, 0); |
|
+ return av_get_frame_filename2(buf, buf_size, path, number, 0, 0); |
|
} |
|
|
|
void av_url_split(char *proto, int proto_size, |