利用FFmpeg编解码库解码h.264压缩数据的demo

下面的程序是参考中华视频网上的一个程序,稍作了修改,在RetHat9上编译通过。使用Darwin Stream Server安装时自带的sample_h264_100kbit.mp4文件做的试验,demo可从文件中读取压缩视频帧,解码,把解码后的YUV数据转换为YUV422格式,写入输出文件(*.yuv)。可以使用YUVviewerPlus.exe观看输出文件。原始文件976KB,解压后输出文件186M。
#define HAVE_AV_CONFIG_H

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

#include "avformat.h"

#undef strcat
#undef sprintf

#define PIC_FMT PIX_FMT_YUV422P

/* new types */
enum bool{false=0,true};
typedef enum bool bool;

int g_yuv_index = 1;

static void smartAV_dump_yuv(char *file_name,AVPicture *pic,int width,int height)
{
  FILE *fp =0;
  char filename[128],index_name[32];
  int i,j,shift;
  uint8_t *yuv_factor;

  strcpy(filename,file_name);
  sprintf(index_name,"new_yuv_dump_%d.yuv",g_yuv_index);
  strcat(filename,index_name);

  fp = fopen(filename,"wb");
  if(fp) {
  for(i = 0; i < 3; i++) {
  shift = (i == 0 ? 0:1);
  yuv_factor = pic->data;
  for(j = 0; j < (height>>shift); j++) {
  fwrite(yuv_factor,(width>>shift),1,fp);
  yuv_factor += pic->linesize;
  }
  }
  fclose(fp);
  g_yuv_index++;
  }
}

static bool GetNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx,int videoStream, AVFrame *pFrame)
{
  static AVPacket packet;
  static int bytesRemaining=0;
  static uint8_t *rawData;
  static bool fFirstTime=true;
  int bytesDecoded;
  int frameFinished;
  // First time we're called, set packet.data to NULL to indicate it
  // doesn't have to be freed
  if (fFirstTime){
  fFirstTime = false;
  packet.data = NULL;
  }
  // Decode packets until we have decoded a complete frame
  while (true)
  {
  // Work on the current packet until we have decoded all of it
  while (bytesRemaining > 0)
  {
  // Decode the next chunk of data
  bytesDecoded = avcodec_decode_video(pCodecCtx, pFrame,
  &frameFinished, rawData, bytesRemaining);
  // Was there an error?
  if (bytesDecoded < 0){
  fprintf(stderr, "Error while decoding frame\n");
  return false;
  }
  bytesRemaining -= bytesDecoded;
  rawData += bytesDecoded;
  // Did we finish the current frame? Then we can return
  if (frameFinished)
  return true;
  }
  // Read the next packet, skipping all packets that aren't for this
  // stream
  do{
  // Free old packet
  if(packet.data != NULL)
  av_free_packet(&packet);
  // Read new packet
  //if(av_read_packet(pFormatCtx, &packet) < 0)
  //goto loop_exit;
  if(av_read_frame(pFormatCtx, &packet)<0)
  goto loop_exit;
  } while(packet.stream_index != videoStream);
  bytesRemaining = packet.size;
  rawData = packet.data;
  }
loop_exit:
  // Decode the rest of the last frame
  bytesDecoded = avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, 
  rawData, bytesRemaining);
  // Free last packet
  if(packet.data != NULL)
  av_free_packet(&packet);
  return frameFinished != 0;
}

int main(int argc, char **argv)
{
  AVFormatContext *pFormatCtx;
  int i, videoStream;
  AVCodecContext *pCodecCtx;
  AVCodec *pCodec;
  AVFrame *pFrame; 
  AVFrame *pFrameYUV;
  clock_t t;
  double fps;
  int y_size, i_frame=0;
  int numBytes;
  uint8_t *buffer;  
  //char* infile="test.mp4";
  //char* outfile="outfile.yuv";
  const char *infile;
  const char *outfile;

  if (argc != 3) {
  printf("usage: %s input_file.mp4 output_file.yuv\n"
  "NOTIC: this is a demo program, it reads the video frames \n" 
  "which are compressed in H.264 standard from input_file.mp4\n"
  "and decode them, it finally gets the raw pictures(YUV422P) \n"
  "and write to output_file.yuv.\n"
  "\n", argv[0]);
  return -1;
  }  

  infile = argv[1];
  outfile = argv[2];

  if(match_ext(outfile, "yuv")==0)
  {
  fprintf(stderr, "\nthe output file must be *.yuv\n");
  return -1;
  }
  
  FILE* fp=fopen(outfile, "wb");
  if (fp==NULL){
  fprintf(stderr, "\nCan't open file %s!", infile);
  return -1;
  }
  
  // Register all formats and codecs
  av_register_all();
   
  // Open video file
  if (av_open_input_file(&pFormatCtx, infile, NULL, 0, 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
  dump_format(pFormatCtx, 0, infile, false);

  t = clock();  
  // Find the first video stream
  videoStream = -1;
  for (i=0; i<pFormatCtx->nb_streams; i++)
  if(pFormatCtx->streams->codec->codec_type == CODEC_TYPE_VIDEO){
  videoStream=i;
  break;
  }

  printf("videoStream: %d\n", videoStream);
   
  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)
  return -1; // Codec not found

  printf("codec_id:%d (28 is ok)\n", pCodecCtx->codec_id);

  /*
  You should not directly try to set CODEC_FLAG_TRUNCATED 
  because libavformat has done the packet spiltter 
  */
  #if 0
  // Inform the codec that we can handle truncated bitstreams -- i.e.,
  // bitstreams where frame boundaries can fall in the middle of packets
  if(pCodec->capabilities & CODEC_CAP_TRUNCATED)
  pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
  #endif
   
  // 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
  pFrameYUV=avcodec_alloc_frame();
  if(pFrameYUV == NULL)
  return -1;  
  
  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(PIC_FMT, pCodecCtx->width,
  pCodecCtx->height);
   
  //buffer = (uint8_t*)malloc(numBytes);
  buffer = (uint8_t*)av_malloc(numBytes);  
   
  // Assign appropriate parts of buffer to image planes in pFrameRGB
  avpicture_fill((AVPicture *)pFrameYUV, buffer, PIC_FMT,
  pCodecCtx->width, pCodecCtx->height);
   
  // Read frames
  while(GetNextFrame(pFormatCtx, pCodecCtx, videoStream, pFrame))
  {  
  img_convert((AVPicture *)pFrameYUV, PIC_FMT, (AVPicture*)pFrame, 
  pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);  
  i_frame++;
  y_size = pCodecCtx->width * pCodecCtx->height;  

  #if 1
  if (i_frame==1) //only output onr time
  {
  printf("\npFrame->linesize[0]=%d, pFrame->linesize[1]=%d, pFrame->linesize[2]=%d!\n",
  pFrame->linesize[0], pFrame->linesize[1], pFrame->linesize[2]);
  printf("\npFrameYUV->linesize[0]=%d, pFrameYUV->linesize[1]=%d, pFrameYUV->linesize[2]=%d!",
  pFrameYUV->linesize[0], pFrameYUV->linesize[1], pFrameYUV->linesize[2]);
  }

  fwrite(pFrameYUV->data[0], 1, y_size, fp);
  fwrite(pFrameYUV->data[1], 1, (y_size/2), fp);
  fwrite(pFrameYUV->data[2], 1, (y_size/2), fp);
  #endif
   
  // if(i_frame > 5)
  // break;
  // smartAV_dump_yuv(outfile, (AVPicture *)pFrame, pCodecCtx->width, pCodecCtx->height);
   
  }
   
  fclose(fp);
  //calculate decode rate
  t = clock() - t;
  fps = (double)(t) / CLOCKS_PER_SEC;
  fps = i_frame / fps;
  printf("\n==>Decode rate %.4f fps!\n", fps);  
   
  // Free the YUV image
  //free(buffer);
  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);
  return 0;
}

你可能感兴趣的:(职场,ffmpeg,h264,休闲)