Advertisement
Guest User

Untitled

a guest
Oct 9th, 2013
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.77 KB | None | 0 0
  1. #include <libavcodec/avcodec.h>
  2. #include <libavformat/avformat.h>
  3. #include <libavutil/avutil.h>
  4. #include <libswscale/swscale.h>
  5.  
  6.  
  7. /** We do a bit of standard file opening, etc., and then write the RGB data.
  8.     *   We write the file one line at a time. A PPM file is simply a file that has RGB
  9.     *   information laid out in a long string. If you know HTML colors, it would be like
  10.     *   laying out the color of each pixel end to end like #ff0000#ff0000.... would be a
  11.     *   red screen. (It's stored in binary and without the separator, but you get the idea.)
  12.     *   The header indicated how wide and tall the image is, and the max size of the RGB values. */
  13.  
  14. void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  15.   FILE *pFile;
  16.   char szFilename[80];
  17.   int  y;
  18.  
  19.   // Open file
  20.   sprintf(szFilename, "frame%d.ppm", iFrame);
  21.   pFile=fopen(szFilename, "wb");
  22.   if(pFile==NULL)
  23.     return;
  24.  
  25.   // Write header
  26.   fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  27.  
  28.   // Write pixel data
  29.   for(y=0; y<height; y++)
  30.     fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  31.  
  32.   // Close file
  33.   fclose(pFile);
  34. }
  35.  
  36. int main ( int argc, char* argv[] )
  37.     {
  38.     /**   This registers all available file formats and codecs with the library
  39.     *      so they will be used automatically when a file with the corresponding
  40.     *      format/codec is opened. Note that you only need to call av_register_all() once,
  41.     *      so we do it here in main(). If you like, it's possible to register only certain
  42.     *      individual file formats and codecs, but there's usually no reason why you
  43.     *      would have to do that.  */
  44.     av_register_all();
  45.  
  46.     AVFormatContext* pFormatCtx;
  47.     pFormatCtx = NULL;
  48.     // Open video file
  49.  
  50.     /**    We get our filename from the first argument.
  51.     *      This function reads the file header and stores information about the file
  52.     *      format in the AVFormatContext structure we have given it.
  53.     *      The last three arguments are used to specify the file format, buffer size,
  54.     *      and format options, but by setting this to NULL or 0, libavformat will
  55.     *      auto-detect these.
  56.     *      This function only looks at the header, so next we need to check out the stream information in the file. */
  57.     if ( avformat_open_input ( &pFormatCtx, argv[1], NULL, NULL ) != 0 )
  58.         return -1; // couldn't open file
  59.  
  60.     // Retrieve stream information
  61.     /**    This function populates pFormatCtx->streams with the proper information.
  62.     *      We introduce a handy debugging function to show us what's inside: */
  63.     if ( avformat_find_stream_info ( pFormatCtx, NULL ) < 0 )
  64.         return -1; // couldn't find stream information
  65.  
  66.     /** Now pFormatCtx->streams is just an array of pointers, of size pFormatCtx->nb_streams,
  67.     *    so let's walk through it until we find a video stream. */
  68.  
  69.     int i;
  70.     AVCodecContext* pCodecCtx;
  71.  
  72.     // find the first video stream
  73.     int videoStream = -1;
  74.  
  75.     for ( i = 0; i < pFormatCtx->nb_streams; i++ )
  76.         if ( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
  77.                 videoStream = i;
  78.                 break;
  79.                 }
  80.  
  81.     if ( videoStream == -1 )
  82.         return -1; // Didn't find a video stream
  83.  
  84.     // Get a pointer to the codec context for the video stream
  85.     pCodecCtx = pFormatCtx->streams[videoStream]->codec;
  86.  
  87.     /** The stream's information about the codec is in what we call the "codec context."
  88.     *   This contains all the information about the codec that the stream is using, and
  89.     *   now we have a pointer to it. But we still have to find the actual codec and open it:
  90.     */
  91.  
  92.  
  93.     AVCodec* pCodec;
  94.  
  95.     // Find the decoder for the video stream
  96.     pCodec = avcodec_find_decoder ( pCodecCtx->codec_id );
  97.  
  98.     if ( pCodec == NULL ) {
  99.             fprintf ( stderr, "Unsupported codec!\n" );
  100.             return -1; // Codec not found
  101.             }
  102.  
  103.     // Open codec
  104.     if ( avcodec_open2 ( pCodecCtx, pCodec, NULL ) < 0 )
  105.         return -1; // Could not open codec
  106.  
  107.     /** Some of you might remember from the old tutorial that there were two other parts to this code:
  108.     *   adding CODEC_FLAG_TRUNCATED to pCodecCtx->flags and adding a hack to correct grossly incorrect
  109.     *   frame rates. These two fixes aren't in ffplay.c anymore, so I have to assume that they are not necessary
  110.     *   anymore. There's another difference to point out since we removed that code: pCodecCtx->time_base now
  111.     *   holds the frame rate information. time_base is a struct that has the numerator and denominator (AVRational).
  112.     *   We represent the frame rate as a fraction because many codecs have non-integer frame rates (like NTSC's 29.97fps).
  113.     */
  114.  
  115.     /** Now we need a place to actually store the frame:  */
  116.  
  117.     AVFrame* pFrame;
  118.     AVFrame* pFrameRGB;
  119.  
  120.     // Allocate video frame
  121.     pFrame = avcodec_alloc_frame();
  122.  
  123.     /** Since we're planning to output PPM files, which are stored in 24-bit RGB,
  124.      *   we're going to have to convert our frame from its native format to RGB.
  125.      *   ffmpeg will do these conversions for us. For most projects (including ours)
  126.      *   we're going to want to convert our initial frame to a specific format.
  127.      *   Let's allocate a frame for the converted frame now. */
  128.  
  129.     // Allocate an AVFrame structure
  130.     pFrameRGB = avcodec_alloc_frame();
  131.  
  132.     if ( pFrameRGB == NULL )
  133.         return -1;
  134.  
  135.     /** Even though we've allocated the frame, we still need a place to put the raw data
  136.     * when we convert it. We use avpicture_get_size to get the size we need, and allocate
  137.     * the space manually:  */
  138.  
  139.     uint8_t* buffer;
  140.     int numBytes;
  141.     // Determine required buffer size and allocate buffer
  142.     numBytes = avpicture_get_size ( PIX_FMT_RGB24, pCodecCtx->width,
  143.                                      pCodecCtx->height );
  144.     buffer = ( uint8_t* ) av_malloc ( numBytes * sizeof ( uint8_t ) );
  145.  
  146.     /** av_malloc is ffmpeg's malloc that is just a simple wrapper around malloc
  147.     * that makes sure the memory addresses are aligned and such. It will not protect
  148.     * you from memory leaks, double freeing, or other malloc problems.
  149.  
  150.     * Now we use avpicture_fill to associate the frame with our newly allocated buffer.
  151.     * About the AVPicture cast: the AVPicture struct is a subset of the AVFrame struct
  152.     * - the beginning of the AVFrame struct is identical to the AVPicture struct. */
  153.  
  154.     // Assign appropriate parts of buffer to image planes in pFrameRGB
  155.     // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  156.     // of AVPicture
  157.     avpicture_fill ( ( AVPicture* ) pFrameRGB, buffer, PIX_FMT_RGB24,
  158.                      pCodecCtx->width, pCodecCtx->height );
  159.  
  160.     //Finally! Now we're ready to read from the stream!
  161.  
  162.     //Reading the Data
  163.  
  164.     /** What we're going to do is read through the entire video stream by reading in the packet,
  165.     *  decoding it into our frame, and once our frame is complete, we will convert and save it. */
  166.  
  167.     int frameFinished;
  168.     AVPacket packet;
  169.  
  170.     i = 0;
  171.     struct SwsContext* pSWSContext;
  172.     pSWSContext = NULL;
  173.     pSWSContext = sws_getCachedContext(pSWSContext, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 1920, 1080, PIX_FMT_RGB24, SWS_BILINEAR, 0, 0, 0);
  174.  
  175.  
  176.     while ( av_read_frame ( pFormatCtx, &packet ) >= 0 ) {
  177.             // Is this a packet from the video stream?
  178.             if ( packet.stream_index == videoStream ) {
  179.                     // Decode video frame
  180.                     avcodec_decode_video2 ( pCodecCtx, pFrame, &frameFinished,
  181.                                            &packet );
  182.  
  183.                     // Did we get a video frame?
  184.                     if ( frameFinished ) {
  185.                             // Convert the image from its native format to RGB
  186.                             sws_scale ( pSWSContext, (const uint8_t * const *) *pFrameRGB->data,  pFrameRGB->linesize, 0,  pFrameRGB->height, pFrame->data,   pFrame->linesize  );
  187.  
  188.                             // Save the frame to disk
  189.                             if ( ++i <= 1000 )
  190.                                 SaveFrame ( pFrameRGB, pCodecCtx->width,
  191.                                             pCodecCtx->height, i );
  192.                             }
  193.                     }
  194.  
  195.             // Free the packet that was allocated by av_read_frame
  196.             av_free_packet ( &packet );
  197.             if(i > 1000) break;
  198.             }
  199.  
  200.     //A note on packets
  201.  
  202.     /** Technically a packet can contain partial frames or other bits of data,
  203.     *   but ffmpeg's parser ensures that the packets we get contain either
  204.     *   complete or multiple frames.
  205.     *  The process, again, is simple: av_read_frame() reads in a packet and stores
  206.     *  it in the AVPacket struct. Note that we've only allocated the packet structure
  207.     *   - ffmpeg allocates the internal data for us, which is pointed to by packet.data.
  208.     *  This is freed by the av_free_packet() later. avcodec_decode_video() converts the
  209.     *  packet to a frame for us. However, we might not have all the information we need
  210.     *  for a frame after decoding a packet, so avcodec_decode_video() sets frameFinished
  211.     *  for us when we have the next frame. Finally, we use img_convert() to convert from
  212.     *  the native format (pCodecCtx->pix_fmt) to RGB. Remember that you can cast an
  213.     *  AVFrame pointer to an AVPicture pointer. Finally, we pass the frame and height and
  214.     *  width information to our SaveFrame function.
  215.  
  216.     * Now all we need to do is make the SaveFrame function to write the RGB information
  217.     * to a file in PPM format. We're going to be kind of sketchy on the PPM format itself;
  218.     * trust us, it works. */
  219.  
  220.     // Now, going back to our main() function. Once we're done reading from the video stream, we just have to clean everything up:
  221.  
  222.     // Free the RGB image
  223.     av_free ( buffer );
  224.     av_free ( pFrameRGB );
  225.  
  226.     // Free the YUV frame
  227.     av_free ( pFrame );
  228.  
  229.     // Close the codec
  230.     avcodec_close ( pCodecCtx );
  231.  
  232.     // Close the video file
  233.     avformat_close_input ( &pFormatCtx );
  234.  
  235.     return 0;
  236.  
  237.     /**You'll notice we use av_free for the memory we allocated with avcode_alloc_frame and av_malloc.
  238.  
  239.         That's it for the code! Now, if you're on Linux or a similar platform, you'll run:
  240.  
  241.         gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lm
  242.  
  243.         If you have an older version of ffmpeg, you may need to drop -lavutil:
  244.  
  245.         gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lz -lm
  246.  
  247.         Most image programs should be able to open PPM files. Test it on some movie files.
  248.     */
  249.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement