use hardware encode presets

This commit is contained in:
Faberto 2026-03-22 19:32:05 +01:00
parent eeb17ae2b8
commit f67297ed58
2 changed files with 60 additions and 44 deletions

View File

@ -15,6 +15,10 @@ from frigate.api.auth import require_camera_access, require_role
from frigate.api.defs.tags import Tags from frigate.api.defs.tags import Tags
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.const import PROCESS_PRIORITY_LOW from frigate.const import PROCESS_PRIORITY_LOW
from frigate.ffmpeg_presets import (
EncodeTypeEnum,
parse_preset_hardware_acceleration_encode,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -83,51 +87,29 @@ def _build_ffmpeg_cmd(
output_playlist = os.path.join(output_dir, "master.m3u8") output_playlist = os.path.join(output_dir, "master.m3u8")
segment_pattern = os.path.join(output_dir, "segment-%d.ts") segment_pattern = os.path.join(output_dir, "segment-%d.ts")
return [ hwaccel_args = config.ffmpeg.hwaccel_args
input_args = (
f"-loglevel warning -y -protocol_whitelist pipe,file,http,tcp -i {input_url}"
)
output_args = (
f"-c:a aac -b:a 128k"
f" -f hls -hls_time 6 -hls_list_size 0"
f" -hls_segment_type mpegts"
f" -hls_flags independent_segments+append_list"
f" -hls_segment_filename {segment_pattern}"
f" {output_playlist}"
)
cmd_str = parse_preset_hardware_acceleration_encode(
config.ffmpeg.ffmpeg_path, config.ffmpeg.ffmpeg_path,
"-hide_banner", hwaccel_args,
"-loglevel", input_args,
"warning", output_args,
"-y", EncodeTypeEnum.transcode,
"-protocol_whitelist", )
"pipe,file,http,tcp",
"-i", return cmd_str.split(" ")
input_url,
# Scale down to 720p max, preserve aspect ratio
"-vf",
"scale=-2:'min(720,ih)'",
# Encode to H.264 (software — universally available)
"-c:v",
"libx264",
"-preset",
"ultrafast",
"-crf",
"26",
"-profile:v",
"high",
"-level:v",
"4.1",
"-pix_fmt",
"yuv420p",
"-c:a",
"aac",
"-b:a",
"128k",
# Output as HLS with MPEG-TS segments
"-f",
"hls",
"-hls_time",
"6",
"-hls_list_size",
"0",
"-hls_segment_type",
"mpegts",
"-hls_flags",
"independent_segments+append_list",
"-hls_segment_filename",
segment_pattern,
output_playlist,
]
async def _wait_for_playlist(session_id: str) -> bool: async def _wait_for_playlist(session_id: str) -> bool:

View File

@ -208,6 +208,37 @@ PRESETS_HW_ACCEL_ENCODE_PREVIEW = {
"default": "{0} -hide_banner {1} -c:v libx264 -profile:v baseline -preset:v ultrafast {2}", "default": "{0} -hide_banner {1} -c:v libx264 -profile:v baseline -preset:v ultrafast {2}",
} }
# Presets for on-demand H.265 to H.264 transcode playback
PRESETS_HW_ACCEL_ENCODE_TRANSCODE = {
# Based on birdseye presets with 720p scaling added
"preset-rpi-64-h264": "{0} -hide_banner {1} -c:v h264_v4l2m2m -vf scale=-2:'min(720,ih)' {2}",
"preset-rpi-64-h265": "{0} -hide_banner {1} -c:v h264_v4l2m2m -vf scale=-2:'min(720,ih)' {2}",
FFMPEG_HWACCEL_VAAPI: "{0} -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device {3} {1} -c:v h264_vaapi -bf 0 -profile:v high -level:v 4.1 -vf format=vaapi|nv12,hwupload,scale_vaapi=w=-2:h=720 {2}",
"preset-intel-qsv-h264": "{0} -hide_banner {1} -c:v h264_qsv -profile:v high -level:v 4.1 -async_depth:v 1 -vf scale=-2:'min(720,ih)' {2}",
"preset-intel-qsv-h265": "{0} -hide_banner {1} -c:v h264_qsv -profile:v high -level:v 4.1 -async_depth:v 1 -vf scale=-2:'min(720,ih)' {2}",
FFMPEG_HWACCEL_NVIDIA: "{0} -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 8 {1} -c:v h264_nvenc -profile:v high -preset:v p2 -tune:v ll -vf scale_cuda=w=-2:h=720 {2}",
"preset-jetson-h264": "{0} -hide_banner {1} -c:v h264_nvmpi -profile high -vf scale=-2:'min(720,ih)' {2}",
"preset-jetson-h265": "{0} -hide_banner {1} -c:v h264_nvmpi -profile high -vf scale=-2:'min(720,ih)' {2}",
FFMPEG_HWACCEL_RKMPP: "{0} -hide_banner {1} -c:v h264_rkmpp -profile:v high -vf scale=-2:'min(720,ih)' {2}",
FFMPEG_HWACCEL_AMF: "{0} -hide_banner {1} -c:v h264_amf -profile:v high -vf scale=-2:'min(720,ih)' {2}",
"default": "{0} -hide_banner {1} -c:v libx264 -preset:v ultrafast -crf 26 -profile:v high -level:v 4.1 -pix_fmt yuv420p -vf scale=-2:'min(720,ih)' {2}",
}
PRESETS_HW_ACCEL_ENCODE_TRANSCODE["preset-nvidia-h264"] = (
PRESETS_HW_ACCEL_ENCODE_TRANSCODE[FFMPEG_HWACCEL_NVIDIA]
)
PRESETS_HW_ACCEL_ENCODE_TRANSCODE["preset-nvidia-h265"] = (
PRESETS_HW_ACCEL_ENCODE_TRANSCODE[FFMPEG_HWACCEL_NVIDIA]
)
PRESETS_HW_ACCEL_ENCODE_TRANSCODE[f"{FFMPEG_HWACCEL_RKMPP}-no-dump_extra"] = (
PRESETS_HW_ACCEL_ENCODE_TRANSCODE[FFMPEG_HWACCEL_RKMPP]
)
PRESETS_HW_ACCEL_ENCODE_TRANSCODE["preset-rk-h264"] = PRESETS_HW_ACCEL_ENCODE_TRANSCODE[
FFMPEG_HWACCEL_RKMPP
]
PRESETS_HW_ACCEL_ENCODE_TRANSCODE["preset-rk-h265"] = PRESETS_HW_ACCEL_ENCODE_TRANSCODE[
FFMPEG_HWACCEL_RKMPP
]
def parse_preset_hardware_acceleration_decode( def parse_preset_hardware_acceleration_decode(
arg: Any, arg: Any,
@ -251,6 +282,7 @@ class EncodeTypeEnum(str, Enum):
birdseye = "birdseye" birdseye = "birdseye"
preview = "preview" preview = "preview"
timelapse = "timelapse" timelapse = "timelapse"
transcode = "transcode"
def parse_preset_hardware_acceleration_encode( def parse_preset_hardware_acceleration_encode(
@ -267,6 +299,8 @@ def parse_preset_hardware_acceleration_encode(
arg_map = PRESETS_HW_ACCEL_ENCODE_PREVIEW arg_map = PRESETS_HW_ACCEL_ENCODE_PREVIEW
elif type == EncodeTypeEnum.timelapse: elif type == EncodeTypeEnum.timelapse:
arg_map = PRESETS_HW_ACCEL_ENCODE_TIMELAPSE arg_map = PRESETS_HW_ACCEL_ENCODE_TIMELAPSE
elif type == EncodeTypeEnum.transcode:
arg_map = PRESETS_HW_ACCEL_ENCODE_TRANSCODE
if not isinstance(arg, str): if not isinstance(arg, str):
return arg_map["default"].format(ffmpeg_path, input, output) return arg_map["default"].format(ffmpeg_path, input, output)