[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