# [FFmpeg] 使用硬體加速 ## 初始化硬體裝置 **範例:**z 列出 FFmpeg 支援的硬體裝置類型: ```powershell ffmpeg -hide_banner -init_hw_device list ``` > 注意:實際可用類型取決於硬體與合適的驅動程式。 初始化一個新的 OpenCL 類型的硬體裝置並命名為 `gpu`: ```text -init_hw_device opencl=gpu ``` ## 硬體加速解碼 列出 FFmpeg 支援的硬體加速類型: ```powershell ffmpeg -hide_banner -hwaccels ``` > * 注意:實際可用類型取決於硬體與合適的驅動程式。 若要使用硬體加速解嗎,對輸入使用 `-hwaccel` 選項指定一個硬體加速類型。若有多個裝置,則可以使用 `-hwaccel_device` 來選擇要使用的裝置。 另外,`-hwaccel` 可用值還有: * none 不使用硬體加速。 * auto 自動選擇硬體加速方式。 當你使用 `-hwaccel` 選擇硬體加速解碼方式,若可用時將會應用選擇的加速方式,若不可用時則會應用軟體解碼方式。你可用觀察 CPU 使用率跟軟體解碼對比來確認是不是有硬體加速效果。 對輸入 input.mp4 自動應用硬體解碼: ```powershell ffmpeg -hwaccel auto -i input.mp4 -f null - ``` 選擇使用 DXVA2 類型的硬體裝置進行解碼: ```powershell 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) 硬體加速解碼: ```powershell ffmpeg -hwaccel dxva2 -i input.mp4 -f null - ``` Direct3D 11 硬體加速解碼: ```powershell ffmpeg -hwaccel d3d11va -i input.mp4 -f null - ``` CUDA 硬體加速解碼: ```powershell ffmpeg -hwaccel cuda -i input.mp4 -f null - ``` QSV 硬體加速解碼: ```powershell ffmpeg -hwaccel qsv -c:v h264_qsv -re -i input.mp4 -f null - ``` > * 以上範例,若硬體加速解碼不可用,會自動應用軟體解碼器。你可用觀察 CPU 使用率來確認是否有硬體加速效果。 ### 直接在硬體表面 (hardware surfaces) 產生解碼輸出 Direct3D 9 (DXVA2) 硬體加速解碼: ```powershell ffmpeg -hwaccel dxva2 -hwaccel_output_format dxva2_vld -i input.mp4 -f null - ``` Direct3D 11 硬體加速解碼: ```powershell ffmpeg -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -f null - ``` CUDA 硬體加速解碼: ```powershell ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -f null - ``` > * 以上範例,若硬體加速解碼不可用,會自動應用軟體解碼器,並輸出影格資料至普通記憶體。此時 `-hwaccel_output_format` 設定無效。你可用觀察輸出格式來確認是否有硬體加速效果。 QSV 硬體加速解碼: ```powershell ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -f null - ``` > * 使用 QSV 硬體加速解碼必須要手動選擇合適解碼器,見 `-decoders` 輸出解碼器表,名稱 `*_qsv` 即 QSV 硬體加速解碼器。 > * 若 QSV 硬體加速解碼不可用,由於已使用 `-c:v` 強制指定硬體解碼器,將會發生錯誤,而不會自動切換為軟體解碼。 ## 搬移影格資料 通常,軟體篩選器與編碼器只能存取普通記憶體中的影格資料,而硬體篩選器與編碼器只能存取硬體表面 (hardware surfaces) 中的影格資料。根據實際情況可能要使用 `hwupload`、`hwupload_cuda`、`hwdownload` 篩選器,在硬體表面與普通記憶體之間搬移影格資料。 ### 上傳影格資料至硬體表面 使用 `hwupload` 可以普通記憶體上的影格資料上傳至硬體表面。需要一併使用 `-init_hw_device` 選項來明確指定初始化適用於硬體篩選的裝置,並加上 `-filter_hw_device` 將命名的裝置傳遞給篩選器流程圖中的所有篩選器。 上傳解碼的影格資料至 QSV 裝置: ```text -init_hw_device qsv=hw -filter_hw_device hw -i INPUT -vf "hwupload=extra_hw_frames=64" ``` 上傳解碼的影格資料至 OpenCL 裝置: ```text -init_hw_device opencl=hw -filter_hw_device hw -i INPUT -vf "hwupload" ``` 上傳解碼的影格資料至 CUDA 裝置: ```text -i INPUT -vf "hwupload_cuda" ``` ### 下載影格資料至普通記憶體 使用 `hwdownload` 可以將硬體表面上的影格資料下載至普通記憶體。`hwdownload` 不支援所有的格式輸出,在它之後接著 `format` 篩選器,以藉此獲得輸出的支援格式。由於下載輸出的影格資料必須符合來源的布局,且 `format` 篩選器沒有任何訊息得知該選擇何種格式作為 `hwdownload` 的輸出,所以要手動指定正確的像素格式,否則將會發生錯誤。 以 CUDA 硬體加速解碼為例。由於 CUDA 解碼器可以將解碼的影格資料輸出至普通記憶體格式,可以先測試解碼輸出至普通記憶體。 測試 CUDA 硬體加速解碼,輸出影格資料至普通記憶體: ```powershell ffmpeg -hwaccel cuda -an -i input.mp4 -f null - ``` 觀察 CPU 使用率以與軟體解碼對比來確定使用硬體加速解碼。 從 FFmpeg 輸出主控台訊息中找到輸出視訊串流部分: ```powershell 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 像素格式: ```powershell 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 硬體下載解碼的影格資料至普通記憶體: ```powershell ffmpeg -hwaccel qsv -c:v h264_qsv -i input_h264_yuv420p.mp4 -vf "hwdownload,format=nv12" -f null - ``` ### 上傳+下載影格資料 `hwupload` 篩選器將上傳一個與軟體影格相同的布局至硬體表面,因此可能需要再這之前使用 format 篩選器將輸出轉換成合適的格式。 規則: ```text format=FOO,hwupload,...,hwdownload,format=FOO ``` > 注意:由於下載輸出的影格資料必須符合來源的布局,所以兩個 format 篩選器必須使用相同的設定值。 上傳解碼影格資料至 OpenCL 裝置並使用 `nlmeans_opencl` 篩選器處裡後下載回系統記憶體: ```text -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 裝置: ```text -hwaccel dxva2 -hwaccel_output_format dxva2_vld -i input.mp4 -vf "hwmap=derive_device=qsv" ``` ## 解碼與篩選 ### 硬體加速解碼、篩選 硬體加速篩選器可以降低 CPU 負擔,且正常情況下執行效率比軟體篩選器,更何況軟體篩選器只能存取正常記憶體,為此搬移影格資料會消耗不少資源。若需要使用篩選器,可以優先考慮硬體加速方案提供的篩選器。而硬體加速篩選器只能存取相應的硬體表面 (hardware surfaces)。 使用 QSV 硬體加速解碼器與篩選器: ```powershell ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf "scale_qsv=1280:720" -f null - ``` 使用 CUDA 硬體加速解碼器與篩選器: ```powershell ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "scale_cuda=1280:720" -f null - ``` ### 硬體加速解碼與軟體篩選 軟體篩選器只能存取普通記憶體內的影格資料,所以必須將解碼後的影格資料輸出至普通記憶體。 使用 Direct3D 9 (DXVA2) 硬體加速解碼器與軟體篩選器: ```powershell ffmpeg -hwaccel dxva2 -i input.mp4 -vf "crop=1920:804:0:138,scale=1280:536" -f null - ``` 使用 Direct3D 11 硬體加速解碼器與軟體篩選器: ```powershell ffmpeg -hwaccel d3d11va -i input.mp4 -vf "crop=1920:804:0:138,scale=1280:536" -f null - ``` 使用 CUDA 硬體加速解碼器與軟體篩選器: ```powershell ffmpeg -hwaccel cuda -i input.mp4 -vf "crop=1920:804:0:138,scale=1280:536" -f null - ``` 使用 QSV 硬體加速解碼器與軟體篩選器: ```powershell ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf "hwdownload,format=nv12,scal=1280:720" -f null - ``` ## 轉碼 若解碼的影格資料位於硬體表面 (hardware surfaces),則只能使用相應硬體加速方式所提供的篩選器。若在普通記憶體,則只能被軟體篩選器與編碼器存取。 當影格資料位於普通記憶體,使用硬體編碼器,通常不需要手動將搬移影格資料,影格資料將被自動上傳到硬體表面 (hardware surfaces),讓硬體編碼器正常讀取。 ### 硬體加速轉碼 QSV 硬體加速解碼、篩選、編碼。 ```powershell ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf "scale_qsv=1280:720" -c:v h264_qsv output.mp4 ``` CUDA 硬體加速解碼、篩選、編碼。 ```powershell ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "scale_cuda=1280:720" -c:v h264_nvenc output.mp4 ``` ### 解碼部分硬體加速轉碼 Direct3D 11 解碼 + 軟體篩選、編碼: ```powershell ffmpeg -hwaccel d3d11va -i input.mp4 -vf "scale=1280:720" -c:v libx264 output.mp4 ``` ### 篩選部分硬體加速轉碼 軟體解碼、篩選 + OpenCL 篩選 + 軟體編碼: ```powershell 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 編碼: ```powershell ffmpeg -i input.mp4 -vf "scale=1280:720" -c:v h264_qsv output.mp4 ``` 軟體解碼、篩選 + CUDA 編碼: ```powershell ffmpeg -i input.mp4 -vf "scale=1280:720" -c:v h264_nvenc output.mp4 ``` 軟體解碼、篩選 + QSV 篩選、編碼: ```powershell 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 篩選、編碼: ```powershell 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 篩選 + 軟體編碼: ```powershell 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 編碼: ```powershell ffmpeg -hwaccel d3d11va -i input.mp4 -vf "scale=1280:720" -c:v h264_qsv output.mp4 ``` Direct3D 11 解碼 + 軟體篩選 + QSV 篩選、編碼: ```powershell 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 編碼: ```powershell 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 編碼: ```powershell 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 篩選、編碼: ```powershell 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`