Try   HackMD

[FFmpeg] 使用硬體加速

初始化硬體裝置

**範例:**z

列出 FFmpeg 支援的硬體裝置類型:

ffmpeg -hide_banner -init_hw_device list

注意:實際可用類型取決於硬體與合適的驅動程式。

初始化一個新的 OpenCL 類型的硬體裝置並命名為 gpu

-init_hw_device opencl=gpu

硬體加速解碼

列出 FFmpeg 支援的硬體加速類型:

ffmpeg -hide_banner -hwaccels
  • 注意:實際可用類型取決於硬體與合適的驅動程式。

若要使用硬體加速解嗎,對輸入使用 -hwaccel 選項指定一個硬體加速類型。若有多個裝置,則可以使用 -hwaccel_device 來選擇要使用的裝置。

另外,-hwaccel 可用值還有:

  • none
    不使用硬體加速。
  • auto
    自動選擇硬體加速方式。

當你使用 -hwaccel 選擇硬體加速解碼方式,若可用時將會應用選擇的加速方式,若不可用時則會應用軟體解碼方式。你可用觀察 CPU 使用率跟軟體解碼對比來確認是不是有硬體加速效果。

對輸入 input.mp4 自動應用硬體解碼:

ffmpeg -hwaccel auto -i input.mp4 -f null -

選擇使用 DXVA2 類型的硬體裝置進行解碼:

ffmpeg -hwaccel dxva2 -i input.mp4 -f null -
  • 使用 -f null - 將不會產生任何輸出,這通常被用在解碼測試。

請注意解碼器輸出視訊影格資料是否硬體加速格式,你可以從 FFmpeg 主控台輸出的訊息的像素格式來判斷。軟體格式例如 nv12、nv21、yuv420p、yuv422p等等;硬體加速格式例如 dxva2_vld、d3d11、qsv、cuda等等。

FFmpeg 主控台輸出訊息 (部分):

Stream #0:0(und): Video: wrapped_avframe, qsv(progressive), 1920x1080, q=2-31, 200 kb/s, 23.98 fps, 23.98 tbn (default)

若為硬體加速格式,則代表解碼器解碼器直接在硬體表面 (hardware surfaces) 產生解碼輸出,而不是在普通記憶體。某些情況下硬體加速解碼的影格資料將被輸出至普通記憶體,若要強制直接在硬體表面產生解碼輸出以獲得更高的效率,則可用 -hwaccel_output_format 指定相應的硬體格式。

若有使用 -hwaccel_output_format 指定相應的硬體加速格式,但輸出依然是軟體格式,則表選擇的硬體加速方式不可用,而自動應用軟體解碼。若沒有指定硬體加速輸出格式,輸出將根據解碼器預設值,可能是軟體格式也可能是硬體加速格式,可以觀察 CPU 使用率來確認是不是有硬體加速效果。

輸出影格資料至普通記憶體

Direct3D 9 (DXVA2) 硬體加速解碼:

ffmpeg -hwaccel dxva2 -i input.mp4 -f null -

Direct3D 11 硬體加速解碼:

ffmpeg -hwaccel d3d11va -i input.mp4 -f null -

CUDA 硬體加速解碼:

ffmpeg -hwaccel cuda -i input.mp4 -f null -

QSV 硬體加速解碼:

ffmpeg -hwaccel qsv -c:v h264_qsv -re -i input.mp4 -f null -
  • 以上範例,若硬體加速解碼不可用,會自動應用軟體解碼器。你可用觀察 CPU 使用率來確認是否有硬體加速效果。

直接在硬體表面 (hardware surfaces) 產生解碼輸出

Direct3D 9 (DXVA2) 硬體加速解碼:

ffmpeg -hwaccel dxva2 -hwaccel_output_format dxva2_vld -i input.mp4 -f null -

Direct3D 11 硬體加速解碼:

ffmpeg -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -f null -

CUDA 硬體加速解碼:

ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -f null -
  • 以上範例,若硬體加速解碼不可用,會自動應用軟體解碼器,並輸出影格資料至普通記憶體。此時 -hwaccel_output_format 設定無效。你可用觀察輸出格式來確認是否有硬體加速效果。

QSV 硬體加速解碼:

ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -f null -
  • 使用 QSV 硬體加速解碼必須要手動選擇合適解碼器,見 -decoders 輸出解碼器表,名稱 *_qsv 即 QSV 硬體加速解碼器。
  • 若 QSV 硬體加速解碼不可用,由於已使用 -c:v 強制指定硬體解碼器,將會發生錯誤,而不會自動切換為軟體解碼。

搬移影格資料

通常,軟體篩選器與編碼器只能存取普通記憶體中的影格資料,而硬體篩選器與編碼器只能存取硬體表面 (hardware surfaces) 中的影格資料。根據實際情況可能要使用 hwuploadhwupload_cudahwdownload 篩選器,在硬體表面與普通記憶體之間搬移影格資料。

上傳影格資料至硬體表面

使用 hwupload 可以普通記憶體上的影格資料上傳至硬體表面。需要一併使用 -init_hw_device 選項來明確指定初始化適用於硬體篩選的裝置,並加上 -filter_hw_device 將命名的裝置傳遞給篩選器流程圖中的所有篩選器。

上傳解碼的影格資料至 QSV 裝置:

-init_hw_device qsv=hw -filter_hw_device hw -i INPUT -vf "hwupload=extra_hw_frames=64"

上傳解碼的影格資料至 OpenCL 裝置:

-init_hw_device opencl=hw -filter_hw_device hw -i INPUT -vf  "hwupload"

上傳解碼的影格資料至 CUDA 裝置:

-i INPUT -vf "hwupload_cuda"

下載影格資料至普通記憶體

使用 hwdownload 可以將硬體表面上的影格資料下載至普通記憶體。hwdownload 不支援所有的格式輸出,在它之後接著 format 篩選器,以藉此獲得輸出的支援格式。由於下載輸出的影格資料必須符合來源的布局,且 format 篩選器沒有任何訊息得知該選擇何種格式作為 hwdownload 的輸出,所以要手動指定正確的像素格式,否則將會發生錯誤。

以 CUDA 硬體加速解碼為例。由於 CUDA 解碼器可以將解碼的影格資料輸出至普通記憶體格式,可以先測試解碼輸出至普通記憶體。

測試 CUDA 硬體加速解碼,輸出影格資料至普通記憶體:

ffmpeg -hwaccel cuda -an -i input.mp4 -f null -

觀察 CPU 使用率以與軟體解碼對比來確定使用硬體加速解碼。

從 FFmpeg 輸出主控台訊息中找到輸出視訊串流部分:

Stream #0:0(und): Video: wrapped_avframe, nv12(progressive), 1920x1080, q=2-31, 200 kb/s, 23.98 fps, 23.98 tbn (default)

從輸出訊息中得知 CUDA 硬體加速解碼片源 input.mp4 的輸出的像素格式為 NV12。所以若使用 hwdownload 從硬體表面下載影格資料至普通記憶體為軟體格式時,需要接著使用 format=nv12 以藉此輸出正確的像素格式。

CUDA 硬體加速解碼,下載影格資料至普通記憶體為 NV12 像素格式:

ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "scale_cuda=1280:720,hwdownload,format=nv12" -c:v libx264 output.mp4

如果需要轉換像素格式,則需要再使用一個 format 篩選器或是 -pix_fmt 選項。

對於 QSV 硬體加速,由於無法輸出解碼影格至普通記憶體,所以只能從解碼器預設值與輸入片源的像素格式推測輸出。對於 YUV420P 的片源通常會硬體加速解碼會輸出 NV12 格式,若是其他像素格式請試誤,通常與片源相同。

從 QSV 硬體下載解碼的影格資料至普通記憶體:

ffmpeg -hwaccel qsv -c:v h264_qsv -i input_h264_yuv420p.mp4 -vf "hwdownload,format=nv12" -f null -

上傳+下載影格資料

hwupload 篩選器將上傳一個與軟體影格相同的布局至硬體表面,因此可能需要再這之前使用 format 篩選器將輸出轉換成合適的格式。

規則:

format=FOO,hwupload,...,hwdownload,format=FOO

注意:由於下載輸出的影格資料必須符合來源的布局,所以兩個 format 篩選器必須使用相同的設定值。

上傳解碼影格資料至 OpenCL 裝置並使用 nlmeans_opencl 篩選器處裡後下載回系統記憶體:

-init_hw_device opencl=hw -filter_hw_device hw -i INPUT -vf "hwupload,format=yuv420p,hwupload,nlmeans_opencl,hwdownload,format=yuv420p"

映射影格資料至其他設備

當解碼器直接在硬體表面產生解碼輸出,若需要使用另一個硬體加速裝置處裡影格資料,則可用 hwmap 篩選器將影格資料映射到另一個裝置的硬體表面。輸出與輸入裝置必須是相容的,實際的意義取決的系統,通常指同一款顯示卡。

映射 Direct3D 9 (DXVA2) 解碼影格資料到 QSV 裝置:

-hwaccel dxva2 -hwaccel_output_format dxva2_vld -i input.mp4 -vf "hwmap=derive_device=qsv"

解碼與篩選

硬體加速解碼、篩選

硬體加速篩選器可以降低 CPU 負擔,且正常情況下執行效率比軟體篩選器,更何況軟體篩選器只能存取正常記憶體,為此搬移影格資料會消耗不少資源。若需要使用篩選器,可以優先考慮硬體加速方案提供的篩選器。而硬體加速篩選器只能存取相應的硬體表面 (hardware surfaces)。

使用 QSV 硬體加速解碼器與篩選器:

ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf "scale_qsv=1280:720" -f null -

使用 CUDA 硬體加速解碼器與篩選器:

ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "scale_cuda=1280:720" -f null -

硬體加速解碼與軟體篩選

軟體篩選器只能存取普通記憶體內的影格資料,所以必須將解碼後的影格資料輸出至普通記憶體。

使用 Direct3D 9 (DXVA2) 硬體加速解碼器與軟體篩選器:

ffmpeg -hwaccel dxva2 -i input.mp4 -vf "crop=1920:804:0:138,scale=1280:536" -f null -

使用 Direct3D 11 硬體加速解碼器與軟體篩選器:

ffmpeg -hwaccel d3d11va -i input.mp4 -vf "crop=1920:804:0:138,scale=1280:536" -f null -

使用 CUDA 硬體加速解碼器與軟體篩選器:

ffmpeg -hwaccel cuda -i input.mp4 -vf "crop=1920:804:0:138,scale=1280:536" -f null -

使用 QSV 硬體加速解碼器與軟體篩選器:

ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf "hwdownload,format=nv12,scal=1280:720" -f null -

轉碼

若解碼的影格資料位於硬體表面 (hardware surfaces),則只能使用相應硬體加速方式所提供的篩選器。若在普通記憶體,則只能被軟體篩選器與編碼器存取。

當影格資料位於普通記憶體,使用硬體編碼器,通常不需要手動將搬移影格資料,影格資料將被自動上傳到硬體表面 (hardware surfaces),讓硬體編碼器正常讀取。

硬體加速轉碼

QSV 硬體加速解碼、篩選、編碼。

ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf "scale_qsv=1280:720" -c:v h264_qsv output.mp4

CUDA 硬體加速解碼、篩選、編碼。

ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "scale_cuda=1280:720" -c:v h264_nvenc output.mp4

解碼部分硬體加速轉碼

Direct3D 11 解碼 + 軟體篩選、編碼:

ffmpeg -hwaccel d3d11va -i input.mp4 -vf "scale=1280:720" -c:v libx264 output.mp4

篩選部分硬體加速轉碼

軟體解碼、篩選 + OpenCL 篩選 + 軟體編碼:

ffmpeg -init_hw_device opencl=hw -filter_hw_device hw -i input.mp4 -vf "format=yuv420p,hwupload,nlmeans_opencl,hwdownload,format=yuv420p" -c:v libx264 output.mp4

編碼部分硬體加速轉碼

軟體解碼、篩選 + QSV 編碼:

ffmpeg -i input.mp4 -vf "scale=1280:720" -c:v h264_qsv output.mp4

軟體解碼、篩選 + CUDA 編碼:

ffmpeg -i input.mp4 -vf "scale=1280:720" -c:v h264_nvenc output.mp4

軟體解碼、篩選 + QSV 篩選、編碼:

ffmpeg -init_hw_device qsv=hw -filter_hw_device hw -i input.mp4 -vf "crop=1920:804:0:138,hwupload=extra_hw_frames=64,scale_qsv=1280:536" -c:v h264_qsv output.mp4

軟體解碼、篩選 + CUDA 篩選、編碼:

ffmpeg -i input.mp4 -vf "crop=1920:804:0:138,hwupload_cuda,scale_cuda=1280:536" -c:v h264_nvenc output.mp4

混合硬體加速轉碼

通過系統記憶體

Direct3D 11 解碼 + 軟體篩選 + OpenCL 篩選 + 軟體編碼:

ffmpeg -init_hw_device opencl=hw -filter_hw_device hw -hwaccel d3d11va -i input.mp4 -vf "format=yuv420p,hwupload,nlmeans_opencl,hwdownload,format=yuv420p" -c:v libx264 output.mp4

Direct3D 11 解碼 + 軟體篩選 + QSV 編碼:

ffmpeg -hwaccel d3d11va -i input.mp4 -vf "scale=1280:720" -c:v h264_qsv output.mp4

Direct3D 11 解碼 + 軟體篩選 + QSV 篩選、編碼:

ffmpeg -init_hw_device qsv=hw -filter_hw_device hw -hwaccel d3d11va -hwaccel_device 1 -i input.mp4 -vf "crop=1920:804:0:138,hwupload=extra_hw_frames=64,format=qsv,scale_qsv=1280:536" -c:v h264_qsv output.mp4

Direct3D 11 解碼 + 軟體篩選 + OpenCL 篩選 + AMF 編碼:

ffmpeg -init_hw_device opencl=hw -filter_hw_device hw -hwaccel d3d11va -i input.mp4 -vf "format=yuv420p,hwupload,nlmeans_opencl,hwdownload,format=yuv420p" -c:v h264_amf output.mp4

軟體解碼、篩選 + OpenCL 篩選 + AMF 編碼:

ffmpeg -init_hw_device opencl=hw -filter_hw_device hw -i input.mp4 -vf "format=yuv420p,hwupload,nlmeans_opencl,hwdownload,format=yuv420p" -c:v h264_amf output.mp4

不通過系統記憶體 - 純硬體

注意:hwmap 的輸出與輸入設備必須是相容的,若失敗請嘗試通過系統記憶體的方式。

Direct3D 9 (DXVA2) 解碼 + QSV 篩選、編碼:

ffmpeg -hwaccel dxva2 -hwaccel_output_format dxva2_vld -i input.mp4 -vf "hwmap=derive_device=qsv,scale_qsv=1280:720" -c:v h264_qsv output.mp4
tags: ffmpeg