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; }