Commit 1a956c64 authored by rogerdpack's avatar rogerdpack Committed by Michael Niedermayer

img2 encoder: allow %t in filename, based on patch from Yuval Adam

Signed-off-by: 's avatarrogerdpack <rogerpack2005@gmail.com>
Signed-off-by: 's avatarMichael Niedermayer <michael@niedermayer.cc>
parent 7ddfa0be
...@@ -619,6 +619,12 @@ If the pattern contains "%d" or "%0@var{N}d", the first filename of ...@@ -619,6 +619,12 @@ If the pattern contains "%d" or "%0@var{N}d", the first filename of
the file list specified will contain the number 1, all the following the file list specified will contain the number 1, all the following
numbers will be sequential. numbers will be sequential.
If the pattern contains "%t", the frame's timestamps will be inserted
in the filename like "00.00.00.000" for hours, minutes, seconds,
and milliseconds.
The "%t" and "%d" patterns may be used simultaneously.
The pattern may contain a suffix which is used to automatically The pattern may contain a suffix which is used to automatically
determine the format of the image files to write. determine the format of the image files to write.
...@@ -664,6 +670,13 @@ can be used: ...@@ -664,6 +670,13 @@ can be used:
ffmpeg -f v4l2 -r 1 -i /dev/video0 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S.jpg" ffmpeg -f v4l2 -r 1 -i /dev/video0 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S.jpg"
@end example @end example
The following example uses the timestamp parameter to generate one
image file per video frame from the input, and name it including its original
timestamp.
@example
ffmpeg -i in.avi -vsync vfr -copyts img-%t.jpg
@end example
@subsection Options @subsection Options
@table @option @table @option
......
...@@ -2780,10 +2780,11 @@ void av_dump_format(AVFormatContext *ic, ...@@ -2780,10 +2780,11 @@ void av_dump_format(AVFormatContext *ic,
* @param path numbered sequence string * @param path numbered sequence string
* @param number frame number * @param number frame number
* @param flags AV_FRAME_FILENAME_FLAGS_* * @param flags AV_FRAME_FILENAME_FLAGS_*
* @param ts frame timestamp in AV_TIME_BASE fractional seconds.
* @return 0 if OK, -1 on format error * @return 0 if OK, -1 on format error
*/ */
int av_get_frame_filename2(char *buf, int buf_size, 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 ts);
int av_get_frame_filename(char *buf, int buf_size, int av_get_frame_filename(char *buf, int buf_size,
const char *path, int number); const char *path, int number);
......
...@@ -654,7 +654,7 @@ static int hls_start(AVFormatContext *s) ...@@ -654,7 +654,7 @@ static int hls_start(AVFormatContext *s)
} else if (c->max_seg_size > 0) { } else if (c->max_seg_size > 0) {
if (av_get_frame_filename2(oc->filename, sizeof(oc->filename), if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
c->basename, c->wrap ? c->sequence % c->wrap : c->sequence, c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) {
av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename); av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename);
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
...@@ -685,14 +685,14 @@ static int hls_start(AVFormatContext *s) ...@@ -685,14 +685,14 @@ static int hls_start(AVFormatContext *s)
} }
} else if (av_get_frame_filename2(oc->filename, sizeof(oc->filename), } else if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
c->basename, c->wrap ? c->sequence % c->wrap : c->sequence, c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) {
av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename); av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename);
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if( c->vtt_basename) { if( c->vtt_basename) {
if (av_get_frame_filename2(vtt_oc->filename, sizeof(vtt_oc->filename), if (av_get_frame_filename2(vtt_oc->filename, sizeof(vtt_oc->filename),
c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence, c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence,
AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) {
av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename); av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename);
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
......
...@@ -80,10 +80,12 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -80,10 +80,12 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
VideoMuxData *img = s->priv_data; VideoMuxData *img = s->priv_data;
AVIOContext *pb[4]; AVIOContext *pb[4];
char filename[1024]; char filename[1024];
AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; AVStream *stream = s->streams[ pkt->stream_index ];
AVCodecParameters *par = stream->codecpar;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(par->format); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(par->format);
int i; int i;
int nb_renames = 0; int nb_renames = 0;
int64_t ts = av_rescale_q(pkt->pts, stream->time_base, AV_TIME_BASE_Q);
if (!img->is_pipe) { if (!img->is_pipe) {
if (img->update) { if (img->update) {
...@@ -99,7 +101,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -99,7 +101,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
} }
} else if (av_get_frame_filename2(filename, sizeof(filename), img->path, } else if (av_get_frame_filename2(filename, sizeof(filename), img->path,
img->img_number, img->img_number,
AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0 && AV_FRAME_FILENAME_FLAGS_MULTIPLE, ts) < 0 &&
img->img_number > 1) { img->img_number > 1) {
av_log(s, AV_LOG_ERROR, av_log(s, AV_LOG_ERROR,
"Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n", "Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n",
......
...@@ -4379,15 +4379,18 @@ uint64_t ff_ntp_time(void) ...@@ -4379,15 +4379,18 @@ uint64_t ff_ntp_time(void)
return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US;
} }
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; const char *p;
char *q, buf1[20], c; char *q, buf1[20], c;
int nd, len, percentd_found; int nd, len, percentd_found, percentt_found;
int hours, mins, secs, ms;
int64_t abs_ts;
q = buf; q = buf;
p = path; p = path;
percentd_found = 0; percentd_found = 0;
percentt_found = 0;
for (;;) { for (;;) {
c = *p++; c = *p++;
if (c == '\0') if (c == '\0')
...@@ -4416,6 +4419,37 @@ int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number ...@@ -4416,6 +4419,37 @@ int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number
memcpy(q, buf1, len); memcpy(q, buf1, len);
q += len; q += len;
break; break;
case 't':
if (!(flags & AV_FRAME_FILENAME_FLAGS_MULTIPLE) && percentt_found) {
av_log(NULL, AV_LOG_ERROR, "double %%t not allowed");
goto fail;
}
if (ts == 0) {
av_log(NULL, AV_LOG_DEBUG, "%%t but no ts, using 0"); // necessary for first frame on some streams
}
percentt_found = 1;
abs_ts = llabs(ts);
ms = abs_ts % AV_TIME_BASE;
abs_ts /= AV_TIME_BASE;
secs = abs_ts % 60;
abs_ts /= 60;
mins = abs_ts % 60;
abs_ts /= 60;
hours = abs_ts;
if (ts < 0)
snprintf(buf1, sizeof(buf1),
"-%02d.%02d.%02d.%03d", hours, mins, secs, ms);
else
snprintf(buf1, sizeof(buf1),
"%02d.%02d.%02d.%03d", hours, mins, secs, ms);
len = strlen(buf1);
if ((q - buf + len) > buf_size - 1) {
av_log(NULL, AV_LOG_ERROR, "%%t size overflow");
goto fail;
}
memcpy(q, buf1, len);
q += len;
break;
default: default:
goto fail; goto fail;
} }
...@@ -4425,7 +4459,7 @@ addchar: ...@@ -4425,7 +4459,7 @@ addchar:
*q++ = c; *q++ = c;
} }
} }
if (!percentd_found) if (!percentd_found && !percentt_found)
goto fail; goto fail;
*q = '\0'; *q = '\0';
return 0; return 0;
...@@ -4436,7 +4470,7 @@ fail: ...@@ -4436,7 +4470,7 @@ fail:
int av_get_frame_filename(char *buf, int buf_size, const char *path, int number) 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, void av_url_split(char *proto, int proto_size,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment