zoukankan      html  css  js  c++  java
  • codecProcess

    • Opening a Video File

      First things first - let's look at how to open a video file and get at the streams contained in it. The first thing we need to do is to initialize libavformat/libavcodec:  

     1 av_register_all(); 

      This registers all available file formats and codecs with the library so they will be used automatically when a file with the corresponding format/codec is opened. Note that you only need to call av_register_all() once, so it's probably best to do this somewhere in your startup code. If you like, it's possible to register only certain individual file formats and codecs, but there's usually no reason why you would have to do that.  
      Next off, opening the file:  

    1 AVFormatContext *pFormatCtx; 
    2 const char  *filename="myvideo.mpg"// Open video file 
    3 if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0)     
    4     handle_error(); //Couldn't open file

      The last three parameters specify the file format, buffer size and format parameters; by simply specifying NULL or 0 we ask libavformat to auto-detect the format and use a default buffer size. Replace handle_error() with appropriate error handling code for your application.  
      Next, we need to retrieve information about the streams contained in the file:  // Retrieve stream information 

     if(av_find_stream_info(pFormatCtx)<0) handle_error();// Couldn't find stream information  

      This fills the streams field of the AVFormatContext with valid information. As a debugging aid, we'll dump this information onto standard error, but of course you don't have to do this in a production application: 

     1 dump_format(pFormatCtx, 0, filename, false);  

      As mentioned in the introduction, we'll handle only video streams, not audio streams. To make things nice and easy, we simply use the first video stream we find:  

     1 int i, videoStream; 
     2 AVCodecContext *pCodecCtx; // Find the first video stream 
     3 videoStream=-1 4 for(i=0; i<pFormatCtx->nb_streams; i++) {
     5     if(pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO) { 
     6         videoStream=i;         
     7         break;     
     8  9     if(videoStream==-110     handle_error(); // Didn't find a video stream 
    11 }    // Get a pointer to the codec context for the video stream pCodecCtx=&pFormatCtx->streams[videoStream]->codec; 

      OK, so now we've got a pointer to the so-called codec context for our video stream, but we still have to find the actual codec and open it:  AVCodec *pCodec; 

    1 // Find the decoder for the video stream 
    2 pCodec=avcodec_find_decoder(pCodecCtx->codec_id); 
    3 if(pCodec==NULL) 
    4     handle_error(); // Codec not found 

      Inform the codec that we can handle truncated bitstreams -- i.e., bitstreams where frame boundaries can fall in the middle of packets 

    1 if(pCodec->capabilities & CODEC_CAP_TRUNCATED)     
    2     pCodecCtx->flags|=CODEC_FLAG_TRUNCATED; // Open codec 
    3 if(avcodec_open(pCodecCtx, pCodec)<04     handle_error(); // Could not open codec

      So what's up with those "truncated bitstreams"? Well, as we'll see in a moment, the data in a video stream is split up into packets. Since the amount of data per video frame can vary, the boundary between two video frames need not coincide with a packet boundary. Here, we're telling the codec that we can handle this situation.
      One important piece of information that is stored in the AVCodecContext structure is the frame rate of the video. To allow for non-integer frame rates (like NTSC's 29.97 fps), the rate is stored as a fraction, with the numerator in pCodecCtx->frame_rate and the denominator in pCodecCtx->frame_rate_base. While testing the library with different video files, I noticed that some codecs (notably ASF) seem to fill these fields incorrectly (frame_rate_base contains 1 instead of 1000). The following hack fixes this:  

    1 // Hack to correct wrong frame rates that seem to be generated by some  // codecs 
    2 if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1)     
    3     pCodecCtx->frame_rate_base=1000

      Note that it shouldn't be a problem to leave this fix in place even if the bug is corrected some day - it's unlikely that a video would have a frame rate of more than 1000 fps.  
      One more thing left to do: 
      Allocate a video frame to store the decoded images in:  

     1 AVFrame *pFrame;  2 pFrame=avcodec_alloc_frame();  

      That's it! Now let's start decoding some video.

    • Decoding Video Frames

      As I've already mentioned, a video file can contain several audio and video streams, and each of those streams is split up into packets of a particular size. Our job is to read these packets one by one using libavformat, filter out all those that aren't part of the video stream we're interested in, and hand them on to libavcodec for decoding. In doing this, we'll have to take care of the fact that the boundary between two frames can occur in the middle of a packet.  
      Sound complicated? Lucikly, we can encapsulate this whole process in a routine that simply returns the next video frame:  

     1 bool GetNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, int videoStream, AVFrame *pFrame) { 
     2     
     3     static AVPacket packet; 
     4     static int      bytesRemaining=0;     
     5     static uint8_t  *rawData; 
     6     static bool     fFirstTime=true;
     7     int bytesDecoded;     
     8     int frameFinished; 
     9     // First time we're called, set packet.data to NULL to indicate it     
    10     // doesn't have to be freed     
    11     if(fFirstTime) { 
    12         fFirstTime=false;         
    13         packet.data=NULL;     
    14     }
    15      
    16     // Decode packets until we have decoded a complete frame     
    17     while(true) { 
    18     // Work on the current packet until we have decoded all of it         
    19         while(bytesRemaining > 0) { 
    20             // Decode the next chunk of data 
    21             bytesDecoded = avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, rawData, bytesRemaining);             
    22             // Was there an error?             
    23             if(bytesDecoded < 0) { 
    24                 fprintf(stderr, "Error while decoding frame
    ");                 
    25                 return false;             
    26 27 
    28             bytesRemaining-=bytesDecoded;             
    29             rawData+=bytesDecoded; 
    30             // Did we finish the current frame? Then we can return             
    31             if(frameFinished)                 
    32                 return true;         
    33 34 
    35         do { // Read the next packet, skipping all packets that aren't for this         
    36             // stream                                  
    37             // Free old packet             
    38             if(packet.data!=NULL) 
    39                 av_free_packet(&packet);             // Read new packet 
    40 
    41             if(av_read_packet(pFormatCtx, &packet)<0)                 
    42                 goto loop_exit; 
    43         } while(packet.stream_index!=videoStream);  
    44        
    45         bytesRemaining=packet.size;         
    46         rawData=packet.data;     
    47 48 
    49 loop_exit: 
    50     // Decode the rest of the last frame 
    51     bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, rawData, bytesRemaining);     // Free last packet     
    52 
    53     if(packet.data!=NULL) 
    54         av_free_packet(&packet);     
    55     return frameFinished!=056

      Now, all we have to do is sit in a loop, calling GetNextFrame() until it returns false. Just one more thing to take care of: Most codecs return images in YUV 420 format (one luminance and two chrominance channels, with the chrominance channels samples at half the spatial resolution of the luminance channel). Depending on what you want to do with the video data, you may want to convert this to RGB. (Note, though, that this is not necessary if all you want to do is display the video data; take a look at the X11 Xvideo extension, which does YUV-to-RGB and scaling in hardware.) Fortunately, libavcodec provides a conversion routine called img_convert, which does conversion between YUV and RGB as well as a variety of other image formats. The loop that decodes the video thus becomes:  

    1 while(GetNextFrame(pFormatCtx, pCodecCtx, videoStream, pFrame)){ 
    2     img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame,          
    3     pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);     
    4     // Process the video frame (save to disk etc.)     
    5     DoSomethingWithTheImage(pFrameRGB); 
    6 }

      The RGB image pFrameRGB (of type AVFrame *) is allocated like this:  

     1 AVFrame *pFrameRGB;  2 int numBytes;  3 uint8_t *buffer;  

      Allocate an AVFrame structure pFrameRGB=avcodec_alloc_frame(); 

    1 if(pFrameRGB==NULL) 
    2     handle_error(); 
    3 // Determine required buffer size and allocate buffer 
    4 numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); 
    5 buffer=new uint8_t[numBytes]; 

      Assign appropriate parts of buffer to image planes in:

     1 pFrameRGB avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); 

    • Cleaning up 

      OK, we've read and processed our video, now all that's left for us to do is clean up after ourselves:  

    1 // Free the RGB image delete [] buffer; 
    2 av_free(pFrameRGB); 
    3 // Free the YUV frame av_free(pFrame); 
    4 // Close the codec 
    5 avcodec_close(pCodecCtx); 
    6 // Close the video file 
    7 av_close_input_file(pFormatCtx); 

      Done! 

  • 相关阅读:
    IPFS实践之初体验
    自己写的屏幕录像及播放软件
    绿色ip扫描工具
    ASIHTTPRequest 编码问题
    ios开发中,A valid provisioning profile for this executable was not found,的解决方法
    毕业设计之蚁群算法的研究——起始篇
    分享两个模拟get和post方法的工具类,让应用能够与服务器进行数据交互
    安卓中生成二维码和扫描二维码
    分享一个安卓中异步获取网络图片并自适应大小的第三方程序(来自github)
    不只是个程序员
  • 原文地址:https://www.cnblogs.com/solo-heart/p/4210964.html
Copyright © 2011-2022 走看看