int av_grab(AVFormatContext *s)

{

    UINT8 audio_buf[AUDIO_FIFO_SIZE];

    UINT8 audio_buf1[AUDIO_FIFO_SIZE];

    UINT8 audio_out[AUDIO_FIFO_SIZE];

    UINT8 video_buffer[1024*1024];

    char buf[256];

    short *samples;

    URLContext *audio_handle = NULL, *video_handle = NULL;

    int ret;

    AVCodecContext *enc, *first_video_enc = NULL;

    int frame_size, frame_bytes;

    int use_audio, use_video;

    int frame_rate, sample_rate, channels;

    int width, height, frame_number, i, pix_fmt = 0;

    AVOutputStream *ost_table[s->nb_streams], *ost;

    UINT8 *picture_in_buf = NULL, *picture_420p = NULL;

    int audio_fifo_size = 0, picture_size = 0;

    INT64 time_start;



    /* init output stream info */

    for(i=0;i<s->nb_streams;i++)

        ost_table[i] = NULL;



    /* output stream init */

    for(i=0;i<s->nb_streams;i++) {

        ost = av_mallocz(sizeof(AVOutputStream));

        if (!ost)

            goto fail;

        ost->index = i;

        ost->st = s->streams[i];

        ost_table[i] = ost;

    }



    use_audio = 0;

    use_video = 0;

    frame_rate = 0;

    sample_rate = 0;

    frame_size = 0;

    channels = 1;

    width = 0;

    height = 0;

    frame_number = 0;

    

    for(i=0;i<s->nb_streams;i++) {

        AVCodec *codec;



        ost = ost_table[i];

        enc = &ost->st->codec;

        codec = avcodec_find_encoder(enc->codec_id);

        if (!codec) {

            fprintf(stderr, "Unknown codec\n");

            return -1;

        }

        if (avcodec_open(enc, codec) < 0) {

            fprintf(stderr, "Incorrect encode parameters\n");

            return -1;

        }

        switch(enc->codec_type) {

        case CODEC_TYPE_AUDIO:

            use_audio = 1;

            if (enc->sample_rate > sample_rate)

                sample_rate = enc->sample_rate;

            if (enc->frame_size > frame_size)

                frame_size = enc->frame_size;

            if (enc->channels > channels)

                channels = enc->channels;

            break;

        case CODEC_TYPE_VIDEO:

            if (!first_video_enc)

                first_video_enc = enc;

            use_video = 1;

            if (enc->frame_rate > frame_rate)

                frame_rate = enc->frame_rate;

            if (enc->width > width)

                width = enc->width;

            if (enc->height > height)

                height = enc->height;

            break;

        }

    }



    /* audio */

    samples = NULL;

    if (use_audio) {

        snprintf(buf, sizeof(buf), "audio:%d,%d", sample_rate, channels);

        ret = url_open(&audio_handle, buf, URL_RDONLY);

        if (ret < 0) {

            fprintf(stderr, "Could not open audio device: disabling audio capture\n");

            use_audio = 0;

        } else {

            URLFormat f;

            /* read back exact grab parameters */

            if (url_getformat(audio_handle, &f) < 0) {

                fprintf(stderr, "could not read back video grab parameters\n");

                goto fail;

            }

            sample_rate = f.sample_rate;

            channels = f.channels;

            audio_fifo_size = ((AUDIO_FIFO_SIZE / 2) / audio_handle->packet_size) * 

                audio_handle->packet_size;

            fprintf(stderr, "Audio sampling: %d Hz, %s\n", 

                    sample_rate, channels == 2 ? "stereo" : "mono");

        }

    }

    

    /* video */

    if (use_video) {

        snprintf(buf, sizeof(buf), "video:%d,%d,%f", 

                 width, height, (float)frame_rate / FRAME_RATE_BASE);



        ret = url_open(&video_handle, buf, URL_RDONLY);

        if (ret < 0) {

            fprintf(stderr,"Could not init video 4 linux capture: disabling video capture\n");

            use_video = 0;

        } else {

            URLFormat f;

            const char *pix_fmt_str;

            /* read back exact grab parameters */

            if (url_getformat(video_handle, &f) < 0) {

                fprintf(stderr, "could not read back video grab parameters\n");

                goto fail;

            }

            width = f.width;

            height = f.height;

            pix_fmt = f.pix_fmt;

            switch(pix_fmt) {

            case PIX_FMT_YUV420P:

                pix_fmt_str = "420P";

                break;

            case PIX_FMT_YUV422:

                pix_fmt_str = "422";

                break;

            case PIX_FMT_RGB24:

                pix_fmt_str = "RGB24";

                break;

            case PIX_FMT_BGR24:

                pix_fmt_str = "BGR24";

                break;

            default:

                pix_fmt_str = "???";

                break;

            }

            picture_size = video_handle->packet_size;

            picture_in_buf = malloc(picture_size);

            if (!picture_in_buf)

                goto fail;

            /* allocate a temporary picture if not grabbing in 420P format */

            if (pix_fmt != PIX_FMT_YUV420P) {

                picture_420p = malloc((width * height * 3) / 2);

            }

            fprintf(stderr, "Video sampling: %dx%d, %s format, %0.2f fps\n", 

                    width, height, pix_fmt_str, (float)frame_rate / FRAME_RATE_BASE);

        }

    }



    if (!use_video && !use_audio) {

        fprintf(stderr,"Could not open grab devices : exiting\n");

        exit(1);

    }



    /* init built in conversion functions */

    for(i=0;i<s->nb_streams;i++) {

        ost = ost_table[i];

        enc = &ost->st->codec;

        switch(enc->codec_type) {

        case CODEC_TYPE_AUDIO:

            ost->audio_resample = 0;

            if ((enc->channels != channels ||

                 enc->sample_rate != sample_rate)) {

                ost->audio_resample = 1;

                ost->resample = audio_resample_init(enc->channels, channels,

                                                    enc->sample_rate, sample_rate);

            }

            if (fifo_init(&ost->fifo, (2 * audio_fifo_size * enc->sample_rate *

                                       enc->channels) / sample_rate))

                goto fail;

            break;

        case CODEC_TYPE_VIDEO:

            ost->video_resample = 0;

            if (enc->width != width ||

                enc->height != height) {

                UINT8 *buf;

                ost->video_resample = 1;

                buf = malloc((enc->width * enc->height * 3) / 2);

                if (!buf)

                    goto fail;

                ost->pict_tmp.data[0] = buf;

                ost->pict_tmp.data[1] = buf + enc->width * height;

                ost->pict_tmp.data[2] = ost->pict_tmp.data[1] + (enc->width * height) / 4;

                ost->pict_tmp.linesize[0] = enc->width;

                ost->pict_tmp.linesize[1] = enc->width / 2;

                ost->pict_tmp.linesize[2] = enc->width / 2;

                ost->img_resample_ctx = img_resample_init(

                                  ost->st->codec.width, ost->st->codec.height,

                                  width, height);

            }

        }

    }



    fprintf(stderr, "Press [q] to stop encoding\n");



    s->format->write_header(s);

    time_start = gettime();

    term_init();

    

    for(;;) {

        /* if 'q' pressed, exits */

        if (read_key() == 'q')

            break;



        /* read & compress audio frames */

        if (use_audio) {

            int ret, nb_samples, nb_samples_out;

            UINT8 *buftmp;



            for(;;) {

                ret = url_read(audio_handle, audio_buf, audio_fifo_size);

                if (ret <= 0)

                    break;

                /* fill each codec fifo by doing the right sample

                   rate conversion. This is not optimal because we

                   do too much work, but it is easy to do */

                nb_samples = ret / (channels * 2);

                for(i=0;i<s->nb_streams;i++) {

                    ost = ost_table[i];

                    enc = &ost->st->codec;

                    if (enc->codec_type == CODEC_TYPE_AUDIO) {

                        /* rate & stereo convertion */

                        if (!ost->audio_resample) {

                            buftmp = audio_buf;

                            nb_samples_out = nb_samples;

                        } else {

                            buftmp = audio_buf1;

                            nb_samples_out = audio_resample(ost->resample, 

                                                            (short *)buftmp, (short *)audio_buf,

                                                            nb_samples);

                        }

                        fifo_write(&ost->fifo, buftmp, nb_samples_out * enc->channels * 2, 

                                   &ost->fifo.wptr);

                    }

                }

                

                /* compress as many frame as possible with each audio codec */

                for(i=0;i<s->nb_streams;i++) {

                    ost = ost_table[i];

                    enc = &ost->st->codec;

                    if (enc->codec_type == CODEC_TYPE_AUDIO) {

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

                        

                        while (fifo_read(&ost->fifo, audio_buf, 

                                         frame_bytes, &ost->fifo.rptr) == 0) {

                            ret = avcodec_encode_audio(enc,

                                                       audio_out, sizeof(audio_out), 

                                                       (short *)audio_buf);

                            s->format->write_packet(s, ost->index, audio_out, ret);

                        }

                    }

                }

            }

        }



        if (use_video) {

            AVPicture *picture1, *picture2, *picture;

            AVPicture picture_tmp0, picture_tmp1;



            ret = url_read(video_handle, picture_in_buf, picture_size);

            if (ret < 0)

                break;

            

            picture2 = &picture_tmp0;

            avpicture_fill(picture2, picture_in_buf, pix_fmt, width, height);



            if (pix_fmt != PIX_FMT_YUV420P) {

                picture = &picture_tmp1;

                avpicture_fill(picture, picture_420p, 

                               PIX_FMT_YUV420P, width, height);

                img_convert(picture, PIX_FMT_YUV420P,

                            picture2, pix_fmt, 

                            width, height);

            } else {

                picture = picture2;

            }

            

            for(i=0;i<s->nb_streams;i++) {

                ost = ost_table[i];

                enc = &ost->st->codec;

                if (enc->codec_type == CODEC_TYPE_VIDEO) {

                    int n1, n2, nb;



                    /* feed each codec with its requested frame rate */

                    n1 = ((INT64)frame_number * enc->frame_rate) / frame_rate;

                    n2 = (((INT64)frame_number + 1) * enc->frame_rate) / frame_rate;

                    nb = n2 - n1;

                    if (nb > 0) {

                        /* resize the picture if needed */

                        if (ost->video_resample) {

                            picture1 = &ost->pict_tmp;

                            img_resample(ost->img_resample_ctx, 

                                         picture1, picture);

                        } else {

                            picture1 = picture;

                        }

                        ret = avcodec_encode_video(enc, video_buffer, 

                                                   sizeof(video_buffer), 

                                                   picture1);

                        s->format->write_packet(s, ost->index, video_buffer, ret);

                    }

                }

            }

            frame_number++;

        }

        

        /* write report */

        {

            char buf[1024];

            INT64 total_size;

            float ti, bitrate;

            static float last_ti;

            INT64 ti1;



            total_size = url_ftell(&s->pb);

            ti1 = gettime() - time_start;

            /* check elapsed time */

            if (recording_time && ti1 >= recording_time)

                break;



            ti = ti1 / 1000000.0;

            if (ti < 0.1)

                ti = 0.1;

            /* dispaly twice per second */

            if ((ti - last_ti) >= 0.5) {

                last_ti = ti;

                bitrate = (int)((total_size * 8) / ti / 1000.0);

                

                buf[0] = '\0';

                if (use_video) {

                    sprintf(buf + strlen(buf), "frame=%5d fps=%4.1f q=%2d ",

                            frame_number, (float)frame_number / ti, first_video_enc->quality);

                }

                

                sprintf(buf + strlen(buf), "size=%8LdkB time=%0.1f bitrate=%6.1fkbits/s", 

                        total_size / 1024, ti, bitrate);

                fprintf(stderr, "%s    \r", buf);

                fflush(stderr);

            }

        }

    }

    term_exit();



    for(i=0;i<s->nb_streams;i++) {

        ost = ost_table[i];

        enc = &ost->st->codec;

        avcodec_close(enc);

    }

    s->format->write_trailer(s);

    

    if (audio_handle)

        url_close(audio_handle);



    if (video_handle)

        url_close(video_handle);



    /* write report */

    {

        float ti, bitrate;

        INT64 total_size;



        total_size = url_ftell(&s->pb);



        ti = (gettime() - time_start) / 1000000.0;

        if (ti < 0.1)

            ti = 0.1;

        bitrate = (int)((total_size * 8) / ti / 1000.0);



        fprintf(stderr, "\033[K\nTotal time = %0.1f s, %Ld KBytes, %0.1f kbits/s\n", 

                ti, total_size / 1024, bitrate);

        if (use_video) {

            fprintf(stderr, "Total frames = %d\n", frame_number);

        }

    }



    ret = 0;

 fail1:

    if (picture_in_buf)

        free(picture_in_buf);

    if (picture_420p)

        free(picture_420p);

    for(i=0;i<s->nb_streams;i++) {

        ost = ost_table[i];

        if (ost) {

            if (ost->fifo.buffer)

                fifo_free(&ost->fifo);

            if (ost->pict_tmp.data[0])

                free(ost->pict_tmp.data[0]);

            if (ost->video_resample)

                img_resample_close(ost->img_resample_ctx);

            if (ost->audio_resample)

                audio_resample_close(ost->resample);

            free(ost);

        }

    }

    return ret;

 fail:

    ret = -ENOMEM;

    goto fail1;

}
