img2 encoder: allow %t in filename, based on patch from Yuval Adam
Signed-off-by: rogerdpack <rogerpack2005@gmail.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
		
							parent
							
								
									7ddfa0be62
								
							
						
					
					
						commit
						1a956c64c8
					
				| @ -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: | |||||||
| 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, | |||||||
|  * @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) | |||||||
|     } 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) | |||||||
|             } |             } | ||||||
|         } 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) | |||||||
|     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) | |||||||
|             } |             } | ||||||
|         } 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) | |||||||
|     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 | |||||||
|                 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: | |||||||
|                 *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: | |||||||
| 
 | 
 | ||||||
| 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, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user