Skip to content
Snippets Groups Projects
utils.c 106 KiB
Newer Older
  • Learn to ignore specific revisions
  • #define MAX_STD_TIMEBASES (60*12+5)
    
    static int get_std_framerate(int i){
        if(i<60*12) return i*1001;
    
        else        return ((const int[]){24,30,60,12,15})[i-60*12]*1000*12;
    
    /*
     * Is the time base unreliable.
     * This is a heuristic to balance between quick acceptance of the values in
     * the headers vs. some extra checks.
    
     * Old DivX and Xvid often have nonsense timebases like 1fps or 2fps.
     * MPEG-2 commonly misuses field repeat flags to store different framerates.
    
     * And there are "variable" fps files this needs to detect as well.
     */
    static int tb_unreliable(AVCodecContext *c){
        if(   c->time_base.den >= 101L*c->time_base.num
           || c->time_base.den <    5L*c->time_base.num
    
    /*       || c->codec_tag == AV_RL32("DIVX")
           || c->codec_tag == AV_RL32("XVID")*/
    
           || c->codec_id == CODEC_ID_MPEG2VIDEO
           || c->codec_id == CODEC_ID_H264
           )
    
        int i, count, ret, read_size, j;
    
        int64_t last_dts[MAX_STREAMS];
    
        int duration_count[MAX_STREAMS]={0};
    
        double (*duration_error)[MAX_STD_TIMEBASES];
    
        int64_t old_offset = url_ftell(ic->pb);
    
        int64_t codec_info_duration[MAX_STREAMS]={0};
        int codec_info_nb_frames[MAX_STREAMS]={0};
    
        duration_error = av_mallocz(MAX_STREAMS * sizeof(*duration_error));
    
        if (!duration_error) return AVERROR(ENOMEM);
    
        for(i=0;i<ic->nb_streams;i++) {
            st = ic->streams[i];
    
            if(st->codec->codec_type == CODEC_TYPE_VIDEO){
    
    /*            if(!st->time_base.num)
                    st->time_base= */
    
                if(!st->codec->time_base.num)
                    st->codec->time_base= st->time_base;
    
                st->parser = av_parser_init(st->codec->codec_id);
    
                if(st->need_parsing == AVSTREAM_PARSE_HEADERS && st->parser){
    
                    st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
                }
    
        for(i=0;i<MAX_STREAMS;i++){
            last_dts[i]= AV_NOPTS_VALUE;
        }
    
            if(url_interrupt_cb()){
                ret= AVERROR(EINTR);
    
                av_log(ic, AV_LOG_DEBUG, "interrupted\n");
    
            /* check if one codec still needs to be handled */
            for(i=0;i<ic->nb_streams;i++) {
                st = ic->streams[i];
    
                /* variable fps and no guess at the real fps */
    
                if(   tb_unreliable(st->codec)
    
                   && duration_count[i]<20 && st->codec->codec_type == CODEC_TYPE_VIDEO)
    
                if(st->parser && st->parser->parser->split && !st->codec->extradata)
    
                if(st->first_dts == AV_NOPTS_VALUE)
                    break;
    
            }
            if (i == ic->nb_streams) {
                /* NOTE: if the format has no header, then we need to read
                   some packets to get most of the streams, so we cannot
                   stop here */
    
                if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) {
    
                    /* if we found the info for all the codecs, we can stop */
                    ret = count;
    
                    av_log(ic, AV_LOG_DEBUG, "All info found\n");
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            /* we did not get all the codec info, but we read too much data */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                ret = count;
    
                av_log(ic, AV_LOG_WARNING, "MAX_READ_SIZE:%d reached\n", ic->probesize);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                break;
            }
    
            /* NOTE: a new stream can be added there if no header in file
               (AVFMTCTX_NOHEADER) */
            ret = av_read_frame_internal(ic, &pkt1);
    
            if(ret == AVERROR(EAGAIN))
                continue;
    
            if (ret < 0) {
                /* EOF or error */
                ret = -1; /* we could not have all the codec parameters before EOF */
    
                for(i=0;i<ic->nb_streams;i++) {
                    st = ic->streams[i];
    
                    if (!has_codec_parameters(st->codec)){
                        char buf[256];
                        avcodec_string(buf, sizeof(buf), st->codec, 0);
    
                        av_log(ic, AV_LOG_WARNING, "Could not find codec parameters (%s)\n", buf);
    
            pkt= add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end);
    
            if(av_dup_packet(pkt) < 0) {
                av_free(duration_error);
    
            read_size += pkt->size;
    
            if(codec_info_nb_frames[st->index]>1) {
    
                if (st->time_base.den > 0 && av_rescale_q(codec_info_duration[st->index], st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration){
    
                    av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n");
    
                codec_info_duration[st->index] += pkt->duration;
    
            if (pkt->duration != 0)
    
                codec_info_nb_frames[st->index]++;
    
                int index= pkt->stream_index;
                int64_t last= last_dts[index];
                int64_t duration= pkt->dts - last;
    
                if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && duration>0){
    
                    double dur= duration * av_q2d(st->time_base);
    
    //                if(st->codec->codec_type == CODEC_TYPE_VIDEO)
    //                    av_log(NULL, AV_LOG_ERROR, "%f\n", dur);
    
                    if(duration_count[index] < 2)
    
                        memset(duration_error[index], 0, sizeof(*duration_error));
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    for(i=1; i<MAX_STD_TIMEBASES; i++){
                        int framerate= get_std_framerate(i);
                        int ticks= lrintf(dur*framerate/(1001*12));
                        double error= dur - ticks*1001*12/(double)framerate;
                        duration_error[index][i] += error*error;
                    }
    
                    duration_count[index]++;
    
                    // ignore the first 4 values, they might have some random jitter
                    if (duration_count[index] > 3)
                        duration_gcd[index] = av_gcd(duration_gcd[index], duration);
    
                if(last == AV_NOPTS_VALUE || duration_count[index]<=1)
                    last_dts[pkt->stream_index]= pkt->dts;
    
            if(st->parser && st->parser->parser->split && !st->codec->extradata){
                int i= st->parser->parser->split(st->codec, pkt->data, pkt->size);
    
                    st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
    
                    memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size);
    
                    memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
    
            /* if still no information, we try to open the codec and to
               decompress the frame. We try to avoid that in most cases as
    
               it takes longer and uses more memory. For MPEG-4, we need to
               decompress for QuickTime. */
    
            if (!has_codec_parameters(st->codec))
    
                try_decode_frame(st, pkt);
    
    Diego Biurrun's avatar
    Diego Biurrun committed
        // close codecs which were opened in try_decode_frame()
    
        for(i=0;i<ic->nb_streams;i++) {
            st = ic->streams[i];
    
            if(st->codec->codec)
                avcodec_close(st->codec);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            if(codec_info_nb_frames[i]>2)
                av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
                         (codec_info_nb_frames[i]-2)*(int64_t)st->time_base.den,
                          codec_info_duration[i]    *(int64_t)st->time_base.num, 60000);
    
            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
    
                if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample)
    
                    st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
    
                // the check for tb_unreliable() is not completely correct, since this is not about handling
                // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
                // ipmovie.c produces.
                if (tb_unreliable(st->codec) && duration_count[i] > 15 && duration_gcd[i] > 1)
                    av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * duration_gcd[i], INT_MAX);
    
                   && tb_unreliable(st->codec) /*&&
    
                   //FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ...
    
                   st->time_base.num*duration_sum[i]/duration_count[i]*101LL > st->time_base.den*/){
    
                    double best_error= 2*av_q2d(st->time_base);
                    best_error= best_error*best_error*duration_count[i]*1000*12*30;
    
                    for(j=1; j<MAX_STD_TIMEBASES; j++){
                        double error= duration_error[i][j] * get_std_framerate(j);
    //                    if(st->codec->codec_type == CODEC_TYPE_VIDEO)
    //                        av_log(NULL, AV_LOG_ERROR, "%f %f\n", get_std_framerate(j) / 12.0/1001, error);
    
                        if(error < best_error){
                            best_error= error;
    
                    // do not increase frame rate by more than 1 % in order to match a standard rate.
                    if (num && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate)))
                        av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX);
    
                if (!st->r_frame_rate.num){
    
                    if(    st->codec->time_base.den * (int64_t)st->time_base.num
    
                        <= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t)st->time_base.den){
    
                        st->r_frame_rate.num = st->codec->time_base.den;
    
                        st->r_frame_rate.den = st->codec->time_base.num * st->codec->ticks_per_frame;
    
                    }else{
                        st->r_frame_rate.num = st->time_base.den;
                        st->r_frame_rate.den = st->time_base.num;
                    }
    
            }else if(st->codec->codec_type == CODEC_TYPE_AUDIO) {
    
                if(!st->codec->bits_per_coded_sample)
                    st->codec->bits_per_coded_sample= av_get_bits_per_sample(st->codec->codec_id);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
        av_estimate_timings(ic, old_offset);
    
        /* correct DTS for B-frame streams with no timestamps */
    
        for(i=0;i<ic->nb_streams;i++) {
            st = ic->streams[i];
    
            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
    
                if(b-frames){
                    ppktl = &ic->packet_buffer;
                    while(ppkt1){
                        if(ppkt1->stream_index != i)
                            continue;
                        if(ppkt1->pkt->dts < 0)
                            break;
                        if(ppkt1->pkt->pts != AV_NOPTS_VALUE)
                            break;
                        ppkt1->pkt->dts -= delta;
                        ppkt1= ppkt1->next;
                    }
                    if(ppkt1)
                        continue;
                    st->cur_dts -= delta;
                }
            }
        }
    #endif
    
    /*******************************************************/
    
    int av_read_play(AVFormatContext *s)
    {
    
        if (s->iformat->read_play)
            return s->iformat->read_play(s);
    
            return av_url_read_fpause(s->pb, 0);
    
    }
    
    int av_read_pause(AVFormatContext *s)
    {
    
        if (s->iformat->read_pause)
            return s->iformat->read_pause(s);
    
            return av_url_read_fpause(s->pb, 1);
    
    void av_close_input_stream(AVFormatContext *s)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        for(i=0;i<s->nb_streams;i++) {
    
            /* free all data in a stream component */
            st = s->streams[i];
    
            if (st->parser) {
                av_parser_close(st->parser);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
    
            av_metadata_free(&st->metadata);
    
            av_free(st->index_entries);
    
            av_free(st->codec->extradata);
    
    #if LIBAVFORMAT_VERSION_INT < (53<<16)
    
            av_free(st->filename);
    
    #endif
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
    #if LIBAVFORMAT_VERSION_INT < (53<<16)
    
            av_freep(&s->programs[i]->provider_name);
            av_freep(&s->programs[i]->name);
    
    #endif
    
            av_metadata_free(&s->programs[i]->metadata);
    
            av_freep(&s->programs[i]->stream_index);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        av_freep(&s->programs);
    
    #if LIBAVFORMAT_VERSION_INT < (53<<16)
    
            av_free(s->chapters[s->nb_chapters]->title);
    
    #endif
    
            av_metadata_free(&s->chapters[s->nb_chapters]->metadata);
    
        }
        av_freep(&s->chapters);
    
        av_metadata_free(&s->metadata);
    
        av_free(s);
    
    void av_close_input_file(AVFormatContext *s)
    {
        ByteIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb;
        av_close_input_stream(s);
        if (pb)
            url_fclose(pb);
    }
    
    
    AVStream *av_new_stream(AVFormatContext *s, int id)
    {
        AVStream *st;
    
    
        if (s->nb_streams >= MAX_STREAMS)
            return NULL;
    
        st = av_mallocz(sizeof(AVStream));
        if (!st)
            return NULL;
    
        if (s->iformat) {
            /* no default bitrate if decoding */
    
        st->start_time = AV_NOPTS_VALUE;
        st->duration = AV_NOPTS_VALUE;
    
            /* we set the current DTS to 0 so that formats without any timestamps
               but durations get some timestamps, formats with some unknown
               timestamps have their first few packets buffered and the
               timestamps corrected before they are returned to the user */
        st->cur_dts = 0;
    
        st->first_dts = AV_NOPTS_VALUE;
    
        st->probe_packets = MAX_PROBE_PACKETS;
    
        /* default pts setting is MPEG-like */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        st->last_IP_pts = AV_NOPTS_VALUE;
    
        for(i=0; i<MAX_REORDER_DELAY+1; i++)
            st->pts_buffer[i]= AV_NOPTS_VALUE;
    
        st->reference_dts = AV_NOPTS_VALUE;
    
        st->sample_aspect_ratio = (AVRational){0,1};
    
    
    AVProgram *av_new_program(AVFormatContext *ac, int id)
    {
        AVProgram *program=NULL;
        int i;
    
    #ifdef DEBUG_SI
        av_log(ac, AV_LOG_DEBUG, "new_program: id=0x%04x\n", id);
    #endif
    
        for(i=0; i<ac->nb_programs; i++)
            if(ac->programs[i]->id == id)
                program = ac->programs[i];
    
        if(!program){
            program = av_mallocz(sizeof(AVProgram));
            if (!program)
                return NULL;
            dynarray_add(&ac->programs, &ac->nb_programs, program);
            program->discard = AVDISCARD_NONE;
        }
        program->id = id;
    
        return program;
    }
    
    
    AVChapter *ff_new_chapter(AVFormatContext *s, int id, AVRational time_base, int64_t start, int64_t end, const char *title)
    
            if(s->chapters[i]->id == id)
                chapter = s->chapters[i];
    
        if(!chapter){
            chapter= av_mallocz(sizeof(AVChapter));
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            if(!chapter)
    
            dynarray_add(&s->chapters, &s->nb_chapters, chapter);
    
    #if LIBAVFORMAT_VERSION_INT < (53<<16)
    
    Aurelien Jacobs's avatar
    Aurelien Jacobs committed
        av_free(chapter->title);
    
    #endif
    
        av_metadata_set(&chapter->metadata, "title", title);
    
        chapter->time_base= time_base;
    
        chapter->start = start;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        chapter->end   = end;
    
    /************************************************************/
    /* output media file */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap)
    {
        int ret;
    
        if (s->oformat->priv_data_size > 0) {
            s->priv_data = av_mallocz(s->oformat->priv_data_size);
            if (!s->priv_data)
    
        } else
            s->priv_data = NULL;
    
        if (s->oformat->set_parameters) {
            ret = s->oformat->set_parameters(s, ap);
            if (ret < 0)
                return ret;
        }
        return 0;
    }
    
    
        // some sanity checks
        for(i=0;i<s->nb_streams;i++) {
            st = s->streams[i];
    
            switch (st->codec->codec_type) {
            case CODEC_TYPE_AUDIO:
                if(st->codec->sample_rate<=0){
                    av_log(s, AV_LOG_ERROR, "sample rate not set\n");
                    return -1;
                }
    
                if(!st->codec->block_align)
                    st->codec->block_align = st->codec->channels *
                        av_get_bits_per_sample(st->codec->codec_id) >> 3;
    
                break;
            case CODEC_TYPE_VIDEO:
                if(st->codec->time_base.num<=0 || st->codec->time_base.den<=0){ //FIXME audio too?
                    av_log(s, AV_LOG_ERROR, "time base not set\n");
                    return -1;
                }
                if(st->codec->width<=0 || st->codec->height<=0){
                    av_log(s, AV_LOG_ERROR, "dimensions not set\n");
                    return -1;
                }
    
                if(av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)){
                    av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between encoder and muxer layer\n");
                    return -1;
                }
    
    
            if(s->oformat->codec_tag){
                if(st->codec->codec_tag){
                    //FIXME
                    //check that tag + id is in the table
    
                    //if neither is in the table -> OK
    
                    //if tag is in the table with another id -> FAIL
                    //if id is in the table with another tag -> FAIL unless strict < ?
                }else
                    st->codec->codec_tag= av_codec_get_tag(s->oformat->codec_tag, st->codec->codec_id);
            }
    
    
            if(s->oformat->flags & AVFMT_GLOBALHEADER &&
                !(st->codec->flags & CODEC_FLAG_GLOBAL_HEADER))
              av_log(s, AV_LOG_WARNING, "Codec for stream %d does not use global headers but container format requires global headers\n", i);
    
        if (!s->priv_data && s->oformat->priv_data_size > 0) {
    
            s->priv_data = av_mallocz(s->oformat->priv_data_size);
            if (!s->priv_data)
    
        ff_metadata_mux_compat(s);
    
        if(s->oformat->write_header){
            ret = s->oformat->write_header(s);
            if (ret < 0)
                return ret;
        }
    
    
        /* init PTS generation */
        for(i=0;i<s->nb_streams;i++) {
    
            case CODEC_TYPE_AUDIO:
    
                den = (int64_t)st->time_base.num * st->codec->sample_rate;
    
                break;
            case CODEC_TYPE_VIDEO:
    
                den = (int64_t)st->time_base.num * st->codec->time_base.den;
    
            if (den != AV_NOPTS_VALUE) {
                if (den <= 0)
                    return AVERROR_INVALIDDATA;
                av_frac_init(&st->pts, 0, 0, den);
            }
    
    //FIXME merge with compute_pkt_fields
    
    static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){
    
        int delay = FFMAX(st->codec->has_b_frames, !!st->codec->max_b_frames);
        int num, den, frame_size, i;
    
    //    av_log(s, AV_LOG_DEBUG, "av_write_frame: pts:%"PRId64" dts:%"PRId64" cur_dts:%"PRId64" b:%d size:%d st:%d\n", pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index);
    
    /*    if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
            return -1;*/
    
        /* duration field */
    
        if (pkt->duration == 0) {
            compute_frame_duration(&num, &den, st, NULL, pkt);
            if (den && num) {
    
                pkt->duration = av_rescale(1, num * (int64_t)st->time_base.den * st->codec->ticks_per_frame, den * (int64_t)st->time_base.num);
    
        if(pkt->pts == AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && delay==0)
            pkt->pts= pkt->dts;
    
    
        //XXX/FIXME this is a temporary hack until all encoders output pts
    
        if((pkt->pts == 0 || pkt->pts == AV_NOPTS_VALUE) && pkt->dts == AV_NOPTS_VALUE && !delay){
    
            pkt->dts=
    //        pkt->pts= st->cur_dts;
            pkt->pts= st->pts.val;
        }
    
    
        //calculate dts from pts
    
        if(pkt->pts != AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY){
    
            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(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){
    
            av_log(s, AV_LOG_ERROR,
                   "st:%d error, non monotone timestamps %"PRId64" >= %"PRId64"\n",
                   st->index, st->cur_dts, pkt->dts);
    
            return -1;
        }
        if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts < pkt->dts){
    
            av_log(s, AV_LOG_ERROR, "st:%d error, pts < dts\n", st->index);
    
    //    av_log(s, AV_LOG_DEBUG, "av_write_frame: pts2:%"PRId64" dts2:%"PRId64"\n", pkt->pts, pkt->dts);
    
        st->cur_dts= pkt->dts;
        st->pts.val= pkt->dts;
    
    
        case CODEC_TYPE_AUDIO:
    
            frame_size = get_audio_frame_size(st->codec, pkt->size);
    
            /* HACK/FIXME, we skip the initial 0 size packets as they are most
               likely equal to the encoder delay, but it would be better if we
               had the real timestamps from the encoder */
    
            if (frame_size >= 0 && (pkt->size || st->pts.num!=st->pts.den>>1 || st->pts.val)) {
    
                av_frac_add(&st->pts, (int64_t)st->time_base.den * frame_size);
    
            break;
        case CODEC_TYPE_VIDEO:
    
            av_frac_add(&st->pts, (int64_t)st->time_base.den * st->codec->time_base.num);
    
    }
    
    int av_write_frame(AVFormatContext *s, AVPacket *pkt)
    {
    
        int ret = compute_pkt_fields2(s, s->streams[pkt->stream_index], pkt);
    
        if(ret<0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
    
        ret= s->oformat->write_packet(s, pkt);
        if(!ret)
    
        return ret;
    
    void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
                                  int (*compare)(AVFormatContext *, AVPacket *, AVPacket *))
    {
        AVPacketList **next_point, *this_pktl;
    
        this_pktl = av_mallocz(sizeof(AVPacketList));
        this_pktl->pkt= *pkt;
    
        pkt->destruct= NULL;             // do not free original but only the copy
        av_dup_packet(&this_pktl->pkt);  // duplicate the packet if it uses non-alloced memory
    
        if(s->streams[pkt->stream_index]->last_in_packet_buffer){
            next_point = &(s->streams[pkt->stream_index]->last_in_packet_buffer->next);
        }else
    
            next_point = &s->packet_buffer;
    
    
        if(*next_point){
            if(compare(s, &s->packet_buffer_end->pkt, pkt)){
                while(!compare(s, &(*next_point)->pkt, pkt)){
    
                    next_point= &(*next_point)->next;
                }
    
            }else{
                next_point = &(s->packet_buffer_end->next);
    
        assert(!*next_point);
    
        s->packet_buffer_end= this_pktl;
    
        s->streams[pkt->stream_index]->last_in_packet_buffer=
        *next_point= this_pktl;
    
    }
    
    int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacket *pkt)
    {
        AVStream *st = s->streams[ pkt ->stream_index];
        AVStream *st2= s->streams[ next->stream_index];
        int64_t left = st2->time_base.num * (int64_t)st ->time_base.den;
        int64_t right= st ->time_base.num * (int64_t)st2->time_base.den;
    
    
        if (pkt->dts == AV_NOPTS_VALUE)
            return 0;
    
    
        return next->dts * left > pkt->dts * right; //FIXME this can overflow
    }
    
    
    int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush){
    
            ff_interleave_add_packet(s, pkt, ff_interleave_compare_dts);
    
            stream_count+= !!s->streams[i]->last_in_packet_buffer;
    
        if(stream_count && (s->nb_streams == stream_count || flush)){
    
    
            s->packet_buffer= pktl->next;
    
            if(!s->packet_buffer)
                s->packet_buffer_end= NULL;
    
    
            if(s->streams[out->stream_index]->last_in_packet_buffer == pktl)
                s->streams[out->stream_index]->last_in_packet_buffer= NULL;
    
     * Interleaves an AVPacket correctly so it can be muxed.
    
     * @param out the interleaved packet will be output here
     * @param in the input packet
     * @param flush 1 if no further packets are available as input and all
     *              remaining packets should be output
    
     * @return 1 if a packet was output, 0 if no packet could be output,
    
     *         < 0 if an error occurred
    
     */
    static int av_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush){
        if(s->oformat->interleave_packet)
            return s->oformat->interleave_packet(s, out, in, flush);
        else
            return av_interleave_packet_per_dts(s, out, in, flush);
    }
    
    
    int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){
        AVStream *st= s->streams[ pkt->stream_index];
    
    
        //FIXME/XXX/HACK drop zero sized packets
    
        if(st->codec->codec_type == CODEC_TYPE_AUDIO && pkt->size==0)
    
    //av_log(NULL, AV_LOG_DEBUG, "av_interleaved_write_frame %d %"PRId64" %"PRId64"\n", pkt->size, pkt->dts, pkt->pts);
    
        if(compute_pkt_fields2(s, st, pkt) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
    
        if(pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
    
        for(;;){
            AVPacket opkt;
            int ret= av_interleave_packet(s, &opkt, pkt, 0);
            if(ret<=0) //FIXME cleanup needed for ret<0 ?
                return ret;
    
            if(url_ferror(s->pb))
                return url_ferror(s->pb);
    
        for(;;){
            AVPacket pkt;
            ret= av_interleave_packet(s, &pkt, NULL, 1);
            if(ret<0) //FIXME cleanup needed for ret<0 ?
    
                goto fail;
    
        if(s->oformat->write_trailer)
            ret = s->oformat->write_trailer(s);
    
        if(ret == 0)
    
        for(i=0;i<s->nb_streams;i++)
            av_freep(&s->streams[i]->priv_data);
    
    void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx)
    {
        int i, j;
        AVProgram *program=NULL;
        void *tmp;
    
    
        if (idx >= ac->nb_streams) {
            av_log(ac, AV_LOG_ERROR, "stream index %d is not valid\n", idx);
            return;
        }
    
    
        for(i=0; i<ac->nb_programs; i++){
            if(ac->programs[i]->id != progid)
                continue;
            program = ac->programs[i];
            for(j=0; j<program->nb_stream_indexes; j++)
                if(program->stream_index[j] == idx)
                    return;
    
            tmp = av_realloc(program->stream_index, sizeof(unsigned int)*(program->nb_stream_indexes+1));
            if(!tmp)
                return;
            program->stream_index = tmp;
            program->stream_index[program->nb_stream_indexes++] = idx;
            return;
        }
    }
    
    
    static void print_fps(double d, const char *postfix){
        uint64_t v= lrintf(d*100);
        if     (v% 100      ) av_log(NULL, AV_LOG_INFO, ", %3.2f %s", d, postfix);
        else if(v%(100*1000)) av_log(NULL, AV_LOG_INFO, ", %1.0f %s", d, postfix);
        else                  av_log(NULL, AV_LOG_INFO, ", %1.0fk %s", d/1000, postfix);
    }
    
    
    static void dump_metadata(void *ctx, AVMetadata *m, const char *indent)
    {
    
        if(m && !(m->count == 1 && av_metadata_get(m, "language", NULL, 0))){
    
            AVMetadataTag *tag=NULL;
    
            av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent);
            while((tag=av_metadata_get(m, "", tag, AV_METADATA_IGNORE_SUFFIX))) {
    
                if(strcmp("language", tag->key))
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    av_log(ctx, AV_LOG_INFO, "%s  %-16s: %s\n", indent, tag->key, tag->value);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* "user interface" functions */
    
    static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
    
        int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
        AVStream *st = ic->streams[i];
    
        int g = av_gcd(st->time_base.num, st->time_base.den);
    
        AVMetadataTag *lang = av_metadata_get(st->metadata, "language", NULL, 0);
    
        avcodec_string(buf, sizeof(buf), st->codec, is_output);
        av_log(NULL, AV_LOG_INFO, "    Stream #%d.%d", index, i);
        /* the pid is an important information, so we display it */
        /* XXX: add a generic system */
        if (flags & AVFMT_SHOW_IDS)
            av_log(NULL, AV_LOG_INFO, "[0x%x]", st->id);
    
        if (lang)
            av_log(NULL, AV_LOG_INFO, "(%s)", lang->value);
    
        av_log(NULL, AV_LOG_DEBUG, ", %d/%d", st->time_base.num/g, st->time_base.den/g);
        av_log(NULL, AV_LOG_INFO, ": %s", buf);
    
        if (st->sample_aspect_ratio.num && // default
            av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) {
            AVRational display_aspect_ratio;
            av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
                      st->codec->width*st->sample_aspect_ratio.num,
                      st->codec->height*st->sample_aspect_ratio.den,
                      1024*1024);
            av_log(NULL, AV_LOG_INFO, ", PAR %d:%d DAR %d:%d",
                     st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
                     display_aspect_ratio.num, display_aspect_ratio.den);
        }
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            if(st->avg_frame_rate.den && st->avg_frame_rate.num)
                print_fps(av_q2d(st->avg_frame_rate), "fps");
    
            if(st->r_frame_rate.den && st->r_frame_rate.num)
    
                print_fps(av_q2d(st->r_frame_rate), "tbr");
    
            if(st->time_base.den && st->time_base.num)
    
                print_fps(1/av_q2d(st->time_base), "tbn");
    
            if(st->codec->time_base.den && st->codec->time_base.num)
    
                print_fps(1/av_q2d(st->codec->time_base), "tbc");
    
        dump_metadata(NULL, st->metadata, "    ");
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    void dump_format(AVFormatContext *ic,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                     const char *url,
                     int is_output)
    {
    
        uint8_t *printed = av_mallocz(ic->nb_streams);
        if (ic->nb_streams && !printed)
            return;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
        av_log(NULL, AV_LOG_INFO, "%s #%d, %s, %s '%s':\n",
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                is_output ? "Output" : "Input",
    
                index,
                is_output ? ic->oformat->name : ic->iformat->name,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                is_output ? "to" : "from", url);
    
        dump_metadata(NULL, ic->metadata, "  ");
    
            av_log(NULL, AV_LOG_INFO, "  Duration: ");
    
            if (ic->duration != AV_NOPTS_VALUE) {
                int hours, mins, secs, us;
                secs = ic->duration / AV_TIME_BASE;
                us = ic->duration % AV_TIME_BASE;
                mins = secs / 60;
                secs %= 60;
                hours = mins / 60;
                mins %= 60;
    
                av_log(NULL, AV_LOG_INFO, "%02d:%02d:%02d.%02d", hours, mins, secs,
                       (100 * us) / AV_TIME_BASE);
    
                av_log(NULL, AV_LOG_INFO, "N/A");
    
            if (ic->start_time != AV_NOPTS_VALUE) {
                int secs, us;
    
                av_log(NULL, AV_LOG_INFO, ", start: ");
    
                secs = ic->start_time / AV_TIME_BASE;
                us = ic->start_time % AV_TIME_BASE;
    
                av_log(NULL, AV_LOG_INFO, "%d.%06d",
    
            av_log(NULL, AV_LOG_INFO, ", bitrate: ");
    
                av_log(NULL, AV_LOG_INFO,"%d kb/s", ic->bit_rate / 1000);
    
                av_log(NULL, AV_LOG_INFO, "N/A");
    
            av_log(NULL, AV_LOG_INFO, "\n");
    
                AVMetadataTag *name = av_metadata_get(ic->programs[j]->metadata,
                                                      "name", NULL, 0);
    
                av_log(NULL, AV_LOG_INFO, "  Program %d %s\n", ic->programs[j]->id,
    
                       name ? name->value : "");
    
                dump_metadata(NULL, ic->programs[j]->metadata, "    ");
    
                for(k=0; k<ic->programs[j]->nb_stream_indexes; k++) {
    
                    dump_stream_format(ic, ic->programs[j]->stream_index[k], index, is_output);
    
                    printed[ic->programs[j]->stream_index[k]] = 1;
                }
                total += ic->programs[j]->nb_stream_indexes;
            }
            if (total < ic->nb_streams)
                av_log(NULL, AV_LOG_INFO, "  No Program\n");
        }
    
        for(i=0;i<ic->nb_streams;i++)
            if (!printed[i])
    
                dump_stream_format(ic, i, index, is_output);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    int parse_image_size(int *width_ptr, int *height_ptr, const char *str)
    {
    
        return av_parse_video_frame_size(width_ptr, height_ptr, str);
    
    int parse_frame_rate(int *frame_rate_num, int *frame_rate_den, const char *arg)
    
        AVRational frame_rate;
        int ret = av_parse_video_frame_rate(&frame_rate, arg);
        *frame_rate_num= frame_rate.num;
        *frame_rate_den= frame_rate.den;
        return ret;
    
    int64_t av_gettime(void)
    {
        struct timeval tv;