




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 江西省玉山一中2025屆高二化學第二學期期末學業質量監測試題含解析
- 2025屆河南省周口市扶溝高級中學高二化學第二學期期末考試模擬試題含解析
- 上海市楊浦區控江中學2025屆化學高一下期末經典模擬試題含解析
- 中國方格布行業市場發展前景及發展趨勢與投資戰略研究報告(2024-2030)
- 2025屆廣西壯族自治區桂林市第十八中化學高二下期末學業質量監測試題含解析
- 2025年中國光控蘑菇燈未來發展趨勢分析及投資規劃建議研究報告
- 2025年中國手持式拉曼光譜儀行業全景評估及投資規劃建議報告
- 四川省眉山一中2025年高一化學第二學期期末復習檢測試題含解析
- 2019-2025年中國標準面粉行業發展趨勢預測及投資戰略咨詢報告
- 2025年硝基化合物項目申請報告模板
- 內網滲透面試題及答案
- 戀愛自愿贈予協議合同
- 2025年知識產權市場環境分析
- 非法金融活動類型與防范指南
- 2025-2030中國循環腫瘤細胞(CTC)和癌癥干細胞(CSC)行業市場現狀供需分析及投資評估規劃分析研究報告
- 人教版八下道德與法治6.5國家司法機關教學設計
- 2023年開封職業學院單招職業技能考試題庫附答案
- 第18課 冷戰與國際格局的演變 【基礎深耕】高一下學期統編版(2019)必修中外歷史綱要下
- 部隊訓練防中暑課件
- 采血后預防淤青的按壓方式
- SnRK1在植物逆境響應和生長發育中的作用
評論
0/150
提交評論