FFMPEG:H264解码-SDL显示(RGB32、RGB24、YUV420P、YUV422)

简介: <p><img src="http://img.blog.csdn.net/20141125163123578?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvMDUxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt=""><br>


FFMpeg对视频文件进行解码的大致流程

1. 注册所有容器格式: av_register_all()
2. 打开文件: av_open_input_file()
3. 从文件中提取流信息: av_find_stream_info()
4. 穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO
5. 查找对应的解码器: avcodec_find_decoder()
6. 打开编解码器: avcodec_open()
7. 为解码帧分配内存: avcodec_alloc_frame()
8. 不停地从码流中提取出帧数据: av_read_frame()
9. 判断帧的类型,对于视频帧调用: avcodec_decode_video()
10. 解码完后,释放解码器: avcodec_close()
11. 关闭输入文件:av_close_input_file()

//添加的库:avcodec.lib avdevice.lib avfilter.lib avformat.lib avutil.lib swscale.lib   SDL.lib 
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>


#include <libsdl/SDL.h>
#include <libsdl/SDL_thread.h>
};


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; y<height; y++)
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

// Close file
fclose(pFile);
}


void CTest0Dlg::OnButton1() 
{
// TODO: Add your control notification handler code here
 AVFormatContext *pFormatCtx;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame; 
  AVFrame         *pFrameRGB;
  AVPacket        packet;
  int             frameFinished;
  int             numBytes;
  uint8_t         *buffer;
  static int sws_flags = SWS_BICUBIC;
  struct SwsContext *img_convert_ctx;
   AVPicture pict;  
//  argc = 2;
  char argv[100] = "d:\\temp\\VIDEO720576.264";
 // argv[1] = "d:\\temp\\ff.mpg";
 
  // /*注册所有可用的格式和编解码器*/
  av_register_all();
  
  // Open video file /*以输入方式打开一个媒体文件,也即源文件,codecs并没有打开,只读取了文件的头信息*/
  if(av_open_input_file(&pFormatCtx, argv, NULL, 0, NULL)!=0)
    return ; // Couldn't open file
  
  // Retrieve stream information
/*通过读取媒体文件的中的包来获取媒体文件中的流信息,对于没有头信息的文件如(mpeg)是非常有用的,
// 该函数通常重算类似mpeg-2帧模式的真实帧率,该函数并未改变逻辑文件的position.
*/
  if(av_find_stream_info(pFormatCtx)<0)
    return ; // Couldn't find stream information
  
  // Dump information about file onto standard error
//该函数的作用就是检查下初始化过程中设置的参数是否符合规范
  dump_format(pFormatCtx, 0, argv, 0);
  
  // Find the first video stream
  videoStream=-1;
  printf("%d\n",pFormatCtx->nb_streams);
  getchar();
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO&&videoStream < 0)
 {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return ; // 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);
/*通过code ID查找一个已经注册的音视频编码器,查找编码器之前,必须先调用av_register_all注册所有支持的编码器
音视频编码器保存在一个链表中,查找过程中,函数从头到尾遍历链表,通过比较编码器的ID来查找
*/
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return ; // Codec not found
  }
  // Open codec
//使用给定的AVCodec初始化AVCodecContext


  if(avcodec_open(pCodecCtx, pCodec)<0)
    return ; // Could not open codec


  //printf("name %s\n",pCodec->name);
  //getchar();


  // Allocate video frame
  pFrame=avcodec_alloc_frame();
  
  // Allocate an AVFrame structure
  pFrameRGB=avcodec_alloc_frame();
  if(pFrameRGB==NULL)
    return ;
  
  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(PIX_FMT_RGB32, 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_RGB32,
   pCodecCtx->width, pCodecCtx->height);
  
  // Read frames and save first five frames to disk
  i=0;
  ////////////////////////////////////////////////////////////////
  if (SDL_Init(SDL_INIT_VIDEO) < 0)
  {
 fprintf(stderr, "can not initialize SDL:%s\n", SDL_GetError());
 exit(1);
   }
  atexit(SDL_Quit);
  SDL_Surface *screen;
  screen = SDL_SetVideoMode(720, 576, 32, SDL_SWSURFACE|SDL_ANYFORMAT);
  if ( screen == NULL ) 
  {
 exit(2);
  }
  SDL_Surface *image;


    Uint32 rmask, gmask, bmask, amask;


    /* SDL interprets each pixel as a 32-bit number, so our masks must depend
       on the endianness (byte order) of the machine */
#if 0//SDL_BYTEORDER == SDL_BIG_ENDIAN
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
#else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
#endif


image = SDL_CreateRGBSurface(SDL_SWSURFACE, 720, 576, 0,
rmask, gmask, bmask, NULL);
    if(image == NULL) 
{
        //fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
        exit(1);
    }
  //////////////////////////////////////////////////////////////////
  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) 
    {
  // Convert the image from its native format to RGB




        img_convert_ctx = sws_getContext( pCodecCtx->width, 
               pCodecCtx->height,
               pCodecCtx->pix_fmt,
               pCodecCtx->width, 
               pCodecCtx->height,
               PIX_FMT_RGB32,
               sws_flags, NULL, NULL, NULL);
        sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);  
        sws_freeContext(img_convert_ctx);
     ////////////////////////////////////////////////////////////////
memcpy(screen->pixels,buffer,720*576*4);

SDL_UpdateRect(screen, 0, 0, image->w, image->h);

/* Free the allocated BMP surface */
    SDL_FreeSurface(image);
/////////////////////////////////////////////////////////////////
     // 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);
  MessageBox("over");
}


void CTest0Dlg::OnButton2() 
{
// TODO: Add your control notification handler code here
 AVFormatContext *pFormatCtx;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame; 
  AVFrame         *pFrameRGB;
  AVPacket        packet;
  int             frameFinished;
  int             numBytes;
  uint8_t         *buffer;
  static int sws_flags = SWS_BICUBIC;
  struct SwsContext *img_convert_ctx;
   AVPicture pict;  
//  argc = 2;
  char argv[100] = "d:\\temp\\VIDEO720576.264";
 // argv[1] = "d:\\temp\\ff.mpg";
 
  // /*注册所有可用的格式和编解码器*/
  av_register_all();
  
  // Open video file /*以输入方式打开一个媒体文件,也即源文件,codecs并没有打开,只读取了文件的头信息*/
  if(av_open_input_file(&pFormatCtx, argv, NULL, 0, NULL)!=0)
    return ; // Couldn't open file
  
  // Retrieve stream information
/*通过读取媒体文件的中的包来获取媒体文件中的流信息,对于没有头信息的文件如(mpeg)是非常有用的,
// 该函数通常重算类似mpeg-2帧模式的真实帧率,该函数并未改变逻辑文件的position.
*/
  if(av_find_stream_info(pFormatCtx)<0)
    return ; // Couldn't find stream information
  
  // Dump information about file onto standard error
//该函数的作用就是检查下初始化过程中设置的参数是否符合规范
  dump_format(pFormatCtx, 0, argv, 0);
  
  // Find the first video stream
  videoStream=-1;
  printf("%d\n",pFormatCtx->nb_streams);
  getchar();
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO&&videoStream < 0)
 {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return ; // 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);
/*通过code ID查找一个已经注册的音视频编码器,查找编码器之前,必须先调用av_register_all注册所有支持的编码器
音视频编码器保存在一个链表中,查找过程中,函数从头到尾遍历链表,通过比较编码器的ID来查找
*/
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return ; // Codec not found
  }
  // Open codec
//使用给定的AVCodec初始化AVCodecContext


  if(avcodec_open(pCodecCtx, pCodec)<0)
    return ; // Could not open codec


  //printf("name %s\n",pCodec->name);
  //getchar();


  // Allocate video frame
  pFrame=avcodec_alloc_frame();
  
  // Allocate an AVFrame structure
  pFrameRGB=avcodec_alloc_frame();
  if(pFrameRGB==NULL)
    return ;
  
  // 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);
  
  // Read frames and save first five frames to disk
  i=0;
  ////////////////////////////////////////////////////////////////
  if (SDL_Init(SDL_INIT_VIDEO) < 0)
  {
 fprintf(stderr, "can not initialize SDL:%s\n", SDL_GetError());
 exit(1);
   }
  atexit(SDL_Quit);
  SDL_Surface *screen;
  screen = SDL_SetVideoMode(720, 576, 24, SDL_SWSURFACE|SDL_ANYFORMAT);
  if ( screen == NULL ) 
  {
 exit(2);
  }
  SDL_Surface *image;


    Uint32 rmask, gmask, bmask, amask;


    /* SDL interprets each pixel as a 32-bit number, so our masks must depend
       on the endianness (byte order) of the machine */
#if 0//SDL_BYTEORDER == SDL_BIG_ENDIAN
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
#else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
#endif


image = SDL_CreateRGBSurface(SDL_SWSURFACE, 720, 576, 0,
rmask, gmask, bmask, NULL);
    if(image == NULL) 
{
        //fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
        exit(1);
    }
  //////////////////////////////////////////////////////////////////
  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) 
    {
  // Convert the image from its native format to RGB




        img_convert_ctx = sws_getContext( pCodecCtx->width, 
               pCodecCtx->height,
               pCodecCtx->pix_fmt,
               pCodecCtx->width, 
               pCodecCtx->height,
               PIX_FMT_BGR24,
               sws_flags, NULL, NULL, NULL);
        sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);  
        sws_freeContext(img_convert_ctx);
     ////////////////////////////////////////////////////////////////
memcpy(screen->pixels,buffer,720*576*3);

SDL_UpdateRect(screen, 0, 0, image->w, image->h);

/* Free the allocated BMP surface */
    SDL_FreeSurface(image);
/////////////////////////////////////////////////////////////////
     // 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);
  MessageBox("over");
}


void CTest0Dlg::OnButton3() 
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
 AVFormatContext *pFormatCtx;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame; 
  AVFrame         *pFrameYUV;
  AVPacket        packet;
  int             frameFinished;
  int             numBytes;
  uint8_t         *buffer;
   SDL_Rect        rect;
  static int sws_flags = SWS_BICUBIC;
  struct SwsContext *img_convert_ctx;
   AVPicture pict;  
//  argc = 2;
  char argv[100] = "d:\\temp\\VIDEO720576.264";
 // argv[1] = "d:\\temp\\ff.mpg";
 
  // /*注册所有可用的格式和编解码器*/
  av_register_all();
  
  // Open video file /*以输入方式打开一个媒体文件,也即源文件,codecs并没有打开,只读取了文件的头信息*/
  if(av_open_input_file(&pFormatCtx, argv, NULL, 0, NULL)!=0)
    return ; // Couldn't open file
  
  // Retrieve stream information
/*通过读取媒体文件的中的包来获取媒体文件中的流信息,对于没有头信息的文件如(mpeg)是非常有用的,
// 该函数通常重算类似mpeg-2帧模式的真实帧率,该函数并未改变逻辑文件的position.
*/
  if(av_find_stream_info(pFormatCtx)<0)
    return ; // Couldn't find stream information
  
  // Dump information about file onto standard error
//该函数的作用就是检查下初始化过程中设置的参数是否符合规范
  dump_format(pFormatCtx, 0, argv, 0);
  
  // Find the first video stream
  videoStream=-1;
  printf("%d\n",pFormatCtx->nb_streams);
  getchar();
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO&&videoStream < 0)
 {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return ; // 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);
/*通过code ID查找一个已经注册的音视频编码器,查找编码器之前,必须先调用av_register_all注册所有支持的编码器
音视频编码器保存在一个链表中,查找过程中,函数从头到尾遍历链表,通过比较编码器的ID来查找
*/
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return ; // Codec not found
  }
  // Open codec
//使用给定的AVCodec初始化AVCodecContext


  if(avcodec_open(pCodecCtx, pCodec)<0)
    return ; // Could not open codec


  //printf("name %s\n",pCodec->name);
  //getchar();


  // Allocate video frame
  pFrame=avcodec_alloc_frame();
  
  // Allocate an AVFrame structure
  pFrameYUV=avcodec_alloc_frame();
  if(pFrameYUV==NULL)
    return ;
  
  // 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));
  
  // 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 *)pFrameYUV, buffer, PIX_FMT_YUV420P,
   pCodecCtx->width, pCodecCtx->height);
  
  // Read frames and save first five frames to disk
  i=0;
  ////////////////////////////////////////////////////////////////
  if (SDL_Init(SDL_INIT_VIDEO) < 0)
  {
 fprintf(stderr, "can not initialize SDL:%s\n", SDL_GetError());
 exit(1);
   }
  atexit(SDL_Quit);
  SDL_Surface *screen;
  screen = SDL_SetVideoMode(720, 576, 24, SDL_SWSURFACE|SDL_ANYFORMAT);
  if ( screen == NULL ) 
  {
 exit(2);
  }
  SDL_Overlay *image;


image = SDL_CreateYUVOverlay(pCodecCtx->width,
pCodecCtx->height,
SDL_YV12_OVERLAY,
screen);


    if(image == NULL) 
{
        //fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
        exit(1);
    }
  //////////////////////////////////////////////////////////////////
  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) 
    {
  // Convert the image from its native format to RGB
          SDL_LockYUVOverlay(image);


// pFrameYUV->data[0] = image->pixels[0];//预先改变指针数据区,不用copy
// pFrameYUV->data[1] = image->pixels[2];
// pFrameYUV->data[2] = image->pixels[1];
//
// pFrameYUV->linesize[0] = image->pitches[0];
// pFrameYUV->linesize[1] = image->pitches[2];
// pFrameYUV->linesize[2] = image->pitches[1];


        img_convert_ctx = sws_getContext( pCodecCtx->width, 
               pCodecCtx->height,
               pCodecCtx->pix_fmt,
               pCodecCtx->width, 
               pCodecCtx->height,
               PIX_FMT_YUV420P,
               sws_flags, NULL, NULL, NULL);
        sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameYUV->data,pFrameYUV->linesize);  
        sws_freeContext(img_convert_ctx);


       memcpy(image->pixels[0], pFrameYUV->data[0],720*576);//拷贝数据yuv420,也可预先改变指针
  memcpy(image->pixels[2], pFrameYUV->data[1],720*576/4);
  memcpy(image->pixels[1], pFrameYUV->data[2],720*576/4);


SDL_UnlockYUVOverlay(image);
 
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
SDL_DisplayYUVOverlay(image, &rect);
    }
}
    
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
  }
  
  // Free the RGB image
  av_free(buffer);
  av_free(pFrameYUV);
  
  // Free the YUV frame
  av_free(pFrame);
  
  // Close the codec
  avcodec_close(pCodecCtx);
  
  // Close the video file
  av_close_input_file(pFormatCtx);
  MessageBox("over");
}


void CTest0Dlg::OnButton4() 
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
 AVFormatContext *pFormatCtx;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame; 
  AVFrame         *pFrameYUV;
  AVPacket        packet;
  int             frameFinished;
  int             numBytes;
  uint8_t         *buffer;
   SDL_Rect        rect;
  static int sws_flags = SWS_BICUBIC;
  struct SwsContext *img_convert_ctx;
   AVPicture pict;  
//  argc = 2;
  char argv[100] = "d:\\temp\\VIDEO720576.264";
 // argv[1] = "d:\\temp\\ff.mpg";
 
  // /*注册所有可用的格式和编解码器*/
  av_register_all();
  
  // Open video file /*以输入方式打开一个媒体文件,也即源文件,codecs并没有打开,只读取了文件的头信息*/
  if(av_open_input_file(&pFormatCtx, argv, NULL, 0, NULL)!=0)
    return ; // Couldn't open file
  
  // Retrieve stream information
/*通过读取媒体文件的中的包来获取媒体文件中的流信息,对于没有头信息的文件如(mpeg)是非常有用的,
// 该函数通常重算类似mpeg-2帧模式的真实帧率,该函数并未改变逻辑文件的position.
*/
  if(av_find_stream_info(pFormatCtx)<0)
    return ; // Couldn't find stream information
  
  // Dump information about file onto standard error
//该函数的作用就是检查下初始化过程中设置的参数是否符合规范
  dump_format(pFormatCtx, 0, argv, 0);
  
  // Find the first video stream
  videoStream=-1;
  printf("%d\n",pFormatCtx->nb_streams);
  getchar();
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO&&videoStream < 0)
 {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return ; // 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);
/*通过code ID查找一个已经注册的音视频编码器,查找编码器之前,必须先调用av_register_all注册所有支持的编码器
音视频编码器保存在一个链表中,查找过程中,函数从头到尾遍历链表,通过比较编码器的ID来查找
*/
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return ; // Codec not found
  }
  // Open codec
//使用给定的AVCodec初始化AVCodecContext


  if(avcodec_open(pCodecCtx, pCodec)<0)
    return ; // Could not open codec


  //printf("name %s\n",pCodec->name);
  //getchar();


  // Allocate video frame
  pFrame=avcodec_alloc_frame();
  
  // Allocate an AVFrame structure
  pFrameYUV=avcodec_alloc_frame();
  if(pFrameYUV==NULL)
    return ;
  
  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(PIX_FMT_YUV422, 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 *)pFrameYUV, buffer, PIX_FMT_YUV422,
   pCodecCtx->width, pCodecCtx->height);
  
  // Read frames and save first five frames to disk
  i=0;
  ////////////////////////////////////////////////////////////////
  if (SDL_Init(SDL_INIT_VIDEO) < 0)
  {
 fprintf(stderr, "can not initialize SDL:%s\n", SDL_GetError());
 exit(1);
   }
  atexit(SDL_Quit);
  SDL_Surface *screen;
  screen = SDL_SetVideoMode(720, 576, 24, SDL_SWSURFACE|SDL_ANYFORMAT);
  if ( screen == NULL ) 
  {
 exit(2);
  }
  SDL_Overlay *image;


image = SDL_CreateYUVOverlay(pCodecCtx->width,
pCodecCtx->height,
SDL_YUY2_OVERLAY,
screen);


    if(image == NULL) 
{
        //fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
        exit(1);
    }
  //////////////////////////////////////////////////////////////////
  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) 
    {
  // Convert the image from its native format to RGB
          SDL_LockYUVOverlay(image);


// pFrameYUV->data[0] = image->pixels[0];
// pFrameYUV->data[1] = image->pixels[2];
// pFrameYUV->data[2] = image->pixels[1];
//
// pFrameYUV->linesize[0] = image->pitches[0];
// pFrameYUV->linesize[1] = image->pitches[2];
// pFrameYUV->linesize[2] = image->pitches[1];


        img_convert_ctx = sws_getContext( pCodecCtx->width, 
               pCodecCtx->height,
               pCodecCtx->pix_fmt,
               pCodecCtx->width, 
               pCodecCtx->height,
               PIX_FMT_YUV422,
               sws_flags, NULL, NULL, NULL);
        sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameYUV->data,pFrameYUV->linesize);  
        sws_freeContext(img_convert_ctx);


       memcpy(image->pixels[0], pFrameYUV->data[0],720*576*2);//拷贝数据yuv422




SDL_UnlockYUVOverlay(image);
 
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
SDL_DisplayYUVOverlay(image, &rect);
    }
}
    
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
  }
  
  // Free the RGB image
  av_free(buffer);
  av_free(pFrameYUV);
  
  // Free the YUV frame
  av_free(pFrame);
  
  // Close the codec
  avcodec_close(pCodecCtx);
  
  // Close the video file
  av_close_input_file(pFormatCtx);
  MessageBox("over");
}

http://download.csdn.net/detail/mao0514/8202691


相关文章
|
4月前
|
数据采集 大数据 Python
FFmpeg 在爬虫中的应用案例:流数据解码详解
在大数据背景下,网络爬虫与FFmpeg结合,高效采集小红书短视频。需准备FFmpeg、Python及库如Requests和BeautifulSoup。通过设置User-Agent、Cookie及代理IP增强隐蔽性,解析HTML提取视频链接,利用FFmpeg下载并解码视频流。示例代码展示完整流程,强调代理IP对避免封禁的关键作用,助你掌握视频数据采集技巧。
FFmpeg 在爬虫中的应用案例:流数据解码详解
|
4月前
|
语音技术 C语言 Windows
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
|
5月前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
243 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
5月前
|
编解码 Linux 计算机视觉
python 调用ffmpeg使用usb摄像头录制视频,输出h264格式,自动获取摄像头的最佳帧率和最大画面尺寸
使用 Python 调用 FFmpeg 进行 USB 摄像头视频录制,需先确保安装 FFmpeg 和 Python 的 `subprocess` 模块。代码示例展示了如何自动获取摄像头的最佳帧率和最大分辨率,然后录制视频。首先通过 FFmpeg 列出摄像头格式获取信息,解析出帧率和分辨率,选择最优值。之后调用 FFmpeg 命令录制视频,设置帧率、分辨率等参数。注意 `/dev/video0` 是 Linux 的摄像头设备路径,Windows 系统需相应调整。代码中未直接实现自动获取最佳参数,通常需要借助其他库如 OpenCV。
|
6月前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
94 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
18天前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
80 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
25天前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
45 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
30天前
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
117 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
|
1月前
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
60 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
|
2月前
|
XML Java Android开发
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
GSYVideoPlayer是一款国产移动端视频播放器,支持弹幕、滤镜、广告等功能,采用IJKPlayer、Media3(EXOPlayer)、MediaPlayer及AliPlayer多种内核。截至2024年8月,其GitHub星标数达2万。集成时需使用新版Android Studio,并按特定步骤配置依赖与权限。提供了NormalGSYVideoPlayer、GSYADVideoPlayer及ListGSYVideoPlayer三种控件,支持HLS、RTMP等多种直播链接。
90 18
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer

热门文章

最新文章