Skip to content
Snippets Groups Projects
utils.c 111 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
     */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    #include "avformat.h"
    
    #include "libavcodec/opt.h"
    
    #include "metadata.h"
    
    #include "libavutil/avstring.h"
    
    #include "audiointerleave.h"
    
    #include <sys/time.h>
    #include <time.h>
    
    #include <strings.h>
    
    #include <stdarg.h>
    #if CONFIG_NETWORK
    #include "network.h"
    #endif
    
    #undef NDEBUG
    #include <assert.h>
    
    
     * various utility functions for use within FFmpeg
    
    unsigned avformat_version(void)
    {
        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;
    }
    
    
    /* fraction handling */
    
    /**
     * f = val + (num / den) + 0.5.
     *
     * 'num' is normalized so that it is such as 0 <= num < den.
     *
     * @param f fractional number
     * @param val integer value
     * @param num must be >= 0
     * @param den must be >= 1
     */
    static void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den)
    {
        num += (den >> 1);
        if (num >= den) {
            val += num / den;
            num = num % den;
        }
        f->val = val;
        f->num = num;
        f->den = den;
    }
    
    /**
     * Fractional addition to f: f = f + (incr / f->den).
     *
     * @param f fractional number
     * @param incr increment, can be positive or negative
     */
    static void av_frac_add(AVFrac *f, int64_t incr)
    {
        int64_t num, den;
    
        num = f->num + incr;
        den = f->den;
        if (num < 0) {
            f->val += num / den;
            num = num % den;
            if (num < 0) {
                num += den;
                f->val--;
            }
        } else if (num >= den) {
            f->val += num / den;
            num = num % den;
        }
        f->num = num;
    }
    
    /** head of registered input format linked list */
    
    /** head of registered output format linked list */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    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)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
        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;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        while (*p != NULL) p = &(*p)->next;
        *p = format;
        format->next = NULL;
    }
    
    
    int av_match_ext(const char *filename, const char *extensions)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        const char *ext, *p;
        char ext1[32], *q;
    
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        if(!filename)
            return 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        ext = strrchr(filename, '.');
        if (ext) {
            ext++;
            p = extensions;
            for(;;) {
                q = ext1;
    
                while (*p != '\0' && *p != ',' && q-ext1<sizeof(ext1)-1)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    *q++ = *p++;
                *q = '\0';
    
                if (!strcasecmp(ext1, ext))
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    return 1;
    
                if (*p == '\0')
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    break;
                p++;
            }
        }
        return 0;
    }
    
    
    static int match_format(const char *name, const char *names)
    {
        const char *p;
        int len, namelen;
    
        if (!name || !names)
            return 0;
    
        namelen = strlen(name);
        while ((p = strchr(names, ','))) {
            len = FFMAX(p - names, namelen);
            if (!strncasecmp(name, names, len))
                return 1;
            names = p+1;
        }
        return !strcasecmp(name, names);
    }
    
    
    #if LIBAVFORMAT_VERSION_MAJOR < 53
    
    AVOutputFormat *guess_format(const char *short_name, const char *filename,
    
    {
        return av_guess_format(short_name, filename, mime_type);
    }
    #endif
    
    AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
                                    const char *mime_type)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int score_max, score;
    
    
        /* specific test for image sequences */
    
    #if CONFIG_IMAGE2_MUXER
    
        if (!short_name && filename &&
    
            av_guess_image2_codec(filename) != CODEC_ID_NONE) {
    
            return av_guess_format("image2", NULL, NULL);
    
        /* Find the proper file type. */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        fmt_found = NULL;
        score_max = 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        while (fmt != NULL) {
            score = 0;
            if (fmt->name && short_name && !strcmp(fmt->name, short_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)) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                score += 5;
            }
            if (score > score_max) {
                score_max = score;
                fmt_found = fmt;
            }
            fmt = fmt->next;
        }
        return fmt_found;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    #if LIBAVFORMAT_VERSION_MAJOR < 53
    
    AVOutputFormat *guess_stream_format(const char *short_name, const char *filename,
    
        AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
    
    
        if (fmt) {
            AVOutputFormat *stream_fmt;
            char stream_format_name[64];
    
            snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
    
            stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
    
    enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
    
                                const char *filename, const char *mime_type, enum CodecType type){
        if(type == CODEC_TYPE_VIDEO){
            enum CodecID codec_id= CODEC_ID_NONE;
    
    
    #if CONFIG_IMAGE2_MUXER
    
            if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){
    
                codec_id= av_guess_image2_codec(filename);
            }
    
            if(codec_id == CODEC_ID_NONE)
                codec_id= fmt->video_codec;
            return codec_id;
        }else if(type == CODEC_TYPE_AUDIO)
            return fmt->audio_codec;
        else
            return CODEC_ID_NONE;
    }
    
    
    AVInputFormat *av_find_input_format(const char *short_name)
    {
        AVInputFormat *fmt;
        for(fmt = first_iformat; fmt != NULL; fmt = fmt->next) {
    
            if (match_format(short_name, fmt->name))
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* memory handling */
    
    
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size)
    {
        int ret= av_new_packet(pkt, size);
    
        if(ret<0)
            return ret;
    
        pkt->pos= url_ftell(s);
    
        ret= get_buffer(s, pkt->data, size);
        if(ret<=0)
            av_free_packet(pkt);
        else
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
        return ret;
    }
    
    
    int av_filename_number_test(const char *filename)
    
        return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0);
    
    static AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)
    
    
        fmt = NULL;
        for(fmt1 = first_iformat; fmt1 != NULL; fmt1 = fmt1->next) {
    
            if (!is_opened == !(fmt1->flags & AVFMT_NOFILE))
    
            if (fmt1->read_probe) {
                score = fmt1->read_probe(pd);
            } else if (fmt1->extensions) {
    
                if (av_match_ext(pd->filename, fmt1->extensions)) {
    
            }else if (score == *score_max)
                fmt = NULL;
    
    AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened){
        int score=0;
        return av_probe_input_format2(pd, is_opened, &score);
    }
    
    
    static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd, int score)
    
    {
        AVInputFormat *fmt;
        fmt = av_probe_input_format2(pd, 1, &score);
    
        if (fmt) {
    
            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);
    
                st->codec->codec_type = CODEC_TYPE_AUDIO;
            } else if (!strcmp(fmt->name, "ac3")) {
    
                st->codec->codec_type = CODEC_TYPE_AUDIO;
    
            } else if (!strcmp(fmt->name, "eac3")) {
                st->codec->codec_id = CODEC_ID_EAC3;
                st->codec->codec_type = CODEC_TYPE_AUDIO;
    
            } else if (!strcmp(fmt->name, "mpegvideo")) {
    
                st->codec->codec_id = CODEC_ID_MPEG2VIDEO;
    
                st->codec->codec_type = CODEC_TYPE_VIDEO;
    
            } else if (!strcmp(fmt->name, "m4v")) {
                st->codec->codec_id = CODEC_ID_MPEG4;
                st->codec->codec_type = CODEC_TYPE_VIDEO;
    
            } else if (!strcmp(fmt->name, "h264")) {
    
                st->codec->codec_id = CODEC_ID_H264;
    
                st->codec->codec_type = CODEC_TYPE_VIDEO;
    
            } else if (!strcmp(fmt->name, "dts")) {
                st->codec->codec_id = CODEC_ID_DTS;
                st->codec->codec_type = CODEC_TYPE_AUDIO;
    
    /************************************************************/
    /* input media file */
    
     * Open a media file from an IO stream. 'fmt' must be specified.
    
    int av_open_input_stream(AVFormatContext **ic_ptr,
                             ByteIOContext *pb, const char *filename,
    
                             AVInputFormat *fmt, AVFormatParameters *ap)
    {
        int err;
        AVFormatContext *ic;
    
        AVFormatParameters default_ap;
    
        if(!ap){
            ap=&default_ap;
            memset(ap, 0, sizeof(default_ap));
        }
    
        if(!ap->prealloced_context)
    
        ic->duration = AV_NOPTS_VALUE;
        ic->start_time = AV_NOPTS_VALUE;
    
        av_strlcpy(ic->filename, filename, sizeof(ic->filename));
    
    
        /* allocate private data */
        if (fmt->priv_data_size > 0) {
            ic->priv_data = av_mallocz(fmt->priv_data_size);
            if (!ic->priv_data) {
    
            err = ic->iformat->read_header(ic, ap);
            if (err < 0)
                goto fail;
    
        if (pb && !ic->data_offset)
    
            ic->data_offset = url_ftell(ic->pb);
    
    #if LIBAVFORMAT_VERSION_MAJOR < 53
        ff_metadata_demux_compat(ic);
    #endif
    
    
        ic->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
    
    
            for(i=0;i<ic->nb_streams;i++) {
                AVStream *st = ic->streams[i];
                if (st) {
                    av_free(st->priv_data);
                    av_free(st->codec->extradata);
                }
                av_free(st);
            }
    
    /** size of probe buffer, for guessing file type from file contents */
    
    #define PROBE_BUF_MAX (1<<20)
    
    int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt,
                              const char *filename, void *logctx,
                              unsigned int offset, unsigned int max_probe_size)
    {
        AVProbeData pd = { filename ? filename : "", NULL, -offset };
        unsigned char *buf = NULL;
        int ret = 0, probe_size;
    
        if (!max_probe_size) {
            max_probe_size = PROBE_BUF_MAX;
        } else if (max_probe_size > PROBE_BUF_MAX) {
            max_probe_size = PROBE_BUF_MAX;
        } else if (max_probe_size < PROBE_BUF_MIN) {
            return AVERROR(EINVAL);
        }
    
        if (offset >= max_probe_size) {
            return AVERROR(EINVAL);
        }
    
        for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt && ret >= 0; probe_size<<=1){
            int ret, score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX/4 : 0;
            int buf_offset = (probe_size == PROBE_BUF_MIN) ? 0 : probe_size>>1;
    
            if (probe_size < offset) {
                continue;
            }
    
            /* read probe data */
            buf = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
            if ((ret = get_buffer(*pb, buf + buf_offset, probe_size - buf_offset)) < 0) {
                /* fail if error was not end of file, otherwise, lower score */
                if (ret != AVERROR_EOF) {
                    av_free(buf);
                    return ret;
                }
                score = 0;
    
                ret = 0;            /* error was end of file, nothing read */
    
            }
            pd.buf_size += ret;
            pd.buf = &buf[offset];
    
            memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
    
            /* guess file format */
            *fmt = av_probe_input_format2(&pd, 1, &score);
            if(*fmt){
                if(score <= AVPROBE_SCORE_MAX/4){ //this can only be true in the last iteration
                    av_log(logctx, AV_LOG_WARNING, "Format detected only with low score of %d, misdetection possible!\n", score);
                }else
                    av_log(logctx, AV_LOG_DEBUG, "Probed with size=%d and score=%d\n", probe_size, score);
            }
        }
    
        av_free(buf);
        if (url_fseek(*pb, 0, SEEK_SET) < 0) {
            url_fclose(*pb);
            if (url_fopen(pb, filename, URL_RDONLY) < 0)
                return AVERROR(EIO);
        }
    
        return 0;
    }
    
    
    int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
        ByteIOContext *pb = NULL;
    
        void *logctx= ap && ap->prealloced_context ? *ic_ptr : NULL;
    
        pd->filename = "";
        if (filename)
            pd->filename = filename;
    
            /* guess format if no file can be opened */
    
            fmt = av_probe_input_format(pd, 0);
    
        /* Do not open file if the format does not need it. XXX: specific
    
           hack needed to handle RTSP/TCP */
    
        if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
    
            /* if no file needed do not try to open one */
    
            if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0) {
    
            if (buf_size > 0) {
    
            if ((err = ff_probe_input_buffer(&pb, &fmt, filename, logctx, 0, 0)) < 0) {
                goto fail;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
        /* check filename in case an image number is expected */
    
        if (fmt->flags & AVFMT_NEEDNUMBER) {
    
                err = AVERROR_NUMEXPECTED;
    
        err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap);
        if (err)
            goto fail;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     fail:
    
        if (pb)
    
        if (ap && ap->prealloced_context)
            av_free(*ic_ptr);
        *ic_ptr = NULL;
    
    /*******************************************************/
    
    
    static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
                                   AVPacketList **plast_pktl){
        AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
    
        if (*packet_buffer)
            (*plast_pktl)->next = pktl;
        else
            *packet_buffer = pktl;
    
    
        /* add the packet in the buffered packet list */
        *plast_pktl = pktl;
        pktl->pkt= *pkt;
        return &pktl->pkt;
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    int av_read_packet(AVFormatContext *s, AVPacket *pkt)
    
        AVStream *st;
    
    
        for(;;){
            AVPacketList *pktl = s->raw_packet_buffer;
    
            if (pktl) {
                *pkt = pktl->pkt;
    
                if(s->streams[pkt->stream_index]->codec->codec_id != CODEC_ID_PROBE ||
    
                   !s->streams[pkt->stream_index]->probe_packets ||
                   s->raw_packet_buffer_remaining_size < pkt->size){
                    AVProbeData *pd = &s->streams[pkt->stream_index]->probe_data;
                    av_freep(&pd->buf);
                    pd->buf_size = 0;
    
                    s->raw_packet_buffer = pktl->next;
    
                    s->raw_packet_buffer_remaining_size += pkt->size;
    
    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++)
                    s->streams[i]->probe_packets = 0;
                continue;
            }
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            st= s->streams[pkt->stream_index];
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            switch(st->codec->codec_type){
            case CODEC_TYPE_VIDEO:
                if(s->video_codec_id)   st->codec->codec_id= s->video_codec_id;
                break;
            case CODEC_TYPE_AUDIO:
                if(s->audio_codec_id)   st->codec->codec_id= s->audio_codec_id;
                break;
            case CODEC_TYPE_SUBTITLE:
                if(s->subtitle_codec_id)st->codec->codec_id= s->subtitle_codec_id;
                break;
            }
    
            if(!pktl && (st->codec->codec_id != CODEC_ID_PROBE ||
                         !st->probe_packets))
    
            add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);
    
            s->raw_packet_buffer_remaining_size -= pkt->size;
    
            if(st->codec->codec_id == CODEC_ID_PROBE){
                AVProbeData *pd = &st->probe_data;
    
                av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index);
    
                pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
                memcpy(pd->buf+pd->buf_size, pkt->data, pkt->size);
                pd->buf_size += pkt->size;
                memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE);
    
    
                if(av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){
    
                    set_codec_from_probe_data(s, st, pd, 1);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    if(st->codec->codec_id != CODEC_ID_PROBE){
                        pd->buf_size=0;
                        av_freep(&pd->buf);
    
                        av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    }
    
    }
    
    /**********************************************************/
    
    
     * Get the number of samples of an audio frame. Return -1 on error.
    
    static int get_audio_frame_size(AVCodecContext *enc, int size)
    {
        int frame_size;
    
    
        if (enc->frame_size <= 1) {
    
            int bits_per_sample = av_get_bits_per_sample(enc->codec_id);
    
            if (bits_per_sample) {
    
                if (enc->channels == 0)
                    return -1;
    
                frame_size = (size << 3) / (bits_per_sample * enc->channels);
    
                /* used for example by ADPCM codecs */
                if (enc->bit_rate == 0)
                    return -1;
    
                frame_size = ((int64_t)size * 8 * enc->sample_rate) / enc->bit_rate;
    
            }
        } else {
            frame_size = enc->frame_size;
        }
        return frame_size;
    }
    
    
    
     * Return the frame duration in seconds. Return 0 if not available.
    
    static void compute_frame_duration(int *pnum, int *pden, AVStream *st,
    
                                       AVCodecParserContext *pc, AVPacket *pkt)
    {
        int frame_size;
    
        *pnum = 0;
        *pden = 0;
    
        case CODEC_TYPE_VIDEO:
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            if(st->time_base.num*1000LL > st->time_base.den){
    
                *pnum = st->time_base.num;
                *pden = st->time_base.den;
    
            }else if(st->codec->time_base.num*1000LL > st->codec->time_base.den){
                *pnum = st->codec->time_base.num;
                *pden = st->codec->time_base.den;
    
                if (pc && pc->repeat_pict) {
    
                    *pnum = (*pnum) * (1 + pc->repeat_pict);
    
            }
            break;
        case CODEC_TYPE_AUDIO:
    
            frame_size = get_audio_frame_size(st->codec, pkt->size);
    
            if (frame_size < 0)
                break;
            *pnum = frame_size;
    
    static int is_intra_only(AVCodecContext *enc){
        if(enc->codec_type == CODEC_TYPE_AUDIO){
            return 1;
        }else if(enc->codec_type == CODEC_TYPE_VIDEO){
            switch(enc->codec_id){
            case CODEC_ID_MJPEG:
            case CODEC_ID_MJPEGB:
            case CODEC_ID_LJPEG:
            case CODEC_ID_RAWVIDEO:
            case CODEC_ID_DVVIDEO:
            case CODEC_ID_HUFFYUV:
    
            case CODEC_ID_FFVHUFF:
    
            case CODEC_ID_ASV1:
            case CODEC_ID_ASV2:
            case CODEC_ID_VCR1:
    
            case CODEC_ID_DNXHD:
    
            case CODEC_ID_JPEG2000:
    
    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->packet_buffer;
    
    
        if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE)
    
            return;
    
        st->first_dts= dts - st->cur_dts;
        st->cur_dts= dts;
    
        for(; pktl; pktl= pktl->next){
            if(pktl->pkt.stream_index != stream_index)
                continue;
            //FIXME think more about this check
            if(pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts)
                pktl->pkt.pts += st->first_dts;
    
            if(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, AVPacket *pkt)
    {
        AVPacketList *pktl= s->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 == pkt->stream_index){
                    if(pktl->pkt.pts != pktl->pkt.dts || pktl->pkt.dts != AV_NOPTS_VALUE || pktl->pkt.duration)
                        break;
                    cur_dts -= pkt->duration;
                }
            }
            pktl= s->packet_buffer;
            st->first_dts = cur_dts;
        }else if(st->cur_dts)
            return;
    
    
        for(; pktl; pktl= pktl->next){
            if(pktl->pkt.stream_index != pkt->stream_index)
                continue;
    
            if(pktl->pkt.pts == pktl->pkt.dts && pktl->pkt.dts == AV_NOPTS_VALUE
               && !pktl->pkt.duration){
    
                    pktl->pkt.pts= cur_dts;
                cur_dts += pkt->duration;
    
        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_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
            pkt->dts= AV_NOPTS_VALUE;
    
    
        if (st->codec->codec_id != CODEC_ID_H264 && pc && pc->pict_type == FF_B_TYPE)
    
            //FIXME Set low_delay = 0 when has_b_frames = 1
    
            st->codec->has_b_frames = 1;
    
    
        /* do we have a video B-frame ? */
        delay= st->codec->has_b_frames;
        presentation_delayed = 0;
        /* XXX: need has_b_frame, but cannot get it if the codec is
            not initialized */
        if (delay &&
            pc && pc->pict_type != FF_B_TYPE)
            presentation_delayed = 1;
    
    
        if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && pkt->dts > pkt->pts && st->pts_wrap_bits<63
           /*&& pkt->dts-(1LL<<st->pts_wrap_bits) < pkt->pts*/){
            pkt->dts -= 1LL<<st->pts_wrap_bits;
        }
    
    
        // some mpeg2 in mpeg-ps lack dts (issue171 / input_file.mpg)
        // we take the conservative approach and discard both
        // Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly.
        if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){
    
            av_log(s, AV_LOG_WARNING, "invalid dts/pts combination\n");
    
        if (pkt->duration == 0) {
    
            compute_frame_duration(&num, &den, st, pc, pkt);
    
                pkt->duration = av_rescale(1, num * (int64_t)st->time_base.den, den * (int64_t)st->time_base.num);
    
                if(pkt->duration != 0 && s->packet_buffer)
    
        /* 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)
                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
            }
        }
    
    
    Diego Biurrun's avatar
    Diego Biurrun committed
        /* This may be redundant, but it should not hurt. */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts)
            presentation_delayed = 1;
    
    //    av_log(NULL, AV_LOG_DEBUG, "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 H264 currently because delay and has_b_frames are not reliably set
        if((delay==0 || (delay==1 && pc)) && st->codec->codec_id != 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;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                st->last_IP_duration  = pkt->duration;
                st->last_IP_pts= pkt->pts;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                /* 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){
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                if(pkt->pts != AV_NOPTS_VALUE && pkt->duration){
                    int64_t old_diff= FFABS(st->cur_dts - pkt->duration - pkt->pts);
                    int64_t new_diff= FFABS(st->cur_dts - pkt->pts);
                    if(old_diff < new_diff && old_diff < (pkt->duration>>3)){
                        pkt->pts += pkt->duration;
        //                av_log(NULL, AV_LOG_DEBUG, "id:%d old:%"PRId64" new:%"PRId64" dur:%d cur:%"PRId64" size:%d\n", pkt->stream_index, old_diff, new_diff, pkt->duration, st->cur_dts, pkt->size);
                    }
    
    Michael Niedermayer's avatar
    Michael Niedermayer 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);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                if(pkt->pts == AV_NOPTS_VALUE)
                    pkt->pts = st->cur_dts;
                pkt->dts = pkt->pts;
    
                if(pkt->pts != AV_NOPTS_VALUE)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    st->cur_dts = pkt->pts + pkt->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];
    
            if(st->codec->codec_id == CODEC_ID_H264){ //we skiped it above so we try here
    
                update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); // this should happen on the first packet
    
            if(pkt->dts > st->cur_dts)
                st->cur_dts = pkt->dts;
        }
    
    //    av_log(NULL, AV_LOG_ERROR, "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->codec))
            pkt->flags |= PKT_FLAG_KEY;
        else if (pc) {
    
            /* keyframe computation */
    
            if (pc->key_frame == 1)
                pkt->flags |= PKT_FLAG_KEY;
            else if (pc->key_frame == -1 && pc->pict_type == FF_I_TYPE)
                pkt->flags |= PKT_FLAG_KEY;
    
        if (pc)
            pkt->convergence_duration = pc->convergence_duration;
    
    }
    
    
    static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt)
    {
        AVStream *st;