1. 程式人生 > >ffmpeg 提取視訊檔案關鍵幀

ffmpeg 提取視訊檔案關鍵幀

http://blog.csdn.net/fengfeifengfei/article/details/43410205

#include "libavformat/avformat.h"

#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#include "libswscale/swscale.h"
#include <unistd.h>
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{

printf("-------------------\n");
FILE *pFile;
char szFilename[32];
int  y;
// Open file
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile=fopen(szFilename, "wb");
if(pFile==NULL)
{
return ;
}
printf("P6\n%d %d\n255\n", width, height);
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
for(y=0; y<height; y++)
{
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1,width*3 , pFile);
}

fclose(pFile);

}

int main(int argc, char *argv[])
{

//註冊所有型別
av_register_all();
avformat_network_init();
AVFormatContext *pformat;
AVCodecContext  *pcodec;

AVCodec         *pcc;

//

if(argc<2)
{
printf("please  input  filename !!!\n");
return  -1;
}
//為pformat結構申請空間 開啟檔案
pformat=avformat_alloc_context();
if(avformat_open_input(&pformat,argv[1],NULL,NULL))
{
printf("avformat_open_input  error!!!\n");
return  -1;
}
//查詢輸入檔案資訊
if(avformat_find_stream_info(pformat,NULL) <  0)
{
printf("avformat_find_stream_info error !!!\n");
return -1;
}
//查詢視訊流
int videoindex=-1;
int i;
for(i=0;i<pformat->nb_streams;i++)
{
if(pformat->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
    break;
}
}
if(videoindex==-1)
{
printf("can't find video stream in %s\n",pformat->filename);
return  -1;
}
//AVFormatContext  ->AVStream ->AVCodecContext
pcodec=pformat->streams[videoindex]->codec;
printf(" find video stream in %s\n",pformat->filename);

//查詢該視訊流對應的解碼器AVCodec
pcc=avcodec_find_decoder(pcodec->codec_id);
//
if(pcc==NULL)
{
printf("cann't find  decoder in %s\n",pformat->filename);
return  -1;
}
//用該解碼器開啟該視訊檔案
if(avcodec_open2(pcodec,pcc,NULL)<0)
{
printf("avcodec_open2  error !!!\n");
return  -1;
}
//AVFrame  是儲存視訊資料的結構
//pframe  是從資料包中讀出來的資料放在其中
//pframeRGB 是通過 sws_scale轉化格式之後所要儲存的資料結構
AVFrame *pframe,*pframeRGB;
//為pframe 開闢記憶體空間
pframe=avcodec_alloc_frame();
//為轉化視訊格式之後的結構開闢記憶體空間
pframeRGB=avcodec_alloc_frame();
if(pframeRGB==NULL)
{
printf("pframeRGB  alloc error !!!\n");
return -1;
}
//申請空間 通過得到PIX_FMT_RGB24的一個畫素所佔用的記憶體(avpicture_get_size())
uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_RGB24, pcodec->width, pcodec->height));
//將out_buffer 以pframeRGB的形式關聯起來
avpicture_fill((AVPicture *)pframeRGB, out_buffer, PIX_FMT_RGB24, pcodec->width, pcodec->height);
struct  SwsContext  *sws;
//轉換上下文  
sws = sws_getContext(pcodec->width, pcodec->height, pcodec->pix_fmt,320,240, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
int  j=0;
AVPacket *ppacket;//cann*t init 
int got_picture;
while(av_read_frame(pformat,ppacket)>=0)
{
if(ppacket->stream_index==videoindex)
{
int ret=avcodec_decode_video2(pcodec, pframe,&got_picture,ppacket);
if(ret < 0)
{  
printf("Decode Error.(解碼錯誤)\n");
return -1;
}

if(got_picture)
{
//提取i幀
if(pframe->pict_type == AV_PICTURE_TYPE_I)
{
sws_scale(sws , (const uint8_t* const*)pframe->data, pframe->linesize,0, pcodec->height, pframeRGB->data, pframeRGB->linesize);
printf("AV_PICTURE_TYPE_I\n");
SaveFrame(pframeRGB, 320,240, j);
j++;
sleep(1);
}
//提取p幀
/*if(pframe->pict_type == AV_PICTURE_TYPE_P)
{
sws_scale(sws , (const uint8_t* const*)pframe->data, pframe->linesize,0, pcodec->height, pframeRGB->data, pframeRGB->linesize);
printf("AV_PICTURE_TYPE_P\n");
SaveFrame(pframeRGB, 320,240, j);
j++;
sleep(1);
}
//提取b幀
if(pframe->pict_type == AV_PICTURE_TYPE_B)
{
sws_scale(sws , (const uint8_t* const*)pframe->data, pframe->linesize,0, pcodec->height, pframeRGB->data, pframeRGB->linesize);
printf("AV_PICTURE_TYPE_B\n");
SaveFrame(pframeRGB, 320,240, j);
j++;
sleep(1);
}
*/

              }

}

}

av_free_packet(ppacket);

return  0;

}

編譯選項:

gcc  demux_decode2.c  -omain  -I/home/fengfei/ffmpeg_Bin/include   -L/home/fengfei/ffmpeg_Bin/lib  -lavformat -lavdevice  -lavcodec -lavutil  -lpthread  

-lswscale -lswresample  -lSDL  -lbz2    -lz -lm  -lrt