diff options
Diffstat (limited to 'libavformat/utils.c')
-rw-r--r-- | libavformat/utils.c | 2157 |
1 files changed, 1695 insertions, 462 deletions
diff --git a/libavformat/utils.c b/libavformat/utils.c index faad9c9db4..6e828f7ce9 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -1,21 +1,21 @@ /* - * various utility functions for use within Libav + * various utility functions for use within FFmpeg * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -35,12 +35,15 @@ #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" +#include "libavutil/timestamp.h" #include "libavcodec/bytestream.h" #include "libavcodec/internal.h" +#include "libavcodec/raw.h" #include "audiointerleave.h" #include "avformat.h" +#include "avio_internal.h" #include "id3v2.h" #include "internal.h" #include "metadata.h" @@ -52,36 +55,136 @@ /** * @file - * various utility functions for use within Libav + * various utility functions for use within FFmpeg */ unsigned avformat_version(void) { + av_assert0(LIBAVFORMAT_VERSION_MICRO >= 100); return LIBAVFORMAT_VERSION_INT; } const char *avformat_configuration(void) { - return LIBAV_CONFIGURATION; + return FFMPEG_CONFIGURATION; } const char *avformat_license(void) { #define LICENSE_PREFIX "libavformat license: " - return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1; + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; +} + +#define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48)) + +static int is_relative(int64_t ts) { + return ts > (RELATIVE_TS_BASE - (1LL<<48)); +} + +/** + * Wrap a given time stamp, if there is an indication for an overflow + * + * @param st stream + * @param timestamp the time stamp to wrap + * @return resulting time stamp + */ +static int64_t wrap_timestamp(AVStream *st, int64_t timestamp) +{ + if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE && + st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) { + if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET && + timestamp < st->pts_wrap_reference) + return timestamp + (1ULL << st->pts_wrap_bits); + else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET && + timestamp >= st->pts_wrap_reference) + return timestamp - (1ULL << st->pts_wrap_bits); + } + return timestamp; +} + +MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec) +MAKE_ACCESSORS(AVFormatContext, format, int, metadata_header_padding) +MAKE_ACCESSORS(AVFormatContext, format, void *, opaque) +MAKE_ACCESSORS(AVFormatContext, format, av_format_control_message, control_message_cb) + +int64_t av_stream_get_end_pts(const AVStream *st) +{ + return st->pts.val; +} + +struct AVCodecParserContext *av_stream_get_parser(const AVStream *st) +{ + return st->parser; +} + +void av_format_inject_global_side_data(AVFormatContext *s) +{ + int i; + s->internal->inject_global_side_data = 1; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + st->inject_global_side_data = 1; + } +} + +static const AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id) +{ + if (st->codec->codec) + return st->codec->codec; + + switch (st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + if (s->video_codec) return s->video_codec; + break; + case AVMEDIA_TYPE_AUDIO: + if (s->audio_codec) return s->audio_codec; + break; + case AVMEDIA_TYPE_SUBTITLE: + if (s->subtitle_codec) return s->subtitle_codec; + break; + } + + return avcodec_find_decoder(codec_id); +} + +int av_format_get_probe_score(const AVFormatContext *s) +{ + return s->probe_score; } /* an arbitrarily chosen "sane" max packet size -- 50M */ #define SANE_CHUNK_SIZE (50000000) +int ffio_limit(AVIOContext *s, int size) +{ + if (s->maxsize>= 0) { + int64_t remaining= s->maxsize - avio_tell(s); + if (remaining < size) { + int64_t newsize = avio_size(s); + if (!s->maxsize || s->maxsize<newsize) + s->maxsize = newsize - !newsize; + remaining= s->maxsize - avio_tell(s); + remaining= FFMAX(remaining, 0); + } + + if (s->maxsize>= 0 && remaining+1 < size) { + av_log(NULL, remaining ? AV_LOG_ERROR : AV_LOG_DEBUG, "Truncating packet of size %d to %"PRId64"\n", size, remaining+1); + size = remaining+1; + } + } + return size; +} + /* Read the data in sane-sized chunks and append to pkt. * Return the number of bytes read or an error. */ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) { - int64_t chunk_size = size; int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos int orig_size = pkt->size; - int ret = 0; + int ret; do { int prev_size = pkt->size; @@ -89,11 +192,13 @@ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) /* When the caller requests a lot of data, limit it to the amount * left in file or SANE_CHUNK_SIZE when it is not known. */ - if (size > SANE_CHUNK_SIZE) { - int64_t filesize = avio_size(s) - avio_tell(s); - chunk_size = FFMAX(filesize, SANE_CHUNK_SIZE); + read_size = size; + if (read_size > SANE_CHUNK_SIZE/10) { + read_size = ffio_limit(s, read_size); + // If filesize/maxsize is unknown, limit to SANE_CHUNK_SIZE + if (s->maxsize < 0) + read_size = FFMIN(read_size, SANE_CHUNK_SIZE); } - read_size = FFMIN(size, chunk_size); ret = av_grow_packet(pkt, read_size); if (ret < 0) @@ -107,6 +212,8 @@ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) size -= read_size; } while (size > 0); + if (size > 0) + pkt->flags |= AV_PKT_FLAG_CORRUPT; pkt->pos = orig_pos; if (!pkt->size) @@ -139,7 +246,7 @@ int av_filename_number_test(const char *filename) } static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, - AVProbeData *pd, int score) + AVProbeData *pd) { static const struct { const char *name; @@ -151,15 +258,17 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, { "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO }, { "eac3", AV_CODEC_ID_EAC3, AVMEDIA_TYPE_AUDIO }, { "h264", AV_CODEC_ID_H264, AVMEDIA_TYPE_VIDEO }, - { "latm", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO }, + { "hevc", AV_CODEC_ID_HEVC, AVMEDIA_TYPE_VIDEO }, + { "loas", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO }, { "m4v", AV_CODEC_ID_MPEG4, AVMEDIA_TYPE_VIDEO }, { "mp3", AV_CODEC_ID_MP3, AVMEDIA_TYPE_AUDIO }, { "mpegvideo", AV_CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO }, { 0 } }; - AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score); + int score; + AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score); - if (fmt) { + if (fmt && st->request_probe <= score) { int i; av_log(s, AV_LOG_DEBUG, "Probe with size=%d, packets=%d detected %s with score=%d\n", @@ -169,44 +278,61 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, if (!strcmp(fmt->name, fmt_id_type[i].name)) { st->codec->codec_id = fmt_id_type[i].id; st->codec->codec_type = fmt_id_type[i].type; - break; + return score; } } } - return !!fmt; + return 0; } /************************************************************/ /* input media file */ +int av_demuxer_open(AVFormatContext *ic) { + int err; + + if (ic->iformat->read_header) { + err = ic->iformat->read_header(ic); + if (err < 0) + return err; + } + + if (ic->pb && !ic->data_offset) + ic->data_offset = avio_tell(ic->pb); + + return 0; +} + /* Open input file and probe the format if necessary. */ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options) { int ret; AVProbeData pd = { filename, NULL, 0 }; + int score = AVPROBE_SCORE_RETRY; if (s->pb) { s->flags |= AVFMT_FLAG_CUSTOM_IO; if (!s->iformat) - return av_probe_input_buffer(s->pb, &s->iformat, filename, - s, 0, s->probesize); + return av_probe_input_buffer2(s->pb, &s->iformat, filename, + s, 0, s->format_probesize); else if (s->iformat->flags & AVFMT_NOFILE) - return AVERROR(EINVAL); + av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and " + "will be ignored with AVFMT_NOFILE format.\n"); return 0; } if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || - (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0)))) - return 0; + (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score)))) + return score; - if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ, + if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags, &s->interrupt_callback, options)) < 0) return ret; if (s->iformat) return 0; - return av_probe_input_buffer(s->pb, &s->iformat, filename, - s, 0, s->probesize); + return av_probe_input_buffer2(s->pb, &s->iformat, filename, + s, 0, s->format_probesize); } static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, @@ -227,13 +353,19 @@ static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, return &pktl->pkt; } -static int queue_attached_pictures(AVFormatContext *s) +int avformat_queue_attached_pictures(AVFormatContext *s) { int i; for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC && s->streams[i]->discard < AVDISCARD_ALL) { AVPacket copy = s->streams[i]->attached_pic; + if (copy.size <= 0) { + av_log(s, AV_LOG_WARNING, + "Attached picture on stream %d has invalid size, " + "ignoring\n", i); + continue; + } copy.buf = av_buffer_ref(copy.buf); if (!copy.buf) return AVERROR(ENOMEM); @@ -254,6 +386,10 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, if (!s && !(s = avformat_alloc_context())) return AVERROR(ENOMEM); + if (!s->av_class) { + av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n"); + return AVERROR(EINVAL); + } if (fmt) s->iformat = fmt; @@ -265,6 +401,8 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, if ((ret = init_input(s, filename, &tmp)) < 0) goto fail; + s->probe_score = ret; + avio_skip(s->pb, s->skip_initial_bytes); /* Check filename in case an image number is expected. */ if (s->iformat->flags & AVFMT_NEEDNUMBER) { @@ -293,21 +431,26 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ if (s->pb) - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); - if (s->iformat->read_header) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) if ((ret = s->iformat->read_header(s)) < 0) goto fail; - if (id3v2_extra_meta && - (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) - goto fail; + if (id3v2_extra_meta) { + if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") || + !strcmp(s->iformat->name, "tta")) { + if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) + goto fail; + } else + av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n"); + } ff_id3v2_free_extra_meta(&id3v2_extra_meta); - if ((ret = queue_attached_pictures(s)) < 0) + if ((ret = avformat_queue_attached_pictures(s)) < 0) goto fail; - if (s->pb && !s->data_offset) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset) s->data_offset = avio_tell(s->pb); s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; @@ -331,44 +474,138 @@ fail: /*******************************************************/ +static void force_codec_ids(AVFormatContext *s, AVStream *st) +{ + switch (st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + if (s->video_codec_id) + st->codec->codec_id = s->video_codec_id; + break; + case AVMEDIA_TYPE_AUDIO: + if (s->audio_codec_id) + st->codec->codec_id = s->audio_codec_id; + break; + case AVMEDIA_TYPE_SUBTITLE: + if (s->subtitle_codec_id) + st->codec->codec_id = s->subtitle_codec_id; + break; + } +} + static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) { - if (st->codec->codec_id == AV_CODEC_ID_PROBE) { + if (st->request_probe>0) { AVProbeData *pd = &st->probe_data; - av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index); + int end; + av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets); --st->probe_packets; if (pkt) { - int err; - if ((err = av_reallocp(&pd->buf, pd->buf_size + pkt->size + - AVPROBE_PADDING_SIZE)) < 0) - return err; + uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); + if (!new_buf) { + av_log(s, AV_LOG_WARNING, + "Failed to reallocate probe buffer for stream %d\n", + st->index); + goto no_packet; + } + pd->buf = new_buf; memcpy(pd->buf + pd->buf_size, pkt->data, pkt->size); pd->buf_size += pkt->size; memset(pd->buf + pd->buf_size, 0, AVPROBE_PADDING_SIZE); } else { +no_packet: st->probe_packets = 0; if (!pd->buf_size) { - av_log(s, AV_LOG_ERROR, + av_log(s, AV_LOG_WARNING, "nothing to probe for stream %d\n", st->index); - return 0; } } - if (!st->probe_packets || - av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) { - set_codec_from_probe_data(s, st, pd, st->probe_packets > 0 - ? AVPROBE_SCORE_MAX / 4 : 0); - if (st->codec->codec_id != AV_CODEC_ID_PROBE) { + end= s->raw_packet_buffer_remaining_size <= 0 + || st->probe_packets<= 0; + + if (end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) { + int score = set_codec_from_probe_data(s, st, pd); + if ( (st->codec->codec_id != AV_CODEC_ID_NONE && score > AVPROBE_SCORE_STREAM_RETRY) + || end) { pd->buf_size = 0; av_freep(&pd->buf); - av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index); + st->request_probe = -1; + if (st->codec->codec_id != AV_CODEC_ID_NONE) { + av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index); + } else + av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index); } + force_codec_ids(s, st); } } return 0; } +static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index, AVPacket *pkt) +{ + int64_t ref = pkt->dts; + int i, pts_wrap_behavior; + int64_t pts_wrap_reference; + AVProgram *first_program; + + if (ref == AV_NOPTS_VALUE) + ref = pkt->pts; + if (st->pts_wrap_reference != AV_NOPTS_VALUE || st->pts_wrap_bits >= 63 || ref == AV_NOPTS_VALUE || !s->correct_ts_overflow) + return 0; + ref &= (1LL << st->pts_wrap_bits)-1; + + // reference time stamp should be 60 s before first time stamp + pts_wrap_reference = ref - av_rescale(60, st->time_base.den, st->time_base.num); + // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset + pts_wrap_behavior = (ref < (1LL << st->pts_wrap_bits) - (1LL << st->pts_wrap_bits-3)) || + (ref < (1LL << st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ? + AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET; + + first_program = av_find_program_from_stream(s, NULL, stream_index); + + if (!first_program) { + int default_stream_index = av_find_default_stream_index(s); + if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) { + for (i = 0; i < s->nb_streams; i++) { + s->streams[i]->pts_wrap_reference = pts_wrap_reference; + s->streams[i]->pts_wrap_behavior = pts_wrap_behavior; + } + } + else { + st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference; + st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior; + } + } + else { + AVProgram *program = first_program; + while (program) { + if (program->pts_wrap_reference != AV_NOPTS_VALUE) { + pts_wrap_reference = program->pts_wrap_reference; + pts_wrap_behavior = program->pts_wrap_behavior; + break; + } + program = av_find_program_from_stream(s, program, stream_index); + } + + // update every program with differing pts_wrap_reference + program = first_program; + while (program) { + if (program->pts_wrap_reference != pts_wrap_reference) { + for (i = 0; i<program->nb_stream_indexes; i++) { + s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference; + s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior; + } + + program->pts_wrap_reference = pts_wrap_reference; + program->pts_wrap_behavior = pts_wrap_behavior; + } + program = av_find_program_from_stream(s, program, stream_index); + } + } + return 1; +} + int ff_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, i, err; @@ -380,16 +617,10 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) if (pktl) { *pkt = pktl->pkt; st = s->streams[pkt->stream_index]; - if (st->codec->codec_id != AV_CODEC_ID_PROBE || - !st->probe_packets || - s->raw_packet_buffer_remaining_size < pkt->size) { - AVProbeData *pd; - if (st->probe_packets) - if ((err = probe_codec(s, st, NULL)) < 0) - return err; - pd = &st->probe_data; - av_freep(&pd->buf); - pd->buf_size = 0; + if (s->raw_packet_buffer_remaining_size <= 0) + if ((err = probe_codec(s, st, NULL)) < 0) + return err; + if (st->request_probe <= 0) { s->raw_packet_buffer = pktl->next; s->raw_packet_buffer_remaining_size += pkt->size; av_free(pktl); @@ -409,6 +640,7 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) if (st->probe_packets) if ((err = probe_codec(s, st, NULL)) < 0) return err; + av_assert0(st->request_probe <= 0); } continue; } @@ -422,25 +654,33 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) continue; } + if (pkt->stream_index >= (unsigned)s->nb_streams) { + av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index); + continue; + } + st = s->streams[pkt->stream_index]; - switch (st->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (s->video_codec_id) - st->codec->codec_id = s->video_codec_id; - break; - case AVMEDIA_TYPE_AUDIO: - if (s->audio_codec_id) - st->codec->codec_id = s->audio_codec_id; - break; - case AVMEDIA_TYPE_SUBTITLE: - if (s->subtitle_codec_id) - st->codec->codec_id = s->subtitle_codec_id; - break; + if (update_wrap_reference(s, st, pkt->stream_index, pkt) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) { + // correct first time stamps to negative values + if (!is_relative(st->first_dts)) + st->first_dts = wrap_timestamp(st, st->first_dts); + if (!is_relative(st->start_time)) + st->start_time = wrap_timestamp(st, st->start_time); + if (!is_relative(st->cur_dts)) + st->cur_dts = wrap_timestamp(st, st->cur_dts); } - if (!pktl && (st->codec->codec_id != AV_CODEC_ID_PROBE || - !st->probe_packets)) + pkt->dts = wrap_timestamp(st, pkt->dts); + pkt->pts = wrap_timestamp(st, pkt->pts); + + force_codec_ids(s, st); + + /* TODO: audio: time filter; video: frame reordering (pts != dts) */ + if (s->use_wallclock_as_timestamps) + pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base); + + if (!pktl && st->request_probe <= 0) return ret; add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); @@ -451,8 +691,27 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) } } +#if FF_API_READ_PACKET +int av_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + return ff_read_packet(s, pkt); +} +#endif + + /**********************************************************/ +static int determinable_frame_size(AVCodecContext *avctx) +{ + if (/*avctx->codec_id == AV_CODEC_ID_AAC ||*/ + avctx->codec_id == AV_CODEC_ID_MP1 || + avctx->codec_id == AV_CODEC_ID_MP2 || + avctx->codec_id == AV_CODEC_ID_MP3/* || + avctx->codec_id == AV_CODEC_ID_CELT*/) + return 1; + return 0; +} + /** * Return the frame duration in seconds. Return 0 if not available. */ @@ -465,9 +724,9 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st, *pden = 0; switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: - if (st->avg_frame_rate.num) { - *pnum = st->avg_frame_rate.den; - *pden = st->avg_frame_rate.num; + if (st->r_frame_rate.num && !pc) { + *pnum = st->r_frame_rate.den; + *pden = st->r_frame_rate.num; } else if (st->time_base.num * 1000LL > st->time_base.den) { *pnum = st->time_base.num; *pden = st->time_base.den; @@ -499,43 +758,138 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st, } } -static int is_intra_only(enum AVCodecID id) +static int is_intra_only(AVCodecContext *enc) { + const AVCodecDescriptor *desc; + + if (enc->codec_type != AVMEDIA_TYPE_VIDEO) + return 1; + + desc = av_codec_get_codec_descriptor(enc); + if (!desc) { + desc = avcodec_descriptor_get(enc->codec_id); + av_codec_set_codec_descriptor(enc, desc); + } + if (desc) + return !!(desc->props & AV_CODEC_PROP_INTRA_ONLY); + return 0; +} + +static int has_decode_delay_been_guessed(AVStream *st) { - const AVCodecDescriptor *d = avcodec_descriptor_get(id); - if (!d) - return 0; - if (d->type == AVMEDIA_TYPE_VIDEO && !(d->props & AV_CODEC_PROP_INTRA_ONLY)) - return 0; - return 1; + if (st->codec->codec_id != AV_CODEC_ID_H264) return 1; + if (!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy + return 1; +#if CONFIG_H264_DECODER + if (st->codec->has_b_frames && + avpriv_h264_has_num_reorder_frames(st->codec) == st->codec->has_b_frames) + return 1; +#endif + if (st->codec->has_b_frames<3) + return st->nb_decoded_frames >= 7; + else if (st->codec->has_b_frames<4) + return st->nb_decoded_frames >= 18; + else + return st->nb_decoded_frames >= 20; +} + +static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList *pktl) +{ + if (pktl->next) + return pktl->next; + if (pktl == s->packet_buffer_end) + return s->parse_queue; + return NULL; +} + +static int64_t select_from_pts_buffer(AVStream *st, int64_t *pts_buffer, int64_t dts) { + int onein_oneout = st->codec->codec_id != AV_CODEC_ID_H264 && + st->codec->codec_id != AV_CODEC_ID_HEVC; + + if(!onein_oneout) { + int delay = st->codec->has_b_frames; + int i; + + if (dts == AV_NOPTS_VALUE) { + int64_t best_score = INT64_MAX; + for (i = 0; i<delay; i++) { + if (st->pts_reorder_error_count[i]) { + int64_t score = st->pts_reorder_error[i] / st->pts_reorder_error_count[i]; + if (score < best_score) { + best_score = score; + dts = pts_buffer[i]; + } + } + } + } else { + for (i = 0; i<delay; i++) { + if (pts_buffer[i] != AV_NOPTS_VALUE) { + int64_t diff = FFABS(pts_buffer[i] - dts) + + (uint64_t)st->pts_reorder_error[i]; + diff = FFMAX(diff, st->pts_reorder_error[i]); + st->pts_reorder_error[i] = diff; + st->pts_reorder_error_count[i]++; + if (st->pts_reorder_error_count[i] > 250) { + st->pts_reorder_error[i] >>= 1; + st->pts_reorder_error_count[i] >>= 1; + } + } + } + } + } + + if (dts == AV_NOPTS_VALUE) + dts = pts_buffer[0]; + + return dts; } static void update_initial_timestamps(AVFormatContext *s, int stream_index, - int64_t dts, int64_t pts) + int64_t dts, int64_t pts, AVPacket *pkt) { AVStream *st = s->streams[stream_index]; - AVPacketList *pktl = s->packet_buffer; + AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue; + int64_t pts_buffer[MAX_REORDER_DELAY+1]; + int64_t shift; + int i, delay; if (st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || - st->cur_dts == AV_NOPTS_VALUE) + st->cur_dts == AV_NOPTS_VALUE || + is_relative(dts)) return; - st->first_dts = dts - st->cur_dts; + delay = st->codec->has_b_frames; + st->first_dts = dts - (st->cur_dts - RELATIVE_TS_BASE); st->cur_dts = dts; + shift = st->first_dts - RELATIVE_TS_BASE; - for (; pktl; pktl = pktl->next) { + for (i = 0; i<MAX_REORDER_DELAY+1; i++) + pts_buffer[i] = AV_NOPTS_VALUE; + + if (is_relative(pts)) + pts += shift; + + for (; pktl; pktl = get_next_pkt(s, st, pktl)) { if (pktl->pkt.stream_index != stream_index) continue; - // FIXME: think more about this check - if (pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts) - pktl->pkt.pts += st->first_dts; + if (is_relative(pktl->pkt.pts)) + pktl->pkt.pts += shift; - if (pktl->pkt.dts != AV_NOPTS_VALUE) - pktl->pkt.dts += st->first_dts; + if (is_relative(pktl->pkt.dts)) + pktl->pkt.dts += shift; if (st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE) st->start_time = pktl->pkt.pts; + + if (pktl->pkt.pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)) { + pts_buffer[0] = pktl->pkt.pts; + for (i = 0; i<delay && pts_buffer[i] > pts_buffer[i + 1]; i++) + FFSWAP(int64_t, pts_buffer[i], pts_buffer[i + 1]); + + pktl->pkt.dts = select_from_pts_buffer(st, pts_buffer, pktl->pkt.dts); + } } + if (st->start_time == AV_NOPTS_VALUE) st->start_time = pts; } @@ -543,12 +897,15 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, static void update_initial_durations(AVFormatContext *s, AVStream *st, int stream_index, int duration) { - AVPacketList *pktl = s->packet_buffer; - int64_t cur_dts = 0; + AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue; + int64_t cur_dts = RELATIVE_TS_BASE; if (st->first_dts != AV_NOPTS_VALUE) { + if (st->update_initial_durations_done) + return; + st->update_initial_durations_done = 1; cur_dts = st->first_dts; - for (; pktl; pktl = pktl->next) { + for (; pktl; pktl = get_next_pkt(s, st, pktl)) { if (pktl->pkt.stream_index == stream_index) { if (pktl->pkt.pts != pktl->pkt.dts || pktl->pkt.dts != AV_NOPTS_VALUE || @@ -557,27 +914,36 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st, cur_dts -= duration; } } - pktl = s->packet_buffer; + if (pktl && pktl->pkt.dts != st->first_dts) { + av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s (pts %s, duration %d) in the queue\n", + av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts), av_ts2str(pktl->pkt.pts), pktl->pkt.duration); + return; + } + if (!pktl) { + av_log(s, AV_LOG_DEBUG, "first_dts %s but no packet with dts in the queue\n", av_ts2str(st->first_dts)); + return; + } + pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue; st->first_dts = cur_dts; - } else if (st->cur_dts) + } else if (st->cur_dts != RELATIVE_TS_BASE) return; - for (; pktl; pktl = pktl->next) { + for (; pktl; pktl = get_next_pkt(s, st, pktl)) { if (pktl->pkt.stream_index != stream_index) continue; if (pktl->pkt.pts == pktl->pkt.dts && - pktl->pkt.dts == AV_NOPTS_VALUE && + (pktl->pkt.dts == AV_NOPTS_VALUE || pktl->pkt.dts == st->first_dts) && !pktl->pkt.duration) { pktl->pkt.dts = cur_dts; if (!st->codec->has_b_frames) pktl->pkt.pts = cur_dts; - cur_dts += duration; - if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) +// if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) pktl->pkt.duration = duration; } else break; + cur_dts = pktl->pkt.dts + pktl->pkt.duration; } - if (st->first_dts == AV_NOPTS_VALUE) + if (!pktl) st->cur_dts = cur_dts; } @@ -586,13 +952,43 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, { int num, den, presentation_delayed, delay, i; int64_t offset; + AVRational duration; + int onein_oneout = st->codec->codec_id != AV_CODEC_ID_H264 && + st->codec->codec_id != AV_CODEC_ID_HEVC; if (s->flags & AVFMT_FLAG_NOFILLIN) return; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pkt->dts != AV_NOPTS_VALUE) { + if (pkt->dts == pkt->pts && st->last_dts_for_order_check != AV_NOPTS_VALUE) { + if (st->last_dts_for_order_check <= pkt->dts) { + st->dts_ordered++; + } else { + av_log(s, st->dts_misordered ? AV_LOG_DEBUG : AV_LOG_WARNING, + "DTS %"PRIi64" < %"PRIi64" out of order\n", + pkt->dts, + st->last_dts_for_order_check); + st->dts_misordered++; + } + if (st->dts_ordered + st->dts_misordered > 250) { + st->dts_ordered >>= 1; + st->dts_misordered >>= 1; + } + } + + st->last_dts_for_order_check = pkt->dts; + if (st->dts_ordered < 8*st->dts_misordered && pkt->dts == pkt->pts) + pkt->dts = AV_NOPTS_VALUE; + } + if ((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE) pkt->dts = AV_NOPTS_VALUE; + if (pc && pc->pict_type == AV_PICTURE_TYPE_B + && !st->codec->has_b_frames) + //FIXME Set low_delay = 0 when has_b_frames = 1 + st->codec->has_b_frames = 1; + /* do we have a video B-frame ? */ delay = st->codec->has_b_frames; presentation_delayed = 0; @@ -606,7 +1002,10 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && st->pts_wrap_bits < 63 && pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) { - pkt->dts -= 1LL << st->pts_wrap_bits; + if (is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits - 1)) > st->cur_dts) { + pkt->dts -= 1LL << st->pts_wrap_bits; + } else + pkt->pts += 1LL << st->pts_wrap_bits; } /* Some MPEG-2 in MPEG-PS lack dts (issue #171 / input_file.mpg). @@ -615,23 +1014,27 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, * 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_DEBUG, "invalid dts/pts combination\n"); - pkt->dts = pkt->pts = AV_NOPTS_VALUE; + av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts); + if ( strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") + && strcmp(s->iformat->name, "flv")) // otherwise we discard correct timestamps for vc1-wmapro.ism + pkt->dts = AV_NOPTS_VALUE; } - if (pkt->duration == 0 && st->codec->codec_type != AVMEDIA_TYPE_AUDIO) { + duration = av_mul_q((AVRational) {pkt->duration, 1}, st->time_base); + if (pkt->duration == 0) { ff_compute_frame_duration(&num, &den, st, pc, pkt); if (den && num) { - pkt->duration = av_rescale_rnd(1, num * (int64_t) st->time_base.den, + duration = (AVRational) {num, den}; + pkt->duration = av_rescale_rnd(1, + num * (int64_t) st->time_base.den, den * (int64_t) st->time_base.num, AV_ROUND_DOWN); - - if (pkt->duration != 0 && s->packet_buffer) - update_initial_durations(s, st, pkt->stream_index, - pkt->duration); } } + if (pkt->duration != 0 && (s->packet_buffer || s->parse_queue)) + update_initial_durations(s, st, pkt->stream_index, pkt->duration); + /* Correct timestamps with byte offset if demuxers only have timestamps * on packet boundaries */ if (pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size) { @@ -650,20 +1053,19 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, presentation_delayed = 1; av_dlog(NULL, - "IN delayed:%d pts:%"PRId64", dts:%"PRId64" " - "cur_dts:%"PRId64" st:%d pc:%p\n", - presentation_delayed, pkt->pts, pkt->dts, st->cur_dts, - pkt->stream_index, pc); - /* Interpolate PTS and DTS if they are not present. We skip H.264 + "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%d\n", + presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), + pkt->stream_index, pc, pkt->duration); + /* Interpolate PTS and DTS if they are not present. We skip H264 * currently because delay and has_b_frames are not reliably set. */ if ((delay == 0 || (delay == 1 && pc)) && - st->codec->codec_id != AV_CODEC_ID_H264) { + onein_oneout) { if (presentation_delayed) { /* DTS = decompression timestamp */ /* PTS = presentation timestamp */ if (pkt->dts == AV_NOPTS_VALUE) pkt->dts = st->last_IP_pts; - update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); + update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); if (pkt->dts == AV_NOPTS_VALUE) pkt->dts = st->cur_dts; @@ -679,58 +1081,40 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, * by knowing the future. */ } else if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE || - pkt->duration || - st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - int duration = pkt->duration; - if (!duration && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - ff_compute_frame_duration(&num, &den, st, pc, pkt); - if (den && num) { - duration = av_rescale_rnd(1, - num * (int64_t) st->time_base.den, - den * (int64_t) st->time_base.num, - AV_ROUND_DOWN); - if (duration != 0 && s->packet_buffer) - update_initial_durations(s, st, pkt->stream_index, - duration); - } - } - - if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE || - duration) { - /* presentation is not delayed : PTS and DTS are the same */ - if (pkt->pts == AV_NOPTS_VALUE) - pkt->pts = pkt->dts; - update_initial_timestamps(s, pkt->stream_index, pkt->pts, - pkt->pts); - if (pkt->pts == AV_NOPTS_VALUE) - pkt->pts = st->cur_dts; - pkt->dts = pkt->pts; - if (pkt->pts != AV_NOPTS_VALUE) - st->cur_dts = pkt->pts + duration; - } + pkt->duration ) { + + /* presentation is not delayed : PTS and DTS are the same */ + if (pkt->pts == AV_NOPTS_VALUE) + pkt->pts = pkt->dts; + update_initial_timestamps(s, pkt->stream_index, pkt->pts, + pkt->pts, pkt); + if (pkt->pts == AV_NOPTS_VALUE) + pkt->pts = st->cur_dts; + pkt->dts = pkt->pts; + if (pkt->pts != AV_NOPTS_VALUE) + st->cur_dts = av_add_stable(st->time_base, pkt->pts, duration, 1); } } - if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) { + if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)) { st->pts_buffer[0] = pkt->pts; for (i = 0; i<delay && st->pts_buffer[i] > st->pts_buffer[i + 1]; i++) FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]); - if (pkt->dts == AV_NOPTS_VALUE) - pkt->dts = st->pts_buffer[0]; - // We skipped it above so we try here. - if (st->codec->codec_id == AV_CODEC_ID_H264) - // This should happen on the first packet - update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); - if (pkt->dts > st->cur_dts) - st->cur_dts = pkt->dts; + + pkt->dts = select_from_pts_buffer(st, st->pts_buffer, pkt->dts); } + // We skipped it above so we try here. + if (!onein_oneout) + // This should happen on the first packet + update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); + if (pkt->dts > st->cur_dts) + st->cur_dts = pkt->dts; - av_dlog(NULL, - "OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n", - presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts); + av_dlog(NULL, "OUTdelayed:%d/%d pts:%s, dts:%s cur_dts:%s\n", + presentation_delayed, delay, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts)); /* update flags */ - if (is_intra_only(st->codec->codec_id)) + if (is_intra_only(st->codec)) pkt->flags |= AV_PKT_FLAG_KEY; if (pc) pkt->convergence_duration = pc->convergence_duration; @@ -764,6 +1148,9 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) av_init_packet(&flush_pkt); pkt = &flush_pkt; got_output = 1; + } else if (!size && st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) { + // preserve 0-size sync packets + compute_pkt_fields(s, st, st->parser, pkt); } while (size > 0 || (pkt == &flush_pkt && got_output)) { @@ -775,6 +1162,7 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) pkt->pts, pkt->dts, pkt->pos); pkt->pts = pkt->dts = AV_NOPTS_VALUE; + pkt->pos = -1; /* increment read pointer */ data += len; size -= len; @@ -808,19 +1196,18 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) out_pkt.dts = st->parser->dts; out_pkt.pos = st->parser->pos; + if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) + out_pkt.pos = st->parser->frame_offset; + if (st->parser->key_frame == 1 || (st->parser->key_frame == -1 && st->parser->pict_type == AV_PICTURE_TYPE_I)) out_pkt.flags |= AV_PKT_FLAG_KEY; - compute_pkt_fields(s, st, st->parser, &out_pkt); + if (st->parser->key_frame == -1 && st->parser->pict_type ==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY)) + out_pkt.flags |= AV_PKT_FLAG_KEY; - if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && - out_pkt.flags & AV_PKT_FLAG_KEY) { - ff_reduce_index(s, st->index); - av_add_index_entry(st, st->parser->frame_offset, out_pkt.dts, - 0, 0, AVINDEX_KEYFRAME); - } + compute_pkt_fields(s, st, st->parser, &out_pkt); if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) { out_pkt.buf = pkt->buf; @@ -901,27 +1288,34 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) cur_pkt.dts != AV_NOPTS_VALUE && cur_pkt.pts < cur_pkt.dts) { av_log(s, AV_LOG_WARNING, - "Invalid timestamps stream=%d, pts=%"PRId64", " - "dts=%"PRId64", size=%d\n", - cur_pkt.stream_index, cur_pkt.pts, - cur_pkt.dts, cur_pkt.size); + "Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n", + cur_pkt.stream_index, + av_ts2str(cur_pkt.pts), + av_ts2str(cur_pkt.dts), + cur_pkt.size); } if (s->debug & FF_FDEBUG_TS) av_log(s, AV_LOG_DEBUG, - "ff_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", " - "size=%d, duration=%d, flags=%d\n", - cur_pkt.stream_index, cur_pkt.pts, cur_pkt.dts, + "ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", + cur_pkt.stream_index, + av_ts2str(cur_pkt.pts), + av_ts2str(cur_pkt.dts), cur_pkt.size, cur_pkt.duration, cur_pkt.flags); if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) { st->parser = av_parser_init(st->codec->codec_id); - if (!st->parser) + if (!st->parser) { + av_log(s, AV_LOG_VERBOSE, "parser not found for codec " + "%s, packets or times may be invalid.\n", + avcodec_get_name(st->codec->codec_id)); /* no parser available: just output the raw packets */ st->need_parsing = AVSTREAM_PARSE_NONE; - else if (st->need_parsing == AVSTREAM_PARSE_HEADERS) + } else if (st->need_parsing == AVSTREAM_PARSE_HEADERS) st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; else if (st->need_parsing == AVSTREAM_PARSE_FULL_ONCE) st->parser->flags |= PARSER_FLAG_ONCE; + else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) + st->parser->flags |= PARSER_FLAG_USE_CODEC_TS; } if (!st->need_parsing || !st->parser) { @@ -942,11 +1336,54 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) /* free packet */ av_free_packet(&cur_pkt); } + if (pkt->flags & AV_PKT_FLAG_KEY) + st->skip_to_keyframe = 0; + if (st->skip_to_keyframe) { + av_free_packet(&cur_pkt); + if (got_packet) { + *pkt = cur_pkt; + } + got_packet = 0; + } } if (!got_packet && s->parse_queue) ret = read_from_packet_buffer(&s->parse_queue, &s->parse_queue_end, pkt); + if (ret >= 0) { + AVStream *st = s->streams[pkt->stream_index]; + if (st->skip_samples) { + uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (p) { + AV_WL32(p, st->skip_samples); + av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples); + } + st->skip_samples = 0; + } + + if (st->inject_global_side_data) { + for (i = 0; i < st->nb_side_data; i++) { + AVPacketSideData *src_sd = &st->side_data[i]; + uint8_t *dst_data; + + if (av_packet_get_side_data(pkt, src_sd->type, NULL)) + continue; + + dst_data = av_packet_new_side_data(pkt, src_sd->type, src_sd->size); + if (!dst_data) { + av_log(s, AV_LOG_WARNING, "Could not inject global side data\n"); + continue; + } + + memcpy(dst_data, src_sd->data, src_sd->size); + } + st->inject_global_side_data = 0; + } + + if (!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) + av_packet_merge_side_data(pkt); + } + av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata); if (metadata) { s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; @@ -957,9 +1394,11 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (s->debug & FF_FDEBUG_TS) av_log(s, AV_LOG_DEBUG, - "read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", " + "read_frame_internal stream=%d, pts=%s, dts=%s, " "size=%d, duration=%d, flags=%d\n", - pkt->stream_index, pkt->pts, pkt->dts, + pkt->stream_index, + av_ts2str(pkt->pts), + av_ts2str(pkt->dts), pkt->size, pkt->duration, pkt->flags); return ret; @@ -969,15 +1408,20 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) { const int genpts = s->flags & AVFMT_FLAG_GENPTS; int eof = 0; + int ret; + AVStream *st; - if (!genpts) - return s->packet_buffer - ? read_from_packet_buffer(&s->packet_buffer, - &s->packet_buffer_end, pkt) - : read_frame_internal(s, pkt); + if (!genpts) { + ret = s->packet_buffer + ? read_from_packet_buffer(&s->packet_buffer, + &s->packet_buffer_end, pkt) + : read_frame_internal(s, pkt); + if (ret < 0) + return ret; + goto return_packet; + } for (;;) { - int ret; AVPacketList *pktl = s->packet_buffer; if (pktl) { @@ -985,23 +1429,42 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) if (next_pkt->dts != AV_NOPTS_VALUE) { int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits; + // last dts seen for this stream. if any of packets following + // current one had no dts, we will set this to AV_NOPTS_VALUE. + int64_t last_dts = next_pkt->dts; while (pktl && next_pkt->pts == AV_NOPTS_VALUE) { if (pktl->pkt.stream_index == next_pkt->stream_index && - (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0) && - av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { - // not B-frame - next_pkt->pts = pktl->pkt.dts; + (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) { + if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { + // not B-frame + next_pkt->pts = pktl->pkt.dts; + } + if (last_dts != AV_NOPTS_VALUE) { + // Once last dts was set to AV_NOPTS_VALUE, we don't change it. + last_dts = pktl->pkt.dts; + } } pktl = pktl->next; } + if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) { + // Fixing the last reference frame had none pts issue (For MXF etc). + // We only do this when + // 1. eof. + // 2. we are not able to resolve a pts value for current packet. + // 3. the packets for this stream at the end of the files had valid dts. + next_pkt->pts = last_dts + next_pkt->duration; + } pktl = s->packet_buffer; } /* read packet from packet buffer, if there is data */ - if (!(next_pkt->pts == AV_NOPTS_VALUE && - next_pkt->dts != AV_NOPTS_VALUE && !eof)) - return read_from_packet_buffer(&s->packet_buffer, + st = s->streams[next_pkt->stream_index]; + if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL && + next_pkt->dts != AV_NOPTS_VALUE && !eof)) { + ret = read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt); + goto return_packet; + } } ret = read_frame_internal(s, pkt); @@ -1017,6 +1480,21 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) &s->packet_buffer_end)) < 0) return AVERROR(ENOMEM); } + +return_packet: + + st = s->streams[pkt->stream_index]; + if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) { + ff_reduce_index(s, st->index); + av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME); + } + + if (is_relative(pkt->dts)) + pkt->dts -= RELATIVE_TS_BASE; + if (is_relative(pkt->pts)) + pkt->pts -= RELATIVE_TS_BASE; + + return ret; } /* XXX: suppress the packet queue */ @@ -1034,23 +1512,36 @@ static void flush_packet_queue(AVFormatContext *s) int av_find_default_stream_index(AVFormatContext *s) { - int first_audio_index = -1; int i; AVStream *st; + int best_stream = 0; + int best_score = -1; if (s->nb_streams <= 0) return -1; for (i = 0; i < s->nb_streams; i++) { + int score = 0; st = s->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { - return i; + if (!st->codec->width && !st->codec->height && !st->codec_info_nb_frames) + score += 25; + else + score += 100; + } + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + if (!st->codec->sample_rate && !st->codec_info_nb_frames) + score += 12; + else + score += 50; + } + + if (score > best_score) { + best_score = score; + best_stream = i; } - if (first_audio_index < 0 && - st->codec->codec_type == AVMEDIA_TYPE_AUDIO) - first_audio_index = i; } - return first_audio_index >= 0 ? first_audio_index : 0; + return best_stream; } /** Flush the frame reader. */ @@ -1070,13 +1561,20 @@ void ff_read_frame_flush(AVFormatContext *s) st->parser = NULL; } st->last_IP_pts = AV_NOPTS_VALUE; - /* We set the current DTS to an unspecified origin. */ - st->cur_dts = AV_NOPTS_VALUE; + st->last_dts_for_order_check = AV_NOPTS_VALUE; + if (st->first_dts == AV_NOPTS_VALUE) + st->cur_dts = RELATIVE_TS_BASE; + else + /* We set the current DTS to an unspecified origin. */ + st->cur_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; for (j = 0; j < MAX_REORDER_DELAY + 1; j++) st->pts_buffer[j] = AV_NOPTS_VALUE; + + if (s->internal->inject_global_side_data) + st->inject_global_side_data = 1; } } @@ -1119,6 +1617,15 @@ int ff_add_index_entry(AVIndexEntry **index_entries, if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) return -1; + if (timestamp == AV_NOPTS_VALUE) + return AVERROR(EINVAL); + + if (size < 0 || size > 0x3FFFFFFF) + return AVERROR(EINVAL); + + if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known + timestamp -= RELATIVE_TS_BASE; + entries = av_fast_realloc(*index_entries, index_entries_allocated_size, (*nb_index_entries + 1) * @@ -1134,7 +1641,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries, if (index < 0) { index = (*nb_index_entries)++; ie = &entries[index]; - assert(index == 0 || ie[-1].timestamp < timestamp); + av_assert0(index == 0 || ie[-1].timestamp < timestamp); } else { ie = &entries[index]; if (ie->timestamp != timestamp) { @@ -1160,6 +1667,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries, int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int size, int distance, int flags) { + timestamp = wrap_timestamp(st, timestamp); return ff_add_index_entry(&st->index_entries, &st->nb_index_entries, &st->index_entries_allocated_size, pos, timestamp, size, distance, flags); @@ -1204,6 +1712,15 @@ int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) wanted_timestamp, flags); } +static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit, + int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )) +{ + int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit); + if (stream_index >= 0) + ts = wrap_timestamp(s->streams[stream_index], ts); + return ts; +} + int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags) { @@ -1217,7 +1734,7 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, if (stream_index < 0) return -1; - av_dlog(s, "read_seek: %d %"PRId64"\n", stream_index, target_ts); + av_dlog(s, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts)); ts_max = ts_min = AV_NOPTS_VALUE; @@ -1237,23 +1754,23 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, if (e->timestamp <= target_ts || e->pos == e->min_distance) { pos_min = e->pos; ts_min = e->timestamp; - av_dlog(s, "using cached pos_min=0x%"PRIx64" dts_min=%"PRId64"\n", - pos_min, ts_min); + av_dlog(s, "using cached pos_min=0x%"PRIx64" dts_min=%s\n", + pos_min, av_ts2str(ts_min)); } else { - assert(index == 0); + av_assert1(index == 0); } index = av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD); - assert(index < st->nb_index_entries); + av_assert0(index < st->nb_index_entries); if (index >= 0) { e = &st->index_entries[index]; - assert(e->timestamp >= target_ts); + av_assert1(e->timestamp >= target_ts); pos_max = e->pos; ts_max = e->timestamp; pos_limit = pos_max - e->min_distance; av_dlog(s, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64 - " dts_max=%"PRId64"\n", pos_max, pos_limit, ts_max); + " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max)); } } @@ -1266,11 +1783,50 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0) return ret; + ff_read_frame_flush(s); ff_update_cur_dts(s, st, ts); return 0; } +int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos, + int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )) +{ + int64_t step = 1024; + int64_t limit, ts_max; + int64_t filesize = avio_size(s->pb); + int64_t pos_max = filesize - 1; + do { + limit = pos_max; + pos_max = FFMAX(0, (pos_max) - step); + ts_max = ff_read_timestamp(s, stream_index, + &pos_max, limit, read_timestamp); + step += step; + } while (ts_max == AV_NOPTS_VALUE && 2*limit > step); + if (ts_max == AV_NOPTS_VALUE) + return -1; + + for (;;) { + int64_t tmp_pos = pos_max + 1; + int64_t tmp_ts = ff_read_timestamp(s, stream_index, + &tmp_pos, INT64_MAX, read_timestamp); + if (tmp_ts == AV_NOPTS_VALUE) + break; + av_assert0(tmp_pos > pos_max); + ts_max = tmp_ts; + pos_max = tmp_pos; + if (tmp_pos >= filesize) + break; + } + + if (ts) + *ts = ts_max; + if (pos) + *pos = pos_max; + + return 0; +} + int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, @@ -1279,45 +1835,35 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t *, int64_t)) { int64_t pos, ts; - int64_t start_pos, filesize; + int64_t start_pos; int no_change; + int ret; - av_dlog(s, "gen_seek: %d %"PRId64"\n", stream_index, target_ts); + av_dlog(s, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts)); if (ts_min == AV_NOPTS_VALUE) { pos_min = s->data_offset; - ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX); + ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); if (ts_min == AV_NOPTS_VALUE) return -1; } - if (ts_max == AV_NOPTS_VALUE) { - int step = 1024; - filesize = avio_size(s->pb); - pos_max = filesize - 1; - do { - pos_max -= step; - ts_max = read_timestamp(s, stream_index, &pos_max, - pos_max + step); - step += step; - } while (ts_max == AV_NOPTS_VALUE && pos_max >= step); - if (ts_max == AV_NOPTS_VALUE) - return -1; + if (ts_min >= target_ts) { + *ts_ret = ts_min; + return pos_min; + } - for (;;) { - int64_t tmp_pos = pos_max + 1; - int64_t tmp_ts = read_timestamp(s, stream_index, - &tmp_pos, INT64_MAX); - if (tmp_ts == AV_NOPTS_VALUE) - break; - ts_max = tmp_ts; - pos_max = tmp_pos; - if (tmp_pos >= filesize) - break; - } + if (ts_max == AV_NOPTS_VALUE) { + if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0) + return ret; pos_limit = pos_max; } + if (ts_max <= target_ts) { + *ts_ret = ts_max; + return pos_max; + } + if (ts_min > ts_max) return -1; else if (ts_min == ts_max) @@ -1325,8 +1871,9 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, no_change = 0; while (pos_min < pos_limit) { - av_dlog(s, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%"PRId64 - " dts_max=%"PRId64"\n", pos_min, pos_max, ts_min, ts_max); + av_dlog(s, + "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n", + pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max)); assert(pos_limit <= pos_max); if (no_change == 0) { @@ -1350,20 +1897,20 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, start_pos = pos; // May pass pos_limit instead of -1. - ts = read_timestamp(s, stream_index, &pos, INT64_MAX); + ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp); if (pos == pos_max) no_change++; else no_change = 0; - av_dlog(s, "%"PRId64" %"PRId64" %"PRId64" / %"PRId64" %"PRId64" %"PRId64 - " target:%"PRId64" limit:%"PRId64" start:%"PRId64" noc:%d\n", - pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, + av_dlog(s, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s" + " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n", + pos_min, pos, pos_max, + av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts), pos_limit, start_pos, no_change); if (ts == AV_NOPTS_VALUE) { av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n"); return -1; } - assert(ts != AV_NOPTS_VALUE); if (target_ts <= ts) { pos_limit = start_pos - 1; pos_max = pos; @@ -1377,12 +1924,14 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max; +#if 0 pos_min = pos; - ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX); + ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); pos_min++; - ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX); - av_dlog(s, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n", - pos, ts_min, target_ts, ts_max); + ts_max = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); + av_dlog(s, "pos=0x%"PRIx64" %s<=%s<=%s\n", + pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max)); +#endif *ts_ret = ts; return pos; } @@ -1402,6 +1951,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index, avio_seek(s->pb, pos, SEEK_SET); + s->io_repositioned = 1; + return 0; } @@ -1423,9 +1974,10 @@ static int seek_frame_generic(AVFormatContext *s, int stream_index, if (index < 0 || index == st->nb_index_entries - 1) { AVPacket pkt; + int nonkey = 0; if (st->nb_index_entries) { - assert(st->index_entries); + av_assert0(st->index_entries); ie = &st->index_entries[st->nb_index_entries - 1]; if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; @@ -1442,9 +1994,14 @@ static int seek_frame_generic(AVFormatContext *s, int stream_index, if (read_status < 0) break; av_free_packet(&pkt); - if (stream_index == pkt.stream_index) - if ((pkt.flags & AV_PKT_FLAG_KEY) && pkt.dts > timestamp) + if (stream_index == pkt.stream_index && pkt.dts > timestamp) { + if (pkt.flags & AV_PKT_FLAG_KEY) + break; + if (nonkey++ > 1000 && st->codec->codec_id != AV_CODEC_ID_CDGRAPHICS) { + av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey); break; + } + } } index = av_index_search_timestamp(st, timestamp, flags); } @@ -1510,10 +2067,22 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index, int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { - int ret = seek_frame_internal(s, stream_index, timestamp, flags); + int ret; + + if (s->iformat->read_seek2 && !s->iformat->read_seek) { + int64_t min_ts = INT64_MIN, max_ts = INT64_MAX; + if ((flags & AVSEEK_FLAG_BACKWARD)) + max_ts = timestamp; + else + min_ts = timestamp; + return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts, + flags & ~AVSEEK_FLAG_BACKWARD); + } + + ret = seek_frame_internal(s, stream_index, timestamp, flags); if (ret >= 0) - ret = queue_attached_pictures(s); + ret = avformat_queue_attached_pictures(s); return ret; } @@ -1523,15 +2092,33 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, { if (min_ts > ts || max_ts < ts) return -1; + if (stream_index < -1 || stream_index >= (int)s->nb_streams) + return AVERROR(EINVAL); + + if (s->seek2any>0) + flags |= AVSEEK_FLAG_ANY; + flags &= ~AVSEEK_FLAG_BACKWARD; if (s->iformat->read_seek2) { int ret; ff_read_frame_flush(s); + + if (stream_index == -1 && s->nb_streams == 1) { + AVRational time_base = s->streams[0]->time_base; + ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); + min_ts = av_rescale_rnd(min_ts, time_base.den, + time_base.num * (int64_t)AV_TIME_BASE, + AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + max_ts = av_rescale_rnd(max_ts, time_base.den, + time_base.num * (int64_t)AV_TIME_BASE, + AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); + } + ret = s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags); if (ret >= 0) - ret = queue_attached_pictures(s); + ret = avformat_queue_attached_pictures(s); return ret; } @@ -1541,13 +2128,19 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, // Fall back on old API if new is not implemented but old is. // Note the old API has somewhat different semantics. - if (s->iformat->read_seek || 1) - return av_seek_frame(s, stream_index, ts, - flags | ((uint64_t) ts - min_ts > - (uint64_t) max_ts - ts - ? AVSEEK_FLAG_BACKWARD : 0)); + if (s->iformat->read_seek || 1) { + int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0); + int ret = av_seek_frame(s, stream_index, ts, flags | dir); + if (ret<0 && ts != min_ts && max_ts != ts) { + ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir); + if (ret >= 0) + ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD)); + } + return ret; + } // try some generic seek like seek_frame_generic() but with new ts semantics + return -1; //unreachable } /*******************************************************/ @@ -1579,12 +2172,14 @@ static int has_duration(AVFormatContext *ic) */ static void update_stream_timings(AVFormatContext *ic) { - int64_t start_time, start_time1, end_time, end_time1; + int64_t start_time, start_time1, start_time_text, end_time, end_time1; int64_t duration, duration1, filesize; int i; AVStream *st; + AVProgram *p; start_time = INT64_MAX; + start_time_text = INT64_MAX; end_time = INT64_MIN; duration = INT64_MIN; for (i = 0; i < ic->nb_streams; i++) { @@ -1592,13 +2187,24 @@ static void update_stream_timings(AVFormatContext *ic) if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) { start_time1 = av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q); - start_time = FFMIN(start_time, start_time1); + if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codec->codec_type == AVMEDIA_TYPE_DATA) { + if (start_time1 < start_time_text) + start_time_text = start_time1; + } else + start_time = FFMIN(start_time, start_time1); + end_time1 = AV_NOPTS_VALUE; if (st->duration != AV_NOPTS_VALUE) { end_time1 = start_time1 + av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); end_time = FFMAX(end_time, end_time1); } + for (p = NULL; (p = av_find_program_from_stream(ic, p, i)); ) { + if (p->start_time == AV_NOPTS_VALUE || p->start_time > start_time1) + p->start_time = start_time1; + if (p->end_time < end_time1) + p->end_time = end_time1; + } } if (st->duration != AV_NOPTS_VALUE) { duration1 = av_rescale_q(st->duration, st->time_base, @@ -1606,17 +2212,33 @@ static void update_stream_timings(AVFormatContext *ic) duration = FFMAX(duration, duration1); } } + if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE)) + start_time = start_time_text; + else if (start_time > start_time_text) + av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE); + if (start_time != INT64_MAX) { ic->start_time = start_time; - if (end_time != INT64_MIN) - duration = FFMAX(duration, end_time - start_time); + if (end_time != INT64_MIN) { + if (ic->nb_programs) { + for (i = 0; i < ic->nb_programs; i++) { + p = ic->programs[i]; + if (p->start_time != AV_NOPTS_VALUE && p->end_time > p->start_time) + duration = FFMAX(duration, p->end_time - p->start_time); + } + } else + duration = FFMAX(duration, end_time - start_time); + } } - if (duration != INT64_MIN) { + if (duration != INT64_MIN && duration > 0 && ic->duration == AV_NOPTS_VALUE) { ic->duration = duration; - if (ic->pb && (filesize = avio_size(ic->pb)) > 0) - /* compute the bitrate */ - ic->bit_rate = (double) filesize * 8.0 * AV_TIME_BASE / - (double) ic->duration; + } + if (ic->pb && (filesize = avio_size(ic->pb)) > 0 && ic->duration != AV_NOPTS_VALUE) { + /* compute the bitrate */ + double bitrate = (double) filesize * 8.0 * AV_TIME_BASE / + (double) ic->duration; + if (bitrate >= 0 && bitrate <= INT_MAX) + ic->bit_rate = bitrate; } } @@ -1642,7 +2264,7 @@ static void fill_all_stream_timings(AVFormatContext *ic) static void estimate_timings_from_bit_rate(AVFormatContext *ic) { int64_t filesize, duration; - int i; + int i, show_warning = 0; AVStream *st; /* if bit_rate is already set, we believe it */ @@ -1667,27 +2289,34 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) filesize = ic->pb ? avio_size(ic->pb) : 0; if (filesize > 0) { for (i = 0; i < ic->nb_streams; i++) { - st = ic->streams[i]; - duration = av_rescale(8 * filesize, st->time_base.den, - ic->bit_rate * - (int64_t) st->time_base.num); - if (st->duration == AV_NOPTS_VALUE) + st = ic->streams[i]; + if ( st->time_base.num <= INT64_MAX / ic->bit_rate + && st->duration == AV_NOPTS_VALUE) { + duration = av_rescale(8 * filesize, st->time_base.den, + ic->bit_rate * + (int64_t) st->time_base.num); st->duration = duration; + show_warning = 1; + } } } } + if (show_warning) + av_log(ic, AV_LOG_WARNING, + "Estimating duration from bitrate, this may be inaccurate\n"); } -#define DURATION_MAX_READ_SIZE 250000 -#define DURATION_MAX_RETRY 3 +#define DURATION_MAX_READ_SIZE 250000LL +#define DURATION_MAX_RETRY 4 /* only usable for MPEG-PS streams */ static void 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; + int num, den, read_size, i, ret; + int found_duration = 0; + int is_end; int64_t filesize, offset, duration; int retry = 0; @@ -1696,9 +2325,11 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; - if (st->start_time == AV_NOPTS_VALUE && st->first_dts == AV_NOPTS_VALUE) + if (st->start_time == AV_NOPTS_VALUE && + st->first_dts == AV_NOPTS_VALUE && + st->codec->codec_type != AVMEDIA_TYPE_UNKNOWN) av_log(st->codec, AV_LOG_WARNING, - "start time is not set in estimate_timings_from_pts\n"); + "start time for stream %d is not set in estimate_timings_from_pts\n", i); if (st->parser) { av_parser_close(st->parser); @@ -1706,11 +2337,12 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) } } + av_opt_set(ic, "skip_changes", "1", AV_OPT_SEARCH_CHILDREN); /* estimate the end time (duration) */ /* XXX: may need to support wrapping */ filesize = ic->pb ? avio_size(ic->pb) : 0; - end_time = AV_NOPTS_VALUE; do { + is_end = found_duration; offset = filesize - (DURATION_MAX_READ_SIZE << retry); if (offset < 0) offset = 0; @@ -1731,31 +2363,76 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) if (pkt->pts != AV_NOPTS_VALUE && (st->start_time != AV_NOPTS_VALUE || st->first_dts != AV_NOPTS_VALUE)) { - duration = end_time = pkt->pts; + if (pkt->duration == 0) { + ff_compute_frame_duration(&num, &den, st, st->parser, pkt); + if (den && num) { + pkt->duration = av_rescale_rnd(1, + num * (int64_t) st->time_base.den, + den * (int64_t) st->time_base.num, + AV_ROUND_DOWN); + } + } + duration = pkt->pts + pkt->duration; + found_duration = 1; if (st->start_time != AV_NOPTS_VALUE) duration -= st->start_time; else duration -= st->first_dts; - if (duration < 0) - duration += 1LL << st->pts_wrap_bits; if (duration > 0) { - if (st->duration == AV_NOPTS_VALUE || st->duration < duration) + if (st->duration == AV_NOPTS_VALUE || st->info->last_duration<= 0 || + (st->duration < duration && FFABS(duration - st->info->last_duration) < 60LL*st->time_base.den / st->time_base.num)) st->duration = duration; + st->info->last_duration = duration; } } av_free_packet(pkt); } - } while (end_time == AV_NOPTS_VALUE && - filesize > (DURATION_MAX_READ_SIZE << retry) && + + /* check if all audio/video streams have valid duration */ + if (!is_end) { + is_end = 1; + for (i = 0; i < ic->nb_streams; i++) { + st = ic->streams[i]; + switch (st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + case AVMEDIA_TYPE_AUDIO: + if (st->duration == AV_NOPTS_VALUE) + is_end = 0; + } + } + } + } while (!is_end && + offset && ++retry <= DURATION_MAX_RETRY); + av_opt_set(ic, "skip_changes", "0", AV_OPT_SEARCH_CHILDREN); + + /* warn about audio/video streams which duration could not be estimated */ + for (i = 0; i < ic->nb_streams; i++) { + st = ic->streams[i]; + if (st->duration == AV_NOPTS_VALUE) { + switch (st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + case AVMEDIA_TYPE_AUDIO: + if (st->start_time != AV_NOPTS_VALUE || st->first_dts != AV_NOPTS_VALUE) { + av_log(ic, AV_LOG_DEBUG, "stream %d : no PTS found at end of file, duration not set\n", i); + } else + av_log(ic, AV_LOG_DEBUG, "stream %d : no TS found at start of file, duration not set\n", i); + } + } + } fill_all_stream_timings(ic); avio_seek(ic->pb, old_offset, SEEK_SET); for (i = 0; i < ic->nb_streams; i++) { + int j; + st = ic->streams[i]; st->cur_dts = st->first_dts; st->last_IP_pts = AV_NOPTS_VALUE; + st->last_dts_for_order_check = AV_NOPTS_VALUE; + for (j = 0; j < MAX_REORDER_DELAY + 1; j++) + st->pts_buffer[j] = AV_NOPTS_VALUE; } } @@ -1776,15 +2453,16 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) file_size && ic->pb->seekable) { /* get accurate estimate from the PTSes */ estimate_timings_from_pts(ic, old_offset); + ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS; } else if (has_duration(ic)) { /* at least one component has timings - we use them for all * the components */ fill_all_stream_timings(ic); + ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM; } else { - av_log(ic, AV_LOG_WARNING, - "Estimating duration from bitrate, this may be inaccurate\n"); /* less precise: use bitrate info */ estimate_timings_from_bit_rate(ic); + ic->duration_estimation_method = AVFMT_DURATION_FROM_BITRATE; } update_stream_timings(ic); @@ -1805,56 +2483,75 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) } } -static int has_codec_parameters(AVStream *st) +static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) { AVCodecContext *avctx = st->codec; - int val; +#define FAIL(errmsg) do { \ + if (errmsg_ptr) \ + *errmsg_ptr = errmsg; \ + return 0; \ + } while (0) + + if ( avctx->codec_id == AV_CODEC_ID_NONE + && avctx->codec_type != AVMEDIA_TYPE_DATA) + FAIL("unknown codec"); switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO: - val = avctx->sample_rate && avctx->channels; + if (!avctx->frame_size && determinable_frame_size(avctx)) + FAIL("unspecified frame size"); if (st->info->found_decoder >= 0 && avctx->sample_fmt == AV_SAMPLE_FMT_NONE) - return 0; + FAIL("unspecified sample format"); + if (!avctx->sample_rate) + FAIL("unspecified sample rate"); + if (!avctx->channels) + FAIL("unspecified number of channels"); + if (st->info->found_decoder >= 0 && !st->nb_decoded_frames && avctx->codec_id == AV_CODEC_ID_DTS) + FAIL("no decodable DTS frames"); break; case AVMEDIA_TYPE_VIDEO: - val = avctx->width; + if (!avctx->width) + FAIL("unspecified size"); if (st->info->found_decoder >= 0 && avctx->pix_fmt == AV_PIX_FMT_NONE) - return 0; + FAIL("unspecified pixel format"); + if (st->codec->codec_id == AV_CODEC_ID_RV30 || st->codec->codec_id == AV_CODEC_ID_RV40) + if (!st->sample_aspect_ratio.num && !st->codec->sample_aspect_ratio.num && !st->codec_info_nb_frames) + FAIL("no frame in rv30/40 and no sar"); break; - default: - val = 1; + case AVMEDIA_TYPE_SUBTITLE: + if (avctx->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !avctx->width) + FAIL("unspecified size"); break; + case AVMEDIA_TYPE_DATA: + if (avctx->codec_id == AV_CODEC_ID_NONE) return 1; } - return avctx->codec_id != AV_CODEC_ID_NONE && val != 0; -} -static int has_decode_delay_been_guessed(AVStream *st) -{ - return st->codec->codec_id != AV_CODEC_ID_H264 || - st->info->nb_decoded_frames >= 6; + return 1; } /* returns 1 or 0 if or if not decoded data was returned, or a negative error */ -static int try_decode_frame(AVStream *st, AVPacket *avpkt, +static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, AVDictionary **options) { const AVCodec *codec; int got_picture = 1, ret = 0; AVFrame *frame = av_frame_alloc(); + AVSubtitle subtitle; AVPacket pkt = *avpkt; if (!frame) return AVERROR(ENOMEM); - if (!avcodec_is_open(st->codec) && !st->info->found_decoder) { + if (!avcodec_is_open(st->codec) && + st->info->found_decoder <= 0 && + (st->codec->codec_id != -st->info->found_decoder || !st->codec->codec_id)) { AVDictionary *thread_opt = NULL; - codec = st->codec->codec ? st->codec->codec - : avcodec_find_decoder(st->codec->codec_id); + codec = find_decoder(s, st, st->codec->codec_id); if (!codec) { - st->info->found_decoder = -1; + st->info->found_decoder = -st->codec->codec_id; ret = -1; goto fail; } @@ -1866,7 +2563,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, if (!options) av_dict_free(&thread_opt); if (ret < 0) { - st->info->found_decoder = -1; + st->info->found_decoder = -st->codec->codec_id; goto fail; } st->info->found_decoder = 1; @@ -1880,7 +2577,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, while ((pkt.size > 0 || (!pkt.data && got_picture)) && ret >= 0 && - (!has_codec_parameters(st) || !has_decode_delay_been_guessed(st) || + (!has_codec_parameters(st, NULL) || !has_decode_delay_been_guessed(st) || (!st->codec_info_nb_frames && st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { got_picture = 0; @@ -1892,18 +2589,26 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, case AVMEDIA_TYPE_AUDIO: ret = avcodec_decode_audio4(st->codec, frame, &got_picture, &pkt); break; + case AVMEDIA_TYPE_SUBTITLE: + ret = avcodec_decode_subtitle2(st->codec, &subtitle, + &got_picture, &pkt); + ret = pkt.size; + break; default: break; } if (ret >= 0) { if (got_picture) - st->info->nb_decoded_frames++; + st->nb_decoded_frames++; pkt.data += ret; pkt.size -= ret; ret = got_picture; } } + if (!pkt.data && !got_picture) + ret = -1; + fail: av_frame_free(&frame); return ret; @@ -1943,6 +2648,7 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags) return AV_CODEC_ID_NONE; } } else { + bps += 7; bps >>= 3; if (sflags & (1 << (bps - 1))) { switch (bps) { @@ -1976,11 +2682,25 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags) unsigned int av_codec_get_tag(const AVCodecTag *const *tags, enum AVCodecID id) { + unsigned int tag; + if (!av_codec_get_tag2(tags, id, &tag)) + return 0; + return tag; +} + +int av_codec_get_tag2(const AVCodecTag * const *tags, enum AVCodecID id, + unsigned int *tag) +{ int i; for (i = 0; tags && tags[i]; i++) { - int tag = ff_codec_get_tag(tags[i], id); - if (tag) - return tag; + const AVCodecTag *codec_tags = tags[i]; + while (codec_tags->id != AV_CODEC_ID_NONE) { + if (codec_tags->id == id) { + *tag = codec_tags->tag; + return 1; + } + codec_tags++; + } } return 0; } @@ -2025,31 +2745,255 @@ static int get_std_framerate(int i) if (i < 60 * 12) return (i + 1) * 1001; else - return ((const int[]) { 24, 30, 60, 12, 15 })[i - 60 * 12] * 1000 * 12; + return ((const int[]) { 24, 30, 60, 12, 15, 48 })[i - 60 * 12] * 1000 * 12; +} + +/* Is the time base unreliable? + * This is a heuristic to balance between quick acceptance of the values in + * the headers vs. some extra checks. + * Old DivX and Xvid often have nonsense timebases like 1fps or 2fps. + * MPEG-2 commonly misuses field repeat flags to store different framerates. + * And there are "variable" fps files this needs to detect as well. */ +static int tb_unreliable(AVCodecContext *c) +{ + if (c->time_base.den >= 101L * c->time_base.num || + c->time_base.den < 5L * c->time_base.num || + // c->codec_tag == AV_RL32("DIVX") || + // c->codec_tag == AV_RL32("XVID") || + c->codec_tag == AV_RL32("mp4v") || + c->codec_id == AV_CODEC_ID_MPEG2VIDEO || + c->codec_id == AV_CODEC_ID_GIF || + c->codec_id == AV_CODEC_ID_H264) + return 1; + return 0; +} + +#if FF_API_FORMAT_PARAMETERS +int av_find_stream_info(AVFormatContext *ic) +{ + return avformat_find_stream_info(ic, NULL); +} +#endif + +int ff_alloc_extradata(AVCodecContext *avctx, int size) +{ + int ret; + + if (size < 0 || size >= INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) { + avctx->extradata_size = 0; + return AVERROR(EINVAL); + } + avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + if (avctx->extradata) { + memset(avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata_size = size; + ret = 0; + } else { + avctx->extradata_size = 0; + ret = AVERROR(ENOMEM); + } + return ret; +} + +int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size) +{ + int ret = ff_alloc_extradata(avctx, size); + if (ret < 0) + return ret; + ret = avio_read(pb, avctx->extradata, size); + if (ret != size) { + av_freep(&avctx->extradata); + avctx->extradata_size = 0; + av_log(avctx, AV_LOG_ERROR, "Failed to read extradata of size %d\n", size); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } + + return ret; +} + +int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts) +{ + int i, j; + int64_t last = st->info->last_dts; + + if ( ts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && ts > last + && ts - (uint64_t)last < INT64_MAX) { + double dts = (is_relative(ts) ? ts - RELATIVE_TS_BASE : ts) * av_q2d(st->time_base); + int64_t duration = ts - last; + + if (!st->info->duration_error) + st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2); + if (!st->info->duration_error) + return AVERROR(ENOMEM); + +// if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) +// av_log(NULL, AV_LOG_ERROR, "%f\n", dts); + for (i = 0; i<MAX_STD_TIMEBASES; i++) { + if (st->info->duration_error[0][1][i] < 1e10) { + int framerate = get_std_framerate(i); + double sdts = dts*framerate/(1001*12); + for (j= 0; j<2; j++) { + int64_t ticks = llrint(sdts+j*0.5); + double error= sdts - ticks + j*0.5; + st->info->duration_error[j][0][i] += error; + st->info->duration_error[j][1][i] += error*error; + } + } + } + st->info->duration_count++; + st->info->rfps_duration_sum += duration; + + if (st->info->duration_count % 10 == 0) { + int n = st->info->duration_count; + for (i = 0; i<MAX_STD_TIMEBASES; i++) { + if (st->info->duration_error[0][1][i] < 1e10) { + double a0 = st->info->duration_error[0][0][i] / n; + double error0 = st->info->duration_error[0][1][i] / n - a0*a0; + double a1 = st->info->duration_error[1][0][i] / n; + double error1 = st->info->duration_error[1][1][i] / n - a1*a1; + if (error0 > 0.04 && error1 > 0.04) { + st->info->duration_error[0][1][i] = 2e10; + st->info->duration_error[1][1][i] = 2e10; + } + } + } + } + + // ignore the first 4 values, they might have some random jitter + if (st->info->duration_count > 3 && is_relative(ts) == is_relative(last)) + st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration); + } + if (ts != AV_NOPTS_VALUE) + st->info->last_dts = ts; + + return 0; +} + +void ff_rfps_calculate(AVFormatContext *ic) +{ + int i, j; + + for (i = 0; i < ic->nb_streams; i++) { + AVStream *st = ic->streams[i]; + + if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) + continue; + // 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) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !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>1 && !st->r_frame_rate.num + && tb_unreliable(st->codec)) { + int num = 0; + double best_error= 0.01; + AVRational ref_rate = st->r_frame_rate.num ? st->r_frame_rate : av_inv_q(st->time_base); + + for (j= 0; j<MAX_STD_TIMEBASES; j++) { + int k; + + if (st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j)) + continue; + if (!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j)) + continue; + + if (av_q2d(st->time_base) * st->info->rfps_duration_sum / st->info->duration_count < (1001*12.0 * 0.8)/get_std_framerate(j)) + continue; + + for (k= 0; k<2; k++) { + int n = st->info->duration_count; + double a= st->info->duration_error[k][0][j] / n; + double error= st->info->duration_error[k][1][j]/n - a*a; + + if (error < best_error && best_error> 0.000000001) { + best_error= error; + num = get_std_framerate(j); + } + if (error < 0.02) + av_log(NULL, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error); + } + } + // do not increase frame rate by more than 1 % in order to match a standard rate. + if (num && (!ref_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(ref_rate))) + av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX); + } + if ( !st->avg_frame_rate.num + && st->r_frame_rate.num && st->info->rfps_duration_sum + && st->info->codec_info_duration <= 0 + && st->info->duration_count > 2 + && fabs(1.0 / (av_q2d(st->r_frame_rate) * av_q2d(st->time_base)) - st->info->rfps_duration_sum / (double)st->info->duration_count) <= 1.0 + ) { + av_log(ic, AV_LOG_DEBUG, "Setting avg frame rate based on r frame rate\n"); + st->avg_frame_rate = st->r_frame_rate; + } + + av_freep(&st->info->duration_error); + st->info->last_dts = AV_NOPTS_VALUE; + st->info->duration_count = 0; + st->info->rfps_duration_sum = 0; + } } int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) { - int i, count, ret, read_size, j; + int i, count, ret = 0, j; + int64_t read_size; AVStream *st; AVPacket pkt1, *pkt; int64_t old_offset = avio_tell(ic->pb); // new streams might appear, no options for those int orig_nb_streams = ic->nb_streams; + int flush_codecs; + int64_t max_analyze_duration = ic->max_analyze_duration2; + int64_t probesize = ic->probesize2; + + if (!max_analyze_duration) + max_analyze_duration = ic->max_analyze_duration; + if (ic->probesize) + probesize = ic->probesize; + flush_codecs = probesize > 0; + + av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN); + + if (!max_analyze_duration) { + if (!strcmp(ic->iformat->name, "flv") && !(ic->ctx_flags & AVFMTCTX_NOHEADER)) { + max_analyze_duration = 10*AV_TIME_BASE; + } else + max_analyze_duration = 5*AV_TIME_BASE; + } + + if (ic->pb) + av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d\n", + avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count); for (i = 0; i < ic->nb_streams; i++) { const AVCodec *codec; AVDictionary *thread_opt = NULL; st = ic->streams[i]; + 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) + st->codec->time_base = st->time_base; + } // only for the split stuff if (!st->parser && !(ic->flags & AVFMT_FLAG_NOPARSE)) { st->parser = av_parser_init(st->codec->codec_id); - if (st->need_parsing == AVSTREAM_PARSE_HEADERS && st->parser) - st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; + if (st->parser) { + if (st->need_parsing == AVSTREAM_PARSE_HEADERS) { + st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; + } else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) { + st->parser->flags |= PARSER_FLAG_USE_CODEC_TS; + } + } else if (st->need_parsing) { + av_log(ic, AV_LOG_VERBOSE, "parser not found for codec " + "%s, packets or times may be invalid.\n", + avcodec_get_name(st->codec->codec_id)); + } } - codec = st->codec->codec ? st->codec->codec - : avcodec_find_decoder(st->codec->codec_id); + codec = find_decoder(ic, st, st->codec->codec_id); /* Force thread count to 1 since the H.264 decoder will not extract * SPS and PPS to extradata during multi-threaded decoding. */ @@ -2057,21 +3001,27 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) /* Ensure that subtitle_header is properly set. */ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE - && codec && !st->codec->codec) - avcodec_open2(st->codec, codec, - options ? &options[i] : &thread_opt); + && codec && !st->codec->codec) { + if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0) + av_log(ic, AV_LOG_WARNING, + "Failed to open codec in av_find_stream_info\n"); + } // Try to just open decoders, in case this is enough to get parameters. - if (!has_codec_parameters(st)) { + if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) { if (codec && !st->codec->codec) - avcodec_open2(st->codec, codec, - options ? &options[i] : &thread_opt); + if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0) + av_log(ic, AV_LOG_WARNING, + "Failed to open codec in av_find_stream_info\n"); } if (!options) av_dict_free(&thread_opt); } for (i = 0; i < ic->nb_streams; i++) { +#if FF_API_R_FRAME_RATE + ic->streams[i]->info->last_dts = AV_NOPTS_VALUE; +#endif ic->streams[i]->info->fps_first_dts = AV_NOPTS_VALUE; ic->streams[i]->info->fps_last_dts = AV_NOPTS_VALUE; } @@ -2090,24 +3040,29 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int fps_analyze_framecount = 20; st = ic->streams[i]; - if (!has_codec_parameters(st)) + if (!has_codec_parameters(st, NULL)) break; /* If the timebase is coarse (like the usual millisecond precision * of mkv), we need to analyze more frames to reliably arrive at * the correct fps. */ if (av_q2d(st->time_base) > 0.0005) fps_analyze_framecount *= 2; + if (!tb_unreliable(st->codec)) + fps_analyze_framecount = 0; if (ic->fps_probe_size >= 0) fps_analyze_framecount = ic->fps_probe_size; + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + fps_analyze_framecount = 0; /* variable fps and no guess at the real fps */ - if (!st->avg_frame_rate.num && - st->codec_info_nb_frames < fps_analyze_framecount && + if (!(st->r_frame_rate.num && st->avg_frame_rate.num) && + st->info->duration_count < fps_analyze_framecount && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) break; if (st->parser && st->parser->parser->split && !st->codec->extradata) break; if (st->first_dts == AV_NOPTS_VALUE && + !(ic->iformat->flags & AVFMT_NOTIMESTAMPS) && st->codec_info_nb_frames < ic->max_ts_probe && (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || st->codec->codec_type == AVMEDIA_TYPE_AUDIO)) @@ -2120,14 +3075,23 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) /* If we found the info for all the codecs, we can stop. */ ret = count; av_log(ic, AV_LOG_DEBUG, "All info found\n"); + flush_codecs = 0; break; } } /* We did not get all the codec info, but we read too much data. */ - if (read_size >= ic->probesize) { + if (read_size >= probesize) { ret = count; av_log(ic, AV_LOG_DEBUG, - "Probe buffer size limit %d reached\n", ic->probesize); + "Probe buffer size limit of %"PRId64" bytes reached\n", probesize); + for (i = 0; i < ic->nb_streams; i++) + if (!ic->streams[i]->r_frame_rate.num && + ic->streams[i]->info->duration_count <= 1 && + ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && + strcmp(ic->iformat->name, "image2")) + av_log(ic, AV_LOG_WARNING, + "Stream #%d: not enough frames to estimate rate; " + "consider increasing probesize\n", i); break; } @@ -2139,56 +3103,31 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) if (ret < 0) { /* EOF or error*/ - AVPacket empty_pkt = { 0 }; - int err = 0; - av_init_packet(&empty_pkt); - - /* We could not have all the codec parameters before EOF. */ - ret = -1; - for (i = 0; i < ic->nb_streams; i++) { - st = ic->streams[i]; - - /* flush the decoders */ - if (st->info->found_decoder == 1) { - do { - err = try_decode_frame(st, &empty_pkt, - (options && i < orig_nb_streams) - ? &options[i] : NULL); - } while (err > 0 && !has_codec_parameters(st)); - } - - if (err < 0) { - av_log(ic, AV_LOG_WARNING, - "decoding for stream %d failed\n", st->index); - } else if (!has_codec_parameters(st)) { - char buf[256]; - avcodec_string(buf, sizeof(buf), st->codec, 0); - av_log(ic, AV_LOG_WARNING, - "Could not find codec parameters (%s)\n", buf); - } else { - ret = 0; - } - } break; } - if (ic->flags & AVFMT_FLAG_NOBUFFER) { - pkt = &pkt1; - } else { + if (ic->flags & AVFMT_FLAG_NOBUFFER) + free_packet_buffer(&ic->packet_buffer, &ic->packet_buffer_end); + { pkt = add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end); + if (!pkt) { + ret = AVERROR(ENOMEM); + goto find_stream_info_err; + } if ((ret = av_dup_packet(pkt)) < 0) goto find_stream_info_err; } - read_size += pkt->size; - st = ic->streams[pkt->stream_index]; + if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + read_size += pkt->size; + if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) { /* check for non-increasing dts */ if (st->info->fps_last_dts != AV_NOPTS_VALUE && st->info->fps_last_dts >= pkt->dts) { - av_log(ic, AV_LOG_WARNING, + av_log(ic, AV_LOG_DEBUG, "Non-increasing DTS in stream %d: packet %d with DTS " "%"PRId64", packet %d with DTS %"PRId64"\n", st->index, st->info->fps_last_dts_idx, @@ -2222,22 +3161,40 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) } st->info->fps_last_dts = pkt->dts; st->info->fps_last_dts_idx = st->codec_info_nb_frames; - - /* check max_analyze_duration */ - if (av_rescale_q(pkt->dts - st->info->fps_first_dts, st->time_base, - AV_TIME_BASE_Q) >= ic->max_analyze_duration) { - av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached\n", - ic->max_analyze_duration); + } + if (st->codec_info_nb_frames>1) { + int64_t t = 0; + + if (st->time_base.den > 0) + t = av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q); + if (st->avg_frame_rate.num > 0) + t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q)); + + if ( t == 0 + && st->codec_info_nb_frames>30 + && st->info->fps_first_dts != AV_NOPTS_VALUE + && st->info->fps_last_dts != AV_NOPTS_VALUE) + t = FFMAX(t, av_rescale_q(st->info->fps_last_dts - st->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q)); + + if (t >= max_analyze_duration) { + av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds\n", + max_analyze_duration, + t); break; } + if (pkt->duration) { + st->info->codec_info_duration += pkt->duration; + st->info->codec_info_duration_fields += st->parser && st->need_parsing && st->codec->ticks_per_frame ==2 ? st->parser->repeat_pict + 1 : 2; + } } +#if FF_API_R_FRAME_RATE + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + ff_rfps_add_frame(ic, st, pkt->dts); +#endif if (st->parser && st->parser->parser->split && !st->codec->extradata) { int i = st->parser->parser->split(st->codec, pkt->data, pkt->size); if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) { - st->codec->extradata_size = i; - st->codec->extradata = av_mallocz(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, i)) return AVERROR(ENOMEM); memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size); @@ -2253,38 +3210,70 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) * least one frame of codec data, this makes sure the codec initializes * the channel configuration and does not only trust the values from * the container. */ - try_decode_frame(st, pkt, + try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams) ? &options[i] : NULL); st->codec_info_nb_frames++; count++; } + if (flush_codecs) { + AVPacket empty_pkt = { 0 }; + int err = 0; + av_init_packet(&empty_pkt); + + for (i = 0; i < ic->nb_streams; i++) { + + st = ic->streams[i]; + + /* flush the decoders */ + if (st->info->found_decoder == 1) { + do { + err = try_decode_frame(ic, st, &empty_pkt, + (options && i < orig_nb_streams) + ? &options[i] : NULL); + } while (err > 0 && !has_codec_parameters(st, NULL)); + + if (err < 0) { + av_log(ic, AV_LOG_INFO, + "decoding for stream %d failed\n", st->index); + } + } + } + } + av_opt_set(ic, "skip_clear", "0", AV_OPT_SEARCH_CHILDREN); + // close codecs which were opened in try_decode_frame() for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; avcodec_close(st->codec); } + + ff_rfps_calculate(ic); + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) { + uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); + if (avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), tag) == st->codec->pix_fmt) + st->codec->codec_tag= tag; + } + /* estimate average framerate if not set by demuxer */ - if (!st->avg_frame_rate.num && - st->info->fps_last_dts != st->info->fps_first_dts) { - int64_t delta_dts = st->info->fps_last_dts - - st->info->fps_first_dts; - int delta_packets = st->info->fps_last_dts_idx - - st->info->fps_first_dts_idx; + if (st->info->codec_info_duration_fields && + !st->avg_frame_rate.num && + st->info->codec_info_duration) { int best_fps = 0; double best_error = 0.01; - if (delta_dts >= INT64_MAX / st->time_base.num || - delta_packets >= INT64_MAX / st->time_base.den || - delta_dts < 0) + if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2|| + st->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den || + st->info->codec_info_duration < 0) continue; av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, - delta_packets * (int64_t) st->time_base.den, - delta_dts * (int64_t) st->time_base.num, 60000); + st->info->codec_info_duration_fields * (int64_t) st->time_base.den, + st->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000); /* Round guessed framerate to a "standard" framerate if it's * within 1% of the original estimate. */ @@ -2302,6 +3291,17 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, best_fps, 12 * 1001, INT_MAX); } + + if (!st->r_frame_rate.num) { + if ( st->codec->time_base.den * (int64_t) st->time_base.num + <= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t) st->time_base.den) { + st->r_frame_rate.num = st->codec->time_base.den; + st->r_frame_rate.den = st->codec->time_base.num * st->codec->ticks_per_frame; + } else { + st->r_frame_rate.num = st->time_base.den; + st->r_frame_rate.den = st->time_base.num; + } + } } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if (!st->codec->bits_per_coded_sample) st->codec->bits_per_coded_sample = @@ -2327,26 +3327,58 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) } } + if (probesize) estimate_timings(ic, old_offset); + if (ret >= 0 && ic->nb_streams) + /* We could not have all the codec parameters before EOF. */ + ret = -1; + for (i = 0; i < ic->nb_streams; i++) { + const char *errmsg; + st = ic->streams[i]; + if (!has_codec_parameters(st, &errmsg)) { + char buf[256]; + avcodec_string(buf, sizeof(buf), st->codec, 0); + av_log(ic, AV_LOG_WARNING, + "Could not find codec parameters for stream %d (%s): %s\n" + "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n", + i, buf, errmsg); + } else { + ret = 0; + } + } + compute_chapters_end(ic); find_stream_info_err: for (i = 0; i < ic->nb_streams; i++) { - ic->streams[i]->codec->thread_count = 0; + st = ic->streams[i]; + if (ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) + ic->streams[i]->codec->thread_count = 0; + if (st->info) + av_freep(&st->info->duration_error); av_freep(&ic->streams[i]->info); } + if (ic->pb) + av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n", + avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, count); return ret; } -static AVProgram *find_program_from_stream(AVFormatContext *ic, int s) +AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, 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]; + for (i = 0; i < ic->nb_programs; i++) { + if (ic->programs[i] == last) { + last = NULL; + } else { + if (!last) + 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; } @@ -2355,12 +3387,12 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, AVCodec **decoder_ret, int flags) { int i, nb_streams = ic->nb_streams; - int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1; + int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1, best_bitrate = -1, best_multiframe = -1, count, bitrate, multiframe; unsigned *program = NULL; - AVCodec *decoder = NULL, *best_decoder = NULL; + const AVCodec *decoder = NULL, *best_decoder = NULL; if (related_stream >= 0 && wanted_stream_nb < 0) { - AVProgram *p = find_program_from_stream(ic, related_stream); + AVProgram *p = av_find_program_from_stream(ic, NULL, related_stream); if (p) { program = p->stream_index; nb_streams = p->nb_stream_indexes; @@ -2374,20 +3406,32 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, continue; if (wanted_stream_nb >= 0 && real_stream_index != wanted_stream_nb) continue; - if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED | + if (wanted_stream_nb != real_stream_index && + st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED | AV_DISPOSITION_VISUAL_IMPAIRED)) continue; + if (type == AVMEDIA_TYPE_AUDIO && !avctx->channels) + continue; if (decoder_ret) { - decoder = avcodec_find_decoder(st->codec->codec_id); + decoder = find_decoder(ic, st, st->codec->codec_id); if (!decoder) { if (ret < 0) ret = AVERROR_DECODER_NOT_FOUND; continue; } } - if (best_count >= st->codec_info_nb_frames) + count = st->codec_info_nb_frames; + bitrate = avctx->bit_rate; + if (!bitrate) + bitrate = avctx->rc_max_rate; + multiframe = FFMIN(5, count); + if ((best_multiframe > multiframe) || + (best_multiframe == multiframe && best_bitrate > bitrate) || + (best_multiframe == multiframe && best_bitrate == bitrate && best_count >= count)) continue; - best_count = st->codec_info_nb_frames; + best_count = count; + best_bitrate = bitrate; + best_multiframe = multiframe; ret = real_stream_index; best_decoder = decoder; if (program && i == nb_streams - 1 && ret < 0) { @@ -2398,7 +3442,7 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, } } if (decoder_ret) - *decoder_ret = best_decoder; + *decoder_ret = (AVCodec*)best_decoder; return ret; } @@ -2422,38 +3466,49 @@ int av_read_pause(AVFormatContext *s) return AVERROR(ENOSYS); } +void ff_free_stream(AVFormatContext *s, AVStream *st) { + int j; + av_assert0(s->nb_streams>0); + av_assert0(s->streams[ s->nb_streams - 1 ] == st); + + for (j = 0; j < st->nb_side_data; j++) + av_freep(&st->side_data[j].data); + av_freep(&st->side_data); + st->nb_side_data = 0; + + if (st->parser) { + av_parser_close(st->parser); + } + if (st->attached_pic.data) + av_free_packet(&st->attached_pic); + av_dict_free(&st->metadata); + av_freep(&st->probe_data.buf); + av_freep(&st->index_entries); + av_freep(&st->codec->extradata); + av_freep(&st->codec->subtitle_header); + av_freep(&st->codec); + av_freep(&st->priv_data); + if (st->info) + av_freep(&st->info->duration_error); + av_freep(&st->info); + av_freep(&s->streams[ --s->nb_streams ]); +} + void avformat_free_context(AVFormatContext *s) { - int i, j; - AVStream *st; + int i; + + if (!s) + return; av_opt_free(s); if (s->iformat && s->iformat->priv_class && s->priv_data) av_opt_free(s->priv_data); + if (s->oformat && s->oformat->priv_class && s->priv_data) + av_opt_free(s->priv_data); - for (i = 0; i < s->nb_streams; i++) { - /* free all data in a stream component */ - st = s->streams[i]; - - for (j = 0; j < st->nb_side_data; j++) - av_freep(&st->side_data[j].data); - av_freep(&st->side_data); - st->nb_side_data = 0; - - if (st->parser) { - av_parser_close(st->parser); - } - if (st->attached_pic.data) - av_free_packet(&st->attached_pic); - av_dict_free(&st->metadata); - av_freep(&st->probe_data.buf); - av_free(st->index_entries); - av_free(st->codec->extradata); - av_free(st->codec->subtitle_header); - av_free(st->codec); - av_free(st->priv_data); - av_free(st->info); - av_free(st); + for (i = s->nb_streams - 1; i >= 0; i--) { + ff_free_stream(s, s->streams[i]); } for (i = s->nb_programs - 1; i >= 0; i--) { av_dict_free(&s->programs[i]->metadata); @@ -2464,19 +3519,33 @@ void avformat_free_context(AVFormatContext *s) av_freep(&s->priv_data); while (s->nb_chapters--) { av_dict_free(&s->chapters[s->nb_chapters]->metadata); - av_free(s->chapters[s->nb_chapters]); + av_freep(&s->chapters[s->nb_chapters]); } av_freep(&s->chapters); av_dict_free(&s->metadata); av_freep(&s->streams); av_freep(&s->internal); + flush_packet_queue(s); av_free(s); } +#if FF_API_CLOSE_INPUT_FILE +void av_close_input_file(AVFormatContext *s) +{ + avformat_close_input(&s); +} +#endif + void avformat_close_input(AVFormatContext **ps) { - AVFormatContext *s = *ps; - AVIOContext *pb = s->pb; + AVFormatContext *s; + AVIOContext *pb; + + if (!ps || !*ps) + return; + + s = *ps; + pb = s->pb; if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || (s->flags & AVFMT_FLAG_CUSTOM_IO)) @@ -2495,16 +3564,28 @@ void avformat_close_input(AVFormatContext **ps) avio_close(pb); } +#if FF_API_NEW_STREAM +AVStream *av_new_stream(AVFormatContext *s, int id) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (st) + st->id = id; + return st; +} +#endif + AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) { AVStream *st; int i; + AVStream **streams; - if (av_reallocp_array(&s->streams, s->nb_streams + 1, - sizeof(*s->streams)) < 0) { - s->nb_streams = 0; + if (s->nb_streams >= INT_MAX/sizeof(*streams)) return NULL; - } + streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams)); + if (!streams) + return NULL; + s->streams = streams; st = av_mallocz(sizeof(AVStream)); if (!st) @@ -2513,6 +3594,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) av_free(st); return NULL; } + st->info->last_dts = AV_NOPTS_VALUE; st->codec = avcodec_alloc_context3(c); if (s->iformat) { @@ -2530,19 +3612,27 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) * but durations get some timestamps, formats with some unknown * timestamps have their first few packets buffered and the * timestamps corrected before they are returned to the user */ - st->cur_dts = 0; + st->cur_dts = s->iformat ? RELATIVE_TS_BASE : 0; st->first_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; + st->pts_wrap_reference = AV_NOPTS_VALUE; + st->pts_wrap_behavior = AV_PTS_WRAP_IGNORE; st->last_IP_pts = AV_NOPTS_VALUE; + st->last_dts_for_order_check = AV_NOPTS_VALUE; for (i = 0; i < MAX_REORDER_DELAY + 1; i++) st->pts_buffer[i] = AV_NOPTS_VALUE; st->sample_aspect_ratio = (AVRational) { 0, 1 }; +#if FF_API_R_FRAME_RATE + st->info->last_dts = AV_NOPTS_VALUE; +#endif st->info->fps_first_dts = AV_NOPTS_VALUE; st->info->fps_last_dts = AV_NOPTS_VALUE; + st->inject_global_side_data = s->internal->inject_global_side_data; + s->streams[s->nb_streams++] = st; return st; } @@ -2566,6 +3656,11 @@ AVProgram *av_new_program(AVFormatContext *ac, int id) program->discard = AVDISCARD_NONE; } program->id = id; + program->pts_wrap_reference = AV_NOPTS_VALUE; + program->pts_wrap_behavior = AV_PTS_WRAP_IGNORE; + + program->start_time = + program->end_time = AV_NOPTS_VALUE; return program; } @@ -2576,6 +3671,11 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base, AVChapter *chapter = NULL; int i; + if (end != AV_NOPTS_VALUE && start > end) { + av_log(s, AV_LOG_ERROR, "Chapter end time %"PRId64" before start %"PRId64"\n", end, start); + return NULL; + } + for (i = 0; i < s->nb_chapters; i++) if (s->chapters[i]->id == id) chapter = s->chapters[i]; @@ -2599,6 +3699,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx) { int i, j; AVProgram *program = NULL; + void *tmp; if (idx >= ac->nb_streams) { av_log(ac, AV_LOG_ERROR, "stream index %d is not valid\n", idx); @@ -2613,12 +3714,10 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx) if (program->stream_index[j] == idx) return; - if (av_reallocp_array(&program->stream_index, - program->nb_stream_indexes + 1, - sizeof(*program->stream_index)) < 0) { - program->nb_stream_indexes = 0; + tmp = av_realloc_array(program->stream_index, program->nb_stream_indexes+1, sizeof(unsigned int)); + if (!tmp) return; - } + program->stream_index = tmp; program->stream_index[program->nb_stream_indexes++] = idx; return; } @@ -2687,7 +3786,7 @@ void av_url_split(char *proto, int proto_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url) { - const char *p, *ls, *at, *col, *brk; + const char *p, *ls, *ls2, *at, *at2, *col, *brk; if (port_ptr) *port_ptr = -1; @@ -2716,8 +3815,11 @@ void av_url_split(char *proto, int proto_size, /* separate path from hostname */ ls = strchr(p, '/'); + ls2 = strchr(p, '?'); if (!ls) - ls = strchr(p, '?'); + ls = ls2; + else if (ls && ls2) + ls = FFMIN(ls, ls2); if (ls) av_strlcpy(path, ls, path_size); else @@ -2726,9 +3828,10 @@ void av_url_split(char *proto, int proto_size, /* the rest is hostname, use that to parse auth/port */ if (ls != p) { /* authorization (user[:pass]@hostname) */ - if ((at = strchr(p, '@')) && at < ls) { - av_strlcpy(authorization, p, - FFMIN(authorization_size, at + 1 - p)); + at2 = p; + while ((at = strchr(p, '@')) && at < ls) { + av_strlcpy(authorization, at2, + FFMIN(authorization_size, at + 1 - at2)); p = at + 1; /* skip '@' */ } @@ -2798,6 +3901,14 @@ int ff_hex_to_data(uint8_t *data, const char *p) return len; } +#if FF_API_SET_PTS_INFO +void av_set_pts_info(AVStream *s, int pts_wrap_bits, + unsigned int pts_num, unsigned int pts_den) +{ + avpriv_set_pts_info(s, pts_wrap_bits, pts_num, pts_den); +} +#endif + void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den) { @@ -2813,11 +3924,13 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, 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", + "Ignoring attempt to set invalid timebase %d/%d for st:%d\n", + new_tb.num, new_tb.den, s->index); return; } s->time_base = new_tb; + av_codec_set_pkt_timebase(s->codec, new_tb); s->pts_wrap_bits = pts_wrap_bits; } @@ -2886,21 +3999,14 @@ int ff_find_stream_index(AVFormatContext *s, int id) int64_t ff_iso8601_to_unix_time(const char *datestr) { -#if HAVE_STRPTIME struct tm time1 = { 0 }, time2 = { 0 }; char *ret1, *ret2; - ret1 = strptime(datestr, "%Y - %m - %d %T", &time1); - ret2 = strptime(datestr, "%Y - %m - %dT%T", &time2); + ret1 = av_small_strptime(datestr, "%Y - %m - %d %H:%M:%S", &time1); + ret2 = av_small_strptime(datestr, "%Y - %m - %dT%H:%M:%S", &time2); if (ret2 && !ret1) return av_timegm(&time2); else return av_timegm(&time1); -#else - av_log(NULL, AV_LOG_WARNING, - "strptime() unavailable on this system, cannot convert " - "the date string.\n"); - return 0; -#endif } int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id, @@ -2982,6 +4088,137 @@ int ff_add_param_change(AVPacket *pkt, int32_t channels, return 0; } +AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame) +{ + AVRational undef = {0, 1}; + AVRational stream_sample_aspect_ratio = stream ? stream->sample_aspect_ratio : undef; + AVRational codec_sample_aspect_ratio = stream && stream->codec ? stream->codec->sample_aspect_ratio : undef; + AVRational frame_sample_aspect_ratio = frame ? frame->sample_aspect_ratio : codec_sample_aspect_ratio; + + av_reduce(&stream_sample_aspect_ratio.num, &stream_sample_aspect_ratio.den, + stream_sample_aspect_ratio.num, stream_sample_aspect_ratio.den, INT_MAX); + if (stream_sample_aspect_ratio.num <= 0 || stream_sample_aspect_ratio.den <= 0) + stream_sample_aspect_ratio = undef; + + av_reduce(&frame_sample_aspect_ratio.num, &frame_sample_aspect_ratio.den, + frame_sample_aspect_ratio.num, frame_sample_aspect_ratio.den, INT_MAX); + if (frame_sample_aspect_ratio.num <= 0 || frame_sample_aspect_ratio.den <= 0) + frame_sample_aspect_ratio = undef; + + if (stream_sample_aspect_ratio.num) + return stream_sample_aspect_ratio; + else + return frame_sample_aspect_ratio; +} + +AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *frame) +{ + AVRational fr = st->r_frame_rate; + AVRational codec_fr = av_inv_q(st->codec->time_base); + AVRational avg_fr = st->avg_frame_rate; + + if (avg_fr.num > 0 && avg_fr.den > 0 && fr.num > 0 && fr.den > 0 && + av_q2d(avg_fr) < 70 && av_q2d(fr) > 210) { + fr = avg_fr; + } + + + if (st->codec->ticks_per_frame > 1) { + codec_fr.den *= st->codec->ticks_per_frame; + if ( codec_fr.num > 0 && codec_fr.den > 0 && av_q2d(codec_fr) < av_q2d(fr)*0.7 + && fabs(1.0 - av_q2d(av_div_q(avg_fr, fr))) > 0.1) + fr = codec_fr; + } + + return fr; +} + +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec) +{ + if (*spec <= '9' && *spec >= '0') /* opt:index */ + return strtol(spec, NULL, 0) == st->index; + else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || + *spec == 't') { /* opt:[vasdt] */ + enum AVMediaType type; + + switch (*spec++) { + case 'v': type = AVMEDIA_TYPE_VIDEO; break; + case 'a': type = AVMEDIA_TYPE_AUDIO; break; + case 's': type = AVMEDIA_TYPE_SUBTITLE; break; + case 'd': type = AVMEDIA_TYPE_DATA; break; + case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; + default: av_assert0(0); + } + if (type != st->codec->codec_type) + return 0; + if (*spec++ == ':') { /* possibly followed by :index */ + int i, index = strtol(spec, NULL, 0); + for (i = 0; i < s->nb_streams; i++) + if (s->streams[i]->codec->codec_type == type && index-- == 0) + return i == st->index; + return 0; + } + return 1; + } else if (*spec == 'p' && *(spec + 1) == ':') { + int prog_id, i, j; + char *endptr; + spec += 2; + prog_id = strtol(spec, &endptr, 0); + for (i = 0; i < s->nb_programs; i++) { + if (s->programs[i]->id != prog_id) + continue; + + if (*endptr++ == ':') { + int stream_idx = strtol(endptr, NULL, 0); + return stream_idx >= 0 && + stream_idx < s->programs[i]->nb_stream_indexes && + st->index == s->programs[i]->stream_index[stream_idx]; + } + + for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) + if (st->index == s->programs[i]->stream_index[j]) + return 1; + } + return 0; + } else if (*spec == '#' || + (*spec == 'i' && *(spec + 1) == ':')) { + int stream_id; + char *endptr; + spec += 1 + (*spec == 'i'); + stream_id = strtol(spec, &endptr, 0); + if (!*endptr) + return stream_id == st->id; + } else if (*spec == 'm' && *(spec + 1) == ':') { + AVDictionaryEntry *tag; + char *key, *val; + int ret; + + spec += 2; + val = strchr(spec, ':'); + + key = val ? av_strndup(spec, val - spec) : av_strdup(spec); + if (!key) + return AVERROR(ENOMEM); + + tag = av_dict_get(st->metadata, key, NULL, 0); + if (tag) { + if (!val || !strcmp(tag->value, val + 1)) + ret = 1; + else + ret = 0; + } else + ret = 0; + + av_freep(&key); + return ret; + } else if (!*spec) /* empty specifier, matches everything */ + return 1; + + av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); + return AVERROR(EINVAL); +} + int ff_generate_avci_extradata(AVStream *st) { static const uint8_t avci100_1080p_extradata[] = { @@ -3026,8 +4263,8 @@ int ff_generate_avci_extradata(AVStream *st) 0x9c, 0x0b, 0x73, 0xe6, 0xc0, 0xb5, 0x18, 0x63, 0x0d, 0x39, 0xe0, 0x5b, 0x02, 0xd4, 0xc6, 0x19, 0x1a, 0x79, 0x8c, 0x32, 0x34, 0x24, 0xf0, 0x16, - 0x81, 0x13, 0xf7, 0xff, 0x80, 0x01, 0x80, 0x02, - 0x71, 0x80, 0x80, 0x80, 0xa0, 0x00, 0x00, 0x03, + 0x81, 0x13, 0xf7, 0xff, 0x80, 0x02, 0x00, 0x01, + 0xf1, 0x80, 0x80, 0x80, 0xa0, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x50, 0x80, 0x00, // PPS 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x31, 0x12, @@ -3073,13 +4310,9 @@ int ff_generate_avci_extradata(AVStream *st) return 0; av_freep(&st->codec->extradata); - st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, size)) return AVERROR(ENOMEM); - memcpy(st->codec->extradata, data, size); - st->codec->extradata_size = size; return 0; } |