[Libav-user] Capturing X11 screen into mpg

Jiří Novák jiri.novak at petriny.net
Fri Jun 10 17:57:02 CEST 2011


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)
#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

  // file format, format context
  AVInputFormat *pInputFormat = av_find_input_format("x11grab");
  AVFormatContext *pFormatCtx = avformat_alloc_context();
  assert(pInputFormat != NULL && "format unrecognized - pInputFormat is
  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,
  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) {
    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->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();
    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,
  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) {

    // 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,
    //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

  //get the delayed frames
  for(; out_size; i++) {
    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);

  return 0;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20110610/eb7582b5/attachment.html>

More information about the Libav-user mailing list