X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=libavformat%2Futils.c;h=f48ed2ab1c31f7e0138bf256bf00d4ed8257c90d;hb=863c471638fa667e6e5c5df059b67af263e1cd40;hp=3f14ad8c1377a8317515fc9b03c7e500b82097cd;hpb=b603ab8dc187677a08bf801fbd6bfc0846d97faa;p=ffmpeg diff --git a/libavformat/utils.c b/libavformat/utils.c index 3f14ad8c137..f48ed2ab1c3 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -21,8 +21,9 @@ #include "avformat.h" #include "internal.h" #include "libavcodec/internal.h" -#include "libavcodec/opt.h" +#include "libavutil/opt.h" #include "metadata.h" +#include "id3v2.h" #include "libavutil/avstring.h" #include "riff.h" #include "audiointerleave.h" @@ -109,8 +110,14 @@ static void av_frac_add(AVFrac *f, int64_t incr) } /** head of registered input format linked list */ +#if !FF_API_FIRST_FORMAT +static +#endif AVInputFormat *first_iformat = NULL; /** head of registered output format linked list */ +#if !FF_API_FIRST_FORMAT +static +#endif AVOutputFormat *first_oformat = NULL; AVInputFormat *av_iformat_next(AVInputFormat *f) @@ -188,7 +195,7 @@ static int match_format(const char *name, const char *names) return !strcasecmp(name, names); } -#if LIBAVFORMAT_VERSION_MAJOR < 53 +#if FF_API_GUESS_FORMAT AVOutputFormat *guess_format(const char *short_name, const char *filename, const char *mime_type) { @@ -199,7 +206,7 @@ AVOutputFormat *guess_format(const char *short_name, const char *filename, AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type) { - AVOutputFormat *fmt, *fmt_found; + AVOutputFormat *fmt = NULL, *fmt_found; int score_max, score; /* specific test for image sequences */ @@ -213,8 +220,7 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, /* Find the proper file type. */ fmt_found = NULL; score_max = 0; - fmt = first_oformat; - while (fmt != NULL) { + while ((fmt = av_oformat_next(fmt))) { score = 0; if (fmt->name && short_name && !strcmp(fmt->name, short_name)) score += 100; @@ -228,12 +234,11 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, score_max = score; fmt_found = fmt; } - fmt = fmt->next; } return fmt_found; } -#if LIBAVFORMAT_VERSION_MAJOR < 53 +#if FF_API_GUESS_FORMAT AVOutputFormat *guess_stream_format(const char *short_name, const char *filename, const char *mime_type) { @@ -269,24 +274,56 @@ enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, return codec_id; }else if(type == AVMEDIA_TYPE_AUDIO) return fmt->audio_codec; + else if (type == AVMEDIA_TYPE_SUBTITLE) + return fmt->subtitle_codec; else return CODEC_ID_NONE; } AVInputFormat *av_find_input_format(const char *short_name) { - AVInputFormat *fmt; - for(fmt = first_iformat; fmt != NULL; fmt = fmt->next) { + AVInputFormat *fmt = NULL; + while ((fmt = av_iformat_next(fmt))) { if (match_format(short_name, fmt->name)) return fmt; } return NULL; } -/* memory handling */ +#if FF_API_SYMVER && CONFIG_SHARED && HAVE_SYMVER +FF_SYMVER(void, av_destruct_packet_nofree, (AVPacket *pkt), "LIBAVFORMAT_52") +{ + av_destruct_packet_nofree(pkt); +} + +FF_SYMVER(void, av_destruct_packet, (AVPacket *pkt), "LIBAVFORMAT_52") +{ + av_destruct_packet(pkt); +} + +FF_SYMVER(int, av_new_packet, (AVPacket *pkt, int size), "LIBAVFORMAT_52") +{ + return av_new_packet(pkt, size); +} + +FF_SYMVER(int, av_dup_packet, (AVPacket *pkt), "LIBAVFORMAT_52") +{ + return av_dup_packet(pkt); +} + +FF_SYMVER(void, av_free_packet, (AVPacket *pkt), "LIBAVFORMAT_52") +{ + av_free_packet(pkt); +} +FF_SYMVER(void, av_init_packet, (AVPacket *pkt), "LIBAVFORMAT_52") +{ + av_log(NULL, AV_LOG_WARNING, "Diverting av_*_packet function calls to libavcodec. Recompile to improve performance\n"); + av_init_packet(pkt); +} +#endif -int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size) +int av_get_packet(AVIOContext *s, AVPacket *pkt, int size) { int ret= av_new_packet(pkt, size); @@ -295,7 +332,7 @@ int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size) pkt->pos= url_ftell(s); - ret= get_buffer(s, pkt->data, size); + ret= avio_read(s, pkt->data, size); if(ret<=0) av_free_packet(pkt); else @@ -304,6 +341,21 @@ int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size) return ret; } +int av_append_packet(AVIOContext *s, AVPacket *pkt, int size) +{ + int ret; + int old_size; + if (!pkt->size) + return av_get_packet(s, pkt, size); + old_size = pkt->size; + ret = av_grow_packet(pkt, size); + if (ret < 0) + return ret; + ret = avio_read(s, pkt->data + old_size, size); + av_shrink_packet(pkt, old_size + FFMAX(ret, 0)); + return ret; +} + int av_filename_number_test(const char *filename) { @@ -313,18 +365,27 @@ int av_filename_number_test(const char *filename) AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) { - AVInputFormat *fmt1, *fmt; + AVProbeData lpd = *pd; + AVInputFormat *fmt1 = NULL, *fmt; int score; + if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) { + int id3len = ff_id3v2_tag_len(lpd.buf); + if (lpd.buf_size > id3len + 16) { + lpd.buf += id3len; + lpd.buf_size -= id3len; + } + } + fmt = NULL; - for(fmt1 = first_iformat; fmt1 != NULL; fmt1 = fmt1->next) { + while ((fmt1 = av_iformat_next(fmt1))) { if (!is_opened == !(fmt1->flags & AVFMT_NOFILE)) continue; score = 0; if (fmt1->read_probe) { - score = fmt1->read_probe(pd); + score = fmt1->read_probe(&lpd); } else if (fmt1->extensions) { - if (av_match_ext(pd->filename, fmt1->extensions)) { + if (av_match_ext(lpd.filename, fmt1->extensions)) { score = 50; } } @@ -381,7 +442,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa * Open a media file from an IO stream. 'fmt' must be specified. */ int av_open_input_stream(AVFormatContext **ic_ptr, - ByteIOContext *pb, const char *filename, + AVIOContext *pb, const char *filename, AVInputFormat *fmt, AVFormatParameters *ap) { int err; @@ -418,6 +479,10 @@ int av_open_input_stream(AVFormatContext **ic_ptr, ic->priv_data = NULL; } + // e.g. AVFMT_NOFILE formats will not have a AVIOContext + if (ic->pb) + ff_id3v2_read(ic, ID3v2_DEFAULT_MAGIC); + if (ic->iformat->read_header) { err = ic->iformat->read_header(ic, ap); if (err < 0) @@ -427,7 +492,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, if (pb && !ic->data_offset) ic->data_offset = url_ftell(ic->pb); -#if LIBAVFORMAT_VERSION_MAJOR < 53 +#if FF_API_OLD_METADATA ff_metadata_demux_compat(ic); #endif @@ -444,6 +509,8 @@ int av_open_input_stream(AVFormatContext **ic_ptr, if (st) { av_free(st->priv_data); av_free(st->codec->extradata); + av_free(st->codec); + av_free(st->info); } av_free(st); } @@ -457,7 +524,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, #define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1<<20) -int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt, +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { @@ -488,7 +555,7 @@ int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt, /* read probe data */ buf = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); - if ((ret = get_buffer(*pb, buf + buf_offset, probe_size - buf_offset)) < 0) { + if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) { /* fail if error was not end of file, otherwise, lower score */ if (ret != AVERROR_EOF) { av_free(buf); @@ -518,7 +585,7 @@ int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt, } /* rewind. reuse probe buffer to avoid seeking */ - if ((ret = ff_rewind_with_probe_data(*pb, buf, pd.buf_size)) < 0) + if ((ret = ff_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) av_free(buf); return ret; @@ -531,7 +598,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, { int err; AVProbeData probe_data, *pd = &probe_data; - ByteIOContext *pb = NULL; + AVIOContext *pb = NULL; void *logctx= ap && ap->prealloced_context ? *ic_ptr : NULL; pd->filename = ""; @@ -549,13 +616,13 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, hack needed to handle RTSP/TCP */ if (!fmt || !(fmt->flags & AVFMT_NOFILE)) { /* if no file needed do not try to open one */ - if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0) { + if ((err=avio_open(&pb, filename, URL_RDONLY)) < 0) { goto fail; } if (buf_size > 0) { url_setbufsize(pb, buf_size); } - if (!fmt && (err = ff_probe_input_buffer(&pb, &fmt, filename, logctx, 0, logctx ? (*ic_ptr)->probesize : 0)) < 0) { + if (!fmt && (err = av_probe_input_buffer(pb, &fmt, filename, logctx, 0, logctx ? (*ic_ptr)->probesize : 0)) < 0) { goto fail; } } @@ -580,7 +647,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, fail: av_freep(&pd->buf); if (pb) - url_fclose(pb); + avio_close(pb); if (ap && ap->prealloced_context) av_free(*ic_ptr); *ic_ptr = NULL; @@ -745,7 +812,7 @@ static void compute_frame_duration(int *pnum, int *pden, AVStream *st, break; case AVMEDIA_TYPE_AUDIO: frame_size = get_audio_frame_size(st->codec, pkt->size); - if (frame_size < 0) + if (frame_size <= 0 || st->codec->sample_rate <= 0) break; *pnum = frame_size; *pden = st->codec->sample_rate; @@ -863,6 +930,12 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, /* do we have a video B-frame ? */ delay= st->codec->has_b_frames; presentation_delayed = 0; + + // ignore delay caused by frame threading so that the mpeg2-without-dts + // warning will not trigger + if (delay && st->codec->active_thread_type&FF_THREAD_FRAME) + delay -= st->codec->thread_count-1; + /* XXX: need has_b_frame, but cannot get it if the codec is not initialized */ if (delay && @@ -878,7 +951,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, // we take the conservative approach and discard both // Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly. if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){ - av_log(s, AV_LOG_WARNING, "invalid dts/pts combination\n"); + av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination\n"); pkt->dts= pkt->pts= AV_NOPTS_VALUE; } @@ -1047,7 +1120,7 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) if(pkt->data == st->cur_pkt.data && pkt->size == st->cur_pkt.size){ s->cur_st = NULL; pkt->destruct= st->cur_pkt.destruct; - st->cur_pkt.destruct= + st->cur_pkt.destruct= NULL; st->cur_pkt.data = NULL; assert(st->cur_len == 0); }else{ @@ -1128,10 +1201,6 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) }else if(st->need_parsing == AVSTREAM_PARSE_FULL_ONCE){ st->parser->flags |= PARSER_FLAG_ONCE; } - if(st->parser && (s->iformat->flags & AVFMT_GENERIC_INDEX)){ - st->parser->next_frame_offset= - st->parser->cur_offset= st->cur_pkt.pos; - } } } } @@ -1159,11 +1228,11 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) AVPacket *next_pkt= &pktl->pkt; if(genpts && next_pkt->dts != AV_NOPTS_VALUE){ + int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits; while(pktl && next_pkt->pts == AV_NOPTS_VALUE){ if( pktl->pkt.stream_index == next_pkt->stream_index - && next_pkt->dts < pktl->pkt.dts - && pktl->pkt.pts != pktl->pkt.dts //not b frame - /*&& pktl->pkt.dts != AV_NOPTS_VALUE*/){ + && (0 > av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) + && av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { //not b frame next_pkt->pts= pktl->pkt.dts; } pktl= pktl->next; @@ -1307,28 +1376,30 @@ void ff_reduce_index(AVFormatContext *s, int stream_index) } } -int av_add_index_entry(AVStream *st, - int64_t pos, int64_t timestamp, int size, int distance, int flags) +int ff_add_index_entry(AVIndexEntry **index_entries, + int *nb_index_entries, + unsigned int *index_entries_allocated_size, + int64_t pos, int64_t timestamp, int size, int distance, int flags) { AVIndexEntry *entries, *ie; int index; - if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) + if((unsigned)*nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) return -1; - entries = av_fast_realloc(st->index_entries, - &st->index_entries_allocated_size, - (st->nb_index_entries + 1) * + entries = av_fast_realloc(*index_entries, + index_entries_allocated_size, + (*nb_index_entries + 1) * sizeof(AVIndexEntry)); if(!entries) return -1; - st->index_entries= entries; + *index_entries= entries; - index= av_index_search_timestamp(st, timestamp, AVSEEK_FLAG_ANY); + index= ff_index_search_timestamp(*index_entries, *nb_index_entries, timestamp, AVSEEK_FLAG_ANY); if(index<0){ - index= st->nb_index_entries++; + index= (*nb_index_entries)++; ie= &entries[index]; assert(index==0 || ie[-1].timestamp < timestamp); }else{ @@ -1336,8 +1407,8 @@ int av_add_index_entry(AVStream *st, if(ie->timestamp != timestamp){ if(ie->timestamp <= timestamp) return -1; - memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index)); - st->nb_index_entries++; + memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(*nb_index_entries - index)); + (*nb_index_entries)++; }else if(ie->pos == pos && distance < ie->min_distance) //do not reduce the distance distance= ie->min_distance; } @@ -1351,11 +1422,17 @@ int av_add_index_entry(AVStream *st, return index; } -int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, - int flags) +int av_add_index_entry(AVStream *st, + int64_t pos, int64_t timestamp, int size, int distance, int flags) +{ + return ff_add_index_entry(&st->index_entries, &st->nb_index_entries, + &st->index_entries_allocated_size, pos, + timestamp, size, distance, flags); +} + +int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries, + int64_t wanted_timestamp, int flags) { - AVIndexEntry *entries= st->index_entries; - int nb_entries= st->nb_index_entries; int a, b, m; int64_t timestamp; @@ -1387,6 +1464,13 @@ int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, return m; } +int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, + int flags) +{ + return ff_index_search_timestamp(st->index_entries, st->nb_index_entries, + wanted_timestamp, flags); +} + #define DEBUG_SEEK int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){ @@ -1447,7 +1531,7 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts return -1; /* do the seek */ - if ((ret = url_fseek(s->pb, pos, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0) return ret; av_update_cur_dts(s, st, ts); @@ -1587,7 +1671,7 @@ static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, if (pos < pos_min) pos= pos_min; else if(pos > pos_max) pos= pos_max; - url_fseek(s->pb, pos, SEEK_SET); + avio_seek(s->pb, pos, SEEK_SET); #if 0 av_update_cur_dts(s, st, ts); @@ -1617,11 +1701,11 @@ static int av_seek_frame_generic(AVFormatContext *s, if(st->nb_index_entries){ assert(st->index_entries); ie= &st->index_entries[st->nb_index_entries-1]; - if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; av_update_cur_dts(s, st, ie->timestamp); }else{ - if ((ret = url_fseek(s->pb, s->data_offset, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, s->data_offset, SEEK_SET)) < 0) return ret; } for(i=0;; i++) { @@ -1648,7 +1732,7 @@ static int av_seek_frame_generic(AVFormatContext *s, return 0; } ie = &st->index_entries[index]; - if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; av_update_cur_dts(s, st, ie->timestamp); @@ -1715,7 +1799,7 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int /*******************************************************/ /** - * Returns TRUE if the stream has accurate duration in any stream. + * Return TRUE if the stream has accurate duration in any stream. * * @return TRUE if the stream has accurate duration for at least one component. */ @@ -1807,10 +1891,11 @@ static void av_estimate_timings_from_bit_rate(AVFormatContext *ic) AVStream *st; /* if bit_rate is already set, we believe it */ - if (ic->bit_rate == 0) { + if (ic->bit_rate <= 0) { bit_rate = 0; for(i=0;inb_streams;i++) { st = ic->streams[i]; + if (st->codec->bit_rate > 0) bit_rate += st->codec->bit_rate; } ic->bit_rate = bit_rate; @@ -1841,7 +1926,7 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset AVPacket pkt1, *pkt = &pkt1; AVStream *st; int read_size, i, ret; - int64_t end_time, start_time[MAX_STREAMS]; + int64_t end_time; int64_t filesize, offset, duration; int retry=0; @@ -1850,13 +1935,9 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset /* flush packet queue */ flush_packet_queue(ic); - for(i=0;inb_streams;i++) { + for (i=0; inb_streams; i++) { st = ic->streams[i]; - if(st->start_time != AV_NOPTS_VALUE){ - start_time[i]= st->start_time; - }else if(st->first_dts != AV_NOPTS_VALUE){ - start_time[i]= st->first_dts; - }else + if (st->start_time == AV_NOPTS_VALUE && st->first_dts == AV_NOPTS_VALUE) av_log(st->codec, AV_LOG_WARNING, "start time is not set in av_estimate_timings_from_pts\n"); if (st->parser) { @@ -1875,7 +1956,7 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset if (offset < 0) offset = 0; - url_fseek(ic->pb, offset, SEEK_SET); + avio_seek(ic->pb, offset, SEEK_SET); read_size = 0; for(;;) { if (read_size >= DURATION_MAX_READ_SIZE<<(FFMAX(retry-1,0))) @@ -1889,9 +1970,11 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset read_size += pkt->size; st = ic->streams[pkt->stream_index]; if (pkt->pts != AV_NOPTS_VALUE && - start_time[pkt->stream_index] != AV_NOPTS_VALUE) { - end_time = pkt->pts; - duration = end_time - start_time[pkt->stream_index]; + (st->start_time != AV_NOPTS_VALUE || + st->first_dts != AV_NOPTS_VALUE)) { + duration = end_time = pkt->pts; + if (st->start_time != AV_NOPTS_VALUE) duration -= st->start_time; + else duration -= st->first_dts; if (duration < 0) duration += 1LL<pts_wrap_bits; if (duration > 0) { @@ -1908,8 +1991,8 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset fill_all_stream_timings(ic); - url_fseek(ic->pb, old_offset, SEEK_SET); - for(i=0; inb_streams; i++){ + avio_seek(ic->pb, old_offset, SEEK_SET); + for (i=0; inb_streams; i++) { st= ic->streams[i]; st->cur_dts= st->first_dts; st->last_IP_pts = AV_NOPTS_VALUE; @@ -1969,7 +2052,7 @@ static int has_codec_parameters(AVCodecContext *enc) int val; switch(enc->codec_type) { case AVMEDIA_TYPE_AUDIO: - val = enc->sample_rate && enc->channels && enc->sample_fmt != SAMPLE_FMT_NONE; + val = enc->sample_rate && enc->channels && enc->sample_fmt != AV_SAMPLE_FMT_NONE; if(!enc->frame_size && (enc->codec_id == CODEC_ID_VORBIS || enc->codec_id == CODEC_ID_AAC || @@ -1989,6 +2072,12 @@ static int has_codec_parameters(AVCodecContext *enc) return enc->codec_id != CODEC_ID_NONE && val != 0; } +static int has_decode_delay_been_guessed(AVStream *st) +{ + return st->codec->codec_id != CODEC_ID_H264 || + st->codec_info_nb_frames >= 6 + st->codec->has_b_frames; +} + static int try_decode_frame(AVStream *st, AVPacket *avpkt) { int16_t *samples; @@ -2005,7 +2094,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt) return ret; } - if(!has_codec_parameters(st->codec)){ + if(!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st)){ switch(st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: avcodec_get_frame_defaults(&picture); @@ -2093,7 +2182,6 @@ static void compute_chapters_end(AVFormatContext *s) } } -#define MAX_STD_TIMEBASES (60*12+5) static int get_std_framerate(int i){ if(i<60*12) return i*1001; else return ((const int[]){24,30,60,12,15})[i-60*12]*1000*12; @@ -2124,24 +2212,18 @@ int av_find_stream_info(AVFormatContext *ic) int i, count, ret, read_size, j; AVStream *st; AVPacket pkt1, *pkt; - int64_t last_dts[MAX_STREAMS]; - int64_t duration_gcd[MAX_STREAMS]={0}; - int duration_count[MAX_STREAMS]={0}; - double (*duration_error)[MAX_STD_TIMEBASES]; int64_t old_offset = url_ftell(ic->pb); - int64_t codec_info_duration[MAX_STREAMS]={0}; - - duration_error = av_mallocz(MAX_STREAMS * sizeof(*duration_error)); - if (!duration_error) return AVERROR(ENOMEM); for(i=0;inb_streams;i++) { + AVCodec *codec; st = ic->streams[i]; if (st->codec->codec_id == CODEC_ID_AAC) { st->codec->sample_rate = 0; st->codec->frame_size = 0; st->codec->channels = 0; } - if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || + st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { /* if(!st->time_base.num) st->time_base= */ if(!st->codec->time_base.num) @@ -2155,16 +2237,29 @@ int av_find_stream_info(AVFormatContext *ic) } } assert(!st->codec->codec); + codec = avcodec_find_decoder(st->codec->codec_id); + + /* Force decoding of at least one frame of codec data + * this makes sure the codec initializes the channel configuration + * and does not trust the values from the container. + */ + if (codec && codec->capabilities & CODEC_CAP_CHANNEL_CONF) + st->codec->channels = 0; + + /* Ensure that subtitle_header is properly set. */ + if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE + && codec && !st->codec->codec) + avcodec_open(st->codec, codec); + //try to just open decoders, in case this is enough to get parameters if(!has_codec_parameters(st->codec)){ - AVCodec *codec = avcodec_find_decoder(st->codec->codec_id); - if (codec) + if (codec && !st->codec->codec) avcodec_open(st->codec, codec); } } - for(i=0;inb_streams; i++) { + ic->streams[i]->info->last_dts = AV_NOPTS_VALUE; } count = 0; @@ -2183,7 +2278,7 @@ int av_find_stream_info(AVFormatContext *ic) break; /* variable fps and no guess at the real fps */ if( tb_unreliable(st->codec) && !(st->r_frame_rate.num && st->avg_frame_rate.num) - && duration_count[i]<20 && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + && st->info->duration_count<20 && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; @@ -2211,9 +2306,7 @@ int av_find_stream_info(AVFormatContext *ic) /* NOTE: a new stream can be added there if no header in file (AVFMTCTX_NOHEADER) */ ret = av_read_frame_internal(ic, &pkt1); - if(ret == AVERROR(EAGAIN)) - continue; - if (ret < 0) { + if (ret < 0 && ret != AVERROR(EAGAIN)) { /* EOF or error */ ret = -1; /* we could not have all the codec parameters before EOF */ for(i=0;inb_streams;i++) { @@ -2229,27 +2322,25 @@ int av_find_stream_info(AVFormatContext *ic) break; } + if (ret == AVERROR(EAGAIN)) + continue; + pkt= add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end); - if(av_dup_packet(pkt) < 0) { - av_free(duration_error); - return AVERROR(ENOMEM); - } + if ((ret = av_dup_packet(pkt)) < 0) + goto find_stream_info_err; read_size += pkt->size; st = ic->streams[pkt->stream_index]; - if(st->codec_info_nb_frames>1) { - if (st->time_base.den > 0 && av_rescale_q(codec_info_duration[st->index], st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration){ + if (st->codec_info_nb_frames>1) { + if (st->time_base.den > 0 && av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) { av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n"); break; } - codec_info_duration[st->index] += pkt->duration; + st->info->codec_info_duration += pkt->duration; } - st->codec_info_nb_frames++; - { - int index= pkt->stream_index; - int64_t last= last_dts[index]; + int64_t last = st->info->last_dts; int64_t duration= pkt->dts - last; if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && duration>0){ @@ -2257,21 +2348,21 @@ int av_find_stream_info(AVFormatContext *ic) // if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) // av_log(NULL, AV_LOG_ERROR, "%f\n", dur); - if(duration_count[index] < 2) - memset(duration_error[index], 0, sizeof(*duration_error)); - for(i=1; iinfo->duration_count < 2) + memset(st->info->duration_error, 0, sizeof(st->info->duration_error)); + for (i=1; iinfo->duration_error); i++) { int framerate= get_std_framerate(i); int ticks= lrintf(dur*framerate/(1001*12)); double error= dur - ticks*1001*12/(double)framerate; - duration_error[index][i] += error*error; + st->info->duration_error[i] += error*error; } - duration_count[index]++; + st->info->duration_count++; // ignore the first 4 values, they might have some random jitter - if (duration_count[index] > 3) - duration_gcd[index] = av_gcd(duration_gcd[index], duration); + if (st->info->duration_count > 3) + st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration); } - if(last == AV_NOPTS_VALUE || duration_count[index]<=1) - last_dts[pkt->stream_index]= pkt->dts; + if (last == AV_NOPTS_VALUE || st->info->duration_count <= 1) + st->info->last_dts = pkt->dts; } if(st->parser && st->parser->parser->split && !st->codec->extradata){ int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); @@ -2287,9 +2378,10 @@ int av_find_stream_info(AVFormatContext *ic) decompress the frame. We try to avoid that in most cases as it takes longer and uses more memory. For MPEG-4, we need to decompress for QuickTime. */ - if (!has_codec_parameters(st->codec)) + if (!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st)) try_decode_frame(st, pkt); + st->codec_info_nb_frames++; count++; } @@ -2301,10 +2393,10 @@ int av_find_stream_info(AVFormatContext *ic) } for(i=0;inb_streams;i++) { st = ic->streams[i]; - if(st->codec_info_nb_frames>2 && !st->avg_frame_rate.num && codec_info_duration[i]) + if (st->codec_info_nb_frames>2 && !st->avg_frame_rate.num && st->info->codec_info_duration) av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, (st->codec_info_nb_frames-2)*(int64_t)st->time_base.den, - codec_info_duration[i] *(int64_t)st->time_base.num, 60000); + st->info->codec_info_duration*(int64_t)st->time_base.num, 60000); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); @@ -2312,18 +2404,18 @@ int av_find_stream_info(AVFormatContext *ic) // the check for tb_unreliable() is not completely correct, since this is not about handling // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g. // ipmovie.c produces. - if (tb_unreliable(st->codec) && duration_count[i] > 15 && duration_gcd[i] > 1 && !st->r_frame_rate.num) - av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * duration_gcd[i], INT_MAX); - if(duration_count[i] && !st->r_frame_rate.num + if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > 1 && !st->r_frame_rate.num) + av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX); + if (st->info->duration_count && !st->r_frame_rate.num && tb_unreliable(st->codec) /*&& //FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ... - st->time_base.num*duration_sum[i]/duration_count[i]*101LL > st->time_base.den*/){ + st->time_base.num*duration_sum[i]/st->info->duration_count*101LL > st->time_base.den*/){ int num = 0; double best_error= 2*av_q2d(st->time_base); - best_error= best_error*best_error*duration_count[i]*1000*12*30; + best_error = best_error*best_error*st->info->duration_count*1000*12*30; - for(j=1; jinfo->duration_error); j++) { + double error = st->info->duration_error[j] * get_std_framerate(j); // if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) // av_log(NULL, AV_LOG_ERROR, "%f %f\n", get_std_framerate(j) / 12.0/1001, error); if(error < best_error){ @@ -2381,8 +2473,72 @@ int av_find_stream_info(AVFormatContext *ic) } #endif - av_free(duration_error); + find_stream_info_err: + for (i=0; i < ic->nb_streams; i++) + av_freep(&ic->streams[i]->info); + return ret; +} + +static AVProgram *find_program_from_stream(AVFormatContext *ic, int s) +{ + int i, j; + + for (i = 0; i < ic->nb_programs; i++) + for (j = 0; j < ic->programs[i]->nb_stream_indexes; j++) + if (ic->programs[i]->stream_index[j] == s) + return ic->programs[i]; + return NULL; +} + +int av_find_best_stream(AVFormatContext *ic, + enum AVMediaType type, + int wanted_stream_nb, + int related_stream, + AVCodec **decoder_ret, + int flags) +{ + int i, nb_streams = ic->nb_streams, stream_number = 0; + int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1; + unsigned *program = NULL; + AVCodec *decoder = NULL, *best_decoder = NULL; + if (related_stream >= 0 && wanted_stream_nb < 0) { + AVProgram *p = find_program_from_stream(ic, related_stream); + if (p) { + program = p->stream_index; + nb_streams = p->nb_stream_indexes; + } + } + for (i = 0; i < nb_streams; i++) { + AVStream *st = ic->streams[program ? program[i] : i]; + AVCodecContext *avctx = st->codec; + if (avctx->codec_type != type) + continue; + if (wanted_stream_nb >= 0 && stream_number++ != wanted_stream_nb) + continue; + if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED)) + continue; + if (decoder_ret) { + decoder = avcodec_find_decoder(ic->streams[i]->codec->codec_id); + if (!decoder) { + if (ret < 0) + ret = AVERROR_DECODER_NOT_FOUND; + continue; + } + } + if (best_count >= st->codec_info_nb_frames) + continue; + best_count = st->codec_info_nb_frames; + ret = program ? program[i] : i; + best_decoder = decoder; + if (program && i == nb_streams - 1 && ret < 0) { + program = NULL; + nb_streams = ic->nb_streams; + i = 0; /* no related stream found, try again with everything */ + } + } + if (decoder_ret) + *decoder_ret = best_decoder; return ret; } @@ -2407,12 +2563,18 @@ int av_read_pause(AVFormatContext *s) } void av_close_input_stream(AVFormatContext *s) +{ + flush_packet_queue(s); + if (s->iformat->read_close) + s->iformat->read_close(s); + avformat_free_context(s); +} + +void avformat_free_context(AVFormatContext *s) { int i; AVStream *st; - if (s->iformat->read_close) - s->iformat->read_close(s); for(i=0;inb_streams;i++) { /* free all data in a stream component */ st = s->streams[i]; @@ -2423,15 +2585,17 @@ void av_close_input_stream(AVFormatContext *s) av_metadata_free(&st->metadata); av_free(st->index_entries); av_free(st->codec->extradata); + av_free(st->codec->subtitle_header); av_free(st->codec); -#if LIBAVFORMAT_VERSION_INT < (53<<16) +#if FF_API_OLD_METADATA av_free(st->filename); #endif av_free(st->priv_data); + av_free(st->info); av_free(st); } for(i=s->nb_programs-1; i>=0; i--) { -#if LIBAVFORMAT_VERSION_INT < (53<<16) +#if FF_API_OLD_METADATA av_freep(&s->programs[i]->provider_name); av_freep(&s->programs[i]->name); #endif @@ -2440,10 +2604,9 @@ void av_close_input_stream(AVFormatContext *s) av_freep(&s->programs[i]); } av_freep(&s->programs); - flush_packet_queue(s); av_freep(&s->priv_data); while(s->nb_chapters--) { -#if LIBAVFORMAT_VERSION_INT < (53<<16) +#if FF_API_OLD_METADATA av_free(s->chapters[s->nb_chapters]->title); #endif av_metadata_free(&s->chapters[s->nb_chapters]->metadata); @@ -2451,15 +2614,16 @@ void av_close_input_stream(AVFormatContext *s) } av_freep(&s->chapters); av_metadata_free(&s->metadata); + av_freep(&s->key); av_free(s); } void av_close_input_file(AVFormatContext *s) { - ByteIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb; + AVIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb; av_close_input_stream(s); if (pb) - url_fclose(pb); + avio_close(pb); } AVStream *av_new_stream(AVFormatContext *s, int id) @@ -2467,14 +2631,29 @@ AVStream *av_new_stream(AVFormatContext *s, int id) AVStream *st; int i; +#if FF_API_MAX_STREAMS if (s->nb_streams >= MAX_STREAMS){ av_log(s, AV_LOG_ERROR, "Too many streams\n"); return NULL; } +#else + AVStream **streams; + + if (s->nb_streams >= INT_MAX/sizeof(*streams)) + return NULL; + streams = av_realloc(s->streams, (s->nb_streams + 1) * sizeof(*streams)); + if (!streams) + return NULL; + s->streams = streams; +#endif st = av_mallocz(sizeof(AVStream)); if (!st) return NULL; + if (!(st->info = av_mallocz(sizeof(*st->info)))) { + av_free(st); + return NULL; + } st->codec= avcodec_alloc_context(); if (s->iformat) { @@ -2546,7 +2725,7 @@ AVChapter *ff_new_chapter(AVFormatContext *s, int id, AVRational time_base, int6 return NULL; dynarray_add(&s->chapters, &s->nb_chapters, chapter); } -#if LIBAVFORMAT_VERSION_INT < (53<<16) +#if FF_API_OLD_METADATA av_free(chapter->title); #endif av_metadata_set2(&chapter->metadata, "title", title, 0); @@ -2569,6 +2748,10 @@ int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) s->priv_data = av_mallocz(s->oformat->priv_data_size); if (!s->priv_data) return AVERROR(ENOMEM); + if (s->oformat->priv_class) { + *(const AVClass**)s->priv_data= s->oformat->priv_class; + av_opt_set_defaults(s->priv_data); + } } else s->priv_data = NULL; @@ -2619,7 +2802,7 @@ int av_write_header(AVFormatContext *s) AVStream *st; // some sanity checks - if (s->nb_streams == 0) { + if (s->nb_streams == 0 && !(s->oformat->flags & AVFMT_NOSTREAMS)) { av_log(s, AV_LOG_ERROR, "no streams\n"); return AVERROR(EINVAL); } @@ -2654,13 +2837,17 @@ int av_write_header(AVFormatContext *s) } if(s->oformat->codec_tag){ + if(st->codec->codec_tag && st->codec->codec_id == CODEC_ID_RAWVIDEO && av_codec_get_tag(s->oformat->codec_tag, st->codec->codec_id) == 0 && !validate_codec_tag(s, st)){ + //the current rawvideo encoding system ends up setting the wrong codec_tag for avi, we override it here + st->codec->codec_tag= 0; + } if(st->codec->codec_tag){ if (!validate_codec_tag(s, st)) { char tagbuf[32]; av_get_codec_tag_string(tagbuf, sizeof(tagbuf), st->codec->codec_tag); av_log(s, AV_LOG_ERROR, - "Tag %s/0x%08x incompatible with output codec '%s'\n", - tagbuf, st->codec->codec_tag, st->codec->codec->name); + "Tag %s/0x%08x incompatible with output codec id '%d'\n", + tagbuf, st->codec->codec_tag, st->codec->codec_id); return AVERROR_INVALIDDATA; } }else @@ -2678,22 +2865,13 @@ int av_write_header(AVFormatContext *s) return AVERROR(ENOMEM); } -#if LIBAVFORMAT_VERSION_MAJOR < 53 +#if FF_API_OLD_METADATA ff_metadata_mux_compat(s); #endif /* set muxer identification string */ - if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { - AVMetadata *m; - AVMetadataTag *t; - - if (!(m = av_mallocz(sizeof(AVMetadata)))) - return AVERROR(ENOMEM); - av_metadata_set2(&m, "encoder", LIBAVFORMAT_IDENT, 0); - metadata_conv(&m, s->oformat->metadata_conv, NULL); - if ((t = av_metadata_get(m, "", NULL, AV_METADATA_IGNORE_SUFFIX))) - av_metadata_set2(&s->metadata, t->key, t->value, 0); - av_metadata_free(&m); + if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { + av_metadata_set2(&s->metadata, "encoder", LIBAVFORMAT_IDENT, 0); } if(s->oformat->write_header){ @@ -2767,12 +2945,12 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){ if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){ av_log(s, AV_LOG_ERROR, - "st:%d error, non monotone timestamps %"PRId64" >= %"PRId64"\n", + "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"PRId64" >= %"PRId64"\n", st->index, st->cur_dts, pkt->dts); return -1; } if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts < pkt->dts){ - av_log(s, AV_LOG_ERROR, "st:%d error, pts < dts\n", st->index); + av_log(s, AV_LOG_ERROR, "pts < dts in stream %d\n", st->index); return -1; } @@ -2850,7 +3028,7 @@ next_non_null: *next_point= this_pktl; } -int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacket *pkt) +static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacket *pkt) { AVStream *st = s->streams[ pkt ->stream_index]; AVStream *st2= s->streams[ next->stream_index]; @@ -2890,7 +3068,7 @@ int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pk } /** - * Interleaves an AVPacket correctly so it can be muxed. + * Interleave an AVPacket correctly so it can be muxed. * @param out the interleaved packet will be output here * @param in the input packet * @param flush 1 if no further packets are available as input and all @@ -3059,14 +3237,44 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out if(st->codec->time_base.den && st->codec->time_base.num) print_fps(1/av_q2d(st->codec->time_base), "tbc"); } + if (st->disposition & AV_DISPOSITION_DEFAULT) + av_log(NULL, AV_LOG_INFO, " (default)"); + if (st->disposition & AV_DISPOSITION_DUB) + av_log(NULL, AV_LOG_INFO, " (dub)"); + if (st->disposition & AV_DISPOSITION_ORIGINAL) + av_log(NULL, AV_LOG_INFO, " (original)"); + if (st->disposition & AV_DISPOSITION_COMMENT) + av_log(NULL, AV_LOG_INFO, " (comment)"); + if (st->disposition & AV_DISPOSITION_LYRICS) + av_log(NULL, AV_LOG_INFO, " (lyrics)"); + if (st->disposition & AV_DISPOSITION_KARAOKE) + av_log(NULL, AV_LOG_INFO, " (karaoke)"); + if (st->disposition & AV_DISPOSITION_FORCED) + av_log(NULL, AV_LOG_INFO, " (forced)"); + if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED) + av_log(NULL, AV_LOG_INFO, " (hearing impaired)"); + if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED) + av_log(NULL, AV_LOG_INFO, " (visual impaired)"); + if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS) + av_log(NULL, AV_LOG_INFO, " (clean effects)"); av_log(NULL, AV_LOG_INFO, "\n"); dump_metadata(NULL, st->metadata, " "); } +#if FF_API_DUMP_FORMAT void dump_format(AVFormatContext *ic, int index, const char *url, int is_output) +{ + av_dump_format(ic, index, url, is_output); +} +#endif + +void av_dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output) { int i; uint8_t *printed = av_mallocz(ic->nb_streams); @@ -3098,7 +3306,7 @@ void dump_format(AVFormatContext *ic, int secs, us; av_log(NULL, AV_LOG_INFO, ", start: "); secs = ic->start_time / AV_TIME_BASE; - us = ic->start_time % AV_TIME_BASE; + us = abs(ic->start_time % AV_TIME_BASE); av_log(NULL, AV_LOG_INFO, "%d.%06d", secs, (int)av_rescale(us, 1000000, AV_TIME_BASE)); } @@ -3142,16 +3350,18 @@ void dump_format(AVFormatContext *ic, av_free(printed); } -#if LIBAVFORMAT_VERSION_MAJOR < 53 +#if FF_API_PARSE_FRAME_PARAM +#include "libavutil/parseutils.h" + int parse_image_size(int *width_ptr, int *height_ptr, const char *str) { - return av_parse_video_frame_size(width_ptr, height_ptr, str); + return av_parse_video_size(width_ptr, height_ptr, str); } int parse_frame_rate(int *frame_rate_num, int *frame_rate_den, const char *arg) { AVRational frame_rate; - int ret = av_parse_video_frame_rate(&frame_rate, arg); + int ret = av_parse_video_rate(&frame_rate, arg); *frame_rate_num= frame_rate.num; *frame_rate_den= frame_rate.den; return ret; @@ -3170,163 +3380,25 @@ uint64_t ff_ntp_time(void) return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; } -int64_t parse_date(const char *datestr, int duration) -{ - const char *p; - int64_t t; - struct tm dt; - int i; - static const char * const date_fmt[] = { - "%Y-%m-%d", - "%Y%m%d", - }; - static const char * const time_fmt[] = { - "%H:%M:%S", - "%H%M%S", - }; - const char *q; - int is_utc, len; - char lastch; - int negative = 0; - -#undef time - time_t now = time(0); - - len = strlen(datestr); - if (len > 0) - lastch = datestr[len - 1]; - else - lastch = '\0'; - is_utc = (lastch == 'z' || lastch == 'Z'); - - memset(&dt, 0, sizeof(dt)); - - p = datestr; - q = NULL; - if (!duration) { - if (!strncasecmp(datestr, "now", len)) - return (int64_t) now * 1000000; - - /* parse the year-month-day part */ - for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) { - q = small_strptime(p, date_fmt[i], &dt); - if (q) { - break; - } - } - - /* if the year-month-day part is missing, then take the - * current year-month-day time */ - if (!q) { - if (is_utc) { - dt = *gmtime(&now); - } else { - dt = *localtime(&now); - } - dt.tm_hour = dt.tm_min = dt.tm_sec = 0; - } else { - p = q; - } - - if (*p == 'T' || *p == 't' || *p == ' ') - p++; - - /* parse the hour-minute-second part */ - for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) { - q = small_strptime(p, time_fmt[i], &dt); - if (q) { - break; - } - } - } else { - /* parse datestr as a duration */ - if (p[0] == '-') { - negative = 1; - ++p; - } - /* parse datestr as HH:MM:SS */ - q = small_strptime(p, time_fmt[0], &dt); - if (!q) { - /* parse datestr as S+ */ - dt.tm_sec = strtol(p, (char **)&q, 10); - if (q == p) - /* the parsing didn't succeed */ - return INT64_MIN; - dt.tm_min = 0; - dt.tm_hour = 0; - } - } +#if FF_API_PARSE_DATE +#include "libavutil/parseutils.h" - /* Now we have all the fields that we can get */ - if (!q) { - return INT64_MIN; - } - - if (duration) { - t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; - } else { - dt.tm_isdst = -1; /* unknown */ - if (is_utc) { - t = mktimegm(&dt); - } else { - t = mktime(&dt); - } - } - - t *= 1000000; - - /* parse the .m... part */ - if (*q == '.') { - int val, n; - q++; - for (val = 0, n = 100000; n >= 1; n /= 10, q++) { - if (!isdigit(*q)) - break; - val += n * (*q - '0'); - } - t += val; - } - return negative ? -t : t; +int64_t parse_date(const char *timestr, int duration) +{ + int64_t timeval; + av_parse_time(&timeval, timestr, duration); + return timeval; } +#endif + +#if FF_API_FIND_INFO_TAG +#include "libavutil/parseutils.h" int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info) { - const char *p; - char tag[128], *q; - - p = info; - if (*p == '?') - p++; - for(;;) { - q = tag; - while (*p != '\0' && *p != '=' && *p != '&') { - if ((q - tag) < sizeof(tag) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - q = arg; - if (*p == '=') { - p++; - while (*p != '&' && *p != '\0') { - if ((q - arg) < arg_size - 1) { - if (*p == '+') - *q++ = ' '; - else - *q++ = *p; - } - p++; - } - *q = '\0'; - } - if (!strcmp(tag, tag1)) - return 1; - if (*p != '&') - break; - p++; - } - return 0; + return av_find_info_tag(arg, arg_size, tag1, info); } +#endif int av_get_frame_filename(char *buf, int buf_size, const char *path, int number) @@ -3422,26 +3494,25 @@ void av_hex_dump_log(void *avcl, int level, uint8_t *buf, int size) hex_dump_internal(avcl, NULL, level, buf, size); } - //FIXME needs to know the time_base -static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int dump_payload) +static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int dump_payload, AVRational time_base) { #undef fprintf #define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0) PRINT("stream #%d:\n", pkt->stream_index); PRINT(" keyframe=%d\n", ((pkt->flags & AV_PKT_FLAG_KEY) != 0)); - PRINT(" duration=%0.3f\n", (double)pkt->duration / AV_TIME_BASE); + PRINT(" duration=%0.3f\n", pkt->duration * av_q2d(time_base)); /* DTS is _always_ valid after av_read_frame() */ PRINT(" dts="); if (pkt->dts == AV_NOPTS_VALUE) PRINT("N/A"); else - PRINT("%0.3f", (double)pkt->dts / AV_TIME_BASE); + PRINT("%0.3f", pkt->dts * av_q2d(time_base)); /* PTS may not be known if B-frames are present. */ PRINT(" pts="); if (pkt->pts == AV_NOPTS_VALUE) PRINT("N/A"); else - PRINT("%0.3f", (double)pkt->pts / AV_TIME_BASE); + PRINT("%0.3f", pkt->pts * av_q2d(time_base)); PRINT("\n"); PRINT(" size=%d\n", pkt->size); #undef PRINT @@ -3451,20 +3522,51 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload) { - pkt_dump_internal(NULL, f, 0, pkt, dump_payload); + AVRational tb = { 1, AV_TIME_BASE }; + pkt_dump_internal(NULL, f, 0, pkt, dump_payload, tb); +} + +void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st) +{ + pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base); } void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload) { - pkt_dump_internal(avcl, NULL, level, pkt, dump_payload); + AVRational tb = { 1, AV_TIME_BASE }; + pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, tb); +} + +void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, + AVStream *st) +{ + pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, st->time_base); } +#if FF_API_URL_SPLIT +attribute_deprecated void ff_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url) +{ + av_url_split(proto, proto_size, + authorization, authorization_size, + hostname, hostname_size, + port_ptr, + path, path_size, + url); +} +#endif + +void av_url_split(char *proto, int proto_size, + char *authorization, int authorization_size, + char *hostname, int hostname_size, + int *port_ptr, + char *path, int path_size, + const char *url) { const char *p, *ls, *at, *col, *brk; @@ -3541,19 +3643,50 @@ char *ff_data_to_hex(char *buff, const uint8_t *src, int s, int lowercase) return buff; } +int ff_hex_to_data(uint8_t *data, const char *p) +{ + int c, len, v; + + len = 0; + v = 1; + for (;;) { + p += strspn(p, SPACE_CHARS); + if (*p == '\0') + break; + c = toupper((unsigned char) *p++); + if (c >= '0' && c <= '9') + c = c - '0'; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else + break; + v = (v << 4) | c; + if (v & 0x100) { + if (data) + data[len] = v; + len++; + v = 1; + } + } + return len; +} + void av_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den) { - s->pts_wrap_bits = pts_wrap_bits; - - if(av_reduce(&s->time_base.num, &s->time_base.den, pts_num, pts_den, INT_MAX)){ - if(s->time_base.num != pts_num) - av_log(NULL, AV_LOG_DEBUG, "st:%d removing common factor %d from timebase\n", s->index, pts_num/s->time_base.num); + AVRational new_tb; + if(av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)){ + if(new_tb.num != pts_num) + av_log(NULL, AV_LOG_DEBUG, "st:%d removing common factor %d from timebase\n", s->index, pts_num/new_tb.num); }else av_log(NULL, AV_LOG_WARNING, "st:%d has too large timebase, reducing\n", s->index); - if(!s->time_base.num || !s->time_base.den) - s->time_base.num= s->time_base.den= 0; + if(new_tb.num <= 0 || new_tb.den <= 0) { + av_log(NULL, AV_LOG_ERROR, "Ignoring attempt to set invalid timebase for st:%d\n", s->index); + return; + } + s->time_base = new_tb; + s->pts_wrap_bits = pts_wrap_bits; } int ff_url_join(char *str, int size, const char *proto, @@ -3567,7 +3700,7 @@ int ff_url_join(char *str, int size, const char *proto, str[0] = '\0'; if (proto) av_strlcatf(str, size, "%s://", proto); - if (authorization) + if (authorization && authorization[0]) av_strlcatf(str, size, "%s@", authorization); #if CONFIG_NETWORK && defined(AF_INET6) /* Determine if hostname is a numerical IPv6 address, @@ -3619,3 +3752,66 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, return av_write_frame(dst, &local_pkt); } +void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf, + void *context) +{ + const char *ptr = str; + + /* Parse key=value pairs. */ + for (;;) { + const char *key; + char *dest = NULL, *dest_end; + int key_len, dest_len = 0; + + /* Skip whitespace and potential commas. */ + while (*ptr && (isspace(*ptr) || *ptr == ',')) + ptr++; + if (!*ptr) + break; + + key = ptr; + + if (!(ptr = strchr(key, '='))) + break; + ptr++; + key_len = ptr - key; + + callback_get_buf(context, key, key_len, &dest, &dest_len); + dest_end = dest + dest_len - 1; + + if (*ptr == '\"') { + ptr++; + while (*ptr && *ptr != '\"') { + if (*ptr == '\\') { + if (!ptr[1]) + break; + if (dest && dest < dest_end) + *dest++ = ptr[1]; + ptr += 2; + } else { + if (dest && dest < dest_end) + *dest++ = *ptr; + ptr++; + } + } + if (*ptr == '\"') + ptr++; + } else { + for (; *ptr && !(isspace(*ptr) || *ptr == ','); ptr++) + if (dest && dest < dest_end) + *dest++ = *ptr; + } + if (dest) + *dest = 0; + } +} + +int ff_find_stream_index(AVFormatContext *s, int id) +{ + int i; + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->id == id) + return i; + } + return -1; +}