ffmpeg tutorial code

| No TrackBacks
I've been doing a lot of ffmpeg programming lately and have been finding it extremely painful. There just isn't much for help out there, certainly no real documentation for using the viatal avcodec library.

'dranger' has about the only comprehensive tutorial around and it's showing its age at this point. There's a few newer notes about updating it, but even those don't cover the latest libavcodec API changes. So I figured I would throw out my version of the first tutorial file, tutorial01.c. The most important change is replacing the long excised img_convert call with the sws_scale call (which also requires creating the SwsContext object). I also just tweaked a couple of the calls to remove any deprecated API calls.

Have at it!

You can build it with the following command:

$     gcc  -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lswscale -lz
Download it here: tutorial01.c

// tutorial01.c
// Code based on a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1

// A small sample program that shows how to use libavformat and libavcodec to
// read video from a file.
//
// Use
//
// gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lz
//
// to build (assuming libavformat and libavcodec are correctly installed
// your system).
//
// Run using
//
// tutorial01 myvideofile.mpg
//
// to write the first five frames from "myvideofile.mpg" to disk in PPM
// format.

#include 
#include 
#include 
#include 

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  FILE *pFile;
  char szFilename[32];
  int  y;
  
  // Open file
  sprintf(szFilename, "frame%d.ppm", iFrame);
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;
  
  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  
  // Write pixel data
  for(y=0; ydata[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  
  // Close file
  fclose(pFile);
}

int main(int argc, char *argv[]) {
  AVFormatContext *pFormatCtx=NULL;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame; 
  AVFrame         *pFrameRGB;
  AVPacket        packet;
  int             frameFinished;
  int             numBytes;
  uint8_t         *buffer;
  struct SwsContext *img_convert_ctx;
  int frameCount=0;
  
  if(argc < 2) {
    printf("Please provide a movie file\n");
    return -1;
  }
  // Register all formats and codecs
  av_register_all();
  
  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(av_find_stream_info(pFormatCtx)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  videoStream=-1;
  for(i=0; inb_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
  pCodecCtx=pFormatCtx->streams[videoStream]->codec;
  
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }
  // Open codec
  if(avcodec_open(pCodecCtx, pCodec)<0)
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=avcodec_alloc_frame();
  
  // Allocate an AVFrame structure
  pFrameRGB=avcodec_alloc_frame();
  if(pFrameRGB==NULL)
    return -1;
  
  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
                              pCodecCtx->height);
  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
  
  // Assign appropriate parts of buffer to image planes in pFrameRGB
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
                 pCodecCtx->width, pCodecCtx->height);
  
  int w = pCodecCtx->width;
  int h = pCodecCtx->height;
  img_convert_ctx = sws_getContext(
    w, 
    h, 
    pCodecCtx->pix_fmt, 
    w, 
    h, 
    PIX_FMT_RGB24, 
    SWS_BICUBIC,
    NULL, 
    NULL, 
    NULL);

  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) {
      // Decode video frame
      int len = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
      if ( len < 0 )
      {
        fprintf(stderr, "Problems decoding frame\n");
        return 1;
      }

      fprintf(stderr, "len = %d\n", len );
      
        
      
      // Did we get a video frame?
      if(frameFinished) {
        ++frameCount;
        
        fprintf(stderr, "Saving frame %d\n", frameCount);
        
#if 0 // this is the old code
        img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, 
                    (AVPicture*)pFrame, pCodecCtx->pix_fmt, 
                    pCodecCtx->width, pCodecCtx->height);
#else
        sws_scale(
          img_convert_ctx, 
          (const uint8_t* const*)pFrame->data, 
          pFrame->linesize, 
          0, 
          pCodecCtx->height, 
          pFrameRGB->data,
          pFrameRGB->linesize);
#endif
        
        // Save the frame to disk
        if(++i<=5)
          SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, 
                    i);
      }
    }
    
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
  }
  
  // Free the RGB image
  av_free(buffer);
  av_free(pFrameRGB);
  
  // Free the YUV frame
  av_free(pFrame);
  
  // Close the codec
  avcodec_close(pCodecCtx);
  
  // Close the video file
  av_close_input_file(pFormatCtx);
  
  return 0;
}
Enhanced by Zemanta

No TrackBacks

TrackBack URL: http://linux.amazingdev.com/cgi-bin/mt/mt-tb.cgi/541

About this Entry

This page contains a single entry by Jonathan published on September 28, 2011 2:23 PM.

My Little Menu was the previous entry in this blog.

My Broken Hardware is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.