C++ffmpeg硬件解碼的實現方法_第1頁
C++ffmpeg硬件解碼的實現方法_第2頁
C++ffmpeg硬件解碼的實現方法_第3頁
C++ffmpeg硬件解碼的實現方法_第4頁
C++ffmpeg硬件解碼的實現方法_第5頁
已閱讀5頁,還剩5頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第C++ffmpeg硬件解碼的實現方法目錄什么是硬件解碼為什么要使用硬件解碼怎樣使用硬件解碼注意事項關鍵函數解析

什么是硬件解碼

普通解碼是利用cpu去解碼也就是軟件解碼硬件解碼就是利用gpu去解碼

為什么要使用硬件解碼

首先最大的好處快硬解播放出來的視頻較為流暢,并且能夠延長移動設備播放視頻的時間;而軟解由于軟解加大CPU工作負荷,會占用過多的移動CPU資源,如果CPU能力不足,則軟件也將受到影響最主要就是一個字快

怎樣使用硬件解碼

ffmpeg內部為我們提供了友好的接口去實現硬件解碼

注意事項

ffmpeg內部有很多編解碼器并不是所有的編解碼器都支持硬件解碼并且就算支持硬件解碼的編解碼器也不一定能支持你的顯卡也就是說在使用硬件解碼時我們首先要去判斷這個解碼器是否支持在這個平臺對這個顯卡進行硬件編解碼不然是無法使用的

對顯卡廠家SDK進行封裝和集成,實現部分的硬件編解碼

其次在ffmpeg中軟件編解碼器可以實現相關硬解加速。如在h264解碼器中可以使用cuda加速,qsv加速,dxva2加速,d3d11va加速,opencl加速等。cudaqsv等就是不同公司推出的針對gpu編程的工具包

AV_CODEC_ID_H264;代表是h264編解碼器。而name代表某一個編碼器或解碼器。通常我們使用avcodec_find_decoder(ID)和avcodec_find_encoder(ID)來解碼器和編碼器。默認采用的軟件編解碼。如果我們需要使用硬件編解碼,采用avcodec_find_encoder_by_name(name)和avcodec_find_decoder_by_name(name)來指定編碼器。其他代碼流程與軟件編解碼一致。

//codec=avcodec_find_decoder(AV_CODEC_ID_H264);

codec=avcodec_find_decoder_by_name("h264_cuvid");

if(!codec){

fprintf(stderr,"Codecnotfound\n");

exit(1);

}

通過id找到的可能并不是你預期中的編解碼器通過name找到的一定是你想要的

下面是ffmpeg官方的硬件解碼例子我加上了中文注釋方便理解

#includestdio.h

#includelibavcodec/avcodec.h

#includelibavformat/avformat.h

#includelibavutil/pixdesc.h

#includelibavutil/hwcontext.h

#includelibavutil/opt.h

#includelibavutil/avassert.h

#includelibavutil/imgutils.h

staticAVBufferRef*hw_device_ctx=NULL;

staticenumAVPixelFormathw_pix_fmt;

staticFILE*output_file=NULL;

staticinthw_decoder_init(AVCodecContext*ctx,constenumAVHWDeviceTypetype)

interr=0;

//創建硬件設備信息上下文

if((err=av_hwdevice_ctx_create(hw_device_ctx,type,

NULL,NULL,0))0){

fprintf(stderr,"FailedtocreatespecifiedHWdevice.\n");

returnerr;

//綁定編解碼器上下文和硬件設備信息上下文

ctx-hw_device_ctx=av_buffer_ref(hw_device_ctx);

returnerr;

staticenumAVPixelFormatget_hw_format(AVCodecContext*ctx,

constenumAVPixelFormat*pix_fmts)

constenumAVPixelFormat*p;

for(p=pix_fmts;*p!=-1;p++){

if(*p==hw_pix_fmt)

return*p;

fprintf(stderr,"FailedtogetHWsurfaceformat.\n");

returnAV_PIX_FMT_NONE;

staticintdecode_write(AVCodecContext*avctx,AVPacket*packet)

AVFrame*frame=NULL,*sw_frame=NULL;

AVFrame*tmp_frame=NULL;

uint8_t*buffer=NULL;

intsize;

intret=0;

ret=avcodec_send_packet(avctx,packet);

if(ret0){

fprintf(stderr,"Errorduringdecoding\n");

returnret;

while(1){

if(!(frame=av_frame_alloc())||!(sw_frame=av_frame_alloc())){

fprintf(stderr,"Cannotallocframe\n");

ret=AVERROR(ENOMEM);

gotofail;

ret=avcodec_receive_frame(avctx,frame);

if(ret==AVERROR(EAGAIN)||ret==AVERROR_EOF){

av_frame_free(frame);

av_frame_free(sw_frame);

return0;

elseif(ret0){

fprintf(stderr,"Errorwhiledecoding\n");

gotofail;

if(frame-format==hw_pix_fmt){

/*retrievedatafromGPUtoCPU*/

if((ret=av_hwframe_transfer_data(sw_frame,frame,0))0){

fprintf(stderr,"Errortransferringthedatatosystemmemory\n");

gotofail;

tmp_frame=sw_frame;

else

tmp_frame=frame;

size=av_image_get_buffer_size(tmp_frame-format,tmp_frame-width,

tmp_frame-height,1);

buffer=av_malloc(size);

if(!buffer){

fprintf(stderr,"Cannotallocbuffer\n");

ret=AVERROR(ENOMEM);

gotofail;

ret=av_image_copy_to_buffer(buffer,size,

(constuint8_t*const*)tmp_frame-data,

(constint*)tmp_frame-linesize,tmp_frame-format,

tmp_frame-width,tmp_frame-height,1);

if(ret0){

fprintf(stderr,"Cannotcopyimagetobuffer\n");

gotofail;

if((ret=fwrite(buffer,1,size,output_file))0){

fprintf(stderr,"Failedtodumprawdata.\n");

gotofail;

fail:

av_frame_free(frame);

av_frame_free(sw_frame);

av_freep(buffer);

if(ret0)

returnret;

intmain(intargc,char*argv[])

AVFormatContext*input_ctx=NULL;

intvideo_stream,ret;

AVStream*video=NULL;

AVCodecContext*decoder_ctx=NULL;

AVCodec*decoder=NULL;

AVPacketpacket;

enumAVHWDeviceTypetype;

inti;

if(argc4){

fprintf(stderr,"Usage:%sdevicetypeinputfileoutputfile\n",argv[0]);

return-1;

//通過你傳入的名字來找到對應的硬件解碼類型

type=av_hwdevice_find_type_by_name(argv[1]);

if(type==AV_HWDEVICE_TYPE_NONE){

fprintf(stderr,"Devicetype%sisnotsupported.\n",argv[1]);

fprintf(stderr,"Availabledevicetypes:");

while((type=av_hwdevice_iterate_types(type))!=AV_HWDEVICE_TYPE_NONE)

fprintf(stderr,"%s",av_hwdevice_get_type_name(type));

fprintf(stderr,"\n");

return-1;

/*opentheinputfile*/

if(avformat_open_input(input_ctx,argv[2],NULL,NULL)!=0){

fprintf(stderr,"Cannotopeninputfile'%s'\n",argv[2]);

return-1;

if(avformat_find_stream_info(input_ctx,NULL)0){

fprintf(stderr,"Cannotfindinputstreaminformation.\n");

return-1;

/*findthevideostreaminformation*/

ret=av_find_best_stream(input_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,decoder,0);

if(ret0){

fprintf(stderr,"Cannotfindavideostreamintheinputfile\n");

return-1;

video_stream=ret;

//去遍歷所有編解碼器支持的硬件解碼配置如果和之前你指定的是一樣的那么就可以繼續執行了不然就找不到

for(i=0;;i++){

constAVCodecHWConfig*config=avcodec_get_hw_config(decoder,i);

if(!config){

fprintf(stderr,"Decoder%sdoesnotsupportdevicetype%s.\n",

decoder-name,av_hwdevice_get_type_name(type));

return-1;

if(config-methodsAV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX

config-device_type==type){

//把硬件支持的像素格式設置進去

hw_pix_fmt=config-pix_fmt;

break;

if(!(decoder_ctx=avcodec_alloc_context3(decoder)))

returnAVERROR(ENOMEM);

video=input_ctx-streams[video_stream];

if(avcodec_parameters_to_context(decoder_ctx,video-codecpar)0)

return-1;

//填入回調函數通過這個函數編解碼器能夠知道顯卡支持的像素格式

decoder_ctx-get_format=get_hw_format;

if(hw_decoder_init(decoder_ctx,type)0)

return-1;

//綁定完成后打開編解碼器

if((ret=avcodec_open2(decoder_ctx,decoder,NULL))0){

fprintf(stderr,"Failedtoopencodecforstream#%u\n",video_stream);

return-1;

/*openthefiletodumprawdata*/

output_file=fopen(argv[3],"w+");

/*actualdecodinganddumptherawdata*/

while(ret=0){

if((ret=av_read_frame(input_ctx,packet))0)

break;

if(video_stream==packet.stream_index)

ret=decode_write(decoder_ctx,packet);

av_packet_unref(packet);

/*flushthedecoder*/

packet.data=NULL;

packet.size=0;

ret=decode_write(decoder_ctx,packet);

av_packet_unref(packet);

if(output_file)

fclose(output_file);

avcodec_free_context(decoder_ctx);

avformat_close_input(input_ctx);

av_buffer_unref(hw_device_ctx);

return0;

}

關鍵函數解析

enumAVHWDeviceTypeav_hwdevice_find_type_by_name(constchar*name);

通過傳入的參數查找對應的硬件類型其中AVHWDeviceType值如下

constAVCodecHWConfig*avcodec_get_hw_config(constAVCodec*codec,intindex);

拿到編解碼器支持的硬件配置比如硬件支持的像素格式等等

staticenumAVPixelFormatget_hw_format(AVCodecContext*ctx,

constenumAVPixelFormat*pix_fmts)

constenumAVPixelFormat*p;

for(p=pix_fmts;*p!=-1;p++){

if

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論