Skip to content
Snippets Groups Projects
utils.c 147 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/internal.h"
    
    #include "libavcodec/raw.h"
    
    #include "libavutil/avassert.h"
    
    #include "libavutil/opt.h"
    
    #include "libavutil/dict.h"
    
    #include "libavutil/pixdesc.h"
    
    #include "metadata.h"
    
    #include "libavutil/avassert.h"
    
    #include "libavutil/avstring.h"
    
    #include "libavutil/mathematics.h"
    
    #include "libavutil/parseutils.h"
    
    #include "libavutil/time.h"
    
    #include "libavutil/timestamp.h"
    
    #include "audiointerleave.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)
    {
    
        av_assert0(LIBAVFORMAT_VERSION_MICRO >= 100);
    
        return LIBAVFORMAT_VERSION_INT;
    }
    
    
    const char *avformat_configuration(void)
    
    const char *avformat_license(void)
    
    {
    #define LICENSE_PREFIX "libavformat license: "
    
        return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
    
    #define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48))
    
        return ts > (RELATIVE_TS_BASE - (1LL<<48));
    
    /**
     * Wrap a given time stamp, if there is an indication for an overflow
     *
     * @param st stream
     * @param timestamp the time stamp to wrap
     * @return resulting time stamp
     */
    static int64_t wrap_timestamp(AVStream *st, int64_t timestamp)
    {
    
        if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE &&
    
            st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) {
            if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET &&
                timestamp < st->pts_wrap_reference)
    
                return timestamp + (1ULL<<st->pts_wrap_bits);
    
            else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET &&
                timestamp >= st->pts_wrap_reference)
    
                return timestamp - (1ULL<<st->pts_wrap_bits);
    
    /** head of registered input format linked list */
    
    static AVInputFormat *first_iformat = NULL;
    
    /** head of registered output format linked list */
    
    static AVOutputFormat *first_oformat = NULL;
    
    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 (!av_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 (!av_strncasecmp(name, names, len))
    
        return !av_strcasecmp(name, names);
    
    AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
                                    const char *mime_type)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
        AVOutputFormat *fmt = NULL, *fmt_found;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int score_max, score;
    
    
        /* specific test for image sequences */
    
    #if CONFIG_IMAGE2_MUXER
    
        if (!short_name && filename &&
    
            ff_guess_image2_codec(filename) != AV_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;
    
        while ((fmt = av_oformat_next(fmt))) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            score = 0;
    
            if (fmt->name && short_name && match_format(short_name, fmt->name))
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                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;
            }
        }
        return fmt_found;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
    
                                const char *filename, const char *mime_type, enum AVMediaType type){
        if(type == AVMEDIA_TYPE_VIDEO){
    
            enum AVCodecID codec_id= AV_CODEC_ID_NONE;
    
    #if CONFIG_IMAGE2_MUXER
    
            if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){
    
                codec_id= ff_guess_image2_codec(filename);
    
            if(codec_id == AV_CODEC_ID_NONE)
    
                codec_id= fmt->video_codec;
            return codec_id;
    
        }else if(type == AVMEDIA_TYPE_AUDIO)
    
            return fmt->audio_codec;
    
        else if (type == AVMEDIA_TYPE_SUBTITLE)
            return fmt->subtitle_codec;
    
            return AV_CODEC_ID_NONE;
    
    AVInputFormat *av_find_input_format(const char *short_name)
    {
    
        AVInputFormat *fmt = NULL;
        while ((fmt = av_iformat_next(fmt))) {
    
            if (match_format(short_name, fmt->name))
    
    int ffio_limit(AVIOContext *s, int size)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    {
    
            int64_t remaining= s->maxsize - avio_tell(s);
    
            if(remaining < size){
                int64_t newsize= avio_size(s);
                if(!s->maxsize || s->maxsize<newsize)
    
                    s->maxsize= newsize - !newsize;
    
                remaining= s->maxsize - avio_tell(s);
    
                av_log(NULL, remaining ? AV_LOG_ERROR : AV_LOG_DEBUG, "Truncating packet of size %d to %"PRId64"\n", size, remaining+1);
    
        return size;
    }
    
    int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
    {
        int ret;
    
        size= ffio_limit(s, size);
    
    
        ret= av_new_packet(pkt, size);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
        if(ret<0)
            return ret;
    
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    
        ret= avio_read(s, pkt->data, size);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        if(ret<=0)
            av_free_packet(pkt);
        else
    
        if (pkt->size < orig_size)
            pkt->flags |= AV_PKT_FLAG_CORRUPT;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
        return ret;
    }
    
    
    int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
    
    {
        int ret;
        int old_size;
        if (!pkt->size)
            return av_get_packet(s, pkt, size);
        old_size = pkt->size;
        ret = av_grow_packet(pkt, size);
        if (ret < 0)
            return ret;
    
        ret = avio_read(s, pkt->data + old_size, size);
    
        av_shrink_packet(pkt, old_size + FFMAX(ret, 0));
        return ret;
    }
    
    
    int av_filename_number_test(const char *filename)
    
        return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0);
    
    AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret)
    
        AVInputFormat *fmt1 = NULL, *fmt;
    
        const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
    
        if (!lpd.buf)
            lpd.buf = zerobuffer;
    
        if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
            int id3len = ff_id3v2_tag_len(lpd.buf);
            if (lpd.buf_size > id3len + 16) {
                lpd.buf += id3len;
                lpd.buf_size -= id3len;
    
        while ((fmt1 = av_iformat_next(fmt1))) {
    
            if (!is_opened == !(fmt1->flags & AVFMT_NOFILE))
    
                if(fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions))
    
                    score = FFMAX(score, nodat ? AVPROBE_SCORE_MAX/4-1 : 1);
    
                if (av_match_ext(lpd.filename, fmt1->extensions)) {
    
            if (score > score_max) {
                score_max = score;
    
            }else if (score == score_max)
    
        *score_ret= score_max;
    
    AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)
    {
        int score_ret;
        AVInputFormat *fmt= av_probe_input_format3(pd, is_opened, &score_ret);
        if(score_ret > *score_max){
            *score_max= score_ret;
            return fmt;
        }else
            return 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)
    
            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 },
    
            { "loas"     , AV_CODEC_ID_AAC_LATM  , AVMEDIA_TYPE_AUDIO },
    
            { "m4v"      , AV_CODEC_ID_MPEG4     , AVMEDIA_TYPE_VIDEO },
            { "mp3"      , AV_CODEC_ID_MP3       , AVMEDIA_TYPE_AUDIO },
            { "mpegvideo", AV_CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO },
    
        int score;
        AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score);
    
        if (fmt && st->request_probe <= score) {
    
            av_log(s, AV_LOG_DEBUG, "Probe with size=%d, packets=%d detected %s with score=%d\n",
                   pd->buf_size, MAX_PROBE_PACKETS - st->probe_packets, fmt->name, score);
    
            for (i = 0; fmt_id_type[i].name; i++) {
                if (!strcmp(fmt->name, fmt_id_type[i].name)) {
                    st->codec->codec_id   = fmt_id_type[i].id;
                    st->codec->codec_type = fmt_id_type[i].type;
                    break;
                }
    
        return score;
    
    /************************************************************/
    /* input media file */
    
    int av_demuxer_open(AVFormatContext *ic){
    
        int err;
    
        if (ic->iformat->read_header) {
    
            err = ic->iformat->read_header(ic);
    
            if (err < 0)
                return err;
        }
    
        if (ic->pb && !ic->data_offset)
            ic->data_offset = avio_tell(ic->pb);
    
        return 0;
    }
    
    
    
    /** size of probe buffer, for guessing file type from file contents */
    
    #define PROBE_BUF_MAX (1<<20)
    
    int av_probe_input_buffer(AVIOContext *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;
    
        uint8_t *mime_type;
    
        int ret = 0, probe_size, buf_offset = 0;
    
    
        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);
        }
    
    
        if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) {
    
            if (!av_strcasecmp(mime_type, "audio/aacp")) {
    
                *fmt = av_find_input_format("aac");
            }
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_freep(&mime_type);
    
        for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt;
    
            probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) {
    
            int score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
    
    
            if (probe_size < offset) {
                continue;
            }
    
            /* read probe data */
    
            buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
            if(!buftmp){
                av_free(buf);
                return AVERROR(ENOMEM);
            }
            buf=buftmp;
    
            if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) {
    
                /* fail if error was not end of file, otherwise, lower score */
                if (ret != AVERROR_EOF) {
                    av_free(buf);
                    return ret;
                }
                score = 0;
    
                ret = 0;            /* error was end of file, nothing read */
    
            pd.buf_size = buf_offset += 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_RETRY){ //this can only be true in the last iteration
    
                    av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, misdetection possible!\n", (*fmt)->name, score);
    
                    av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score);
    
        /* rewind. reuse probe buffer to avoid seeking */
    
        ret = ffio_rewind_with_probe_data(pb, &buf, pd.buf_size);
    
    /* open input file and probe the format if necessary */
    
    static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options)
    
    {
        int ret;
        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)
    
                av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
                                          "will be ignored with AVFMT_NOFILE format.\n");
    
        if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
    
            (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
    
    Reimar Döffinger's avatar
    Reimar Döffinger committed
        if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
    
                              &s->interrupt_callback, options)) < 0)
    
            return ret;
    
        return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize);
    
    static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
                                   AVPacketList **plast_pktl){
        AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
        if (!pktl)
            return NULL;
    
        if (*packet_buffer)
            (*plast_pktl)->next = pktl;
        else
            *packet_buffer = pktl;
    
        /* add the packet in the buffered packet list */
        *plast_pktl = pktl;
        pktl->pkt= *pkt;
        return &pktl->pkt;
    }
    
    
    void avformat_queue_attached_pictures(AVFormatContext *s)
    
    {
        int i;
        for (i = 0; i < s->nb_streams; i++)
    
            if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC &&
                s->streams[i]->discard < AVDISCARD_ALL) {
    
                AVPacket copy = s->streams[i]->attached_pic;
                copy.destruct = NULL;
                add_to_pktbuf(&s->raw_packet_buffer, &copy, &s->raw_packet_buffer_end);
            }
    }
    
    
    int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
    {
        AVFormatContext *s = *ps;
    
        ID3v2ExtraMeta *id3v2_extra_meta = NULL;
    
    
        if (!s && !(s = avformat_alloc_context()))
            return AVERROR(ENOMEM);
    
            av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
    
        if (fmt)
            s->iformat = fmt;
    
        if (options)
            av_dict_copy(&tmp, *options, 0);
    
        if ((ret = av_opt_set_dict(s, &tmp)) < 0)
            goto fail;
    
    
        if ((ret = init_input(s, filename, &tmp)) < 0)
    
        avio_skip(s->pb, s->skip_initial_bytes);
    
    
        /* check filename in case an image number is expected */
        if (s->iformat->flags & AVFMT_NEEDNUMBER) {
            if (!av_filename_number_test(filename)) {
                ret = AVERROR(EINVAL);
    
        }
    
        s->duration = s->start_time = AV_NOPTS_VALUE;
    
        av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
    
    
        /* allocate private data */
        if (s->iformat->priv_data_size > 0) {
            if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
                ret = AVERROR(ENOMEM);
    
            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 (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
    
            if ((ret = s->iformat->read_header(s)) < 0)
    
        if (id3v2_extra_meta) {
            if (!strcmp(s->iformat->name, "mp3")) {
                if((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
                    goto fail;
            } else
    
    Clément Bœsch's avatar
    Clément Bœsch committed
                av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");
    
        ff_id3v2_free_extra_meta(&id3v2_extra_meta);
    
    
        avformat_queue_attached_pictures(s);
    
        if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
    
            s->data_offset = avio_tell(s->pb);
    
        s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
    
        if (options) {
            av_dict_free(options);
            *options = tmp;
    
        ff_id3v2_free_extra_meta(&id3v2_extra_meta);
    
        av_dict_free(&tmp);
        if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
            avio_close(s->pb);
        avformat_free_context(s);
        *ps = NULL;
        return ret;
    
    /*******************************************************/
    
    
    static void force_codec_ids(AVFormatContext *s, AVStream *st)
    {
        switch(st->codec->codec_type){
        case AVMEDIA_TYPE_VIDEO:
            if(s->video_codec_id)   st->codec->codec_id= s->video_codec_id;
            break;
        case AVMEDIA_TYPE_AUDIO:
            if(s->audio_codec_id)   st->codec->codec_id= s->audio_codec_id;
            break;
        case AVMEDIA_TYPE_SUBTITLE:
            if(s->subtitle_codec_id)st->codec->codec_id= s->subtitle_codec_id;
            break;
        }
    }
    
    
    static void probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
    {
    
        if(st->request_probe>0){
    
            AVProbeData *pd = &st->probe_data;
    
            int end;
            av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets);
    
            --st->probe_packets;
    
    
                uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
                if(!new_buf)
                    goto no_packet;
                pd->buf = new_buf;
    
                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);
            } else {
    
                    av_log(s, AV_LOG_WARNING, "nothing to probe for stream %d\n",
    
            end=    s->raw_packet_buffer_remaining_size <= 0
                    || st->probe_packets<=0;
    
            if(end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){
                int score= set_codec_from_probe_data(s, st, pd);
    
                if(    (st->codec->codec_id != AV_CODEC_ID_NONE && score > AVPROBE_SCORE_RETRY)
    
                    pd->buf_size=0;
                    av_freep(&pd->buf);
    
                    st->request_probe= -1;
    
                    if(st->codec->codec_id != AV_CODEC_ID_NONE){
    
                        av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
                    }else
                        av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index);
    
                force_codec_ids(s, st);
    
    int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
    
        AVStream *st;
    
    
        for(;;){
            AVPacketList *pktl = s->raw_packet_buffer;
    
            if (pktl) {
                *pkt = pktl->pkt;
    
                st = s->streams[pkt->stream_index];
    
                if(st->request_probe <= 0){
    
                    s->raw_packet_buffer = pktl->next;
    
                    s->raw_packet_buffer_remaining_size += pkt->size;
    
            pkt->data = NULL;
            pkt->size = 0;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_init_packet(pkt);
            ret= s->iformat->read_packet(s, pkt);
    
            if (ret < 0) {
                if (!pktl || ret == AVERROR(EAGAIN))
                    return ret;
    
                for (i = 0; i < s->nb_streams; i++) {
                    st = s->streams[i];
                    if (st->probe_packets) {
                        probe_codec(s, st, NULL);
                    }
    
                    av_assert0(st->request_probe <= 0);
    
            if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) &&
                (pkt->flags & AV_PKT_FLAG_CORRUPT)) {
                av_log(s, AV_LOG_WARNING,
                       "Dropped corrupted packet (stream = %d)\n",
                       pkt->stream_index);
    
                av_free_packet(pkt);
    
            if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))
                av_packet_merge_side_data(pkt);
    
            if(pkt->stream_index >= (unsigned)s->nb_streams){
                av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index);
                continue;
            }
    
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            st= s->streams[pkt->stream_index];
    
            pkt->dts = wrap_timestamp(st, pkt->dts);
            pkt->pts = wrap_timestamp(st, pkt->pts);
    
            force_codec_ids(s, st);
    
    
            /* TODO: audio: time filter; video: frame reordering (pts != dts) */
            if (s->use_wallclock_as_timestamps)
                pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
    
            if(!pktl && st->request_probe <= 0)
    
            add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);
    
            s->raw_packet_buffer_remaining_size -= pkt->size;
    
            probe_codec(s, st, pkt);
    
    #if FF_API_READ_PACKET
    int av_read_packet(AVFormatContext *s, AVPacket *pkt)
    {
        return ff_read_packet(s, pkt);
    }
    #endif
    
    
    
    /**********************************************************/
    
    
    static int determinable_frame_size(AVCodecContext *avctx)
    {
    
        if (/*avctx->codec_id == AV_CODEC_ID_AAC ||*/
            avctx->codec_id == AV_CODEC_ID_MP1 ||
            avctx->codec_id == AV_CODEC_ID_MP2 ||
            avctx->codec_id == AV_CODEC_ID_MP3/* ||
            avctx->codec_id == AV_CODEC_ID_CELT*/)
    
     * Get the number of samples of an audio frame. Return -1 on error.
    
    int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux)
    
        /* give frame_size priority if demuxing */
        if (!mux && enc->frame_size > 1)
            return enc->frame_size;
    
        if ((frame_size = av_get_audio_frame_duration(enc, size)) > 0)
            return frame_size;
    
        /* fallback to using frame_size if muxing */
        if (enc->frame_size > 1)
            return enc->frame_size;
    
    
        //For WMA we currently have no other means to calculate duration thus we
        //do it here by assuming CBR, which is true for all known cases.
        if(!mux && enc->bit_rate>0 && size>0 && enc->sample_rate>0 && enc->block_align>1) {
            if (enc->codec_id == AV_CODEC_ID_WMAV1 || enc->codec_id == AV_CODEC_ID_WMAV2)
                return  ((int64_t)size * 8 * enc->sample_rate) / enc->bit_rate;
        }
    
    
     * Return the frame duration in seconds. Return 0 if not available.
    
    void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st,
                                   AVCodecParserContext *pc, AVPacket *pkt)
    
    {
        int frame_size;
    
        *pnum = 0;
        *pden = 0;
    
            if (st->r_frame_rate.num && !pc) {
    
                *pnum = st->r_frame_rate.den;
                *pden = st->r_frame_rate.num;
            } else if(st->time_base.num*1000LL > st->time_base.den) {
    
                *pnum = st->time_base.num;
                *pden = st->time_base.den;
    
            }else if(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) {
    
                    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->codec->ticks_per_frame>1 && !pc){
                    *pnum = *pden = 0;
                }
    
            frame_size = ff_get_audio_frame_size(st->codec, pkt->size, 0);
    
            if (frame_size <= 0 || st->codec->sample_rate <= 0)
    
                break;
            *pnum = frame_size;
    
    static int is_intra_only(AVCodecContext *enc){
    
    
        desc = av_codec_get_codec_descriptor(enc);
        if (!desc) {
            desc = avcodec_descriptor_get(enc->codec_id);
            av_codec_set_codec_descriptor(enc, desc);
    
        if (desc)
            return !!(desc->props & AV_CODEC_PROP_INTRA_ONLY);
    
    static int has_decode_delay_been_guessed(AVStream *st)
    {
    
        if(st->codec->codec_id != AV_CODEC_ID_H264) return 1;
    
        if(!st->info) // if we have left find_stream_info then nb_decoded_frames wont increase anymore for stream copy
            return 1;
    
    #if CONFIG_H264_DECODER
        if(st->codec->has_b_frames &&
           avpriv_h264_has_num_reorder_frames(st->codec) == st->codec->has_b_frames)
            return 1;
    #endif
        if(st->codec->has_b_frames<3)
    
            return st->nb_decoded_frames >= 7;
    
            return st->nb_decoded_frames >= 18;
    
            return st->nb_decoded_frames >= 20;
    
    static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList *pktl)
    {
        if (pktl->next)
            return pktl->next;
        if (pktl == s->parse_queue_end)
            return s->packet_buffer;
        return NULL;
    }
    
    
    static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index)
    {
    
        if (s->correct_ts_overflow && st->pts_wrap_bits < 63 &&
    
            st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) {
            int i;
    
            // reference time stamp should be 60 s before first time stamp
            int64_t pts_wrap_reference = st->first_dts - av_rescale(60, st->time_base.den, st->time_base.num);
            // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
            int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
                (st->first_dts < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
                AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
    
            AVProgram *first_program = av_find_program_from_stream(s, NULL, stream_index);
    
            if (!first_program) {
                int default_stream_index = av_find_default_stream_index(s);
                if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
                    for (i=0; i<s->nb_streams; i++) {
                        s->streams[i]->pts_wrap_reference = pts_wrap_reference;
                        s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
                    }
                }
                else {
                    st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
                    st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
                }
            }
            else {
                AVProgram *program = first_program;
                while (program) {
                    if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
                        pts_wrap_reference = program->pts_wrap_reference;
                        pts_wrap_behavior = program->pts_wrap_behavior;
                        break;
                    }
                    program = av_find_program_from_stream(s, program, stream_index);
                }
    
                // update every program with differing pts_wrap_reference
                program = first_program;
                while(program) {
                    if (program->pts_wrap_reference != pts_wrap_reference) {
                        for (i=0; i<program->nb_stream_indexes; i++) {
                            s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
                            s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
                        }
    
                        program->pts_wrap_reference = pts_wrap_reference;
                        program->pts_wrap_behavior = pts_wrap_behavior;
                    }
                    program = av_find_program_from_stream(s, program, stream_index);
                }
            }
            return 1;
        }
        return 0;
    }
    
    
    static void update_initial_timestamps(AVFormatContext *s, int stream_index,
    
                                          int64_t dts, int64_t pts, AVPacket *pkt)
    
        AVStream *st= s->streams[stream_index];
    
        AVPacketList *pktl= s->parse_queue ? s->parse_queue : s->packet_buffer;
    
        int64_t pts_buffer[MAX_REORDER_DELAY+1];