[Libav-user] Capturing X11 screen into mpg
Alex Cohn
alexcohn at netvision.net.il
Fri Jun 10 20:22:28 CEST 2011
You should set pts and maybe duration for pFrameYUV before you feed it
into video encoder.
Alex
On Friday, June 10, 2011, Jiří Novák <jiri.novak at petriny.net> wrote:
> Hello,
>
> I am trying to capture the X11 screen (using "x11grab") to the mpg output format. This is first step (afterward i will need to add alsa audio), join it into conteiner and at some point send it by socket.
>
> The problem I have is, that the mpg video I received is not syncronized, in other words it looses its timing and is reproduced all in 2 seconds :(.
>
> Could anybody with experience of this please help me to correct this issue in my code?
>
> Thank you very much,
> Jiri Novak
>
> /*==========================================================================================================*/
> #include <iostream>
> #include <stdio.h>
> #include <assert.h>
> #include <fstream>
>
> extern "C" {
> #ifndef INT64_C
> #define INT64_C(c) (c ## LL)
> #define UINT64_C(c) (c ## ULL)
> #endif
> #include <libavcodec/avcodec.h>
> #include <libswscale/swscale.h>
> #include <libavformat/avformat.h>
> #include <libavdevice/avdevice.h>
> #include <libavfilter/avfilter.h>
> }
>
> int main(int argc, char *argv[]) {
> // register devices, filters and codecs
> avdevice_register_all();
> avfilter_register_all();
> avcodec_init();
> avcodec_register_all();
> av_register_all();
>
> // file format, format context
> AVInputFormat *pInputFormat = av_find_input_format("x11grab");
> AVFormatContext *pFormatCtx = avformat_alloc_context();
> assert(pInputFormat != NULL && "format unrecognized - pInputFormat is NULL!");
> assert(pFormatCtx != NULL && "format context could not be allocated - pFormatCtx pointer is NULL!");
>
> // format parameters
> AVFormatParameters input_video_parameters, *ivp = &input_video_parameters;
> memset(ivp, 0, sizeof(*ivp));
> ivp->prealloced_context = 1;
> ivp->time_base= (AVRational){1,25};
> ivp->width = 1400;
> ivp->height = 1050;
>
> // input_format_context, filename, input_format, buffer_size, format_parameters
> int ret = av_open_input_file(&pFormatCtx, ":0.0", pInputFormat, 0, ivp);
> assert(ret >= 0 && "input video file could not be opened!");
>
> // retrieve stream information
> ret = av_find_stream_info(pFormatCtx);
> assert(pFormatCtx >= 0 && "could not retrieve input video stream info!");
>
> // dump information
> dump_format(pFormatCtx, 0, ":0.0", 0);
>
> // find the first video stream
> int videoStream=-1;
> for(int i=0; i<pFormatCtx->nb_streams; i++)
> if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
> videoStream=i;
> break;
> }
> if(videoStream==-1)
> return -1; // Didn't find a video stream
>
> // get a pointer to the codec context for the video stream
> AVCodecContext *pCodecCtxDec = pFormatCtx->streams[videoStream]->codec;
>
> // find the decoder for the video stream
> AVCodec *pCodecDec = avcodec_find_decoder(pCodecCtxDec->codec_id);
> if(pCodecDec==NULL) {
> fprintf(stderr, "Unsupported codec!\n");
> return -1; // Codec not found
> }
>
> // open codec
> if (avcodec_open(pCodecCtxDec, pCodecDec)<0)
> return -1; // Could not open codec
>
> // alocate codec context
> AVCodecContext *pCodecCtxEnc = avcodec_alloc_context();
> assert(pCodecCtxEnc != NULL && "pCodecCtxEnc pointer is null!");
>
> // put sample parameters
> pCodecCtxEnc->bit_rate = 400000;
> pCodecCtxEnc->width = 1400;
> pCodecCtxEnc->height = 1050;
> pCodecCtxEnc->time_base= (AVRational){1,25};
> pCodecCtxEnc->gop_size = 10;
> pCodecCtxEnc->max_b_frames=1;
> pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
>
> // find MPEG4 encoder
> AVCodec *pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);
> assert(pCodecEnc != NULL && "pCodecEnc pointer is null!");
>
> // open the codec
> int retval = avcodec_open(pCodecCtxEnc, pCodecEnc);
> assert(retval == 0 && "could not open codec!");
>
> // allocate video frame
> AVFrame *pFrame = avcodec_alloc_frame();
>
> // allocate an AVFrame structure
> AVFrame *pFrameYUV=avcodec_alloc_frame();
> if(pFrameYUV==NULL)
> return -1;
>
> // calculate the bytes needed for the output image and create buffer for the output image
> int nbytes = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
> uint8_t* outbuffer = (uint8_t*)av_malloc(nbytes*10);
>
> // assign appropriate parts of buffer to image planes in pFrameYUV
> avpicture_fill((AVPicture *)pFrameYUV, outbuffer, PIX_FMT_YUV420P, pCodecCtxDec->width, pCodecCtxDec->height);
>
> int frameFinished;
> AVPacket packet;
>
> int i=0;
> struct SwsContext *img_convert_ctx = NULL;
>
> FILE *f = fopen("output.mpg", "wb");
> int out_size;
>
> while (av_read_frame(pFormatCtx, &packet)>=0 && i<50) {
> fflush(stdout);
>
> // is this a packet from the video stream
> if(packet.stream_index==videoStream) {
> // Decode video frame
> avcodec_decode_video2(pCodecCtxDec, pFrame, &frameFinished, &packet);
>
> // Did we get a video frame?
> if(frameFinished) {
> if (img_convert_ctx == NULL) {
> img_convert_ctx = sws_getContext(pCodecCtxDec->width, pCodecCtxDec->height, PIX_FMT_BGRA, pCodecCtxEnc->width, pCodecCtxEnc->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
>
> if (img_convert_ctx == NULL)
> std::cerr << "Error" << std::endl;
> }
> sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtxEnc->height, pFrameYUV->data, pFrameYUV->linesize);
>
> out_size = avcodec_encode_video(pCodecCtxEnc, outbuffer, nbytes, pFrameYUV);
> //printf("write frame %3d (size=%5d)\n", i, out_size);
> fwrite(outbuffer, 1, out_size, f);
> }
> }
>
> // Free the packet that was allocated by av_read_frame
> av_free_packet(&packet);
> i++;
> }
>
> //get the delayed frames
> for(; out_size; i++) {
> fflush(stdout);
> out_size = avcodec_encode_video(pCodecCtxEnc, outbuffer, nbytes, NULL);
> //printf("write frame %3d (size=%5d)\n", i, out_size);
> fwrite(outbuffer, 1, out_size, f);
> }
>
> // add sequence end code to have a real mpeg file
> outbuffer[0] = 0x00;
> outbuffer[1] = 0x00;
> outbuffer[2] = 0x01;
> outbuffer[3] = 0xb7;
> fwrite(outbuffer, 1, 4, f);
> fclose(f);
>
> return 0;
> }
>
>
More information about the Libav-user
mailing list