Skip to content
Snippets Groups Projects
utils.c 86.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Fabrice Bellard's avatar
    Fabrice Bellard committed
    /*
     * Various utilities for ffmpeg system
    
     * 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 "opt.h"
    
    #include "avstring.h"
    
    #include <sys/time.h>
    #include <time.h>
    
    #undef NDEBUG
    #include <assert.h>
    
    
    /**
     * @file libavformat/utils.c
     * Various utility functions for using ffmpeg library.
     */
    
    
    static void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den);
    static void av_frac_add(AVFrac *f, int64_t incr);
    
    
    /** head of registered input format linked list. */
    
    /** head of registered output format linked list. */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    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 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;
    }
    
    
    AVOutputFormat *guess_format(const char *short_name, const char *filename,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int score_max, score;
    
    
        /* specific test for image sequences */
    
    #ifdef CONFIG_IMAGE2_MUXER
    
        if (!short_name && filename &&
    
            av_guess_image2_codec(filename) != CODEC_ID_NONE) {
            return guess_format("image2", NULL, NULL);
        }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        /* find the proper file type */
        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 &&
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                match_ext(filename, fmt->extensions)) {
                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
    
    
    AVOutputFormat *guess_stream_format(const char *short_name, const char *filename,
    
                                 const char *mime_type)
    {
        AVOutputFormat *fmt = 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 = guess_format(stream_format_name, NULL, NULL);
    
            if (stream_fmt)
                fmt = stream_fmt;
        }
    
        return fmt;
    }
    
    
    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;
    
    
    #ifdef 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 (!strcmp(fmt->name, short_name))
                return fmt;
        }
        return NULL;
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* memory handling */
    
    
    {
        av_free(pkt->data);
        pkt->data = NULL; pkt->size = 0;
    }
    
    
    Ramiro Polla's avatar
    Ramiro Polla committed
    void av_init_packet(AVPacket *pkt)
    {
        pkt->pts   = AV_NOPTS_VALUE;
        pkt->dts   = AV_NOPTS_VALUE;
        pkt->pos   = -1;
        pkt->duration = 0;
        pkt->flags = 0;
        pkt->stream_index = 0;
        pkt->destruct= av_destruct_packet_nofree;
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    int av_new_packet(AVPacket *pkt, int size)
    {
    
        if((unsigned)size > (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
    
        data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
    
        memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
    
        pkt->data = data;
    
        pkt->size = size;
        pkt->destruct = av_destruct_packet;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        return 0;
    }
    
    
    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
            pkt->size= ret;
    
        return ret;
    }
    
    
    int av_dup_packet(AVPacket *pkt)
    {
        if (pkt->destruct != av_destruct_packet) {
            uint8_t *data;
    
            /* we duplicate the packet and don't forget to put the padding
               again */
    
            if((unsigned)pkt->size > (unsigned)pkt->size + FF_INPUT_BUFFER_PADDING_SIZE)
    
            data = av_malloc(pkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
    
            }
            memcpy(data, pkt->data, pkt->size);
    
            memset(data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
    
            pkt->data = data;
            pkt->destruct = av_destruct_packet;
        }
        return 0;
    }
    
    
    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 (match_ext(pd->filename, fmt1->extensions)) {
                    score = 50;
                }
    
    AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened){
        int score=0;
        return av_probe_input_format2(pd, is_opened, &score);
    }
    
    
    /************************************************************/
    /* input media file */
    
     * Open a media file from an IO stream. 'fmt' must be specified.
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    static const char* format_to_name(void* ptr)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        AVFormatContext* fc = (AVFormatContext*) ptr;
    
        if(fc->iformat) return fc->iformat->name;
        else if(fc->oformat) return fc->oformat->name;
        else return "NULL";
    }
    
    
    #define OFFSET(x) offsetof(AVFormatContext,x)
    
    Diego Biurrun's avatar
    Diego Biurrun committed
    #define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C
    
    //these names are too long to be readable
    #define E AV_OPT_FLAG_ENCODING_PARAM
    #define D AV_OPT_FLAG_DECODING_PARAM
    
    static const AVOption options[]={
    
    {"probesize", NULL, OFFSET(probesize), FF_OPT_TYPE_INT, 32000, 32, INT_MAX, D}, /* 32000 from mpegts.c: 1.0 second at 24Mbit/s */
    
    {"muxrate", "set mux rate", OFFSET(mux_rate), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E},
    
    {"packetsize", "set packet size", OFFSET(packet_size), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E},
    
    {"fflags", NULL, OFFSET(flags), FF_OPT_TYPE_FLAGS, DEFAULT, INT_MIN, INT_MAX, D|E, "fflags"},
    
    {"ignidx", "ignore index", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_IGNIDX, INT_MIN, INT_MAX, D, "fflags"},
    {"genpts", "generate pts", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_GENPTS, INT_MIN, INT_MAX, D, "fflags"},
    
    {"track", " set the track number", OFFSET(track), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E},
    
    {"year", "set the year", OFFSET(year), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, E},
    
    {"analyzeduration", "how many microseconds are analyzed to estimate duration", OFFSET(max_analyze_duration), FF_OPT_TYPE_INT, 3*AV_TIME_BASE, 0, INT_MAX, D},
    
    static const AVClass av_format_context_class = { "AVFormatContext", format_to_name, options };
    
    
    static void avformat_get_context_defaults(AVFormatContext *s)
    {
    
        memset(s, 0, sizeof(AVFormatContext));
    
        s->av_class = &av_format_context_class;
    
        av_opt_set_defaults(s);
    
    
    AVFormatContext *av_alloc_format_context(void)
    {
        AVFormatContext *ic;
    
        ic = av_malloc(sizeof(AVFormatContext));
    
        avformat_get_context_defaults(ic);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        ic->av_class = &av_format_context_class;
    
    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 = av_alloc_format_context();
        else
            ic = *ic_ptr;
    
            goto fail;
        }
        ic->iformat = fmt;
        if (pb)
            ic->pb = *pb;
        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) {
    
                goto fail;
            }
        } else {
            ic->priv_data = NULL;
        }
    
        err = ic->iformat->read_header(ic, ap);
        if (err < 0)
            goto fail;
    
        if (pb && !ic->data_offset)
    
            ic->data_offset = url_ftell(&ic->pb);
    
    
        *ic_ptr = ic;
        return 0;
     fail:
        if (ic) {
            av_freep(&ic->priv_data);
        }
        av_free(ic);
        *ic_ptr = NULL;
        return err;
    }
    
    
    /** Size of probe buffer, for guessing file type from file contents. */
    
    #define PROBE_BUF_MAX (1<<20)
    
    int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
        int err, must_open_file, file_opened, probe_size;
    
        ByteIOContext pb1, *pb = &pb1;
    
        file_opened = 0;
        pd->filename = "";
        if (filename)
            pd->filename = filename;
    
        pd->buf_size = 0;
    
        if (!fmt) {
            /* 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 */
        must_open_file = 1;
    
        if (fmt && (fmt->flags & AVFMT_NOFILE)) {
    
            must_open_file = 0;
    
    Diego Biurrun's avatar
    Diego Biurrun committed
            pb= NULL; //FIXME this or memset(pb, 0, sizeof(ByteIOContext)); otherwise it is uninitialized
    
        }
    
        if (!fmt || must_open_file) {
    
            /* if no file needed do not try to open one */
    
            if ((err=url_fopen(pb, filename, URL_RDONLY)) < 0) {
    
            if (buf_size > 0) {
    
    
            for(probe_size= PROBE_BUF_MIN; probe_size<=PROBE_BUF_MAX && !fmt; probe_size<<=1){
    
                int score= probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX/4 : 0;
    
                pd->buf= av_realloc(pd->buf, probe_size + AVPROBE_PADDING_SIZE);
    
                pd->buf_size = get_buffer(pb, pd->buf, probe_size);
    
                if (url_fseek(pb, 0, SEEK_SET) < 0) {
    
                    url_fclose(pb);
                    if (url_fopen(pb, filename, URL_RDONLY) < 0) {
    
                fmt = av_probe_input_format2(pd, 1, &score);
    
        }
    
        /* if still no format found, error */
        if (!fmt) {
            err = AVERROR_NOFMT;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
        /* XXX: suppress this hack for redirectors */
    
    #ifdef CONFIG_REDIR_DEMUXER
    
        if (fmt == &redir_demuxer) {
    
            err = redir_open(ic_ptr, pb);
            url_fclose(pb);
    
        /* check filename in case of 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:
    
    /*******************************************************/
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    int av_read_packet(AVFormatContext *s, AVPacket *pkt)
    
        av_init_packet(pkt);
    
        return s->iformat->read_packet(s, pkt);
    }
    
    /**********************************************************/
    
    
    /**
     * Get the number of samples of an audio frame. Return (-1) if 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 = (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) {
                    *pden *= 2;
                    *pnum = (*pnum) * (2 + 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:
                return 1;
            default: break;
            }
        }
        return 0;
    }
    
    
    static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
    
                                   AVCodecParserContext *pc, AVPacket *pkt)
    {
    
        int num, den, presentation_delayed, delay, i;
    
        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);
    
        /* 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;
        }
    
    
        /* do we have a video B frame ? */
    
        delay= st->codec->has_b_frames;
    
        presentation_delayed = 0;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        /* 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;
    
    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;
    
        if(st->cur_dts == AV_NOPTS_VALUE){
    
            st->cur_dts = -delay * pkt->duration;
    
    //    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 */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        if(delay <=1){
            if (presentation_delayed) {
                /* DTS = decompression time stamp */
                /* PTS = presentation time stamp */
                if (pkt->dts == AV_NOPTS_VALUE)
                    pkt->dts = st->last_IP_pts;
                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 */
                if (st->last_IP_duration == 0)
                    st->last_IP_duration = pkt->duration;
                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 futur */
    
            } 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;
                if(pkt->pts == AV_NOPTS_VALUE)
                    pkt->pts = st->cur_dts;
                pkt->dts = pkt->pts;
                st->cur_dts = pkt->pts + pkt->duration;
            }
    
    
        if(pkt->pts != AV_NOPTS_VALUE){
            st->pts_buffer[0]= pkt->pts;
            for(i=1; i<delay+1 && st->pts_buffer[i] == AV_NOPTS_VALUE; i++)
                st->pts_buffer[i]= (i-delay-1) * pkt->duration;
            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(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);
    
        /* update flags */
        if (pc) {
            pkt->flags = 0;
            /* key frame computation */
                if (pc->pict_type == FF_I_TYPE)
                    pkt->flags |= PKT_FLAG_KEY;
        }
    }
    
    
    void av_destruct_packet_nofree(AVPacket *pkt)
    
    {
        pkt->data = NULL; pkt->size = 0;
    }
    
    static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt)
    {
        AVStream *st;
    
        av_init_packet(pkt);
    
    
        for(;;) {
            /* select current input stream component */
            st = s->cur_st;
            if (st) {
    
                    /* no parsing needed: we just output the packet as is */
                    /* raw data support */
                    *pkt = s->cur_pkt;
                    compute_pkt_fields(s, st, NULL, pkt);
                    s->cur_st = NULL;
    
                } else if (s->cur_len > 0 && st->discard < AVDISCARD_ALL) {
    
                    len = av_parser_parse(st->parser, st->codec, &pkt->data, &pkt->size,
    
                                          s->cur_ptr, s->cur_len,
                                          s->cur_pkt.pts, s->cur_pkt.dts);
                    s->cur_pkt.pts = AV_NOPTS_VALUE;
                    s->cur_pkt.dts = AV_NOPTS_VALUE;
    
                    /* increment read pointer */
                    s->cur_ptr += len;
                    s->cur_len -= len;
    
                    /* return packet if any */
                    if (pkt->size) {
    
                        pkt->pos = s->cur_pkt.pos;              // Isn't quite accurate but close.
    
                        pkt->duration = 0;
                        pkt->stream_index = st->index;
    
                        pkt->pts = st->parser->pts;
                        pkt->dts = st->parser->dts;
    
                        pkt->destruct = av_destruct_packet_nofree;
                        compute_pkt_fields(s, st, st->parser, pkt);
    
    
                        if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & PKT_FLAG_KEY){
                            av_add_index_entry(st, st->parser->frame_offset, pkt->dts,
                                               0, 0, AVINDEX_KEYFRAME);
                        }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    /* free packet */
    
                    av_free_packet(&s->cur_pkt);
    
                    s->cur_st = NULL;
                }
            } else {
                /* read next packet */
                ret = av_read_packet(s, &s->cur_pkt);
    
                        return ret;
                    /* return the last frames, if any */
                    for(i = 0; i < s->nb_streams; i++) {
                        st = s->streams[i];
    
                            av_parser_parse(st->parser, st->codec,
                                            &pkt->data, &pkt->size,
                                            NULL, 0,
    
                            if (pkt->size)
                                goto got_packet;
                        }
                    }
                    /* no more packets: really terminates parsing */
    
                st = s->streams[s->cur_pkt.stream_index];
    
                if(st->codec->debug & FF_DEBUG_PTS)
    
                    av_log(s, AV_LOG_DEBUG, "av_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d\n",
    
                        s->cur_pkt.stream_index,
                        s->cur_pkt.pts,
                        s->cur_pkt.dts,
                        s->cur_pkt.size);
    
    
                s->cur_st = st;
                s->cur_ptr = s->cur_pkt.data;
                s->cur_len = s->cur_pkt.size;
                if (st->need_parsing && !st->parser) {
    
                    st->parser = av_parser_init(st->codec->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;
    
                    if(st->parser && (s->iformat->flags & AVFMT_GENERIC_INDEX)){
                        st->parser->last_frame_offset=
                        st->parser->cur_offset= s->cur_pkt.pos;
                    }
    
        if(st->codec->debug & FF_DEBUG_PTS)
    
            av_log(s, AV_LOG_DEBUG, "av_read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d\n",
    
                pkt->stream_index,
                pkt->pts,
                pkt->dts,
                pkt->size);
    
        return 0;
    
    }
    
    int av_read_frame(AVFormatContext *s, AVPacket *pkt)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        AVPacketList *pktl;
    
        int eof=0;
        const int genpts= s->flags & AVFMT_FLAG_GENPTS;
    
        for(;;){
            pktl = s->packet_buffer;
            if (pktl) {
                AVPacket *next_pkt= &pktl->pkt;
    
                if(genpts && next_pkt->dts != AV_NOPTS_VALUE){
                    while(pktl && next_pkt->pts == AV_NOPTS_VALUE){
    
                        if(   pktl->pkt.stream_index == next_pkt->stream_index
    
                           && next_pkt->dts < pktl->pkt.dts
                           && pktl->pkt.pts != pktl->pkt.dts //not b frame
                           /*&& pktl->pkt.dts != AV_NOPTS_VALUE*/){
                            next_pkt->pts= pktl->pkt.dts;
                        }
                        pktl= pktl->next;
                    }
                    pktl = s->packet_buffer;
                }
    
    
                if(   next_pkt->pts != AV_NOPTS_VALUE
                   || next_pkt->dts == AV_NOPTS_VALUE
    
                   || !genpts || eof){
                    /* read packet from packet buffer, if there is data */
                    *pkt = *next_pkt;
                    s->packet_buffer = pktl->next;
                    av_free(pktl);
                    return 0;
                }
            }
            if(genpts){
                AVPacketList **plast_pktl= &s->packet_buffer;
                int ret= av_read_frame_internal(s, pkt);
                if(ret<0){
    
                    if(pktl && ret != AVERROR(EAGAIN)){
    
                /* duplicate the packet */
                if (av_dup_packet(pkt) < 0)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
                while(*plast_pktl) plast_pktl= &(*plast_pktl)->next; //FIXME maybe maintain pointer to the last?
    
                pktl = av_mallocz(sizeof(AVPacketList));
                if (!pktl)
    
                /* add the packet in the buffered packet list */
                *plast_pktl = pktl;
    
                pktl->pkt= *pkt;
    
            }else{
                assert(!s->packet_buffer);
                return av_read_frame_internal(s, pkt);
            }
    
        }
    }
    
    /* XXX: suppress the packet queue */
    static void flush_packet_queue(AVFormatContext *s)
    {
        AVPacketList *pktl;
    
        for(;;) {
            pktl = s->packet_buffer;
    
                break;
            s->packet_buffer = pktl->next;
            av_free_packet(&pktl->pkt);
            av_free(pktl);
    
    /*******************************************************/
    /* seek support */
    
    
    int av_find_default_stream_index(AVFormatContext *s)
    {
        int i;
        AVStream *st;
    
        if (s->nb_streams <= 0)
            return -1;
        for(i = 0; i < s->nb_streams; i++) {
            st = s->streams[i];
    
            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
    
    static void av_read_frame_flush(AVFormatContext *s)
    {
        AVStream *st;
        int i;
    
        flush_packet_queue(s);
    
        /* free previous packet */
        if (s->cur_st) {
            if (s->cur_st->parser)
                av_free_packet(&s->cur_pkt);
            s->cur_st = NULL;
        }
        /* fail safe */
        s->cur_ptr = NULL;
        s->cur_len = 0;
    
        /* for each stream, reset read state */
        for(i = 0; i < s->nb_streams; i++) {
            st = s->streams[i];
    
            if (st->parser) {
                av_parser_close(st->parser);
                st->parser = NULL;
            }
    
            st->last_IP_pts = AV_NOPTS_VALUE;
    
            st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */
    
    void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp){
    
        int i;
    
        for(i = 0; i < s->nb_streams; i++) {
    
            st->cur_dts = av_rescale(timestamp,
    
                                     st->time_base.den * (int64_t)ref_st->time_base.num,
                                     st->time_base.num * (int64_t)ref_st->time_base.den);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                                int64_t pos, int64_t timestamp, int size, int distance, int flags)
    
    {
        AVIndexEntry *entries, *ie;
    
        if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
            return -1;
    
        entries = av_fast_realloc(st->index_entries,
                                  &st->index_entries_allocated_size,
    
                                  (st->nb_index_entries + 1) *
    
                                  sizeof(AVIndexEntry));
    
        if(!entries)
            return -1;
    
    
        index= av_index_search_timestamp(st, timestamp, AVSEEK_FLAG_ANY);
    
        if(index<0){
    
            index= st->nb_index_entries++;
            ie= &entries[index];
    
            assert(index==0 || ie[-1].timestamp < timestamp);
        }else{
            ie= &entries[index];
            if(ie->timestamp != timestamp){
    
                if(ie->timestamp <= timestamp)
                    return -1;
    
                memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index));
                st->nb_index_entries++;
    
    Diego Biurrun's avatar
    Diego Biurrun committed
            }else if(ie->pos == pos && distance < ie->min_distance) //do not reduce the distance
    
                distance= ie->min_distance;
    
        ie->pos = pos;
        ie->timestamp = timestamp;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        ie->size= size;
    
    int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp,