注意:
VAAPI 是inter gpu 提供的硬編解碼接口VDPAU 是 video decode present api for unixnvdec / ncvid 都是nivida產(chǎn)出的硬解接口,區(qū)別在于解碼方式,和數(shù)據(jù)傳輸方式不同nvenc nivida 硬編接口
編譯 & 運(yùn)行
linux: gcc -g video_decode_gpu.c `pkg-config –libs libavformat libavcodec libswresample libswscale libavutil` -o video_decode_gpurun cmd: ./video_decode_gpu data/left.mp4 ./bmp
gpu解碼原理
問(wèn)題1? gpu 解碼 是把內(nèi)存中AVPacket 拷貝到gp顯存中進(jìn)行處理的嗎? 看來(lái)是的,代碼中通過(guò) av_read_frame(input_ctx, &packet) 讀取數(shù)據(jù)包,其數(shù)據(jù)操作流向應(yīng)該是 video file -> memory問(wèn)題2? gpu 解碼 的 數(shù)據(jù)流向? videofile-> avpacket ->decoding frame’s in gpu-> transfer rame in gpu into host memory問(wèn)題3? gpu 解碼數(shù)據(jù) cuvid 解碼器,也是api,對(duì)應(yīng)的數(shù)據(jù)操作流向? videofile-> avpacket ->decoding frame’s in gpu-> transfer rame in gpu into host memory
VDPAU 簡(jiǎn)介
Developed by NVIDIA for Unix/Linux systems. To enable this you typically need the libvdpau development package in your distribution, and a compatible graphics card. Note that VDPAU cannot be used to decode frames in memory, the compressed frames are sent by libavcodec to the GPU device supported by VDPAU and then the decoded image can be accessed using the VDPAU API. This is not done automatically by FFmpeg, but must be done at the application level (check for example the ffmpeg_vdpau.c file used by ffmpeg.c). Also, note that with this API it is not possible to move the decoded frame back to RAM, for example in case you need to encode again the decoded frame (e.g. when doing transcoding on a server). Several decoders are currently supported through VDPAU in libavcodec, in particular H.264, MPEG-1/2/4, and VC-1. 翻譯: 由NVIDIA開(kāi)發(fā)的Unix / Linux系統(tǒng)。 要啟用此功能,您通常需要分發(fā)中的libvdpau開(kāi)發(fā)包和兼容的圖形卡。 注意,VDPAU不能用于解碼內(nèi)存中的幀,壓縮幀由libavcodec發(fā)送到VDPAU支持的GPU設(shè)備,然后可以使用VDPAU API訪問(wèn)解碼圖像。 這不是由FFmpeg自動(dòng)完成的,但必須在應(yīng)用程序級(jí)別完成(例如檢查ffmpeg.c使用的ffmpeg_vdpau.c文件)。此外,請(qǐng)注意,使用此API時(shí),無(wú)法將解碼后的幀移回RAM,例如,如果您需要再次對(duì)解碼幀進(jìn)行編碼(例如,在服務(wù)器上進(jìn)行轉(zhuǎn)碼時(shí))。 目前通過(guò)libavcodec中的VDPAU支持幾個(gè)解碼器,特別是H.264,MPEG-1/2/4和VC-1。
VDPAU 學(xué)習(xí):
VdpDecoder -> 解碼 壓縮包數(shù)據(jù)VdpVideoSurface -> 解碼完數(shù)據(jù)放置的空間VdpVideoMixer -> 對(duì)解碼完的數(shù)據(jù)做后置處理VdpOutputSurface -> 處理完數(shù)據(jù)放置的位置
cuvid 與 VDPAU 是平級(jí)的東西,不能拿來(lái)直接使用,使用成本太大
cuvid 學(xué)習(xí)
cuvid nvidia 提供的gpu 視頻硬解碼庫(kù),底層依賴cuda并行計(jì)算框架 將cpu 解碼轉(zhuǎn)化到gpu 解碼上,減少cpu壓力,提升解碼速度
CUVID 硬解碼
note:
cuvid nvdec 兩者都是解碼api,不同點(diǎn)在于解碼方式 & 數(shù)據(jù)傳輸nvenc vaapi cdpau 都是硬件編解碼api
CUVID解碼rtsp視頻流
note
OpenCV中VideoReader_GPU可以方便地利用GPU讀取視頻文件,加速解碼過(guò)程,但OpenCV中VideoReader_GPU無(wú)法讀取rtsp視頻流數(shù)據(jù)。
這是因?yàn)镃UVID中CuvideoSource不支持rtsp視頻流數(shù)據(jù),不能由rtsp地址創(chuàng)建VideoSource。
但是videoSource 支持 視頻文件
查看nvidia 驅(qū)動(dòng) & nvcc 版本
cat /proc/driver/nvidia/version nvcc編譯器的版本nvcc -V
Note: For Video Codec SDK 7.0 and later, NVCUVID has been renamed to NVDECODE API.
編譯 & 運(yùn)行
領(lǐng)取C++音視頻開(kāi)發(fā)學(xué)習(xí)資料:點(diǎn)擊 音視頻開(kāi)發(fā)(資料文檔+視頻教程+面試題)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)
編譯
linux: gcc -g hw_decode_cuvid.c `pkg-config –libs libavformat libavcodec libswresample libswscale libavutil` -o hw_decode_cuvid
運(yùn)行
./hw_decode_cuvid cuda input_data/left.mp4 ./output_data/raw.out
運(yùn)行結(jié)果
raw.out 文件生成
raw.out 文件生成
cpu 軟解碼 cpu 占用率
cpu 軟解碼 cpu使用率g
gpu cuvid 硬解碼 cpu 占用率
gpu 硬解碼 cpu使用率
gpu 硬解碼 gpu 使用情況
gpu 硬解碼 gpu 使用情況
問(wèn)題:
1、為什么 gpu 硬解碼顯卡使用率那么低?需要排查下問(wèn)題。
2、將 gpu 中frame 直接做 AV_PIX_FMT_CUDA-> AV_PIX_FMT_BGR24 轉(zhuǎn)化 不能直接用 sws_getContext ,如何才能實(shí)現(xiàn)
3、ffmpeg 將 gpu解碼 數(shù)據(jù)的像素格式進(jìn)行 yuv-rgb 格式轉(zhuǎn)換 ,是否直接支持,是否需要自己寫函數(shù)
4、將 gpu 中數(shù)據(jù)直接存儲(chǔ)在磁盤上? 如果不可以的話 ,則進(jìn)行 device data ->host memory data ->file
5、數(shù)據(jù)拷貝方式 transfer_data_from 源碼
gpu decoded frame pix format AV_PIX_FMT_CUDA 直接在顯存中 轉(zhuǎn)化為 AV_PIX_FMT_BGR24
可行路徑,試了三種:
兩種cpu層面轉(zhuǎn)換像素格式 的方法(1種失敗,1種成功);直接使用ffmpeg api 在gpu層面進(jìn)行像素格式轉(zhuǎn)換(失敗)
CPU 主導(dǎo)像素轉(zhuǎn)換
1. 使用 sws_scale 實(shí)現(xiàn) AV_PIX_FMT_CUDA-> AV_PIX_FMT_BGR24 的直接轉(zhuǎn)換(cpu 層面)
這是我第一次使用的方式,模仿 cpu 上軟解碼(獲取視頻幀,并存儲(chǔ)為bmp格式,經(jīng)驗(yàn)原則,這種方式最容易想到)運(yùn)行結(jié)果:失敗,bad src img pointers運(yùn)行結(jié)果如下圖所示:
問(wèn)題原因:
如代碼 hw_decode_cuvid_origin.c 中所示, 直接通過(guò)transfer_data 將gpu 中解碼后的frame download到系統(tǒng)內(nèi)存,則系統(tǒng)內(nèi)存中的frames piex->format 仍為 AV_PIX_FMT_CUDA ,而 AV_PIX_FMT_CUDA 是gpu 顯存中存儲(chǔ)的解碼后的幀像素格式所以通過(guò) sws_scale 是不能直接change的
GPU 主導(dǎo)像素轉(zhuǎn)換
gpu 不支持 sws_scale + AV_PIX_FMT_CUDA-> AV_PIX_FMT_BGR24 的直接像素轉(zhuǎn)換方式,那么 能否直接在gpu中直接轉(zhuǎn)化 AV_PIX_FMT_CUDA 為 AV_PIX_FMT_BGR24呢?如果可以直接實(shí)現(xiàn),性能會(huì)有很大提升,因?yàn)闇p少了device->host 的數(shù)據(jù)傳輸,且gpu多核心并行處理,肯定比cpu處理性能要強(qiáng)悍。
av_hwframe_transfer_data() 執(zhí)行操作前 設(shè)置 內(nèi)存中目標(biāo)frame的像素格式為 AV_PIX_FMT_BGR24,gpu 黑盒操作實(shí)現(xiàn)在gpu上直接將像素格式轉(zhuǎn)化為目標(biāo)bgr24格式
運(yùn)行結(jié)果:失敗,像素沒(méi)對(duì)齊,只有亮度運(yùn)行結(jié)果如下圖所示:![預(yù)先設(shè)置內(nèi)存中frame目標(biāo)像素格式為 AV_PIX_FMT_BGR24]
問(wèn)題原因:如下圖所示:
問(wèn)題原因-transfer_data_pix_format_limit
紅框表示的意思為:src->frame->format 轉(zhuǎn)換為 dst->frame->format 是受限制的,主要是受av_hwframe_transfer_get_formats() 函數(shù)返回的formats 列表限制
所以gdb了下源碼,發(fā)現(xiàn)src->frame->format 轉(zhuǎn)換為 dst->frame->format 的受限范圍很小,然后找出了 av_hwframe_transfer_get_formats 支持的formats,調(diào)試過(guò)程如下所示:gdb -tui hw_decode_cuvid (-tui 支持查看源碼)
gdb_tui.png
在調(diào)用 av_hwframe_transfer_data() 函數(shù)處打上斷點(diǎn),且設(shè)置程序運(yùn)行所需參數(shù)
enter_break_point.png
run 程序,step 進(jìn)入函數(shù)調(diào)用棧
run & step-run_enter_func_call_stack
n 單步運(yùn)行,函數(shù)調(diào)用至 transfer_data_alloc()
enter_transfer_data_alloc.png
領(lǐng)取C++音視頻開(kāi)發(fā)學(xué)習(xí)資料:點(diǎn)擊 音視頻開(kāi)發(fā)(資料文檔+視頻教程+面試題)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)
發(fā)現(xiàn) av_hwframe_transfer_get_formats()函數(shù)
find_func_call_av_hwframe_transfer_get_formats.png
更改 dst->format 的值為<0的值,并打印支持的像素轉(zhuǎn)換列表
get_can_changed_pix_formats.png
可以看到只支持 gpu 硬件像素編碼格式->AV_PIX_FMT_NV12 的轉(zhuǎn)換
CPU 主導(dǎo)像素轉(zhuǎn)換
經(jīng)過(guò)前兩次的試驗(yàn),可以明確當(dāng)前最新版本的ffmpeg還不支持硬解完成之后直接將像素格式轉(zhuǎn)換為目標(biāo)rgb24數(shù)據(jù),還是回歸到 cpu + sws_scale 上,經(jīng)過(guò)第二步,可以知道AV_PIX_FMT_CUDA->AV_PIX_FMT_NV12這條路行的通,AV_PIX_FMT_NV12 其實(shí)是 YUV 格式的數(shù)據(jù),yuv 數(shù)據(jù)到 rgb 的像素轉(zhuǎn)換是完全支持的,所以就自然編寫了 AV_PIX_FMT_CUDA->AV_PIX_FMT_NV12->AV_PIX_FMT_BGR24 的代碼,經(jīng)測(cè)試沒(méi)問(wèn)題。當(dāng)然,不可否認(rèn):實(shí)現(xiàn) AV_PIX_FMT_CUDA-> AV_PIX_FMT_NV12->AV_PIX_FMT_BGR24 格式轉(zhuǎn)換 (cpu 實(shí)現(xiàn) pix format 轉(zhuǎn)換,這種cpu層面上的像素格式轉(zhuǎn)換方式比較弱)
運(yùn)行結(jié)果:成功,如下圖所示: