affaan-m/ECC · error · RuntimeError

ffmpeg encode failed

Error message

ffmpeg encode failed: {err}

What it means

`grade_clip_direct()` pipes raw frames into an FFmpeg subprocess and after the stream ends reads FFmpeg's stderr; if the encoder exits non-zero it raises a RuntimeError with the last 400 bytes of stderr. This detects encode-side failures that only appear at flush/termination — invalid encoder options, corrupted output target, disk full, or an FFmpeg that died mid-stream.

Solutions

  1. Read the stderr captured in the exception (last 400 chars) for the concrete FFmpeg message.
  2. Verify FFmpeg supports libx264: `ffmpeg -encoders | grep libx264`; install a full build if absent.
  3. Check destination disk space and write permissions before encoding.
  4. Ensure probe-derived width/height/fps actually match the source frames so the rawvideo header is correct.

Example fix

// before
cmd = [..., '-c:v', 'libx264', '-crf', str(crf), ...]   # libx264 absent -> encode failed
// after
if b'libx264' not in subprocess.run(['ffmpeg','-encoders'], capture_output=True).stdout:
    cmd = [c if c != 'libx264' else 'mpeg4' for c in cmd]
subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE, ...)
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil, subprocess
assert shutil.which('ffmpeg')
enc = subprocess.run(['ffmpeg', '-hide_banner', '-encoders'], capture_output=True)
assert b'libx264' in enc.stdout, 'libx264 encoder unavailable'

Try / catch

try:
    grade_clip_direct(src, dst, lut)
except RuntimeError as e:
    if str(e).startswith('ffmpeg encode failed'):
        err = str(e).split(':', 1)[-1]
        logger.error('encoder stderr: %s', err)
        cleanup_partial(dst)
        raise EncodeError(dst, err) from e
    raise

Prevention

When it happens

Trigger: Calling `grade_clip_direct()` where the piped ffmpeg process returns non-zero at wait() — bad `-crf`/encoder args, destination path unwritable, ffmpeg killed or OOM, unsupported output pixel format.

Common situations: Very old or unusual FFmpeg builds missing libx264; output volume filling mid-encode; destination file locked by another process; stderr revealing 'Conversion failed' after a frame-size mismatch between declared `-s` and actual frames.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/f5687d5f5e79ffbb. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/taste/grade.py:817

                       tone_mode=tone_mode)
        proc.stdin.write((np.clip(out, 0, 1) * 255).astype(np.uint8).tobytes())
        buf.clear()

    try:
        while True:
            ok, bgr = cap.read()
            if not ok:
                break
            buf.append(_cv2.cvtColor(bgr, _cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0)
            if len(buf) >= batch:
                flush()
        flush()
    finally:
        cap.release()
        proc.stdin.close()
        err = proc.stderr.read().decode()[-400:]
        if proc.wait() != 0:
            raise RuntimeError(f"ffmpeg encode failed: {err}")
    return dst

View on GitHub (pinned to 8321021c54)