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?

AXERA org
β€’
edited 1 day ago

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

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

https://github.com/AXERA-TECH/frigate/actions/runs/33721655977

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.

Follow-up: separate issue, not the same as the original preview.py bug

Confirmed the preset-axera-h265 fix works for hourly preview generation β€” thanks. However, while testing (both on our own axera-dev build and the official CI artifact from run 33721655977, commit 36e1176), we found a separate, unrelated issue with live MSE preview in the dashboard, which we initially misdiagnosed as camera/network instability before isolating it properly.

Symptom: On a fresh MSE WebSocket connection (opening a camera's live view), the rendered image shows horizontal-banded corruption (magenta/green noise) for a few seconds, then self-corrects. Reproduced on two independent Frigate images, ruling out our build process as the cause.

Root cause (confirmed via ffmpeg -vf showinfo against the local RTSP restream):

A fresh connection starts decoding mid-GOP, before receiving an I-frame. Keyframe interval on our camera is ~4.3s. All frames before the first I-frame show flat/uniform pixel data (mean ~128,128,128), consistent with the decoder rendering from an uninitialized reference buffer rather than failing gracefully.
On the eventual keyframe, showinfo reports conflicting metadata on the same frame: pict_type: P alongside iskey:1 type:I. This inconsistency appears to originate in hevc_axdec itself, not in Frigate or go2rtc (both showed clean logs throughout β€” no decode errors reported anywhere in the stack).

Environment: same as original report (AX8850, AXCL passthrough, x86). Camera: H.265 main stream via go2rtc. Happy to share full showinfo output or reproduce with different keyframe intervals if useful β€” this seems like it could affect anyone using hevc_axdec for live MSE preview, not just our setup.

Full command used: ffmpeg -v info -i rtsp://127.0.0.1:8554/lewa_1 -vf showinfo -f null -t 15 -, run inside the frigate container against the local go2rtc restream.
Raw evidence (ffmpeg -vf showinfo against local RTSP restream, fresh connection):

First frames after connect β€” no I-frame yet, uniform/flat pixel data:

[Parsed_showinfo_0] n: 33 pts_time:2.666667 fmt:yuvj420p s:3840x2160 i:P iskey:0 type:P checksum:03701C4D mean:[128 128 128] stdev:[22.6 2.5 3.0]
[Parsed_showinfo_0] n: 34 pts_time:2.75 fmt:yuvj420p s:3840x2160 i:P iskey:0 type:P checksum:FFD1AAD3 mean:[128 128 128] stdev:[22.8 2.5 3.0]
[Parsed_showinfo_0] n: 41 pts_time:3.333333 fmt:yuvj420p s:3840x2160 i:P iskey:0 type:P checksum:E363E9F3 mean:[128 128 128] stdev:[23.7 2.6 3.3]
[Parsed_showinfo_0] n: 49 pts_time:4 fmt:yuvj420p s:3840x2160 i:P iskey:0 type:P checksum:EE93E8E1 mean:[128 128 128] stdev:[24.8 2.8 3.6]

Note mean:[128 128 128] held constant across ~1.3s / 16 frames β€” consistent with an uninitialized/flat reference buffer, not real image content.

First keyframe (~4.3s after connect) β€” conflicting type metadata on the same frame:

[Parsed_showinfo_0] n: 53 pts_time:4.333333 fmt:yuvj420p s:3840x2160 i:P iskey:1 type:I checksum:89D03FBC mean:[120 126 123] stdev:[57.8 7.4 10.4]

pict_type reports P while the same frame is flagged iskey:1 type:I β€” and stdev jumps to values consistent with real image content only at this point.

Thanks for the detailed report. We’ll try to reproduce this issue as soon as possible and will update this discussion with our findings.

Sign up or log in to comment