Bug: frigate.output.preview module broken β€” FFmpeg build missing libx264, h264_axenc segfaults without hw_device_ctx

#2
by RATMANrush - opened

obraz_2026-08-18_100358448
The preview-generation module (frigate/output/preview.py) hard-codes -c:v libx264 for encoding hourly preview clips. The AXCL FFmpeg build shipped in this image (frigate:x86-axcl-70a0545) does not include libx264 at all, so every preview-generation attempt fails once per hour, per camera. This produces empty/corrupted preview MP4 files, which surface as visible garbage/artifacts (shifted or noisy image blocks) in the Frigate dashboard grid and in review/alert thumbnails β€” even though the actual recorded footage (record role) is unaffected.

Environment

  • Image: frigate:x86-axcl-70a0545
  • Frigate version: 0.17.0-70a0545
  • Host: Proxmox LXC (privileged), AXCL passthrough, AX8850 NPU cards
  • FFmpeg (custom AXCL build) version info:
    ffmpeg version 7.1 Copyright (c) 2000-2024 the FFmpeg developers
    built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~18.04)
    configuration: --prefix=.../axcl/3rdparty/ffmpeg/out/x64 --enable-cross-compile
      --arch=x86_64 --host-os=linux --target-os=linux --cc=gcc --enable-shared
      --disable-static --enable-gpl --enable-muxer=mp4 --enable-muxer=flv
      --enable-muxer=h264 --enable-muxer=hevc --enable-demuxer=flv
      --enable-demuxer=h264 --enable-demuxer=hevc --enable-demuxer=rtsp
      --enable-parser=hevc --enable-ffmpeg --enable-swscale --disable-avdevice
      --enable-encoders --enable-filters --enable-axmm --disable-large-tests
      --disable-doc --enable-pic --disable-x86asm --disable-libxcb --disable-zlib
      --disable-bzlib --disable-libxcb_shm --disable-lzma --disable-logging
    
    Note: no --enable-libx264 in the configure flags.

Steps to reproduce

  1. Run Frigate normally with 2 cameras (H.265 main streams, restreamed through go2rtc).
  2. Wait for the top of the hour (preview clips are generated on a fixed 1-hour cadence, PREVIEW_SEGMENT_DURATION = 3600 in frigate/output/preview.py).
  3. Observe the container logs.

Actual behavior (logs)

error | 2026-08-18 09:00:00 | frigate.output.preview | Error saving preview for lewa :: Unrecognized option 'preset:v'.
unknown | 2026-08-18 07:00:00 | unknown | Error splitting the argument list: Option not found
error | 2026-08-18 09:00:00 | frigate.output.preview | Error saving preview for prawa :: Unrecognized option 'preset:v'.
unknown | 2026-08-18 07:00:00 | unknown | Error splitting the argument list: Option not found

This repeats every hour, on both cameras simultaneously. The resulting preview MP4 for that hour is missing/empty, which the frontend then renders as a visibly corrupted/garbled thumbnail in:

  • the live dashboard camera grid preview,
  • the Review/Alerts thumbnail list.

The actual recording files under /media/frigate/recordings/... are not affected β€” verified by pulling a recording segment directly and inspecting frames, which were clean. This is purely a preview-generation bug, but it is confusing/alarming to end users because it visually looks like a camera/decoding fault.

Root cause analysis

Traced end-to-end:

  1. frigate/output/preview.py builds the encode command via:

    self.ffmpeg_cmd = parse_preset_hardware_acceleration_encode(
        config.ffmpeg.ffmpeg_path,
        "default",
        input="-f concat -y -protocol_whitelist pipe,file -safe 0 -threads 1 -i /dev/stdin",
        output=f"-threads 1 -g {PREVIEW_KEYFRAME_INTERVAL} -bf 0 -b:v {...} {FPS_VFR_PARAM} -movflags +faststart -pix_fmt yuv420p {self.path}",
        type=EncodeTypeEnum.preview,
    )
    

    It always passes the literal string "default" β€” there is no way to override this via user config.

  2. frigate/ffmpeg_presets.py defines:

    PRESETS_HW_ACCEL_ENCODE_PREVIEW = {
        "default": "{0} -hide_banner {1} -c:v libx264 -profile:v baseline -preset:v ultrafast {2}",
    }
    

    This is unconditional β€” there is no AXCL/hwaccel-aware branch for EncodeTypeEnum.preview, unlike PRESETS_HW_ACCEL_ENCODE_BIRDSEYE and PRESETS_HW_ACCEL_ENCODE_TIMELAPSE, which both have hardware-specific entries.

  3. The resulting command string is split naively with .split(" ") in preview.py (lines ~109, ~120) and executed via the ffmpeg-axcl wrapper (/usr/local/lib/ffmpeg-axcl/bin/ffmpeg), which is a thin shell wrapper:

    #!/bin/bash
    export LD_LIBRARY_PATH=/usr/lib/axcl/ffmpeg:/usr/lib/axcl:$LD_LIBRARY_PATH
    exec /usr/bin/axcl/ffmpeg/ffmpeg "$@"
    

    The wrapper passes arguments through unmodified ("$@"), so it is not the source of the malformed-looking error message.

  4. The actual binary, /usr/bin/axcl/ffmpeg/ffmpeg, does not recognize libx264:

    $ ffmpeg -h encoder=libx264
    Codec 'libx264' is not recognized by FFmpeg.
    

    Confirmed via -encoders:

    $ ffmpeg -encoders | grep 264
    V..... h264_axenc     AX H.264 encoder (codec h264)
    V..... h264_v4l2m2m   V4L2 mem2mem H.264 encoder wrapper (codec h264)
    

    Because FFmpeg cannot resolve -c:v libx264 to a known encoder, it cannot associate the subsequent -preset:v ultrafast with any encoder-specific option table, and the option is reported back malformed ('preset:v', missing the leading dash) in the error message β€” this is what produces the confusing "Unrecognized option 'preset:v'" log line. The real problem is the missing libx264, not a literal typo anywhere in the Python code (verified β€” ffmpeg_presets.py in the image has the dash present, exactly matching upstream).

  5. Tried swapping to the available hardware encoder h264_axenc manually, replicating the exact preview.py command shape:

    ffmpeg -hide_banner -f concat -y -protocol_whitelist pipe,file -safe 0 -threads 1 \
      -i test_concat.txt -c:v h264_axenc -profile 66 -threads 1 -g 60 -bf 0 -b:v 200k \
      -movflags +faststart -pix_fmt nv12 test_preview.mp4
    

    Result:

    [h264_axenc @ ...] ff_h264_axenc_init format(nv12) requires hw_device_ctx must be set
    Segmentation fault (core dumped)
    

    h264_axenc requires a properly initialized AXCL hardware device context (comparable to -init_hw_device/-hwaccel used elsewhere in the decode pipeline) β€” it cannot be used as a drop-in replacement for libx264 by simply changing the codec name. Without that context it segfaults rather than failing gracefully.

Impact

  • Preview clip generation (frigate/output/preview.py) is completely non-functional on this image, for every camera, every hour.
  • This degrades the review/alert timeline UX (broken/garbled thumbnails) and could confuse users into thinking their camera feed or decoder is corrupted (as happened in our case β€” we spent significant time ruling out network jitter, hevc_axdec decode issues, and disk space before isolating this).
  • Actual recordings (record role, main NVR functionality) are unaffected β€” this is purely cosmetic/UX, but the misleading error message and visual symptom make it very easy to misdiagnose as a hardware/decode/network problem.

Suggested fixes (any of)

  1. Preferred: Add an AXCL-specific entry to PRESETS_HW_ACCEL_ENCODE_PREVIEW in ffmpeg_presets.py (mirroring what's already done for PRESETS_HW_ACCEL_ENCODE_BIRDSEYE/_TIMELAPSE), targeting h264_axenc, including whatever -init_hw_device/hwupload filter chain is required to avoid the hw_device_ctx segfault. Since preview frames are just periodic low-res webp stills being concatenated, this doesn't need to be fast β€” correctness matters more than performance here.
  2. Alternative: Ship a static/software libx264 in the AXCL FFmpeg build (even if not used for the main decode/detect/record pipelines) purely to satisfy modules like output/preview.py and output/birdseye.py's "default" fallback that assume software x264 is always available.
  3. Minimum viable fix: At minimum, the segfault on h264_axenc without hw_device_ctx should be hardened to fail gracefully (return an error Frigate can catch/log) rather than crashing the encode subprocess β€” this affects anyone who tries to use h264_axenc outside of a fully-wired hwaccel context.

Additional notes

  • ffmpeg_presets.py itself (as shipped in this image) is otherwise unmodified/identical to upstream blakeblackshear/frigate for the preview section β€” the bug is an omission (no AXCL-aware preview preset), not a code regression introduced by the AXERA fork.
  • Happy to provide full logs, the exact recording/preview cache directory listing, or test further changes if a patch is proposed β€” this is a home-lab deployment, not time-critical, but the misdiagnosis risk for others hitting this silently (thinking it's a camera/network fault) seems worth flagging clearly.

Update: found the fix already exists in source β€” commit 896794f on axera-dev adds preset-axera-h264/h265 entries to PRESETS_HW_ACCEL_ENCODE_PREVIEW with proper -init_hw_device axmm:axmm,alloc_blk=1 init. But the published x86-axcl image (branch v0.17-axcl on HF, tag 70a0545) doesn't include it yet β€” verified by inspecting ffmpeg_presets.py inside the tar directly. Could you cut a new x86-axcl build with this commit included?

@RATMANrush Yes. The fix is available in the public axera-dev branch:

https://github.com/AXERA-TECH/frigate/tree/axera-dev

You can build the x86-axcl image directly from that branch:

git clone --branch axera-dev --single-branch https://github.com/AXERA-TECH/frigate.git
cd frigate
docker buildx bake --file=docker/axcl/x86-axcl.hcl x86-axcl

Please make sure the camera configuration uses either:

hwaccel_args: preset-axera-h264

or:

hwaccel_args: preset-axera-h265

The previously published frigate:x86-axcl-70a0545 image predates this fix.

Sign up or log in to comment