在window下使用ffmpeg进行解码

ffmpeg的库可下载:搜索ffmpeg sdk 3.2即可得到。

一、解码显示过程

我使用的环境是vs2008

头文件:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>

 #ifdef __cplusplus

extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif

1、注册所用编码器或者解码器
    av_register_all();

2、打开视频文件
    AVFormatContext *pFormatCtx;//AVFormatContext 即format I/O context,比较重要,里面记录了流文件相关信息,基本贯穿整个处理流程

    // Open video file

    if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
       return -1; // Couldn't open file
    dump_format(pFormatCtx, 0,argv[1],  0);//用于调试,可以输出一些相关信息的

3、获取流的一些信息,比如说解码时需要的height及width
    if(av_find_stream_info(pFormatCtx)<0)
       return -1; // Couldn't find stream information

4、找到视频流

 AVCodecContext *pCodecCtx;//AVCodecContext即Codec的相关信息
 
 // 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
 
 pCodecCtx=pFormatCtx->streams[videoStream]->codec;
5、为对应的视频流找到编解码器
    // Find the decoder for the video stream
 
 AVCodec *pCodec;//编解码器信息
 pCodec = NULL;
 pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
 
 if(pCodec==NULL) {
  
   fprintf(stderr, "Unsupported codec!\n");
  
   return -1; // Codec not found
  
 }
6、为对应的流打开所需要的编码器
    // Open codec
 
 if(avcodec_open(pCodecCtx, pCodec)<0)
  
   return -1; // Could not open code
7、解码
-----分配一个AVFrame的结构,用于记录原始图像信息
 AVFrame *pFrame;
 pFrame = NULL;
 pFrame = avcodec_alloc_frame();
 
 if(pFrame==NULL)
  
   return -1;
-----根据图像大小创建一个缓冲区
 uint8_t *buffer;
 
 int numBytes;
 
 // Determine required buffer size and allocate buffer
 
 numBytes=avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width,
  
 pCodecCtx->height);
 
 buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
 avpicture_fill((AVPicture *)pFrame, buffer, PIX_FMT_RGB24,
  
 pCodecCtx->width, pCodecCtx->height);//填充AVPicture对应域
-------解码
 int frameFinished;
 
 AVPacket packet;
 
 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
   
     avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
    
     packet.data, packet.size);
   
   // Did we get a video frame?
   
   if(frameFinished) {


    显示视频。。。。。。
    
 
   }
   
  }
  
  // Free the packet that was allocated by av_read_frame
  
  
  
 }
-------释放资源
 
 av_free_packet(&packet);
 av_free(buffer);
 
 av_free(pFrame);
 
 // Close the codec
 
 avcodec_close(pCodecCtx);
 
 // Close the video file
 
 av_close_input_file(pFormatCtx);
-------显示视频
 1)加入SDL动态库
          1)下载SDL开发包SDL-devel-1.2.14-VC6.zip,并解压主要生成include、lib文件,下载地址:http://www.libsdl.org/download-1.2.php;
          2)在vc的安装目录Microsoft Visual Studio\VC98\Include下创建一个新文件夹SDL,将1)中解压后的include文件夹中所有文件拷贝到所创建SDL文件夹中
          3)将1)中解压后的lib文件夹中.lib文件以及.dll文件拷贝到所创建的工程目录下
          4)在工程的选项配置为多线程已解决库冲突问题
          5)编译后会发现数据定义有冲突,我解决的办法是把SDL中对应的项注释掉
 2)初始化SDL库

 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) 
 {//SDL init
  
   fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
  
   return -1;
  
 }
 3)设置视频模式
 SDL_Surface *screen;
 
 screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
 
 if(!screen) //create a screen
 {
  
   fprintf(stderr, "SDL: could not set video mode - exiting\n");
   return -2;
 }
 4)创建贴图
 SDL_Overlay *bmp;
 
 bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,
  
 SDL_YV12_OVERLAY, screen);
 
 SDL_LockYUVOverlay(bmp);
 
 AVPicture pict;
 
 pict.data[0] = bmp->pixels[0];
 
 pict.data[1] = bmp->pixels[2];
 
 pict.data[2] = bmp->pixels[1];
 
 pict.linesize[0] = bmp->pitches[0];
 
 pict.linesize[1] = bmp->pitches[2];
 
 pict.linesize[2] = bmp->pitches[1];
 
 SwsContext *ctx;
 ctx = sws_getContext(
  pCodecCtx->width,
  pCodecCtx->height,
  pCodecCtx->pix_fmt,
  pCodecCtx->width,
  pCodecCtx->height,
  PIX_FMT_YUV420P,
  SWS_BICUBIC, NULL, NULL, NULL);
    
 if(ctx == NULL) 
 {
   fprintf(stderr, "Cannot get resampling context\n");
   return -3;
 }
 //sws_scale(  ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrame->data,pFrame->linesize);//原文中这句话没有注释,我在测试时发现需要注释掉才能成功
 sws_scale(  ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pict.data,pict.linesize);
 SDL_UnlockYUVOverlay(bmp);
 

 //draw
 
 5)显示图像
 SDL_Rect rect;
 rect.x = 0;   
 rect.y = 0; 
 rect.w = pCodecCtx->width;
 rect.h = pCodecCtx->height;
 SDL_DisplayYUVOverlay(bmp, &rect);
二、注意
1、此实例只解码视频
2、显示图像的时候没有帧率方面的处理,所以播放速度过快,cpu占用率过高,有待完善

原文地址:http://tianyou8.blog.hexun.com/46861549_d.html

你可能感兴趣的:(Microsoft,video,null,buffer,include,Codec)