initial duration/start_time generic support - displays stream duration and average total bitrate when using an input file
Originally committed as revision 2115 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
		
							parent
							
								
									5b685a7a76
								
							
						
					
					
						commit
						12f996edfa
					
				| @ -321,6 +321,8 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, | |||||||
|         err = AVERROR_NOMEM; |         err = AVERROR_NOMEM; | ||||||
|         goto fail; |         goto fail; | ||||||
|     } |     } | ||||||
|  |     ic->duration = AV_NOPTS_VALUE; | ||||||
|  |     ic->start_time = AV_NOPTS_VALUE; | ||||||
|     pstrcpy(ic->filename, sizeof(ic->filename), filename); |     pstrcpy(ic->filename, sizeof(ic->filename), filename); | ||||||
|     pd->filename = ic->filename; |     pd->filename = ic->filename; | ||||||
|     pd->buf = buf; |     pd->buf = buf; | ||||||
| @ -439,6 +441,295 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | /* return TRUE if the stream has accurate timings for at least one component */ | ||||||
|  | static int av_has_timings(AVFormatContext *ic) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     AVStream *st; | ||||||
|  | 
 | ||||||
|  |     for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |         st = ic->streams[i]; | ||||||
|  |         if (st->start_time != AV_NOPTS_VALUE && | ||||||
|  |             st->duration != AV_NOPTS_VALUE) | ||||||
|  |             return 1; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* estimate the stream timings from the one of each components. Also
 | ||||||
|  |    compute the global bitrate if possible */ | ||||||
|  | static void av_update_stream_timings(AVFormatContext *ic) | ||||||
|  | { | ||||||
|  |     int64_t start_time, end_time, end_time1; | ||||||
|  |     int i; | ||||||
|  |     AVStream *st; | ||||||
|  | 
 | ||||||
|  |     start_time = MAXINT64; | ||||||
|  |     end_time = MININT64; | ||||||
|  |     for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |         st = ic->streams[i]; | ||||||
|  |         if (st->start_time != AV_NOPTS_VALUE) { | ||||||
|  |             if (st->start_time < start_time) | ||||||
|  |                 start_time = st->start_time; | ||||||
|  |             if (st->duration != AV_NOPTS_VALUE) { | ||||||
|  |                 end_time1 = st->start_time + st->duration; | ||||||
|  |                 if (end_time1 > end_time) | ||||||
|  |                     end_time = end_time1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (start_time != MAXINT64) { | ||||||
|  |         ic->start_time = start_time; | ||||||
|  |         if (end_time != MAXINT64) { | ||||||
|  |             ic->duration = end_time - start_time; | ||||||
|  |             if (ic->file_size > 0) { | ||||||
|  |                 /* compute the bit rate */ | ||||||
|  |                 ic->bit_rate = (double)ic->file_size * 8.0 * AV_TIME_BASE /  | ||||||
|  |                     (double)ic->duration; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void fill_all_stream_timings(AVFormatContext *ic) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     AVStream *st; | ||||||
|  | 
 | ||||||
|  |     av_update_stream_timings(ic); | ||||||
|  |     for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |         st = ic->streams[i]; | ||||||
|  |         if (st->start_time == AV_NOPTS_VALUE) { | ||||||
|  |             st->start_time = ic->start_time; | ||||||
|  |             st->duration = ic->duration; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void av_estimate_timings_from_bit_rate(AVFormatContext *ic) | ||||||
|  | { | ||||||
|  |     int64_t filesize, duration; | ||||||
|  |     int bit_rate, i; | ||||||
|  |     AVStream *st; | ||||||
|  | 
 | ||||||
|  |     /* if bit_rate is already set, we believe it */ | ||||||
|  |     if (ic->bit_rate == 0) { | ||||||
|  |         bit_rate = 0; | ||||||
|  |         for(i=0;i<ic->nb_streams;i++) { | ||||||
|  |             st = ic->streams[i]; | ||||||
|  |             bit_rate += st->codec.bit_rate; | ||||||
|  |         } | ||||||
|  |         ic->bit_rate = bit_rate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* if duration is already set, we believe it */ | ||||||
|  |     if (ic->duration == AV_NOPTS_VALUE &&  | ||||||
|  |         ic->bit_rate != 0 &&  | ||||||
|  |         ic->file_size != 0)  { | ||||||
|  |         filesize = ic->file_size; | ||||||
|  |         if (filesize > 0) { | ||||||
|  |             duration = (int64_t)((8 * AV_TIME_BASE * (double)filesize) / (double)ic->bit_rate); | ||||||
|  |             for(i = 0; i < ic->nb_streams; i++) { | ||||||
|  |                 st = ic->streams[i]; | ||||||
|  |                 if (st->start_time == AV_NOPTS_VALUE || | ||||||
|  |                     st->duration == AV_NOPTS_VALUE) { | ||||||
|  |                     st->start_time = 0; | ||||||
|  |                     st->duration = duration; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void flush_packet_queue(AVFormatContext *s) | ||||||
|  | { | ||||||
|  |     AVPacketList *pktl; | ||||||
|  | 
 | ||||||
|  |     for(;;) { | ||||||
|  |         pktl = s->packet_buffer; | ||||||
|  |         if (!pktl)  | ||||||
|  |             break; | ||||||
|  |         s->packet_buffer = pktl->next; | ||||||
|  |         av_free(pktl); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define DURATION_MAX_READ_SIZE 250000 | ||||||
|  | 
 | ||||||
|  | /* only usable for MPEG-PS streams */ | ||||||
|  | static void av_estimate_timings_from_pts(AVFormatContext *ic) | ||||||
|  | { | ||||||
|  |     AVPacket pkt1, *pkt = &pkt1; | ||||||
|  |     AVStream *st; | ||||||
|  |     int read_size, i, ret; | ||||||
|  |     int64_t start_time, end_time, end_time1; | ||||||
|  |     int64_t filesize, offset, duration; | ||||||
|  |      | ||||||
|  |     /* we read the first packets to get the first PTS (not fully
 | ||||||
|  |        accurate, but it is enough now) */ | ||||||
|  |     url_fseek(&ic->pb, 0, SEEK_SET); | ||||||
|  |     read_size = 0; | ||||||
|  |     for(;;) { | ||||||
|  |         if (read_size >= DURATION_MAX_READ_SIZE) | ||||||
|  |             break; | ||||||
|  |         /* if all info is available, we can stop */ | ||||||
|  |         for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |             st = ic->streams[i]; | ||||||
|  |             if (st->start_time == AV_NOPTS_VALUE) | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         if (i == ic->nb_streams) | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         ret = av_read_packet(ic, pkt); | ||||||
|  |         if (ret != 0) | ||||||
|  |             break; | ||||||
|  |         read_size += pkt->size; | ||||||
|  |         st = ic->streams[pkt->stream_index]; | ||||||
|  |         if (pkt->pts != AV_NOPTS_VALUE) { | ||||||
|  |             if (st->start_time == AV_NOPTS_VALUE) | ||||||
|  |                 st->start_time = (int64_t)((double)pkt->pts * ic->pts_num * (double)AV_TIME_BASE / ic->pts_den); | ||||||
|  |          } | ||||||
|  |          av_free_packet(pkt); | ||||||
|  |      } | ||||||
|  | 
 | ||||||
|  |     /* we compute the minimum start_time and use it as default */ | ||||||
|  |     start_time = MAXINT64; | ||||||
|  |     for(i = 0; i < ic->nb_streams; i++) { | ||||||
|  |         st = ic->streams[i]; | ||||||
|  |         if (st->start_time != AV_NOPTS_VALUE && | ||||||
|  |             st->start_time < start_time) | ||||||
|  |             start_time = st->start_time; | ||||||
|  |     } | ||||||
|  |     printf("start=%lld\n", start_time); | ||||||
|  |     if (start_time != MAXINT64) | ||||||
|  |         ic->start_time = start_time; | ||||||
|  |      | ||||||
|  |     /* estimate the end time (duration) */ | ||||||
|  |     /* XXX: may need to support wrapping */ | ||||||
|  |     filesize = ic->file_size; | ||||||
|  |     offset = filesize - DURATION_MAX_READ_SIZE; | ||||||
|  |     if (offset < 0) | ||||||
|  |         offset = 0; | ||||||
|  | 
 | ||||||
|  |     /* flush packet queue */ | ||||||
|  |     flush_packet_queue(ic); | ||||||
|  | 
 | ||||||
|  |     url_fseek(&ic->pb, offset, SEEK_SET); | ||||||
|  |     read_size = 0; | ||||||
|  |     for(;;) { | ||||||
|  |         if (read_size >= DURATION_MAX_READ_SIZE) | ||||||
|  |             break; | ||||||
|  |         /* if all info is available, we can stop */ | ||||||
|  |         for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |             st = ic->streams[i]; | ||||||
|  |             if (st->duration == AV_NOPTS_VALUE) | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         if (i == ic->nb_streams) | ||||||
|  |             break; | ||||||
|  |          | ||||||
|  |         ret = av_read_packet(ic, pkt); | ||||||
|  |         if (ret != 0) | ||||||
|  |             break; | ||||||
|  |         read_size += pkt->size; | ||||||
|  |         st = ic->streams[pkt->stream_index]; | ||||||
|  |         if (pkt->pts != AV_NOPTS_VALUE) { | ||||||
|  |             end_time = (int64_t)((double)pkt->pts * ic->pts_num * (double)AV_TIME_BASE / ic->pts_den); | ||||||
|  |             duration = end_time - st->start_time; | ||||||
|  |             if (duration > 0) { | ||||||
|  |                 if (st->duration == AV_NOPTS_VALUE || | ||||||
|  |                     st->duration < duration) | ||||||
|  |                     st->duration = duration; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         av_free_packet(pkt); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* estimate total duration */ | ||||||
|  |     end_time = MININT64; | ||||||
|  |     for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |         st = ic->streams[i]; | ||||||
|  |         if (st->duration != AV_NOPTS_VALUE) { | ||||||
|  |             end_time1 = st->start_time + st->duration; | ||||||
|  |             if (end_time1 > end_time) | ||||||
|  |                 end_time = end_time1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* update start_time (new stream may have been created, so we do
 | ||||||
|  |        it at the end */ | ||||||
|  |     if (ic->start_time != AV_NOPTS_VALUE) { | ||||||
|  |         for(i = 0; i < ic->nb_streams; i++) { | ||||||
|  |             st = ic->streams[i]; | ||||||
|  |             if (st->start_time == AV_NOPTS_VALUE) | ||||||
|  |                 st->start_time = ic->start_time; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (end_time != MININT64) { | ||||||
|  |         /* put dummy values for duration if needed */ | ||||||
|  |         for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |             st = ic->streams[i]; | ||||||
|  |             if (st->duration == AV_NOPTS_VALUE &&  | ||||||
|  |                 st->start_time != AV_NOPTS_VALUE) | ||||||
|  |                 st->duration = end_time - st->start_time; | ||||||
|  |         } | ||||||
|  |         ic->duration = end_time - ic->start_time; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     url_fseek(&ic->pb, 0, SEEK_SET); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void av_estimate_timings(AVFormatContext *ic) | ||||||
|  | { | ||||||
|  |     URLContext *h; | ||||||
|  |     int64_t file_size; | ||||||
|  | 
 | ||||||
|  |     /* get the file size, if possible */ | ||||||
|  |     if (ic->iformat->flags & AVFMT_NOFILE) { | ||||||
|  |         file_size = 0; | ||||||
|  |     } else { | ||||||
|  |         h = url_fileno(&ic->pb); | ||||||
|  |         file_size = url_filesize(h); | ||||||
|  |         if (file_size < 0) | ||||||
|  |             file_size = 0; | ||||||
|  |     } | ||||||
|  |     ic->file_size = file_size; | ||||||
|  | 
 | ||||||
|  |     if (ic->iformat == &mpegps_demux) { | ||||||
|  |         /* get accurate estimate from the PTSes */ | ||||||
|  |         av_estimate_timings_from_pts(ic); | ||||||
|  |     } else if (av_has_timings(ic)) { | ||||||
|  |         /* at least one components has timings - we use them for all
 | ||||||
|  |            the components */ | ||||||
|  |         fill_all_stream_timings(ic); | ||||||
|  |     } else { | ||||||
|  |         /* less precise: use bit rate info */ | ||||||
|  |         av_estimate_timings_from_bit_rate(ic); | ||||||
|  |     } | ||||||
|  |     av_update_stream_timings(ic); | ||||||
|  | 
 | ||||||
|  | #if 0 | ||||||
|  |     { | ||||||
|  |         int i; | ||||||
|  |         AVStream *st; | ||||||
|  |         for(i = 0;i < ic->nb_streams; i++) { | ||||||
|  |             st = ic->streams[i]; | ||||||
|  |         printf("%d: start_time: %0.3f duration: %0.3f\n",  | ||||||
|  |                i, (double)st->start_time / AV_TIME_BASE,  | ||||||
|  |                (double)st->duration / AV_TIME_BASE); | ||||||
|  |         } | ||||||
|  |         printf("stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",  | ||||||
|  |                (double)ic->start_time / AV_TIME_BASE,  | ||||||
|  |                (double)ic->duration / AV_TIME_BASE, | ||||||
|  |                ic->bit_rate / 1000); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* state for codec information */ | /* state for codec information */ | ||||||
| #define CSTATE_NOTFOUND    0 | #define CSTATE_NOTFOUND    0 | ||||||
| #define CSTATE_DECODING    1 | #define CSTATE_DECODING    1 | ||||||
| @ -662,6 +953,8 @@ int av_find_stream_info(AVFormatContext *ic) | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     av_estimate_timings(ic); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -725,6 +1018,8 @@ AVStream *av_new_stream(AVFormatContext *s, int id) | |||||||
| 
 | 
 | ||||||
|     st->index = s->nb_streams; |     st->index = s->nb_streams; | ||||||
|     st->id = id; |     st->id = id; | ||||||
|  |     st->start_time = AV_NOPTS_VALUE; | ||||||
|  |     st->duration = AV_NOPTS_VALUE; | ||||||
|     s->streams[s->nb_streams++] = st; |     s->streams[s->nb_streams++] = st; | ||||||
|     return st; |     return st; | ||||||
| } | } | ||||||
| @ -874,6 +1169,29 @@ void dump_format(AVFormatContext *ic, | |||||||
|             index,  |             index,  | ||||||
|             is_output ? ic->oformat->name : ic->iformat->name,  |             is_output ? ic->oformat->name : ic->iformat->name,  | ||||||
|             is_output ? "to" : "from", url); |             is_output ? "to" : "from", url); | ||||||
|  |     if (!is_output) { | ||||||
|  |         printf("  Duration: "); | ||||||
|  |         if (ic->duration != AV_NOPTS_VALUE) { | ||||||
|  |             int hours, mins, secs, us; | ||||||
|  |             secs = ic->duration / AV_TIME_BASE; | ||||||
|  |             us = ic->duration % AV_TIME_BASE; | ||||||
|  |             mins = secs / 60; | ||||||
|  |             secs %= 60; | ||||||
|  |             hours = mins / 60; | ||||||
|  |             mins %= 60; | ||||||
|  |             printf("%02d:%02d:%02d.%01d", hours, mins, secs,  | ||||||
|  |                    (10 * us) / AV_TIME_BASE); | ||||||
|  |         } else { | ||||||
|  |             printf("N/A"); | ||||||
|  |         } | ||||||
|  |         printf(", bitrate: "); | ||||||
|  |         if (ic->bit_rate) { | ||||||
|  |             printf("%d kb/s", ic->bit_rate / 1000); | ||||||
|  |         } else { | ||||||
|  |             printf("N/A"); | ||||||
|  |         } | ||||||
|  |         printf("\n"); | ||||||
|  |     } | ||||||
|     for(i=0;i<ic->nb_streams;i++) { |     for(i=0;i<ic->nb_streams;i++) { | ||||||
|         AVStream *st = ic->streams[i]; |         AVStream *st = ic->streams[i]; | ||||||
|         avcodec_string(buf, sizeof(buf), &st->codec, is_output); |         avcodec_string(buf, sizeof(buf), &st->codec, is_output); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user