ffmpeg-skill
스크립트는 이 파일과 같은 디렉토리의 scripts/에 있으며, python3 <skill-dir>/scripts/<name>.py로 실행합니다. 템플릿은 templates/에 있습니다. 이 파일만으로도 작업을 수행할 수 있습니다: 아래 표가 요청을 라우팅하며, 실행할 스크립트의 --help가 가장 저렴한 전체 플래그 목록입니다. 참조 파일은 이 파일과 비용이 같으며, 궁금한 점이 있을 때만 열어보십시오: references/scripts.md (42개 스크립트의 모든 플래그), references/devices.md (iPhone HDR, GoPro, DJI, 화면 녹화, Zoom), references/gotchas.md (마지막에 있는 한 줄 규칙의 상세 버전). MCP: tools/list는 기본적으로 핵심 12개만 표시합니다. 나머지 30개(이 표 기준)는 tools/call로 이름을 호출하여 사용할 수 있으며, contract --json으로 설명됩니다. 모든 42개를 보려면 FFMPEG_SKILL_MCP_FULL=1을 설정하십시오.
공유 플래그 (모든 스크립트): --dry-run; --json (출력 경로, 프로브, 실행된 명령어); --json-brief (상태/출력/확인 + summary; 작성 단계에 선호); --fast (미리보기 품질); --progress (백분율/ETA); --timeout SECONDS (kind: timeout, 기본값 1800); --overwrite (7단계); --plan FILE (나중에 실행할 render.py의 드라이 런 파일; 입력이 변경되면 거부). 재인코딩 도구는 또한 --hw (Apple Silicon GPU, 큰 파일; FFMPEG_SKILL_HW=1 = 기본값, 내보내기 아님), --codec h264|hevc|av1|prores 및 --quality N을 사용합니다: 설정되지 않은 경우, SDR은 x264 (cut.py --keep-hevc: HEVC 소스는 HEVC 유지), HDR은 x265 Main10; prores는 -o NAME.mov가 필요하며, h264는 HDR을 거부합니다 (color.py --to-sdr 먼저).
작성 도구는 --dry-run에서 아무것도 실행하지 않습니다. 측정 도구(probe, check, sync, multicam, scenes, cropdetect, report, silence, loudness, stabilize; FFmpeg 8.0-8.1.0에서 여러 줄 --text를 위한 overlay)는 아티팩트/사이드 파일(--edl, --sheet, 생성된 .ass)을 건너뛰고 ffmpeg/ffprobe를 여전히 실행할 수 있습니다. verify는 플래그를 무시합니다. 도구별: contract --json dry_run.
워크플로 (이 순서대로)
- 환경, 실패 시에만.
doctor로 작업을 시작하지 마십시오: 고장난 머신은kind: missing_tool또는 필터/인코더를 명명한 ffmpeg 오류로 실패합니다. 이러한 실패 후 또는 머신이 무엇을 할 수 있는지 물을 때python3 <skill-dir>/scripts/_contract.py doctor(또는npx ffmpeg-skill doctor)를 실행하십시오:ok/usable을 읽고, 누락된 기능을 보고하십시오.contract --json의 도구 스키마는 계획 에이전트를 위한 것이지, 이 워크플로를 위한 것이 아닙니다. - 계획에 필요한 것을 프로브하십시오. 계획할 각 입력에 대해
probe.py를 실행하십시오 — 지속 시간, fps, 해상도, 코덱, 채널,variable_frame_rate_suspected— 사용자가 파일에 대해 물을 때마다. 모든 편집 전에 별도의 프로브가 필요하지 않습니다: 모든 작성 도구의--json은 이미 입력과 출력 프로브를 포함합니다. 실제 숫자로 계획하고, 가정하지 마십시오. - 무손실을 선호하십시오. 요청이 재인코딩 없이 충족될 수 있는 경우(키프레임에서의 일반 컷, 리먹싱, 오디오 전용 변경), 재인코딩하지 마십시오.
cut.py와loudness.py는 기본적으로 비디오를 스트림 복사합니다. 프레임 정확한 컷에만cut.py에--accurate를 사용하십시오. --dry-run --json으로 계획한 후 실행하십시오. 계획의 숫자에 대해 드라이 런의 요약 줄이 아닌--json을 신뢰하십시오 (거기서 차원이 플레이스홀더일 수 있음). 긴 인코딩 전에 사실을 보고하는 데 사용하십시오. 사용자가 교체를 요청하지 않는 한-o를 이 작업에서 생성하지 않은 파일로 지정하지 마십시오. 그런 경우에만--overwrite를 전달하십시오.- 합리적인 순서로 체인하십시오. 다른 편집 없이 전달 요청만 있는 경우는 하나의 템플릿 실행(
render.py --template NAME INPUT)이며, 수동으로 구축된 체인이 아닙니다. 그 외에는: 색상 (HDR→SDR / LUT) → 자르기 → 연결 → 무음 → 맞춤 → 자막/오버레이 → 동기화 → 오디오 → 음량 → 내보내기. 자막 전에 프레임을 변경하여 최종 프레임에 맞게 텍스트 크기를 조정하십시오. 가능한 적게 재인코딩하십시오: 중간 파일은 CRF 18,export.py는 마지막에. 세 단계 이상: project.json과 함께render.py를 사용하십시오. - 결과물을 확인하십시오. 보고하기 전에, 대상 플랫폼에 대해
check.py OUTPUT --platform X를 실행하십시오 (템플릿 실행은 이미 수행). 형식 행(코덱, 픽셀 형식, 크기, 실제 피크, 색상 태그, VFR)은 안전하게 수정할 수 있습니다. 판단 행은 내용을 변경합니다: 지속 시간(컷으로 재료 손실), 종횡비(크롭으로 가장자리 손실), fps(모션 드롭), 음량(앰비언스를 부스트하지 않아야 함) — 요청이 답을 암시하는 경우에만 수정하고, 그렇지 않으면 선택과 그 비용을 명시하십시오. WARN을 언급하되, 추구하지 마십시오. - 출력을 확인하십시오. 작성 도구의
--json/--json-brief프로브 또는probe.py에서 지속 시간, 해상도, fps 및 오디오가 요청과 일치하는지 확인하고, 그 숫자를 보고하십시오 ("final.mp4: 59.98 s, 1080x1920, 30 fps, AAC 스테레오"). 스크립트가 0으로 종료되고 출력이 예상대로 프로브될 때만 단계가 완료됩니다: 0이 아닌 종료, 누락되거나 빈 파일, 또는 요청과 모순되는 프로브는 스크립트의 오류 메시지와 함께 실패로 보고됩니다. - 사용자의 원본을 보존하십시오. 소스를 덮어쓰지 마십시오. 입력 옆 또는 요청된 곳에 새 파일을 작성하십시오. 기존 출력 경로는 거부됩니다 (
kind: input);--overwrite는 "예, 교체하십시오"라고 말하는 유일한 방법입니다. - 사진을 보십시오. 사진이 변경될 때마다 (자막, 오버레이, 그래픽, 크롭/패드, 크기 조정, 색상, 전환,
join.py가 클립을 첫 번째 클립의 프레임으로 스케일링,color.py --to-sdr)look.py OUTPUT --tiles 3x2(또는 한 프레임을 위해--at T)를 실행하고 PNG를 보십시오 (전체 클립 레이아웃의 경우 4x3).Look:이 해당 PNG를 명명할 때까지 완료되지 않습니다 — 프로브는 얼굴 위의 자막을 볼 수 없습니다. 오디오 전용:Look: not needed. 확인해야 할 사항은 5단계의check.py행과 같이 나뉩니다:- 기계적 (이 스킬의 고유한 확인 및 보고 작업): 지정된 텍스트/로고가 지정된 위치에 있고, 자막이 지정된 타임스탬프에 나타나며, 치수가 짝수입니다.
fit.py --fit pad의 레터박싱은 해당 모드의 올바른 결과이며, 결함으로 표시하지 마십시오. - 판단 (무음 통과 또는 실패하지 말고 보고): 피사체나 얼굴이 잘렸는지, 텍스트가 얼굴 위에 있는지, 색상이 바래 보이는지, 전환이 제대로 이루어지는지. 이는 피사체가 무엇인지 결정하는 것을 필요로 하며, 호출 에이전트의 판단에 맡깁니다 — 한 줄로 본 것을 말하십시오; 그들이 판단합니다.
시각 기능이 없으면,
Look: PATH (pixels not inspected; agent has no image view)를 작성하십시오 — 가능하지 않은 기능을 기다리지 않고 사진이 검사되었다고 주장하지 마십시오.
- 기계적 (이 스킬의 고유한 확인 및 보고 작업): 지정된 텍스트/로고가 지정된 위치에 있고, 자막이 지정된 타임스탬프에 나타나며, 치수가 짝수입니다.
실행 전에: 무엇을 물을 것인가, 무엇을 가정할 것인가
답변이 출력을 실질적으로 변경하고 요청이 이를 암시하지 않는 경우에만 짧은 질문을 하십시오. 여러 사항이 동시에 열려 있을 때 (모호한 "소셜 미디어용으로 만들어 줘"가 대상, 종횡비, 길이 및 자막을 열어둠), 턴당 한 번만 묻지 마십시오: 기본값을 포함한 하나의 번들을 제안하고 사용자가 어떤 부분이든 변경할 수 있도록 하십시오 ("Reels: 9:16 패딩, 60초, -14 LUFS, 자막 없음 — 괜찮나요?"). 한 번의 질문, 한 번의 답변, 그런 다음 실행. probe.py가 알려줄 수 있는 것을 묻지 마십시오.
- 대상은 종횡비, 길이 제한, 음량 및 코덱을 결정합니다. "Reels용"은 네 가지 모두를 답하고 템플릿을 명명합니다. 대상이 없고 단순한 컷/자막인 경우: 소스 형식을 유지하고 그렇게 말하십시오. 사용자가 "내보내기", "게시" 또는 "전달"을 말하면, 어디에 물어보십시오.
- 지속 시간 ("60초로 만들어 줘") 방법 없음: ≤1.5× 변경은 속도 증가, 그렇지 않으면 트림, 그리고 그렇게 말하십시오. 내용이 대화이고 변경이 큰 경우 물어보십시오 (트림은 단어를 잃음).
- 자막 텍스트 소스 없음: 로컬 엔진이 존재하면
--transcribe, 그렇지 않으면 텍스트 또는 시간 파일을 요청하십시오. 대화를 절대 발명하지 마십시오. - 폰트 및 브랜드: 사용자가 브랜드, 색상 또는 "우리 폰트"를 언급하면, 한 번
brand.json을 요청하거나 생성하고 재사용하십시오. - CJK / 비라틴 텍스트: 도구가 스크립트별로 폰트를 선택하도록 하십시오 (
--font가 끔). 한자 전용 텍스트에는--lang ja|ko.doctor --json.fonts.scripts는 여기서 렌더링되는 항목을 알려줍니다. 토후는 실패한 작업입니다. - 크롭 위치
--fit crop의 경우: 기본적으로 중앙. 그러나 요청이나 소스가 중앙이 아닌 피사체를 명명하는 경우 ("제품을 오른쪽에 유지", 시트에서 누군가가 보기에 중앙에 있지 않음), 중앙을 추측하는 대신--crop-x/--crop-y(0=왼쪽/상단, 1=오른쪽/하단)를 사용하거나 어떤 가장자리를 유지할지 물어보십시오. - 그 외의 것 (전환 유형, 자막 스타일): 관례적인 기본값을 선택하고, 무엇을 선택했는지 말하고, 한 줄로 대안을 제공하십시오.
이 스킬이 결정하는 것과 결정하지 않는 것
이 스킬은 파일을 자르고, 연결하고, 측정하고, 동기화하고, 내보내고, 확인합니다 — 편집을 실행하지만 결정하지는 않습니다. 인간, 호출 에이전트 또는 다른 스킬에 속하는 것:
- 어떤 컷이 올바른지, 또는 결과물이 승인 가능한지 — 이 스킬은 측정하고 보고합니다 (
check.py의 PASS/WARN/FAIL,cut.py의 지속 시간 오류). 사용자 또는 제작 에이전트가 배송 여부를 결정합니다. - 하이라이트를 흥미롭게 만드는 것 —
scenes.py --highlights는 측정된 프록시(오디오 에너지, 지속 시간)로 순위를 매깁니다: 후보자이며, 평결이 아닙니다. - 썸네일 또는 커버 구성 — 디자인 결정, 측정이 아닙니다.
- 비디오가 무엇에 관한 것인지 이해 — 여기에는
look.py의 접촉 시트 이상의 시각이 없으며, 호출 에이전트의 눈을 위한 것이지 이 스킬이 해석하기 위한 것이 아닙니다. - 무엇이 좋아 보이는지 판단 — "이 LUT 적용", "노출을 +0.3 스톱 보정" (
color.py)은 기계적입니다. "이 장면을 영화처럼 등급 조정"은 매개변수를 결정한 다음color.py를 호출하는 색상 등급 스킬(color-grading-skill)에 속합니다. - 자막의 단어 — 큐 텍스트는 작성된 대로 굽습니다. 프레임에 너무 길면 더 작은 크기,
--max-lines또는 사용자 자신의 편집을 의미합니다. "맞추기" 요청에도 다시 쓰거나, 줄이거나, 의역하지 마십시오 — 그렇게 말하고, 더 작은 크기로--max-lines 1을 제공하십시오. - 주어지지 않은 피사체 또는 영역 선택 — "x=200, y=0으로 크롭"은 상자가 알려지면 기계적입니다. "화자(話者)를 프레임에 유지하기 위해 크롭"은 화자가 무엇인지 결정해야 하며, 호출 에이전트의 판단입니다 (
look.py시트에서).
경계: 동일한 입력 + 동일한 명시적 매개변수가 항상 동일한 검증 가능한 출력을 생성하는 것은 여기에 속합니다. 취향, 이해 또는 보거나 들을 때 좋은 것에 의존하는 것은 그 판단을 내리는 사람에게 속합니다.
요청이 42개 스크립트 중 어느 것도 노출하지 않는 FFmpeg 기능이 필요한 경우, 그렇게 말하고 가장 가까운 내장 옵션을 명명하십시오 — scripts/*.py 외부에서 원시 ffmpeg/ffprobe 호출을 추측하지 마십시오. 이는 이 스킬이 제공하는 모든 보장을 우회하므로 절대 대체 수단이 아닙니다.
요청 → 스크립트
이 표와 doctor --json의 tools 목록은 존재하는 것에 대한 진실의 원천입니다: 스크립트 중 하나에서 본 것만 명명하십시오 (doctor.py, trim.py, subtitle.py는 없습니다).
타임스탬프 플래그 (--start, --end, --at, --from, --duration, --offset, 그리고 큐 및 챕터 파일의 시간)는 초, mm:ss(.fff), hh:mm:ss(.fff) 또는 @fps와 함께 SMPTE hh:mm:ss:ff (00:01:02:[email protected])를 사용합니다 — NLE 큐 시트를 그대로 붙여넣으십시오. 길이 플래그 (--min-silence, --margin, --fade)는 일반 초입니다.
| 사용자 말함 | 수행할 작업 |
|---|---|
| "1:20에서 2:05까지 잘라", "처음 10초 트림" | cut.py input.mp4 --start 1:20 --end 2:05 |
| "이 부분들만 유지", "중간 제거" | cut.py input.mp4 --segments 0-1:00,1:30-2:00 |
| "정확히 60초로 만들어 줘" | fit.py input.mp4 --duration 60 (속도) 또는 --method trim |
| "이걸 자르고 HEVC / AV1 / ProRes로 만들어 줘" (출력 코덱 명명) | cut.py input.mp4 --start 0:10 --end 0:40 --codec hevc (ProRes는 -o NAME.mov 필요) |
| "멈춤 부분 잘라", "점프 컷" | silence.py input.mp4 [--threshold -40 --min-silence 0.8] |
| "음, 어 잘라", "필러 단어 제거" | silence.py input.mp4 --filler --words words.json (측정된 단어 타이밍; --transcribe가 생성) |
| "문장 내에서 자르지 말고, 실제 멈춤 부분만" | silence.py input.mp4 --speech-aware — 문장 내 --min-silence 미만의 호흡은 유지, 문장 경계 멈춤만 잘라냄; --filler와 함께 하나의 목록으로 구성 |
| "이 한 시간에서 60초 하이라이트" | scenes.py long.mp4 --highlights 6 --target 60 --edl picks.txt → cut.py --segments |
| "비트에 맞춰 잘라", "음악에 맞게 편집" | scenes.py track.mp4 --beats --json > beats.json, then cut.py input.mp4 --segments ... --snap beats --snap-source beats.json (--snap-source는 측정된 그리드를 전달) |
| "여기 속도 증가, 거기 슬로우 모션" (알려진 세그먼트) | speedramp.py action.mp4 --segment 0-3:1.0 --segment 3-4:0.25 --segment 4-8:2.0 |
| "이 프레임에서 멈춤", "마지막 프레임 고정" | freeze.py clip.mp4 --hold 2 |
| "부드러운 슬로우 모션", "반속도지만 유연하게" | fit.py input.mp4 --duration 2x --smooth interpolate (느림) 또는 --smooth blend |
| "이 클립 역재생" | reverse.py input.mp4 |
| "이 클립을 30초 동안 반복" | loop.py bg_loop.mp4 --duration 30 |
| "세로 / 9:16 / 정사각형으로 만들어 줘" | fit.py input.mp4 --aspect 9:16 --fit pad (또는 --fit crop; 흐린 막대는 --pad-fill blur) |
| "높이/너비로 크기 조정" | fit.py input.mp4 --height 1080 (또는 --width, 또는 정확한 프레임을 위해 둘 다) |
| "이 정확한 상자로 크롭" (알려진 x/y/w/h) | crop.py input.mp4 --x 100 --y 0 --width 1080 --height 1920 |
| "검은 막대 대신 흐린 배경" | fit.py input.mp4 --aspect 9:16 --fit blur (전체 사진 유지, 테두리는 흐리고 어두운 복사본) |
| "90도 회전", "미러" | fit.py input.mp4 --rotate 90 / fit.py input.mp4 --flip h |
| "수평선이 기울어짐" (알려진 각도) | straighten.py tilted.mp4 --degrees -2.5 |
| "이 360 비디오에서 평면 보기" (알려진 요/피치/fov) | sphere.py insta360.mp4 --yaw 90 --pitch 0 --h-fov 100 --v-fov 70 |
| "이 오래된 영상이 인터레이스됨" | deinterlace.py input.mp4 |
| "입자/노이즈 있음, 정리" | denoise.py input.mp4 --strength medium |
| "이 얼굴/번호판 블러/픽셀화" (알려진 상자) | redact.py input.mp4 --x 820 --y 140 --width 240 --height 240 --mode pixelate |
| "이 고정 로고 제거" (알려진 상자) | redact.py input.mp4 --x 40 --y 20 --width 180 --height 60 --mode delogo |
| "이 흔들리는 영상 안정화" | stabilize.py input.mp4 |
| "여기에 검은 막대가 있나?" | cropdetect.py input.mp4 |
| "iPhone Dolby Vision 클립이 이상해 보임" | color.py input.mp4 --to-sdr |
| "영화 같은 룩을 원해" (구체적인 LUT 없음) | "색상 등급 스킬이 LUT를 선택하고 매개변수를 설정하며, 그런 다음 color.py --lut ...을 호출합니다"라고 말하십시오 |
| "HDR 비디오를 내보내기" (SDR 디스플레이용) | color.py hdr.mp4 --to-sdr |
| "노출 수정", "더 밝게", "대비 높여" (구체적인 값 없음) | "색상 등급 스킬이 매개변수를 결정합니다"라고 말하십시오. 값이 알려진 경우: color.py input.mp4 --exposure +0.5 / --contrast 1.2 |
| "사용자 정의 LUT 적용" (LUT 파일 제공) | color.py log.mp4 --lut path/to/lut.cube |