{"record":{"id":"44561b7103466e35","repo":"affaan-m/ECC","slug":"ffmpeg-is-required-for-temporal-style-feature-extraction","errorCode":null,"errorMessage":"ffmpeg is required for temporal/style feature extraction","messagePattern":"ffmpeg is required for temporal/style feature extraction","errorType":"exception","errorClass":"MediaToolUnavailable","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/workflow.py","lineNumber":351,"sourceCode":"    style_samples = []\n    scene_changes = []\n    for record in records:\n        if \"luma_raw\" in record:\n            style_samples.append({\n                \"time\": round(record[\"time\"], 6),\n                \"luma\": round(record[\"luma_raw\"] / 255.0, 6),\n                \"saturation\": round(record.get(\"saturation_raw\", 0.0) / 100.0, 6),\n                \"hue\": record.get(\"hue\"),\n            })\n        if record.get(\"scene_score\", 0.0) >= scene_threshold:\n            scene_changes.append(round(record[\"time\"], 6))\n    return {\"style_samples\": style_samples, \"scene_changes\": scene_changes}\n\n\ndef _run_ffmpeg_features(path: Path) -> dict[str, Any]:\n    ffmpeg = shutil.which(\"ffmpeg\")\n    if not ffmpeg:\n        raise MediaToolUnavailable(\"ffmpeg is required for temporal/style feature extraction\")\n    filters = (\n        \"scale=320:-2,\"\n        \"select='not(mod(n\\\\,12))+gt(scene\\\\,0.30)',\"\n        \"signalstats,metadata=print:file=-\"\n    )\n    result = subprocess.run(\n        [ffmpeg, \"-v\", \"error\", \"-i\", str(path), \"-vf\", filters,\n         \"-an\", \"-vsync\", \"0\", \"-f\", \"null\", \"-\"],\n        check=True,\n        capture_output=True,\n        text=True,\n    )\n    return parse_feature_output(result.stderr + \"\\n\" + result.stdout)\n\n\ndef probe_media(path: Path) -> dict[str, Any]:\n    \"\"\"Probe local media and extract timestamped style/temporal features.\"\"\"\n    ffprobe = shutil.which(\"ffprobe\")","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/workflow.py#L333-L369","documentation":"Dependency guard in _run_ffmpeg_features: the ffmpeg binary was not found on PATH, so timestamped luma/saturation/scene-change features cannot be extracted from the media. The message fires before any probing runs.","triggerScenarios":"probe_media -> _run_ffmpeg_features is invoked on a media file while shutil.which('ffmpeg') returns None (ffmpeg not installed or not on PATH of the calling process).","commonSituations":"Minimal Docker images or CI runners without ffmpeg; virtualenv/conda environments lacking the binary; PATH differences between interactive shell and cron/systemd.","solutions":["Install ffmpeg (apt install ffmpeg / brew install ffmpeg / conda install ffmpeg)","Ensure the ffmpeg binary's directory is on PATH for the process running the workflow","Pin ffmpeg in your Dockerfile/CI setup so it is always present"],"exampleFix":"// before\n$ python workflow.py --config cfg.json  # MediaToolUnavailable\n// after\n$ sudo apt-get update && sudo apt-get install -y ffmpeg\n$ which ffmpeg && python workflow.py --config cfg.json","handlingStrategy":"fallback","validationCode":"import shutil\nif shutil.which(\"ffmpeg\") is None:\n    raise SystemExit(\"ffmpeg not found on PATH; install it before running tasteforge\")","typeGuard":"def has_ffmpeg() -> bool:\n    import shutil\n    return shutil.which(\"ffmpeg\") is not None","tryCatchPattern":"try:\n    features = probe_media(path)\nexcept MediaToolUnavailable:\n    features = fallback_features_without_temporal_style(path)  # or abort with clear message","preventionTips":["Bake ffmpeg into your container/CI image","Check `which ffmpeg` in entrypoint scripts before running the workflow","Keep PATH consistent between interactive shells and service contexts"],"tags":["ffmpeg","missing-binary","environment"],"backgroundTag":"missing-dependency","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}