利用ffmpeg0.5 和libjpeg实现抽取视频帧并将其保存为jpeg文件格式程序

简单修改网上关于ffmpeg的例子,实现提取视频帧并将其保存为jpeg图像的源程序。

由于ffmpeg0.5不在兼容img_convert函数,使用sws_scale函数修改了实现YUV颜色空间到RGB空间的转换

这里面一定要注意sws_getCachedContext函数参数的设置问题,一旦设置错了,会出现解码出来的图像出现3个现象!

直接使用libjpeg库实现图像数据的jpeg压缩

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>//注意要包含此头文件与sprintf函数相关

extern "C"
{
 //ffmpeg相关的头文件
 #include "avstring.h"
 #include "avformat.h"
 #include "swscale.h"
 #include "opt.h"
 //libjpeg相关的头文件

 #include "jpeglib.h"

}
int framenum=0 ;
//static int  sws_flags = SWS_BICUBIC ;

//实现视频帧的jpeg压缩
void draw_jpeg(AVPicture *pic,int width,int height)
{
 char fname[128] ;
// AVPicture my_pic ;
 struct jpeg_compress_struct cinfo ;
 struct jpeg_error_mgr jerr ;
 JSAMPROW  row_pointer[1] ;
 int row_stride ;
 uint8_t *buffer ;
 FILE *fp ;
 
 //vfmt2rgb(my_pic,pic) ;
    buffer = pic->data[0];

#ifdef __MINGW32__
    sprintf(fname, "%sDLPShot-%d.jpg", "frame", framenum++);
#else
    sprintf(fname, "%sDLPShot-%d.jpg", "frame", framenum++);
#endif
    fp = fopen (fname, "wb");
    if (fp == NULL)
    {
        av_log(NULL, AV_LOG_ERROR, "fopen %s error/n", fname);
        return;
    }
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fp);

    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
   

    jpeg_set_quality(&cinfo, 80,true);
   
   
    jpeg_start_compress(&cinfo, TRUE);

    row_stride = width * 3;
    while (cinfo.next_scanline < height)
    {
        row_pointer[0] = &buffer[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    fclose(fp);
    jpeg_destroy_compress(&cinfo);
 printf("compress %d frame finished!/n",framenum) ;
    return ;
 
}

void main()
{
 AVFormatContext *pFormatCtx;
 static char *ifilename="1.asf" ;
 AVStream *st;
 AVCodecContext *pCodecCtx;
 AVCodec *pCodec;
 AVFrame *pFrame,*pFrameRGB;
 uint8_t *buffer;
 AVPacket packet;
 struct SwsContext *img_convert_ctx=NULL;
 int numBytes;

 int i,videoStream=-1,frameFinished;
 

 av_register_all();
 if(av_open_input_file(&pFormatCtx, ifilename, NULL, 0, NULL)!=0)
 {
  printf("open video failed!/n") ;
  return ;
 }

 //read information about input file ;
 if(av_find_stream_info(pFormatCtx)<0)
 {
  printf("get information failed!/n") ;
  return ;
 }
//print information about file
 dump_format(pFormatCtx, 0, ifilename, 0);
 
 for(i=0; i<pFormatCtx->nb_streams; i++)
 {
  if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
  {
  videoStream=i;
  break;
  }
 }
 if(videoStream==-1)
  return ; // Didn't find a video stream

  // Get a pointer to the codec context for the video stream
 st=pFormatCtx->streams[videoStream] ;
 pCodecCtx=st->codec;

 // Find the decoder for the video stream
 pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
 if(pCodec==NULL) {
  fprintf(stderr, "Unsupported codec!/n");
  return ; // Codec not found
 }
// Open codec
 if(avcodec_open(pCodecCtx, pCodec)<0)
 {
  printf("open encoder failed!") ;
  return ;
 }

 // Allocate video frame
 pFrame=avcodec_alloc_frame();
 
 // Allocate an AVFrame structure
 pFrameRGB=avcodec_alloc_frame();
 if(pFrameRGB==NULL)
 {
  printf("allocate AVframe failed!/n") ;
  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,
 //  avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
     pCodecCtx->width, pCodecCtx->height);
 //pFrameRGB->alloc_picture(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height) ;

 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)
   {
  // Convert the image from its native format to RGB
   
    if(img_convert_ctx==NULL)
    {
      img_convert_ctx=sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,
      //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
       pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,
     SWS_X ,NULL,NULL,NULL) ;
      if (img_convert_ctx == NULL)
      {
      
       printf("can't init convert context!/n") ;
       return ;
      }

    }
    sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
         0, pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);
   //av_picture_copy((AVPicture*)pFrameRGB,(AVPicture*)pFrame,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height) ;

   // Save the frame to disk
   int a=++i ;
    if((a>50)&&(a<100))
    // SaveFrame(pFrameRGB, pCodecCtx->width,
    //  pCodecCtx->height, i);
    draw_jpeg((AVPicture*)pFrameRGB,pCodecCtx->width,pCodecCtx->height) ;
   }
  }
   
  // 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);

 

}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值