Skip to content
Snippets Groups Projects
utils.c 152 KiB
Newer Older
  • Learn to ignore specific revisions
  • Fabrice Bellard's avatar
    Fabrice Bellard committed
    /*
    
     * various utility functions for use within FFmpeg
    
     * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * This file is part of FFmpeg.
     *
     * 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.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * FFmpeg is distributed in the hope that it will be useful,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     * 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.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * You should have received a copy of the GNU Lesser General Public
    
     * License along with FFmpeg; if not, write to the Free Software
    
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     */
    
    #undef NDEBUG
    #include <assert.h>
    #include <stdarg.h>
    
    #include "config.h"
    
    
    #include "libavutil/avassert.h"
    
    #include "libavutil/avstring.h"
    
    #include "libavutil/dict.h"
    #include "libavutil/internal.h"
    
    #include "libavutil/mathematics.h"
    
    #include "libavutil/opt.h"
    
    #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"
    
    #if CONFIG_NETWORK
    #include "network.h"
    #endif
    
    #include "riff.h"
    #include "url.h"
    
    #include "libavutil/ffversion.h"
    const char av_format_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
    
    
     * 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)
    
    const char *avformat_license(void)
    
    {
    #define LICENSE_PREFIX "libavformat license: "
    
        return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
    
    #define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48))
    
        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);
    
    MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate)
    
    MAKE_ACCESSORS(AVStream, stream, char *, recommended_encoder_configuration)
    
    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;
        }
    }
    
    
    int ff_copy_whitelists(AVFormatContext *dst, AVFormatContext *src)
    {
        av_assert0(!dst->codec_whitelist && !dst->format_whitelist);
        dst-> codec_whitelist = av_strdup(src->codec_whitelist);
        dst->format_whitelist = av_strdup(src->format_whitelist);
        if (   (src-> codec_whitelist && !dst-> codec_whitelist)
            || (src->format_whitelist && !dst->format_whitelist)) {
            av_log(dst, AV_LOG_ERROR, "Failed to duplicate whitelist\n");
            return AVERROR(ENOMEM);
        }
        return 0;
    }
    
    
    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;
    
        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)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    int ffio_limit(AVIOContext *s, int size)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    {
    
            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);
    
            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);
    
    /* 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 orig_pos   = pkt->pos; // av_grow_packet might reset pos
    
        int orig_size      = pkt->size;
    
    
        do {
            int prev_size = pkt->size;
            int read_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. */
    
            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);
            }
    
            ret = av_grow_packet(pkt, read_size);
            if (ret < 0)
                break;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    
            ret = avio_read(s, pkt->data + prev_size, read_size);
            if (ret != read_size) {
                av_shrink_packet(pkt, prev_size + FFMAX(ret, 0));
                break;
            }
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    
            size -= read_size;
        } while (size > 0);
    
        if (size > 0)
            pkt->flags |= AV_PKT_FLAG_CORRUPT;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    
        pkt->pos = orig_pos;
        if (!pkt->size)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_free_packet(pkt);
    
        return pkt->size > orig_size ? pkt->size - orig_size : ret;
    }
    
    int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
    {
        av_init_packet(pkt);
        pkt->data = NULL;
        pkt->size = 0;
        pkt->pos  = avio_tell(s);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    
        return append_packet_chunked(s, pkt, size);
    
    int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
    
    {
        if (!pkt->size)
            return av_get_packet(s, pkt, size);
    
        return append_packet_chunked(s, pkt, size);
    
    int av_filename_number_test(const char *filename)
    
        return filename &&
               (av_get_frame_filename(buf, sizeof(buf), filename, 1) >= 0);
    
    static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st,
    
            const char *name;
            enum AVCodecID id;
            enum AVMediaType type;
    
            { "aac",       AV_CODEC_ID_AAC,        AVMEDIA_TYPE_AUDIO },
            { "ac3",       AV_CODEC_ID_AC3,        AVMEDIA_TYPE_AUDIO },
            { "dts",       AV_CODEC_ID_DTS,        AVMEDIA_TYPE_AUDIO },
            { "eac3",      AV_CODEC_ID_EAC3,       AVMEDIA_TYPE_AUDIO },
            { "h264",      AV_CODEC_ID_H264,       AVMEDIA_TYPE_VIDEO },
    
            { "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 },
    
        int score;
        AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score);
    
        if (fmt && st->request_probe <= score) {
    
            av_log(s, AV_LOG_DEBUG,
                   "Probe with size=%d, packets=%d detected %s with score=%d\n",
                   pd->buf_size, MAX_PROBE_PACKETS - st->probe_packets,
                   fmt->name, score);
    
            for (i = 0; fmt_id_type[i].name; i++) {
                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;
    
    /************************************************************/
    /* input media file */
    
    int av_demuxer_open(AVFormatContext *ic) {
    
        if (ic->format_whitelist && av_match_list(ic->iformat->name, ic->format_whitelist, ',') <= 0) {
            av_log(ic, AV_LOG_ERROR, "Format not on whitelist\n");
            return AVERROR(EINVAL);
        }
    
    
        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)
    
        AVProbeData pd = { filename, NULL, 0 };
    
    
        if (s->pb) {
            s->flags |= AVFMT_FLAG_CUSTOM_IO;
            if (!s->iformat)
    
                return av_probe_input_buffer2(s->pb, &s->iformat, filename,
    
            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");
    
        if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
    
            (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
    
            return score;
    
    Reimar Döffinger's avatar
    Reimar Döffinger committed
        if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
    
                              &s->interrupt_callback, options)) < 0)
    
            return ret;
    
        return av_probe_input_buffer2(s->pb, &s->iformat, filename,
    
    static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
    
                                   AVPacketList **plast_pktl)
    {
    
        AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
        if (!pktl)
            return NULL;
    
        if (*packet_buffer)
            (*plast_pktl)->next = pktl;
        else
            *packet_buffer = pktl;
    
    
        /* Add the packet in the buffered packet list. */
    
        pktl->pkt   = *pkt;
    
    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);
    
    
                add_to_pktbuf(&s->raw_packet_buffer, &copy,
                              &s->raw_packet_buffer_end);
    
    int avformat_open_input(AVFormatContext **ps, const char *filename,
                            AVInputFormat *fmt, AVDictionary **options)
    
        ID3v2ExtraMeta *id3v2_extra_meta = NULL;
    
    
        if (!s && !(s = avformat_alloc_context()))
            return AVERROR(ENOMEM);
    
            av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
    
        if (fmt)
            s->iformat = fmt;
    
        if (options)
            av_dict_copy(&tmp, *options, 0);
    
        if ((ret = av_opt_set_dict(s, &tmp)) < 0)
            goto fail;
    
    
        if ((ret = init_input(s, filename, &tmp)) < 0)
    
        s->probe_score = ret;
    
    
        if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
            av_log(s, AV_LOG_ERROR, "Format not on whitelist\n");
            ret = AVERROR(EINVAL);
            goto fail;
        }
    
    
        avio_skip(s->pb, s->skip_initial_bytes);
    
        /* Check filename in case an image number is expected. */
    
        if (s->iformat->flags & AVFMT_NEEDNUMBER) {
            if (!av_filename_number_test(filename)) {
                ret = AVERROR(EINVAL);
    
        }
    
        s->duration = s->start_time = AV_NOPTS_VALUE;
    
        av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
    
        /* Allocate private data. */
    
        if (s->iformat->priv_data_size > 0) {
            if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
                ret = AVERROR(ENOMEM);
    
                *(const AVClass **) s->priv_data = s->iformat->priv_class;
    
                av_opt_set_defaults(s->priv_data);
                if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
                    goto fail;
            }
    
        /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
        if (s->pb)
    
            ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0);
    
        if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
    
            if ((ret = s->iformat->read_header(s)) < 0)
    
            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)
    
    Clément Bœsch's avatar
    Clément Bœsch committed
                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 = avformat_queue_attached_pictures(s)) < 0)
    
        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;
    
        if (options) {
            av_dict_free(options);
            *options = tmp;
    
        ff_id3v2_free_extra_meta(&id3v2_extra_meta);
    
        av_dict_free(&tmp);
        if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
            avio_close(s->pb);
        avformat_free_context(s);
        *ps = NULL;
        return ret;
    
    /*******************************************************/
    
    
    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;
    
    static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
    
            AVProbeData *pd = &st->probe_data;
    
            int end;
            av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets);
    
            --st->probe_packets;
    
    
                uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
    
                    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);
    
                memset(pd->buf + pd->buf_size, 0, AVPROBE_PADDING_SIZE);
    
                           "nothing to probe for stream %d\n", st->index);
    
            end=    s->raw_packet_buffer_remaining_size <= 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)
    
                    pd->buf_size = 0;
    
                    av_freep(&pd->buf);
    
                    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);
    
                        av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index);
    
                force_codec_ids(s, st);
    
    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;
    
                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)
    
        AVStream *st;
    
            AVPacketList *pktl = s->raw_packet_buffer;
    
            if (pktl) {
                *pkt = pktl->pkt;
    
                st   = s->streams[pkt->stream_index];
    
                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;
    
            pkt->data = NULL;
            pkt->size = 0;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_init_packet(pkt);
    
            ret = s->iformat->read_packet(s, pkt);
    
            if (ret < 0) {
                if (!pktl || ret == AVERROR(EAGAIN))
                    return ret;
    
                for (i = 0; i < s->nb_streams; i++) {
                    st = s->streams[i];
    
                    if (st->probe_packets)
    
                        if ((err = probe_codec(s, st, NULL)) < 0)
                            return err;
    
                    av_assert0(st->request_probe <= 0);
    
            if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) &&
                (pkt->flags & AV_PKT_FLAG_CORRUPT)) {
                av_log(s, AV_LOG_WARNING,
                       "Dropped corrupted packet (stream = %d)\n",
                       pkt->stream_index);
    
                av_free_packet(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);
    
            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)
    
            add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);
    
            s->raw_packet_buffer_remaining_size -= pkt->size;
    
            if ((err = probe_codec(s, st, pkt)) < 0)
                return err;
    
    /**********************************************************/
    
    
    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 the frame duration in seconds. Return 0 if not available.
    
    void ff_compute_frame_duration(AVFormatContext *s, int *pnum, int *pden, AVStream *st,
    
                                   AVCodecParserContext *pc, AVPacket *pkt)
    
        AVRational codec_framerate = s->iformat ? st->codec->framerate :
    
                                                  av_mul_q(av_inv_q(st->codec->time_base), (AVRational){1, st->codec->ticks_per_frame});
    
        int frame_size;
    
        *pnum = 0;
        *pden = 0;
    
        switch (st->codec->codec_type) {
    
            if (st->r_frame_rate.num && !pc && s->iformat) {
    
                *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;
    
            } else if (codec_framerate.den * 1000LL > codec_framerate.num) {
    
                av_assert0(st->codec->ticks_per_frame);
    
                av_reduce(pnum, pden,
                          codec_framerate.den,
                          codec_framerate.num * (int64_t)st->codec->ticks_per_frame,
                          INT_MAX);
    
    
                if (pc && pc->repeat_pict) {
    
                    av_assert0(s->iformat); // this may be wrong for interlaced encoding but its not used for that case
    
                    av_reduce(pnum, pden,
                              (*pnum) * (1LL + pc->repeat_pict),
                              (*pden),
                              INT_MAX);
    
                /* If this codec can be interlaced or progressive then we need
                 * a parser to compute duration of a packet. Thus if we have
                 * no parser in such case leave duration undefined. */
                if (st->codec->ticks_per_frame > 1 && !pc)
    
            frame_size = av_get_audio_frame_duration(st->codec, pkt->size);
    
            if (frame_size <= 0 || st->codec->sample_rate <= 0)
    
                break;
            *pnum = frame_size;
    
    static int is_intra_only(AVCodecContext *enc) {
    
        if (enc->codec_type != AVMEDIA_TYPE_VIDEO)
    
    
        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);
    
    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 won't increase anymore for stream copy
    
        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;
    
            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;
    
    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, AVPacket *pkt)
    
        AVStream *st       = s->streams[stream_index];
    
        AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue;
    
        int64_t pts_buffer[MAX_REORDER_DELAY+1];
    
        if (st->first_dts != AV_NOPTS_VALUE ||
            dts           == AV_NOPTS_VALUE ||
    
            st->cur_dts   == AV_NOPTS_VALUE ||
            is_relative(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 (i = 0; i<MAX_REORDER_DELAY+1; i++)
    
        for (; pktl; pktl = get_next_pkt(s, st, pktl)) {
    
            if (pktl->pkt.stream_index != stream_index)
    
            if (is_relative(pktl->pkt.pts))
    
            if (is_relative(pktl->pkt.dts))
    
            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;
    
    static void update_initial_durations(AVFormatContext *s, AVStream *st,
                                         int stream_index, int duration)
    
        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 = 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 ||
                        pktl->pkt.duration)
    
            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);
    
                av_log(s, AV_LOG_DEBUG, "first_dts %s but no packet with dts in the queue\n", av_ts2str(st->first_dts));
    
            pktl          = s->packet_buffer ? s->packet_buffer : s->parse_queue;
    
        } else if (st->cur_dts != RELATIVE_TS_BASE)
    
        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 || 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;
    
    //            if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
    
            cur_dts = pktl->pkt.dts + pktl->pkt.duration;
    
            st->cur_dts = cur_dts;
    
    static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
    
                                   AVCodecParserContext *pc, AVPacket *pkt,
                                   int64_t next_dts, int64_t next_pts)
    
        int num, den, presentation_delayed, delay, i;
    
        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",