From f7813a5324be39d13ab536c245d15dfc602a7849 Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Sun, 29 Dec 2013 12:19:38 +0000 Subject: basic type mechanism working --- ffmpeg/libavformat/utils.c | 1163 ++++++++++++++++++++------------------------ 1 file changed, 514 insertions(+), 649 deletions(-) (limited to 'ffmpeg/libavformat/utils.c') diff --git a/ffmpeg/libavformat/utils.c b/ffmpeg/libavformat/utils.c index f9acc0e..40d886f 100644 --- a/ffmpeg/libavformat/utils.c +++ b/ffmpeg/libavformat/utils.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* #define DEBUG */ +#include #include "avformat.h" #include "avio_internal.h" @@ -27,9 +27,9 @@ #include "libavcodec/internal.h" #include "libavcodec/raw.h" #include "libavcodec/bytestream.h" -#include "libavutil/avassert.h" #include "libavutil/opt.h" #include "libavutil/dict.h" +#include "libavutil/internal.h" #include "libavutil/pixdesc.h" #include "metadata.h" #include "id3v2.h" @@ -99,156 +99,34 @@ static int64_t wrap_timestamp(AVStream *st, int64_t timestamp) return timestamp; } -#define MAKE_ACCESSORS(str, name, type, field) \ - type av_##name##_get_##field(const str *s) { return s->field; } \ - void av_##name##_set_##field(str *s, type v) { s->field = v; } - 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) -/** head of registered input format linked list */ -static AVInputFormat *first_iformat = NULL; -/** head of registered output format linked list */ -static AVOutputFormat *first_oformat = NULL; - -AVInputFormat *av_iformat_next(AVInputFormat *f) -{ - if(f) return f->next; - else return first_iformat; -} - -AVOutputFormat *av_oformat_next(AVOutputFormat *f) -{ - if(f) return f->next; - else return first_oformat; -} - -void av_register_input_format(AVInputFormat *format) -{ - AVInputFormat **p; - p = &first_iformat; - while (*p != NULL) p = &(*p)->next; - *p = format; - format->next = NULL; -} - -void av_register_output_format(AVOutputFormat *format) -{ - AVOutputFormat **p; - p = &first_oformat; - while (*p != NULL) p = &(*p)->next; - *p = format; - format->next = NULL; -} - -int av_match_ext(const char *filename, const char *extensions) +static AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id) { - const char *ext, *p; - char ext1[32], *q; - - if(!filename) - return 0; + if (st->codec->codec) + return st->codec->codec; - ext = strrchr(filename, '.'); - if (ext) { - ext++; - p = extensions; - for(;;) { - q = ext1; - while (*p != '\0' && *p != ',' && q-ext1name && short_name && match_format(short_name, fmt->name)) - score += 100; - if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type)) - score += 10; - if (filename && fmt->extensions && - av_match_ext(filename, fmt->extensions)) { - score += 5; - } - if (score > score_max) { - score_max = score; - fmt_found = fmt; - } + 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 fmt_found; -} - -enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, - const char *filename, const char *mime_type, enum AVMediaType type){ - if(type == AVMEDIA_TYPE_VIDEO){ - enum AVCodecID codec_id= AV_CODEC_ID_NONE; -#if CONFIG_IMAGE2_MUXER - if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){ - codec_id= ff_guess_image2_codec(filename); - } -#endif - if(codec_id == AV_CODEC_ID_NONE) - codec_id= fmt->video_codec; - return codec_id; - }else if(type == AVMEDIA_TYPE_AUDIO) - return fmt->audio_codec; - else if (type == AVMEDIA_TYPE_SUBTITLE) - return fmt->subtitle_codec; - else - return AV_CODEC_ID_NONE; + return avcodec_find_decoder(codec_id); } -AVInputFormat *av_find_input_format(const char *short_name) +int av_format_get_probe_score(const AVFormatContext *s) { - AVInputFormat *fmt = NULL; - while ((fmt = av_iformat_next(fmt))) { - if (match_format(short_name, fmt->name)) - return fmt; - } - return NULL; + return s->probe_score; } /* an arbitrarily chosen "sane" max packet size -- 50M */ @@ -280,7 +158,7 @@ int ffio_limit(AVIOContext *s, int size) */ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) { - int orig_pos = pkt->pos; // av_grow_packet might reset pos + int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos int orig_size = pkt->size; int ret; @@ -372,10 +250,10 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score if (fmt1->read_probe) { score = fmt1->read_probe(&lpd); if(fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) - score = FFMAX(score, nodat ? AVPROBE_SCORE_MAX/4-1 : 1); + score = FFMAX(score, nodat ? AVPROBE_SCORE_EXTENSION / 2 - 1 : 1); } else if (fmt1->extensions) { if (av_match_ext(lpd.filename, fmt1->extensions)) { - score = 50; + score = AVPROBE_SCORE_EXTENSION; } } if (score > score_max) { @@ -384,6 +262,8 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score }else if (score == score_max) fmt = NULL; } + if(nodat) + score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max); *score_ret= score_max; return fmt; @@ -458,11 +338,7 @@ int av_demuxer_open(AVFormatContext *ic){ } -/** size of probe buffer, for guessing file type from file contents */ -#define PROBE_BUF_MIN 2048 -#define PROBE_BUF_MAX (1<<20) - -int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { @@ -470,6 +346,7 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, unsigned char *buf = NULL; uint8_t *mime_type; int ret = 0, probe_size, buf_offset = 0; + int score = 0; if (!max_probe_size) { max_probe_size = PROBE_BUF_MAX; @@ -494,20 +371,15 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt; probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) { - int score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; - void *buftmp; if (probe_size < offset) { continue; } + score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; /* read probe data */ - buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); - if(!buftmp){ - av_free(buf); - return AVERROR(ENOMEM); - } - buf=buftmp; + if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0) + return ret; if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) { /* fail if error was not end of file, otherwise, lower score */ if (ret != AVERROR_EOF) { @@ -529,6 +401,11 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, misdetection possible!\n", (*fmt)->name, score); }else av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score); +#if 0 + FILE *f = fopen("probestat.tmp", "ab"); + fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename); + fclose(f); +#endif } } @@ -540,9 +417,18 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, /* rewind. reuse probe buffer to avoid seeking */ ret = ffio_rewind_with_probe_data(pb, &buf, pd.buf_size); - return ret; + return ret < 0 ? ret : score; } +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size) +{ + int ret = av_probe_input_buffer2(pb, fmt, filename, logctx, offset, max_probe_size); + return ret < 0 ? ret : 0; +} + + /* open input file and probe the format if necessary */ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options) { @@ -553,7 +439,7 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o 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->probesize); else if (s->iformat->flags & AVFMT_NOFILE) av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and " "will be ignored with AVFMT_NOFILE format.\n"); @@ -562,14 +448,14 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) || (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score)))) - return 0; + return score; 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->probesize); } static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, @@ -629,6 +515,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma 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 */ @@ -665,7 +552,8 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma goto fail; if (id3v2_extra_meta) { - if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac")) { + 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 @@ -715,7 +603,7 @@ static void force_codec_ids(AVFormatContext *s, AVStream *st) } } -static void probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) +static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) { if(st->request_probe>0){ AVProbeData *pd = &st->probe_data; @@ -725,8 +613,12 @@ static void probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) if (pkt) { uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); - if(!new_buf) + 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; @@ -758,11 +650,76 @@ no_packet: 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<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<pts_wrap_bits) - (1LL<pts_wrap_bits-3)) || + (ref < (1LL<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; inb_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; inb_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; + int ret, i, err; AVStream *st; for(;;){ @@ -771,8 +728,10 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) if (pktl) { *pkt = pktl->pkt; st = s->streams[pkt->stream_index]; - if (s->raw_packet_buffer_remaining_size <= 0) - probe_codec(s, st, NULL); + 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; @@ -791,7 +750,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->probe_packets) { - probe_codec(s, st, NULL); + if ((err = probe_codec(s, st, NULL)) < 0) + return err; } av_assert0(st->request_probe <= 0); } @@ -807,15 +767,23 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) continue; } - if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) - av_packet_merge_side_data(pkt); - 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]; + + 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); + } + pkt->dts = wrap_timestamp(st, pkt->dts); pkt->pts = wrap_timestamp(st, pkt->pts); @@ -831,7 +799,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); s->raw_packet_buffer_remaining_size -= pkt->size; - probe_codec(s, st, pkt); + if ((err = probe_codec(s, st, pkt)) < 0) + return err; } } @@ -870,7 +839,7 @@ int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux) if ((frame_size = av_get_audio_frame_duration(enc, size)) > 0) return frame_size; - /* fallback to using frame_size if muxing */ + /* Fall back on using frame_size if muxing. */ if (enc->frame_size > 1) return enc->frame_size; @@ -950,7 +919,7 @@ static int is_intra_only(AVCodecContext *enc){ static int has_decode_delay_been_guessed(AVStream *st) { 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 wont increase anymore for stream copy + 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 && @@ -974,65 +943,6 @@ static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList return NULL; } -static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index) -{ - if (s->correct_ts_overflow && st->pts_wrap_bits < 63 && - st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) { - int i; - - // reference time stamp should be 60 s before first time stamp - int64_t pts_wrap_reference = st->first_dts - 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 - int pts_wrap_behavior = (st->first_dts < (1LL<pts_wrap_bits) - (1LL<pts_wrap_bits-3)) || - (st->first_dts < (1LL<pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ? - AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET; - - AVProgram *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; inb_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; inb_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; - } - return 0; -} - static void update_initial_timestamps(AVFormatContext *s, int stream_index, int64_t dts, int64_t pts, AVPacket *pkt) { @@ -1077,15 +987,6 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, } } - if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) { - // correct first time stamps to negative values - st->first_dts = wrap_timestamp(st, st->first_dts); - st->cur_dts = wrap_timestamp(st, st->cur_dts); - pkt->dts = wrap_timestamp(st, pkt->dts); - pkt->pts = wrap_timestamp(st, pkt->pts); - pts = wrap_timestamp(st, pts); - } - if (st->start_time == AV_NOPTS_VALUE) st->start_time = pts; } @@ -1106,7 +1007,8 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st, } } if(pktl && pktl->pkt.dts != st->first_dts) { - av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s in the queue\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.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) { @@ -1148,7 +1050,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE) pkt->dts= AV_NOPTS_VALUE; - if (st->codec->codec_id != AV_CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B) + 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; @@ -1162,7 +1065,9 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, pc && pc->pict_type != AV_PICTURE_TYPE_B) presentation_delayed = 1; - 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){ + 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) { if(is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > st->cur_dts) { pkt->dts -= 1LL<pts_wrap_bits; } else @@ -1174,7 +1079,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, // Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly. if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){ av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts); - if(strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2")) // otherwise we discard correct timestamps for vc1-wmapro.ism + 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; } @@ -1198,25 +1104,6 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, pkt->dts += offset; } - if (pc && pc->dts_sync_point >= 0) { - // we have synchronization info from the parser - int64_t den = st->codec->time_base.den * (int64_t) st->time_base.num; - if (den > 0) { - int64_t num = st->codec->time_base.num * (int64_t) st->time_base.den; - if (pkt->dts != AV_NOPTS_VALUE) { - // got DTS from the stream, update reference timestamp - st->reference_dts = pkt->dts - pc->dts_ref_dts_delta * num / den; - pkt->pts = pkt->dts + pc->pts_dts_delta * num / den; - } else if (st->reference_dts != AV_NOPTS_VALUE) { - // compute DTS based on reference timestamp - pkt->dts = st->reference_dts + pc->dts_ref_dts_delta * num / den; - pkt->pts = pkt->dts + pc->pts_dts_delta * num / den; - } - if (pc->dts_sync_point > 0) - st->reference_dts = pkt->dts; // new reference - } - } - /* This may be redundant, but it should not hurt. */ if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts) presentation_delayed = 1; @@ -1338,6 +1225,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) if (!out_pkt.size) continue; + if (pkt->side_data) { + out_pkt.side_data = pkt->side_data; + out_pkt.side_data_elems = pkt->side_data_elems; + pkt->side_data = NULL; + pkt->side_data_elems = 0; + } + /* set the duration */ out_pkt.duration = 0; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { @@ -1377,8 +1271,10 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) out_pkt.buf = pkt->buf; pkt->buf = NULL; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS out_pkt.destruct = pkt->destruct; pkt->destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif } if ((ret = av_dup_packet(&out_pkt)) < 0) @@ -1502,6 +1398,9 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) st->skip_to_keyframe = 0; if (st->skip_to_keyframe) { av_free_packet(&cur_pkt); + if (got_packet) { + *pkt = cur_pkt; + } got_packet = 0; } } @@ -1509,6 +1408,21 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) 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(ret >= 0 && !(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) + av_packet_merge_side_data(pkt); + if(s->debug & FF_FDEBUG_TS) av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", pkt->stream_index, @@ -1598,13 +1512,6 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) return_packet: 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); - 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 ((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); @@ -1672,7 +1579,6 @@ void ff_read_frame_flush(AVFormatContext *s) st->last_IP_pts = AV_NOPTS_VALUE; if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = RELATIVE_TS_BASE; else st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ - st->reference_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; @@ -1721,6 +1627,9 @@ int ff_add_index_entry(AVIndexEntry **index_entries, 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; @@ -1738,7 +1647,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){ @@ -1850,14 +1759,14 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts 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; @@ -1880,14 +1789,51 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_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, int flags, int64_t *ts_ret, int64_t (*read_timestamp)(struct AVFormatContext *, int , 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 %s\n", stream_index, av_ts2str(target_ts)); @@ -1904,27 +1850,8 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, } if(ts_max == AV_NOPTS_VALUE){ - int step= 1024; - filesize = avio_size(s->pb); - pos_max = filesize - 1; - do{ - pos_max = FFMAX(0, pos_max - step); - ts_max = ff_read_timestamp(s, stream_index, &pos_max, pos_max + step, read_timestamp); - step += step; - }while(ts_max == AV_NOPTS_VALUE && pos_max > 0); - 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; - ts_max= tmp_ts; - pos_max= tmp_pos; - if(tmp_pos >= filesize) - break; - } + if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0) + return ret; pos_limit= pos_max; } @@ -2014,6 +1941,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, in avio_seek(s->pb, pos, SEEK_SET); + s->io_repositioned = 1; + return 0; } @@ -2037,7 +1966,7 @@ static int seek_frame_generic(AVFormatContext *s, 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; @@ -2127,7 +2056,19 @@ 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 = avformat_queue_attached_pictures(s); @@ -2144,6 +2085,7 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int if(s->seek2any>0) flags |= AVSEEK_FLAG_ANY; + flags &= ~AVSEEK_FLAG_BACKWARD; if (s->iformat->read_seek2) { int ret; @@ -2171,8 +2113,8 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int //try to seek via read_timestamp() } - //Fallback to old API if new is not implemented but old is - //Note the old has somewhat different semantics + // 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) { 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); @@ -2304,16 +2246,21 @@ static void fill_all_stream_timings(AVFormatContext *ic) static void estimate_timings_from_bit_rate(AVFormatContext *ic) { int64_t filesize, duration; - int bit_rate, i; + int i, show_warning = 0; AVStream *st; /* if bit_rate is already set, we believe it */ if (ic->bit_rate <= 0) { - bit_rate = 0; + int bit_rate = 0; for(i=0;inb_streams;i++) { st = ic->streams[i]; - if (st->codec->bit_rate > 0) - bit_rate += st->codec->bit_rate; + if (st->codec->bit_rate > 0) { + if (INT_MAX - st->codec->bit_rate < bit_rate) { + bit_rate = 0; + break; + } + bit_rate += st->codec->bit_rate; + } } ic->bit_rate = bit_rate; } @@ -2325,12 +2272,17 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) 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) + 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 250000LL @@ -2410,7 +2362,6 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) st= ic->streams[i]; st->cur_dts= st->first_dts; st->last_IP_pts = AV_NOPTS_VALUE; - st->reference_dts = AV_NOPTS_VALUE; } } @@ -2438,7 +2389,6 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) 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; @@ -2507,11 +2457,11 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) } /* 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, AVDictionary **options) +static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, AVDictionary **options) { const AVCodec *codec; int got_picture = 1, ret = 0; - AVFrame *frame = avcodec_alloc_frame(); + AVFrame *frame = av_frame_alloc(); AVSubtitle subtitle; AVPacket pkt = *avpkt; @@ -2521,8 +2471,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option if (!avcodec_is_open(st->codec) && !st->info->found_decoder) { 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; @@ -2555,7 +2504,6 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option !has_decode_delay_been_guessed(st) || (!st->codec_info_nb_frames && st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { got_picture = 0; - avcodec_get_frame_defaults(frame); switch(st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: ret = avcodec_decode_video2(st->codec, frame, @@ -2585,7 +2533,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option ret = -1; fail: - avcodec_free_frame(&frame); + av_frame_free(&frame); return ret; } @@ -2733,9 +2681,158 @@ int av_find_stream_info(AVFormatContext *ic) } #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; iinfo->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; iinfo->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; inb_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; + + for (j=0; jinfo->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 && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate))) + av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX); + } + + 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, j; + int i, count, ret = 0, j; int64_t read_size; AVStream *st; AVPacket pkt1, *pkt; @@ -2744,7 +2841,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int flush_codecs = ic->probesize > 0; if(ic->pb) - av_log(ic, AV_LOG_DEBUG, "File position before avformat_find_stream_info() is %"PRId64"\n", avio_tell(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;inb_streams;i++) { const AVCodec *codec; @@ -2773,8 +2871,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) 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 h264 decoder will not extract SPS * and PPS to extradata during multi-threaded decoding */ @@ -2782,15 +2879,16 @@ 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, 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); @@ -2859,7 +2957,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) av_log(ic, AV_LOG_DEBUG, "Probe buffer size limit of %d bytes reached\n", ic->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]->info->duration_count <= 1 && + strcmp(ic->iformat->name, "image2")) av_log(ic, AV_LOG_WARNING, "Stream #%d: not enough frames to estimate rate; " "consider increasing probesize\n", i); @@ -2877,18 +2976,23 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) 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 && @@ -2928,57 +3032,30 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) 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 >= ic->max_analyze_duration) { - av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached at %"PRId64" microseconds\n", ic->max_analyze_duration, t); + av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %d reached at %"PRId64" microseconds\n", ic->max_analyze_duration, t); break; } if (pkt->duration) { st->info->codec_info_duration += pkt->duration; - st->info->codec_info_duration_fields += st->parser && st->codec->ticks_per_frame==2 ? st->parser->repeat_pict + 1 : 2; + 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 - { - int64_t last = st->info->last_dts; - - if( pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last - && pkt->dts - (uint64_t)last < INT64_MAX){ - double dts= (is_relative(pkt->dts) ? pkt->dts - RELATIVE_TS_BASE : pkt->dts) * av_q2d(st->time_base); - int64_t duration= pkt->dts - last; - - if (!st->info->duration_error) - st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2); - -// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -// av_log(NULL, AV_LOG_ERROR, "%f\n", dts); - for (i=0; iinfo->duration_error[j][0][i] += error; - st->info->duration_error[j][1][i] += error*error; - } - } - st->info->duration_count++; - // ignore the first 4 values, they might have some random jitter - if (st->info->duration_count > 3 && is_relative(pkt->dts) == is_relative(last)) - st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration); - } - if (pkt->dts != AV_NOPTS_VALUE) - st->info->last_dts = pkt->dts; - } + 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_malloc(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); - memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE); } } @@ -2991,7 +3068,7 @@ 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, (options && i < orig_nb_streams ) ? &options[i] : NULL); + try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL); st->codec_info_nb_frames++; count++; @@ -3002,16 +3079,14 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int err = 0; av_init_packet(&empty_pkt); - ret = -1; /* we could not have all the codec parameters before EOF */ for(i=0;inb_streams;i++) { - const char *errmsg; st = ic->streams[i]; /* flush the decoders */ if (st->info->found_decoder == 1) { do { - err = try_decode_frame(st, &empty_pkt, + err = try_decode_frame(ic, st, &empty_pkt, (options && i < orig_nb_streams) ? &options[i] : NULL); } while (err > 0 && !has_codec_parameters(st, NULL)); @@ -3021,17 +3096,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) "decoding for stream %d failed\n", st->index); } } - - 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; - } } } @@ -3040,6 +3104,9 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) st = ic->streams[i]; avcodec_close(st->codec); } + + ff_rfps_calculate(ic); + for(i=0;inb_streams;i++) { st = ic->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -3054,6 +3121,10 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int best_fps = 0; double best_error = 0.01; + 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, 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); @@ -3074,40 +3145,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) best_fps, 12*1001, INT_MAX); } } - // 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; - - for (j=0; jinfo->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; - 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 && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate))) - av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX); - } if (!st->r_frame_rate.num){ if( st->codec->time_base.den * (int64_t)st->time_base.num @@ -3141,19 +3178,37 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) if(ic->probesize) estimate_timings(ic, old_offset); + if (ret >= 0 && ic->nb_streams) + ret = -1; /* we could not have all the codec parameters before EOF */ + for(i=0;inb_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++) { st = ic->streams[i]; - if (ic->streams[i]->codec) + if (ic->streams[i]->codec && 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, "File position after avformat_find_stream_info() is %"PRId64"\n", avio_tell(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; } @@ -3204,7 +3259,7 @@ int av_find_best_stream(AVFormatContext *ic, if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED)) 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; @@ -3264,6 +3319,7 @@ void ff_free_stream(AVFormatContext *s, AVStream *st){ 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); @@ -3272,7 +3328,6 @@ void ff_free_stream(AVFormatContext *s, AVStream *st){ if (st->info) av_freep(&st->info->duration_error); av_freep(&st->info); - av_freep(&st->probe_data.buf); av_freep(&s->streams[ --s->nb_streams ]); } @@ -3316,8 +3371,14 @@ void av_close_input_file(AVFormatContext *s) 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)) @@ -3355,7 +3416,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) if (s->nb_streams >= INT_MAX/sizeof(*streams)) return NULL; - streams = av_realloc(s->streams, (s->nb_streams + 1) * sizeof(*streams)); + streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams)); if (!streams) return NULL; s->streams = streams; @@ -3392,7 +3453,6 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) st->last_IP_pts = AV_NOPTS_VALUE; for(i=0; ipts_buffer[i]= AV_NOPTS_VALUE; - st->reference_dts = AV_NOPTS_VALUE; st->sample_aspect_ratio = (AVRational){0,1}; @@ -3477,7 +3537,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i if(program->stream_index[j] == idx) return; - tmp = av_realloc(program->stream_index, sizeof(unsigned int)*(program->nb_stream_indexes+1)); + tmp = av_realloc_array(program->stream_index, program->nb_stream_indexes+1, sizeof(unsigned int)); if(!tmp) return; program->stream_index = tmp; @@ -3788,27 +3848,11 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int av_hex_dump(f, pkt->data, pkt->size); } -#if FF_API_PKT_DUMP -void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload) -{ - AVRational tb = { 1, AV_TIME_BASE }; - pkt_dump_internal(NULL, f, 0, pkt, dump_payload, tb); -} -#endif - void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st) { pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base); } -#if FF_API_PKT_DUMP -void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload) -{ - AVRational tb = { 1, AV_TIME_BASE }; - pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, tb); -} -#endif - void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, AVStream *st) { @@ -3956,72 +4000,6 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, s->pts_wrap_bits = pts_wrap_bits; } -int ff_url_join(char *str, int size, const char *proto, - const char *authorization, const char *hostname, - int port, const char *fmt, ...) -{ -#if CONFIG_NETWORK - struct addrinfo hints = { 0 }, *ai; -#endif - - str[0] = '\0'; - if (proto) - av_strlcatf(str, size, "%s://", proto); - if (authorization && authorization[0]) - av_strlcatf(str, size, "%s@", authorization); -#if CONFIG_NETWORK && defined(AF_INET6) - /* Determine if hostname is a numerical IPv6 address, - * properly escape it within [] in that case. */ - hints.ai_flags = AI_NUMERICHOST; - if (!getaddrinfo(hostname, NULL, &hints, &ai)) { - if (ai->ai_family == AF_INET6) { - av_strlcat(str, "[", size); - av_strlcat(str, hostname, size); - av_strlcat(str, "]", size); - } else { - av_strlcat(str, hostname, size); - } - freeaddrinfo(ai); - } else -#endif - /* Not an IPv6 address, just output the plain string. */ - av_strlcat(str, hostname, size); - - if (port >= 0) - av_strlcatf(str, size, ":%d", port); - if (fmt) { - va_list vl; - int len = strlen(str); - - va_start(vl, fmt); - vsnprintf(str + len, size > len ? size - len : 0, fmt, vl); - va_end(vl); - } - return strlen(str); -} - -int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, - AVFormatContext *src) -{ - AVPacket local_pkt; - - local_pkt = *pkt; - local_pkt.stream_index = dst_stream; - if (pkt->pts != AV_NOPTS_VALUE) - local_pkt.pts = av_rescale_q(pkt->pts, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - if (pkt->dts != AV_NOPTS_VALUE) - local_pkt.dts = av_rescale_q(pkt->dts, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - if (pkt->duration) - local_pkt.duration = av_rescale_q(pkt->duration, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - return av_write_frame(dst, &local_pkt); -} - void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf, void *context) { @@ -4086,75 +4064,6 @@ int ff_find_stream_index(AVFormatContext *s, int id) return -1; } -void ff_make_absolute_url(char *buf, int size, const char *base, - const char *rel) -{ - char *sep, *path_query; - /* Absolute path, relative to the current server */ - if (base && strstr(base, "://") && rel[0] == '/') { - if (base != buf) - av_strlcpy(buf, base, size); - sep = strstr(buf, "://"); - if (sep) { - /* Take scheme from base url */ - if (rel[1] == '/') { - sep[1] = '\0'; - } else { - /* Take scheme and host from base url */ - sep += 3; - sep = strchr(sep, '/'); - if (sep) - *sep = '\0'; - } - } - av_strlcat(buf, rel, size); - return; - } - /* If rel actually is an absolute url, just copy it */ - if (!base || strstr(rel, "://") || rel[0] == '/') { - av_strlcpy(buf, rel, size); - return; - } - if (base != buf) - av_strlcpy(buf, base, size); - - /* Strip off any query string from base */ - path_query = strchr(buf, '?'); - if (path_query != NULL) - *path_query = '\0'; - - /* Is relative path just a new query part? */ - if (rel[0] == '?') { - av_strlcat(buf, rel, size); - return; - } - - /* Remove the file name from the base url */ - sep = strrchr(buf, '/'); - if (sep) - sep[1] = '\0'; - else - buf[0] = '\0'; - while (av_strstart(rel, "../", NULL) && sep) { - /* Remove the path delimiter at the end */ - sep[0] = '\0'; - sep = strrchr(buf, '/'); - /* If the next directory name to pop off is "..", break here */ - if (!strcmp(sep ? &sep[1] : buf, "..")) { - /* Readd the slash we just removed */ - av_strlcat(buf, "/", size); - break; - } - /* Cut off the directory name */ - if (sep) - sep[1] = '\0'; - else - buf[0] = '\0'; - rel += 3; - } - av_strlcat(buf, rel, size); -} - int64_t ff_iso8601_to_unix_time(const char *datestr) { struct tm time1 = {0}, time2 = {0}; @@ -4244,15 +4153,6 @@ int ff_add_param_change(AVPacket *pkt, int32_t channels, return 0; } -const struct AVCodecTag *avformat_get_riff_video_tags(void) -{ - return ff_codec_bmp_tags; -} -const struct AVCodecTag *avformat_get_riff_audio_tags(void) -{ - return ff_codec_wav_tags; -} - AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame) { AVRational undef = {0, 1}; @@ -4276,6 +4176,22 @@ AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *strea return frame_sample_aspect_ratio; } +AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *frame) +{ + AVRational fr = st->r_frame_rate; + + if (st->codec->ticks_per_frame > 1) { + AVRational codec_fr = av_inv_q(st->codec->time_base); + AVRational avg_fr = st->avg_frame_rate; + 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) { @@ -4337,7 +4253,7 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, return AVERROR(EINVAL); } -void ff_generate_avci_extradata(AVStream *st) +int ff_generate_avci_extradata(AVStream *st) { static const uint8_t avci100_1080p_extradata[] = { // SPS @@ -4404,8 +4320,10 @@ void ff_generate_avci_extradata(AVStream *st) 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x31, 0x12, 0x11 }; + + const uint8_t *data = NULL; int size = 0; - const uint8_t *data = 0; + if (st->codec->width == 1920) { if (st->codec->field_order == AV_FIELD_PROGRESSIVE) { data = avci100_1080p_extradata; @@ -4421,67 +4339,14 @@ void ff_generate_avci_extradata(AVStream *st) data = avci100_720p_extradata; size = sizeof(avci100_720p_extradata); } + if (!size) - return; + 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) - return; + if (ff_alloc_extradata(st->codec, size)) + return AVERROR(ENOMEM); memcpy(st->codec->extradata, data, size); - st->codec->extradata_size = size; -} -static int match_host_pattern(const char *pattern, const char *hostname) -{ - int len_p, len_h; - if (!strcmp(pattern, "*")) - return 1; - // Skip a possible *. at the start of the pattern - if (pattern[0] == '*') - pattern++; - if (pattern[0] == '.') - pattern++; - len_p = strlen(pattern); - len_h = strlen(hostname); - if (len_p > len_h) - return 0; - // Simply check if the end of hostname is equal to 'pattern' - if (!strcmp(pattern, &hostname[len_h - len_p])) { - if (len_h == len_p) - return 1; // Exact match - if (hostname[len_h - len_p - 1] == '.') - return 1; // The matched substring is a domain and not just a substring of a domain - } return 0; } - -int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) -{ - char *buf, *start; - int ret = 0; - if (!no_proxy) - return 0; - if (!hostname) - return 0; - buf = av_strdup(no_proxy); - if (!buf) - return 0; - start = buf; - while (start) { - char *sep, *next = NULL; - start += strspn(start, " ,"); - sep = start + strcspn(start, " ,"); - if (*sep) { - next = sep + 1; - *sep = '\0'; - } - if (match_host_pattern(start, hostname)) { - ret = 1; - break; - } - start = next; - } - av_free(buf); - return ret; -} -- cgit v1.2.3