ffmpeg 提取視訊檔案關鍵幀
阿新 • • 發佈:2019-01-23
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