當前位置:編程學習大全網 - 編程語言 - 如何強制ffmpeg編碼時輸出壹個關鍵幀

如何強制ffmpeg編碼時輸出壹個關鍵幀

如何強制ffmpeg編碼時輸出壹個關鍵幀

AVCodecContext *c //編碼器環境句柄

AVFrame* f //需要編碼的壹幀視頻

/*在avcodec.h文件中有這樣的定義

#define FF_I_TYPE 1 ///< Intra

#define FF_P_TYPE 2 ///< Predicted

#define FF_B_TYPE 3 ///< Bi-dir predicted

#define FF_S_TYPE 4 ///< S(GMC)-VOP MPEG4

#define FF_SI_TYPE 5 ///< Switching Intra

#define FF_SP_TYPE 6 ///< Switching Predicted

#define FF_BI_TYPE 7

*/

在編碼前設置

f->pict_type=FF_I_TYPE;

f->key_frame=1;

註:該幀為I幀時,f->pict_type==FF_I_TYPE && f->key_frame==1

然後編碼

*outsize = avcodec_encode_video(c, temp, outbuf_size, f);

則編碼之後通過如下參數判斷是否為關鍵幀:

key_frame=c->coded_frame->key_frame;

pict_type=c->coded_frame->pict_type;

key_frame==FF_I_TYPE && pict_type==1

ffmpeg如何提取視頻的關鍵幀

av_register_all();

if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0)

printf("error!\n");

if(av_find_stream_info(pFormatCtx)<0)

printf("error!\n");

videoStream=-1;

for(i=0; i<pFormatCtx->nb_streams; i++)

if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)

{

videoStream=i;

break;

}

if(videoStream==-1)

printf("error!\n");// Didn't find a video stream

// 得到視頻流編碼上下文的指針

pCodecCtx=pFormatCtx->streams[videoStream]->codec;

然後選擇解碼器進行解碼:

AVCodec *pCodec;

// 尋找視頻流的解碼器

pCodec=avcodec_find_decoder(pCodecCtx->codec_id);

if(pCodec==NULL)

printf("error!\n");// 找不到解碼器

// 打開解碼器

if(avcodec_open(pCodecCtx, pCodec)<0)

printf("error!\n"); // 打不開解碼器

現在開始,進入解碼和提取關鍵幀的過程:

pFrame=avcodec_alloc_frame();

pFrameRGB = avcodec_alloc_frame();

numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,pCodecCtx->height);

buffer=new uint8_t[numBytes];

avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);

pSWSCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

i=0;

while(av_read_frame(pFormatCtx,&packet)>=0)

{

if(packet.stream_index==videoStream)

{

avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,packet.data, packet.size);

if(frameFinished)

{

if(pFrame->key_frame==1) // 這就是關鍵幀

{

sws_scale(pSWSCtx, pFrame->data, pFrame->linesize,0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

// 保存到磁盤

char pic[200];

sprintf(pic,"pic%d.bmp",i);

i++;

av_create_bmp(pic,pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height,24);

}

}

}

av_free_packet(&packet);

}

最後,釋放資源和句柄

// 釋放 RGB 圖象

av_free(pFrameRGB);

// 釋放YUV 幀

av_free(pFrame);

sws_freeContext(pSWSCtx);

// 關閉解碼器(codec)

avcodec_close(pCodecCtx);

// 關閉視頻文件

av_close_input_file(pFormatCtx)

ffmpeg SDK就支持,以下代碼是ffmpeg官方小組提供的

int main()

{

SwsContext *pSWSCtx;

AVFormatContext *pFormatCtx;

const char *filename="sample.mpg";

int i,videoStream,y_size;

AVCodecContext *pCodecCtx;

AVFrame *pFrame;

AVFrame *pFrameRGB;

int numBytes,frameFinished;

uint8_t *buffer;

static AVPacket packet;

av_register_all();

if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0)

printf("error!\n");

if(av_find_stream_info(pFormatCtx)<0)

printf("error!\n");

dump_format(pFormatCtx, 0, filename, false);

videoStream=-1;

for(i=0; i<pFormatCtx->nb_streams; i++)

if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)

{

videoStream=i;

break;

}

if(videoStream==-1)

printf("error!\n");// Didn't find a video stream

pCodecCtx=pFormatCtx->streams[videoStream]->codec;

AVCodec *pCodec;

pCodec=avcodec_find_decoder(pCodecCtx->codec_id);

if(pCodec==NULL)

printf("error!\n");

if(avcodec_open(pCodecCtx, pCodec)<0)

printf("error!\n");

pFrame=avcodec_alloc_frame();

pFrameRGB = avcodec_alloc_frame();

numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,pCodecCtx->height);

buffer=new uint8_t[numBytes];

avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);

pSWSCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

i=0;

while(av_read_frame(pFormatCtx,&packet)>=0)

{

if(packet.stream_index==videoStream)

{

avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,packet.data, packet.size);

if(frameFinished)

{

if(pFrame->key_frame==1)//這裏取到關鍵幀數據

{

sws_scale(pSWSCtx, pFrame->data, pFrame->linesize,0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

i++;

}

}

}

av_free_packet(&packet);

}

av_free(pFrameRGB);

av_free(pFrame);

sws_freeContext(pSWSCtx);

avcodec_close(pCodecCtx);

av_close_input_file(pFormatCtx);

return 0;

}

live555+ffmpeg如何提取關鍵幀(I幀,P幀,B幀)

live555+ffmpeg如何提取關鍵幀(I幀,P幀,B幀)開發流媒體播放器的時候,特別是在windows mobile,symbian(S60)平臺開發時,很可能遇到需要自己開發播放器的情況。S60平臺提供了CVideoPlayUtility接口可以實現流媒體播放器,但由於非開源,所以相對於自己開發播放器,很多操作受到限制。live555主要用於網絡流接收,ffmpeg則是對接收到的數據進行編碼/解碼。I幀,P幀,B幀是視頻流中三種分類,其中I幀也就是關鍵幀是基礎幀,P幀壹般根據I幀確定,而B幀需要前面兩著的信息。舉例說:the Input sequence for video encoder1 2 3 4 5 6 7I B B P B B I Let's take 1,2,3.. as PTS for simplification the out sequence for video encoder ( this equals the decoder sequence)1 4 2 3 7 5 6I P B B I B B 播放器LIVE555收到的序列順序就應該是: 1 4 2 3 7 5 6 經過解碼器解碼,順序又回到1 2 3 4 5 6 7這種正常順序。 所以我們可以根據avcodec_decode_video來判斷幀別。avcodec_decode_video之後的順序是壹定的。嚴格按照1 2 3 4。。。這樣的順序來。判斷I幀,P,B幀方法:(1):假如解碼成功,則不是I幀就是P幀(根據AVFrame->keyframe判斷是否是I幀)。假如不是I幀,也不是P幀,則只能是B幀(通過pts判斷)。(2):采用AVFrame->pict_type綜合pts的辦法:if(FF_I_TYPE==picture->pict_type) { Printlog("<II>"); } else if(FF_P_TYPE==picture->pict_type) { Printlog("<PP>"); } else if(FF_B_TYPE==picture->pict_type) { Printlog("<BB>"); } else if(FF_S_TYPE==picture->pict_type) { Printlog("<SS>"); } else { Printlog("<OtherType>"); }正常情況下是不會打印出B幀的,因為解碼成功的肯定是I幀或者是P幀.

  • 上一篇:幼兒園中班數學教案:連點成線變圖形
  • 下一篇:自貢市意樹文化傳播有限公司怎麽樣?
  • copyright 2024編程學習大全網