static void do_audio_out(AVFormatContext *s,

                         AVOutputStream *ost,

                         AVInputStream *ist,

                         unsigned char *buf, int size)

{

    uint8_t *buftmp;

    int64_t audio_out_size, audio_buf_size;

    int64_t allocated_for_size= size;



    int size_out, frame_bytes, ret;

    AVCodecContext *enc= ost->st->codec;

    AVCodecContext *dec= ist->st->codec;

    int osize= av_get_bits_per_sample_format(enc->sample_fmt)/8;

    int isize= av_get_bits_per_sample_format(dec->sample_fmt)/8;

    const int coded_bps = av_get_bits_per_sample(enc->codec->id);



need_realloc:

    audio_buf_size= (allocated_for_size + isize*dec->channels - 1) / (isize*dec->channels);

    audio_buf_size= (audio_buf_size*enc->sample_rate + dec->sample_rate) / dec->sample_rate;

    audio_buf_size= audio_buf_size*2 + 10000; //safety factors for the deprecated resampling API

    audio_buf_size= FFMAX(audio_buf_size, enc->frame_size);

    audio_buf_size*= osize*enc->channels;



    audio_out_size= FFMAX(audio_buf_size, enc->frame_size * osize * enc->channels);

    if(coded_bps > 8*osize)

        audio_out_size= audio_out_size * coded_bps / (8*osize);

    audio_out_size += FF_MIN_BUFFER_SIZE;



    if(audio_out_size > INT_MAX || audio_buf_size > INT_MAX){

        fprintf(stderr, "Buffer sizes too large\n");

        ffmpeg_exit(1);

    }



    av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);

    av_fast_malloc(&audio_out, &allocated_audio_out_size, audio_out_size);

    if (!audio_buf || !audio_out){

        fprintf(stderr, "Out of memory in do_audio_out\n");

        ffmpeg_exit(1);

    }



    if (enc->channels != dec->channels)

        ost->audio_resample = 1;



    if (ost->audio_resample && !ost->resample) {

        if (dec->sample_fmt != SAMPLE_FMT_S16)

            fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n");

        ost->resample = av_audio_resample_init(enc->channels,    dec->channels,

                                               enc->sample_rate, dec->sample_rate,

                                               enc->sample_fmt,  dec->sample_fmt,

                                               16, 10, 0, 0.8);

        if (!ost->resample) {

            fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",

                    dec->channels, dec->sample_rate,

                    enc->channels, enc->sample_rate);

            ffmpeg_exit(1);

        }

    }



#define MAKE_SFMT_PAIR(a,b) ((a)+SAMPLE_FMT_NB*(b))

    if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt &&

        MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) {

        if (ost->reformat_ctx)

            av_audio_convert_free(ost->reformat_ctx);

        ost->reformat_ctx = av_audio_convert_alloc(enc->sample_fmt, 1,

                                                   dec->sample_fmt, 1, NULL, 0);

        if (!ost->reformat_ctx) {

            fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",

                avcodec_get_sample_fmt_name(dec->sample_fmt),

                avcodec_get_sample_fmt_name(enc->sample_fmt));

            ffmpeg_exit(1);

        }

        ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);

    }



    if(audio_sync_method){

        double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts

                - av_fifo_size(ost->fifo)/(enc->channels * 2);

        double idelta= delta*dec->sample_rate / enc->sample_rate;

        int byte_delta= ((int)idelta)*2*dec->channels;



        //FIXME resample delay

        if(fabs(delta) > 50){

            if(ist->is_start || fabs(delta) > audio_drift_threshold*enc->sample_rate){

                if(byte_delta < 0){

                    byte_delta= FFMAX(byte_delta, -size);

                    size += byte_delta;

                    buf  -= byte_delta;

                    if(verbose > 2)

                        fprintf(stderr, "discarding %d audio samples\n", (int)-delta);

                    if(!size)

                        return;

                    ist->is_start=0;

                }else{

                    static uint8_t *input_tmp= NULL;

                    input_tmp= av_realloc(input_tmp, byte_delta + size);



                    if(byte_delta > allocated_for_size - size){

                        allocated_for_size= byte_delta + (int64_t)size;

                        goto need_realloc;

                    }

                    ist->is_start=0;



                    memset(input_tmp, 0, byte_delta);

                    memcpy(input_tmp + byte_delta, buf, size);

                    buf= input_tmp;

                    size += byte_delta;

                    if(verbose > 2)

                        fprintf(stderr, "adding %d audio samples of silence\n", (int)delta);

                }

            }else if(audio_sync_method>1){

                int comp= av_clip(delta, -audio_sync_method, audio_sync_method);

                assert(ost->audio_resample);

                if(verbose > 2)

                    fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate);

//                fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2));

                av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate);

            }

        }

    }else

        ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate)

                        - av_fifo_size(ost->fifo)/(enc->channels * 2); //FIXME wrong



    if (ost->audio_resample) {

        buftmp = audio_buf;

        size_out = audio_resample(ost->resample,

                                  (short *)buftmp, (short *)buf,

                                  size / (dec->channels * isize));

        size_out = size_out * enc->channels * osize;

    } else {

        buftmp = buf;

        size_out = size;

    }



    if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt) {

        const void *ibuf[6]= {buftmp};

        void *obuf[6]= {audio_buf};

        int istride[6]= {isize};

        int ostride[6]= {osize};

        int len= size_out/istride[0];

        if (av_audio_convert(ost->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {

            printf("av_audio_convert() failed\n");

            if (exit_on_error)

                ffmpeg_exit(1);

            return;

        }

        buftmp = audio_buf;

        size_out = len*osize;

    }



    /* now encode as many frames as possible */

    if (enc->frame_size > 1) {

        /* output resampled raw samples */

        if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {

            fprintf(stderr, "av_fifo_realloc2() failed\n");

            ffmpeg_exit(1);

        }

        av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL);



        frame_bytes = enc->frame_size * osize * enc->channels;



        while (av_fifo_size(ost->fifo) >= frame_bytes) {

            AVPacket pkt;

            av_init_packet(&pkt);



            av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);



            //FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()



            ret = avcodec_encode_audio(enc, audio_out, audio_out_size,

                                       (short *)audio_buf);

            if (ret < 0) {

                fprintf(stderr, "Audio encoding failed\n");

                ffmpeg_exit(1);

            }

            audio_size += ret;

            pkt.stream_index= ost->index;

            pkt.data= audio_out;

            pkt.size= ret;

            if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)

                pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);

            pkt.flags |= AV_PKT_FLAG_KEY;

            write_frame(s, &pkt, enc, bitstream_filters[ost->file_index][pkt.stream_index]);



            ost->sync_opts += enc->frame_size;

        }

    } else {

        AVPacket pkt;

        av_init_packet(&pkt);



        ost->sync_opts += size_out / (osize * enc->channels);



        /* output a pcm frame */

        /* determine the size of the coded buffer */

        size_out /= osize;

        if (coded_bps)

            size_out = size_out*coded_bps/8;



        if(size_out > audio_out_size){

            fprintf(stderr, "Internal error, buffer size too small\n");

            ffmpeg_exit(1);

        }



        //FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()

        ret = avcodec_encode_audio(enc, audio_out, size_out,

                                   (short *)buftmp);

        if (ret < 0) {

            fprintf(stderr, "Audio encoding failed\n");

            ffmpeg_exit(1);

        }

        audio_size += ret;

        pkt.stream_index= ost->index;

        pkt.data= audio_out;

        pkt.size= ret;

        if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)

            pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);

        pkt.flags |= AV_PKT_FLAG_KEY;

        write_frame(s, &pkt, enc, bitstream_filters[ost->file_index][pkt.stream_index]);

    }

}
