Skip to content
Snippets Groups Projects
utils.c 109 KiB
Newer Older
  • Learn to ignore specific revisions
  • Fabrice Bellard's avatar
    Fabrice Bellard committed
    /*
    
     * various utility functions for use within Libav
    
     * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * This file is part of Libav.
    
     * Libav 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
     *
    
     * Libav 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 Libav; 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 "libavcodec/bytestream.h"
    #include "libavcodec/internal.h"
    
    
    #include "audiointerleave.h"
    
    #include "avformat.h"
    #include "id3v2.h"
    #include "internal.h"
    #include "metadata.h"
    
    #if CONFIG_NETWORK
    #include "network.h"
    #endif
    
    #include "riff.h"
    #include "url.h"
    
     * various utility functions for use within Libav
    
    unsigned avformat_version(void)
    {
        return LIBAVFORMAT_VERSION_INT;
    }
    
    
    const char *avformat_configuration(void)
    
        return LIBAV_CONFIGURATION;
    
    const char *avformat_license(void)
    
    {
    #define LICENSE_PREFIX "libavformat license: "
    
        return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
    
    /* an arbitrarily chosen "sane" max packet size -- 50M */
    #define SANE_CHUNK_SIZE (50000000)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    /* 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)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    {
    
        int64_t chunk_size = size;
    
        int64_t orig_pos   = pkt->pos; // av_grow_packet might reset pos
    
        int orig_size      = pkt->size;
        int ret = 0;
    
        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. */
    
            if (size > SANE_CHUNK_SIZE) {
                int64_t filesize = avio_size(s) - avio_tell(s);
                chunk_size = FFMAX(filesize, SANE_CHUNK_SIZE);
            }
            read_size = FFMIN(size, 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);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    
        pkt->pos = orig_pos;
        if (!pkt->size)
    
        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,
                                         AVProbeData *pd, int score)
    
            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 },
    
            { "latm",      AV_CODEC_ID_AAC_LATM,   AVMEDIA_TYPE_AUDIO },
    
            { "m4v",       AV_CODEC_ID_MPEG4,      AVMEDIA_TYPE_VIDEO },
            { "mp3",       AV_CODEC_ID_MP3,        AVMEDIA_TYPE_AUDIO },
    
            { "mpegvideo", AV_CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO },
    
            { 0 }
        };
        AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score);
    
            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->codecpar->codec_id   = fmt_id_type[i].id;
                    st->codecpar->codec_type = fmt_id_type[i].type;
    #if FF_API_LAVF_AVCTX
    FF_DISABLE_DEPRECATION_WARNINGS
                    st->codec->codec_type = st->codecpar->codec_type;
                    st->codec->codec_id   = st->codecpar->codec_id;
    FF_ENABLE_DEPRECATION_WARNINGS
    #endif
    
    /************************************************************/
    /* input media file */
    
    /* 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_buffer(s->pb, &s->iformat, filename,
                                             s, 0, s->probesize);
    
            else if (s->iformat->flags & AVFMT_NOFILE)
                return AVERROR(EINVAL);
            return 0;
        }
    
    
        if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
    
            (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0))))
            return 0;
    
    
        ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ, options);
        if (ret < 0)
    
            return ret;
    
        return av_probe_input_buffer(s->pb, &s->iformat, filename,
                                     s, 0, s->probesize);
    
    static int add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
                             AVPacketList **plast_pktl, int ref)
    
        AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
    
            return AVERROR(ENOMEM);
    
        if (ref) {
            if ((ret = av_packet_ref(&pktl->pkt, pkt)) < 0) {
                av_free(pktl);
                return ret;
            }
        } else {
            pktl->pkt = *pkt;
        }
    
    
        if (*packet_buffer)
            (*plast_pktl)->next = pktl;
        else
            *packet_buffer = pktl;
    
    
        /* Add the packet in the buffered packet list. */
    
        return 0;
    
    static int queue_attached_pictures(AVFormatContext *s)
    
        int i, ret;
    
        for (i = 0; i < s->nb_streams; i++)
    
            if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC &&
                s->streams[i]->discard < AVDISCARD_ALL) {
    
                ret = add_to_pktbuf(&s->internal->raw_packet_buffer,
                                    &s->streams[i]->attached_pic,
                                    &s->internal->raw_packet_buffer_end, 1);
                if (ret < 0)
                    return ret;
    
    #if FF_API_LAVF_AVCTX
    FF_DISABLE_DEPRECATION_WARNINGS
    static int update_stream_avctx(AVFormatContext *s)
    {
        int i, ret;
        for (i = 0; i < s->nb_streams; i++) {
            AVStream *st = s->streams[i];
    
            if (!st->internal->need_codec_update)
                continue;
    
            ret = avcodec_parameters_to_context(st->codec, st->codecpar);
            if (ret < 0)
                return ret;
    
            st->internal->need_codec_update = 0;
        }
        return 0;
    }
    FF_ENABLE_DEPRECATION_WARNINGS
    #endif
    
    
    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);
        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)
    
        /* Check filename in case an image number is expected. */
    
        if (s->iformat->flags & AVFMT_NEEDNUMBER) {
            if (!av_filename_number_test(filename)) {
                ret = AVERROR(EINVAL);
                goto fail;
            }
        }
    
        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);
                goto fail;
            }
            if (s->iformat->priv_class) {
    
                *(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);
    
            if ((ret = s->iformat->read_header(s)) < 0)
    
        if (id3v2_extra_meta &&
            (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
            goto fail;
        ff_id3v2_free_extra_meta(&id3v2_extra_meta);
    
    
        if ((ret = queue_attached_pictures(s)) < 0)
            goto fail;
    
        if (s->pb && !s->internal->data_offset)
            s->internal->data_offset = avio_tell(s->pb);
    
        s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
    
    #if FF_API_LAVF_AVCTX
        update_stream_avctx(s);
    #endif
    
        for (i = 0; i < s->nb_streams; i++)
            s->streams[i]->internal->orig_codec_id = s->streams[i]->codecpar->codec_id;
    
    
        if (options) {
            av_dict_free(options);
            *options = tmp;
        }
        *ps = s;
        return 0;
    
    fail:
    
        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 int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
    
        if (st->codecpar->codec_id == AV_CODEC_ID_PROBE) {
    
            AVProbeData *pd = &st->probe_data;
            av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index);
            --st->probe_packets;
    
    
                int err;
                if ((err = av_reallocp(&pd->buf, pd->buf_size + pkt->size +
                                       AVPROBE_PADDING_SIZE)) < 0)
                    return err;
    
                memcpy(pd->buf + pd->buf_size, pkt->data, pkt->size);
    
                memset(pd->buf + pd->buf_size, 0, AVPROBE_PADDING_SIZE);
    
                    av_log(s, AV_LOG_ERROR,
                           "nothing to probe for stream %d\n", st->index);
    
            if (!st->probe_packets ||
                av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) {
    
                set_codec_from_probe_data(s, st, pd, st->probe_packets > 0
                                                     ? AVPROBE_SCORE_MAX / 4 : 0);
    
                if (st->codecpar->codec_id != AV_CODEC_ID_PROBE) {
    
                    pd->buf_size = 0;
    
                    av_freep(&pd->buf);
                    av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
                }
            }
        }
    
    int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
    
        AVStream *st;
    
            AVPacketList *pktl = s->internal->raw_packet_buffer;
    
    
            if (pktl) {
                *pkt = pktl->pkt;
    
                st   = s->streams[pkt->stream_index];
    
                if (st->codecpar->codec_id != AV_CODEC_ID_PROBE ||
    
                    !st->probe_packets ||
    
                    s->internal->raw_packet_buffer_remaining_size < pkt->size) {
    
                    if (st->probe_packets)
    
                        if ((err = probe_codec(s, st, NULL)) < 0)
                            return err;
    
                    av_freep(&pd->buf);
                    pd->buf_size = 0;
    
                    s->internal->raw_packet_buffer                 = pktl->next;
                    s->internal->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;
    
            if (!pkt->buf) {
                AVPacket tmp = { 0 };
                ret = av_packet_ref(&tmp, pkt);
                if (ret < 0)
                    return ret;
                *pkt = tmp;
            }
    
    
            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);
    
            st = s->streams[pkt->stream_index];
    
            switch (st->codecpar->codec_type) {
    
                if (s->video_codec_id)
    
                    st->codecpar->codec_id = s->video_codec_id;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                break;
    
                if (s->audio_codec_id)
    
                    st->codecpar->codec_id = s->audio_codec_id;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                break;
    
                if (s->subtitle_codec_id)
    
                    st->codecpar->codec_id = s->subtitle_codec_id;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                break;
            }
    
            if (!pktl && (st->codecpar->codec_id != AV_CODEC_ID_PROBE ||
    
                          !st->probe_packets))
    
            err = add_to_pktbuf(&s->internal->raw_packet_buffer, pkt,
                                &s->internal->raw_packet_buffer_end, 0);
            if (err)
                return err;
    
            s->internal->raw_packet_buffer_remaining_size -= pkt->size;
    
            if ((err = probe_codec(s, st, pkt)) < 0)
                return err;
    
    }
    
    /**********************************************************/
    
    
     * 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->internal->avctx->framerate :
                                                  (AVRational){ 0, 1 };
    
        int frame_size;
    
        *pnum = 0;
        *pden = 0;
    
        switch (st->codecpar->codec_type) {
    
            if (st->avg_frame_rate.num) {
                *pnum = st->avg_frame_rate.den;
                *pden = st->avg_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) {
                *pnum = codec_framerate.den;
                *pden = codec_framerate.num;
    
                if (pc && pc->repeat_pict) {
    
                    if (*pnum > INT_MAX / (1 + pc->repeat_pict))
                        *pden /= 1 + pc->repeat_pict;
                    else
                        *pnum *= 1 + pc->repeat_pict;
    
                /* 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->internal->avctx->ticks_per_frame > 1 && !pc)
    
            frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size);
            if (frame_size <= 0 || st->codecpar->sample_rate <= 0)
    
                break;
            *pnum = frame_size;
    
            *pden = st->codecpar->sample_rate;
    
    static int is_intra_only(enum AVCodecID id)
    {
        const AVCodecDescriptor *d = avcodec_descriptor_get(id);
        if (!d)
            return 0;
        if (d->type == AVMEDIA_TYPE_VIDEO && !(d->props & AV_CODEC_PROP_INTRA_ONLY))
            return 0;
        return 1;
    
    static void update_initial_timestamps(AVFormatContext *s, int stream_index,
                                          int64_t dts, int64_t pts)
    {
    
        AVStream *st       = s->streams[stream_index];
    
        AVPacketList *pktl = s->internal->packet_buffer;
    
        if (st->first_dts != AV_NOPTS_VALUE ||
            dts           == AV_NOPTS_VALUE ||
            st->cur_dts   == AV_NOPTS_VALUE)
    
        st->first_dts = dts - st->cur_dts;
        st->cur_dts   = dts;
    
        for (; pktl; pktl = pktl->next) {
            if (pktl->pkt.stream_index != stream_index)
    
            // FIXME: think more about this check
            if (pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts)
    
                pktl->pkt.pts += st->first_dts;
    
    
            if (pktl->pkt.dts != AV_NOPTS_VALUE)
    
                pktl->pkt.dts += st->first_dts;
    
            if (st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE)
                st->start_time = pktl->pkt.pts;
    
        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->internal->packet_buffer;
    
        int64_t cur_dts    = 0;
    
        if (st->first_dts != AV_NOPTS_VALUE) {
            cur_dts = st->first_dts;
            for (; pktl; pktl = pktl->next) {
                if (pktl->pkt.stream_index == stream_index) {
                    if (pktl->pkt.pts != pktl->pkt.dts  ||
                        pktl->pkt.dts != AV_NOPTS_VALUE ||
                        pktl->pkt.duration)
    
            pktl          = s->internal->packet_buffer;
    
        } else if (st->cur_dts)
    
        for (; pktl; pktl = pktl->next) {
            if (pktl->pkt.stream_index != stream_index)
    
            if (pktl->pkt.pts == pktl->pkt.dts  &&
                pktl->pkt.dts == AV_NOPTS_VALUE &&
                !pktl->pkt.duration) {
                pktl->pkt.dts = cur_dts;
    
                if (!st->internal->avctx->has_b_frames)
    
                    pktl->pkt.pts = cur_dts;
    
                if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
    
        if (st->first_dts == AV_NOPTS_VALUE)
            st->cur_dts = cur_dts;
    
    static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
    
                                   AVCodecParserContext *pc, AVPacket *pkt)
    {
    
        int num, den, presentation_delayed, delay, i;
    
        if (s->flags & AVFMT_FLAG_NOFILLIN)
            return;
    
    
        if ((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
            pkt->dts = AV_NOPTS_VALUE;
    
        /* do we have a video B-frame ? */
    
        delay = st->internal->avctx->has_b_frames;
    
        /* XXX: need has_b_frame, but cannot get it if the codec is
    
         *  not initialized */
    
            pc && pc->pict_type != AV_PICTURE_TYPE_B)
    
        if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE &&
            st->pts_wrap_bits < 63 &&
            pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) {
    
            pkt->dts -= 1LL << st->pts_wrap_bits;
    
        /* Some MPEG-2 in MPEG-PS lack dts (issue #171 / input_file.mpg).
         * We take the conservative approach and discard both.
         * Note: If this is misbehaving for an 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\n");
    
        if (pkt->duration == 0 && st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
    
            ff_compute_frame_duration(s, &num, &den, st, pc, pkt);
    
                pkt->duration = av_rescale_rnd(1, num * (int64_t) st->time_base.den,
                                               den * (int64_t) st->time_base.num,
                                               AV_ROUND_DOWN);
    
                if (pkt->duration != 0 && s->internal->packet_buffer)
    
                    update_initial_durations(s, st, pkt->stream_index,
                                             pkt->duration);
    
        /* Correct timestamps with byte offset if demuxers only have timestamps
         * on packet boundaries */
        if (pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size) {
    
            /* this will estimate bitrate based on this frame's duration and size */
            offset = av_rescale(pc->offset, pkt->duration, pkt->size);
    
            if (pkt->pts != AV_NOPTS_VALUE)
    
                pkt->pts += offset;
    
            if (pkt->dts != AV_NOPTS_VALUE)
    
    Diego Biurrun's avatar
    Diego Biurrun committed
        /* This may be redundant, but it should not hurt. */
    
        if (pkt->dts != AV_NOPTS_VALUE &&
            pkt->pts != AV_NOPTS_VALUE &&
            pkt->pts > pkt->dts)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            presentation_delayed = 1;
    
        av_log(NULL, AV_LOG_TRACE,
    
                "IN delayed:%d pts:%"PRId64", dts:%"PRId64" "
                "cur_dts:%"PRId64" st:%d pc:%p\n",
    
                presentation_delayed, pkt->pts, pkt->dts, st->cur_dts,
                pkt->stream_index, pc);
    
        /* Interpolate PTS and DTS if they are not present. We skip H.264
         * currently because delay and has_b_frames are not reliably set. */
        if ((delay == 0 || (delay == 1 && pc)) &&
    
            st->codecpar->codec_id != AV_CODEC_ID_H264) {
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            if (presentation_delayed) {
    
                /* DTS = decompression timestamp */
                /* PTS = presentation timestamp */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                if (pkt->dts == AV_NOPTS_VALUE)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    pkt->dts = st->last_IP_pts;
    
                update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                if (pkt->dts == AV_NOPTS_VALUE)
                    pkt->dts = st->cur_dts;
    
    
                /* This is tricky: the dts must be incremented by the duration
                 * of the frame we are displaying, i.e. the last I- or P-frame. */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                if (st->last_IP_duration == 0)
                    st->last_IP_duration = pkt->duration;
    
                if (pkt->dts != AV_NOPTS_VALUE)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    st->cur_dts = pkt->dts + st->last_IP_duration;
    
                st->last_IP_duration = pkt->duration;
                st->last_IP_pts      = pkt->pts;
                /* Cannot compute PTS if not present (we can compute it only
                 * by knowing the future. */
    
            } else if (pkt->pts != AV_NOPTS_VALUE ||
                       pkt->dts != AV_NOPTS_VALUE ||
                       pkt->duration              ||
    
                       st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
    
                if (!duration && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
    
                    ff_compute_frame_duration(s, &num, &den, st, pc, pkt);
    
                        duration = av_rescale_rnd(1,
                                                  num * (int64_t) st->time_base.den,
                                                  den * (int64_t) st->time_base.num,
                                                  AV_ROUND_DOWN);
    
                        if (duration != 0 && s->internal->packet_buffer)
    
                            update_initial_durations(s, st, pkt->stream_index,
                                                     duration);
                    }
                }
    
    
                if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE ||
                    duration) {
    
    Justin Ruggles's avatar
    Justin Ruggles committed
                    /* presentation is not delayed : PTS and DTS are the same */
                    if (pkt->pts == AV_NOPTS_VALUE)
                        pkt->pts = pkt->dts;
                    update_initial_timestamps(s, pkt->stream_index, pkt->pts,
                                              pkt->pts);
                    if (pkt->pts == AV_NOPTS_VALUE)
                        pkt->pts = st->cur_dts;
                    pkt->dts = pkt->pts;
                    if (pkt->pts != AV_NOPTS_VALUE)
                        st->cur_dts = pkt->pts + duration;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            }
    
        if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) {
            st->pts_buffer[0] = pkt->pts;
            for (i = 0; i<delay && st->pts_buffer[i] > st->pts_buffer[i + 1]; i++)
                FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]);
            if (pkt->dts == AV_NOPTS_VALUE)
                pkt->dts = st->pts_buffer[0];
            // We skipped it above so we try here.
    
            if (st->codecpar->codec_id == AV_CODEC_ID_H264)
    
                // This should happen on the first packet
                update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
            if (pkt->dts > st->cur_dts)
    
                st->cur_dts = pkt->dts;
        }
    
    
        av_log(NULL, AV_LOG_TRACE,
    
                "OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n",
                presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts);
    
        if (is_intra_only(st->codecpar->codec_id))
    
            pkt->flags |= AV_PKT_FLAG_KEY;
    
    #if FF_API_CONVERGENCE_DURATION
    FF_DISABLE_DEPRECATION_WARNINGS
    
        if (pc)
            pkt->convergence_duration = pc->convergence_duration;
    
    FF_ENABLE_DEPRECATION_WARNINGS
    #endif
    
    static void free_packet_buffer(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end)
    {
        while (*pkt_buf) {
            AVPacketList *pktl = *pkt_buf;
            *pkt_buf = pktl->next;
    
            av_packet_unref(&pktl->pkt);
    
            av_freep(&pktl);
        }
        *pkt_buf_end = NULL;
    }
    
    
     * Parse a packet, add all split parts to parse_queue.
    
     * @param pkt Packet to parse, NULL when flushing the parser at end of stream.
    
     */
    static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
    {
        AVPacket out_pkt = { 0 }, flush_pkt = { 0 };
    
        AVStream *st = s->streams[stream_index];
        uint8_t *data = pkt ? pkt->data : NULL;
        int size      = pkt ? pkt->size : 0;
    
        int ret = 0, got_output = 0;
    
        if (!pkt) {
            av_init_packet(&flush_pkt);
    
            pkt        = &flush_pkt;
    
            got_output = 1;
        }
    
        while (size > 0 || (pkt == &flush_pkt && got_output)) {
            int len;
    
            av_init_packet(&out_pkt);
    
            len = av_parser_parse2(st->parser, st->internal->avctx,
    
                                   &out_pkt.data, &out_pkt.size, data, size,
                                   pkt->pts, pkt->dts, pkt->pos);
    
            pkt->pts = pkt->dts = AV_NOPTS_VALUE;
            /* increment read pointer */
            data += len;
            size -= len;
    
            got_output = !!out_pkt.size;
    
            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->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
                if (st->internal->avctx->sample_rate > 0) {
    
                    out_pkt.duration =
                        av_rescale_q_rnd(st->parser->duration,
    
                                         (AVRational) { 1, st->internal->avctx->sample_rate },
    
                                         st->time_base,
                                         AV_ROUND_DOWN);
    
                }
            }
    
            out_pkt.stream_index = st->index;
    
            out_pkt.pts          = st->parser->pts;
            out_pkt.dts          = st->parser->dts;
            out_pkt.pos          = st->parser->pos;
    
    
            if (st->parser->key_frame == 1 ||
                (st->parser->key_frame == -1 &&
                 st->parser->pict_type == AV_PICTURE_TYPE_I))
                out_pkt.flags |= AV_PKT_FLAG_KEY;
    
            compute_pkt_fields(s, st, st->parser, &out_pkt);
    
            if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
                out_pkt.flags & AV_PKT_FLAG_KEY) {
                ff_reduce_index(s, st->index);
                av_add_index_entry(st, st->parser->frame_offset, out_pkt.dts,
                                   0, 0, AVINDEX_KEYFRAME);
            }
    
    
            if ((ret = add_to_pktbuf(&s->internal->parse_queue, &out_pkt,
                                     &s->internal->parse_queue_end,
                                     1))) {
    
                av_packet_unref(&out_pkt);
    
                goto fail;
            }
        }
    
        /* end of the stream => close and free the parser */
        if (pkt == &flush_pkt) {
            av_parser_close(st->parser);
            st->parser = NULL;
        }
    
    fail:
    
    static int read_from_packet_buffer(AVPacketList **pkt_buffer,
                                       AVPacketList **pkt_buffer_end,
                                       AVPacket      *pkt)
    {
        AVPacketList *pktl;
        av_assert0(*pkt_buffer);
    
        pktl        = *pkt_buffer;
        *pkt        = pktl->pkt;
    
        *pkt_buffer = pktl->next;
        if (!pktl->next)
            *pkt_buffer_end = NULL;
        av_freep(&pktl);
        return 0;
    }
    
    
    static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
    
        int ret = 0, i, got_packet = 0;
    
        av_init_packet(pkt);
    
    
        while (!got_packet && !s->internal->parse_queue) {
    
            AVStream *st;
            AVPacket cur_pkt;
    
            /* read next packet */
    
            ret = ff_read_packet(s, &cur_pkt);
    
            if (ret < 0) {
                if (ret == AVERROR(EAGAIN))
    
                /* flush the parsers */
    
                for (i = 0; i < s->nb_streams; i++) {
    
                    st = s->streams[i];
                    if (st->parser && st->need_parsing)
                        parse_packet(s, NULL, st->index);
    
                /* all remaining packets are now in parse_queue =>
                 * really terminate parsing */
                break;
            }
            ret = 0;
            st  = s->streams[cur_pkt.stream_index];
    
            if (cur_pkt.pts != AV_NOPTS_VALUE &&
                cur_pkt.dts != AV_NOPTS_VALUE &&
                cur_pkt.pts < cur_pkt.dts) {
    
                av_log(s, AV_LOG_WARNING,
                       "Invalid timestamps stream=%d, pts=%"PRId64", "
                       "dts=%"PRId64", size=%d\n",
                       cur_pkt.stream_index, cur_pkt.pts,
                       cur_pkt.dts, cur_pkt.size);
    
            }
            if (s->debug & FF_FDEBUG_TS)
    
                av_log(s, AV_LOG_DEBUG,
                       "ff_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", "
    
                       "size=%d, duration=%"PRId64", flags=%d\n",
    
                       cur_pkt.stream_index, cur_pkt.pts, cur_pkt.dts,
                       cur_pkt.size, cur_pkt.duration, cur_pkt.flags);
    
    
            if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {
    
                st->parser = av_parser_init(st->codecpar->codec_id);
    
                if (!st->parser)
    
                    /* no parser available: just output the raw packets */
                    st->need_parsing = AVSTREAM_PARSE_NONE;
    
                else if (st->need_parsing == AVSTREAM_PARSE_HEADERS)
    
                    st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
    
                else if (st->need_parsing == AVSTREAM_PARSE_FULL_ONCE)
    
                    st->parser->flags |= PARSER_FLAG_ONCE;
            }
    
            if (!st->need_parsing || !st->parser) {
                /* no parsing needed: we just output the packet as is */
                *pkt = cur_pkt;
                compute_pkt_fields(s, st, NULL, pkt);
                if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
                    (pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {
                    ff_reduce_index(s, st->index);
    
                    av_add_index_entry(st, pkt->pos, pkt->dts,
                                       0, 0, AVINDEX_KEYFRAME);
    
                got_packet = 1;
            } else if (st->discard < AVDISCARD_ALL) {
                if ((ret = parse_packet(s, &cur_pkt, cur_pkt.stream_index)) < 0)
                    return ret;
            } else {
                /* free packet */
    
                av_packet_unref(&cur_pkt);
    
        if (!got_packet && s->internal->parse_queue)
            ret = read_from_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt);
    
        av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata);
        if (metadata) {