Communitygithub.com

비디오 자막 스킬

로컬 Whisper + ffmpeg를 사용하여 비디오에 자막을 추가하는 Claude Code 스킬입니다. 5★.

비디오 자막 스킬란 무엇인가요?

이 스킬은 Claude Code 환경에서 로컬 Whisper 모델(mlx-whisper 또는 openai-whisper)과 ffmpeg를 활용해 동영상에 자막을 추가하는 전체 파이프라인을 제공합니다. 사용자는 비디오 파일 경로를 지정하면 오디오 추출, Whisper 기반 음성 인식, SRT 파일 생성 및 정리, 최종 자막 하드코딩(burn-in)까지 자동으로 수행됩니다. Apple Silicon(Mac)에서는 mlx-whisper를 권장하며, 그 외 플랫폼에서는 openai-whisper를 사용합니다. ffmpeg의 libass 필터를 통해 SRT 자막을 영상에 직접 입히며, libass가 없을 경우 기본 자막 트랙으로 소프트 임베딩하는 대체 모드도 제공합니다. 스킬은 `/video-subtitle` 명령어로 호출되며, 인자에 따라 전체 파이프라인, SRT만 생성, 또는 기존 SRT를 굽기(burn)만 할 수 있습니다. 자막 품질 향상을 위해 환각(hallucination) 제거, 고유명사 보정, 짧은 조각 병합, 재번호 부여 등의 자동 정리 단계를 포함하며, 최종 자막을 사용자에게 확인 후 굽기 과정을 진행합니다. 문제 발생 시 ffmpeg 필터 누락, 자막 문자 깨짐 등에 대한 트러블슈팅 가이드도 함께 제공됩니다.

지원 대상✓Claude Code✓Codex CLI~Cursor
npx skills add Tofuswang/video-subtitle-skill

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

/video-subtitle — 비디오 자막 도구

로컬 Whisper 모델을 사용하여 비디오 오디오를 SRT 자막으로 변환한 후, 비디오에 자막을 입힙니다.

사용자 호출

사용자가 /video-subtitle을 입력하면 이 스킬을 실행합니다.

사전 요구사항

이 스킬에는 두 가지 도구가 필요합니다. 진행하기 전에 사용 가능 여부를 확인하세요.

1. mlx-whisper (Apple Silicon) 또는 openai-whisper

사용 가능한 것을 감지합니다:

which mlx_whisper whisper 2>/dev/null

둘 다 없을 경우, 사용자에게 다음 중 하나를 설치하도록 안내합니다:

  • Apple Silicon Mac (권장): pip install mlx-whisper
  • 모든 플랫폼: pip install openai-whisper

2. libass를 지원하는 ffmpeg

libass 지원 여부 확인:

ffmpeg -filters 2>&1 | grep subtitles

출력이 없으면(libass 누락) subtitles 필터를 사용할 수 없습니다:

  • macOS: brew install ffmpeg-full (keg-only, /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg)
  • Linux: sudo apt install ffmpeg (보통 libass 포함)
  • 대체: 사용자가 libass가 없는 일반 ffmpeg를 사용 중이라면, 자막을 굽는 대신 SRT를 자막 트랙으로 소프트 임베딩합니다.

Whisper 모델 선택

캐시된 모델 확인:

ls ~/.cache/huggingface/hub/ 2>/dev/null | grep whisper

가장 큰 사용 가능한 모델을 선호합니다. 캐시된 것이 없으면 다음을 사용합니다:

  • mlx-whisper: mlx-community/whisper-large-v3-mlx
  • openai-whisper: large-v3

모드

  • /video-subtitle path/to/video.mov → 전체 파이프라인 (변환 + 보정 + 굽기)
  • /video-subtitle srt path/to/video.mov → SRT만 (변환, 굽지 않음)
  • /video-subtitle burn path/to/video.mov path/to/sub.srt → 굽기만 (기존 SRT 사용)
  • /video-subtitle (인자 없음) → 대화형, 비디오 경로 요청

전체 파이프라인

1단계: 비디오 확인

경로가 제공되지 않으면 AskUserQuestion으로 요청합니다. 파일이 존재하는지 확인하고 메타데이터를 읽습니다:

ffmpeg -i "<video_path>" 2>&1 | grep -E "Duration|Stream.*(Video|Audio)"

지속 시간, 해상도, 파일 크기를 사용자에게 보고합니다.

2단계: 오디오 추출

ffmpeg -i "<video_path>" -vn -acodec pcm_s16le -ar 16000 -ac 1 "<output_dir>/<basename>_audio.wav" -y

16kHz 모노 WAV는 Whisper에 최적의 입력 형식입니다.

3단계: 언어 확인

AskUserQuestion으로 사용자에게 물어봅니다. 일반적인 옵션:

언어플래그
한국어--language ko
영어--language en
일본어--language ja
자동 감지--language 생략

4단계: 변환

mlx-whisper:

mlx_whisper --model "<model>" --language <lang> --output-format srt --output-dir "<output_dir>" "<audio_wav>"

openai-whisper:

whisper "<audio_wav>" --model large-v3 --language <lang> --output_format srt --output_dir "<output_dir>"

사용자에게 알립니다: "변환 중입니다. 잠시 기다려 주세요..."

5단계: SRT 정리

생성된 SRT를 읽고 다음을 수정합니다:

  1. 환각 제거: 지속 시간이 0인 타임스탬프(예: 00:00:57,640 --> 00:00:57,640)나 빈 텍스트가 있는 항목 삭제
  2. 고유명사 수정: Whisper가 브랜드명이나 기술 용어를 잘못 인식하는 경우가 많음 — 대화 맥락을 사용하여 수정
  3. 조각 병합: 의미적으로 연결된 0.5초 미만의 짧은 항목 결합
  4. 재번호 부여: 다음 Python 스니펫을 실행하여 모든 항목에 번호를 다시 매깁니다:
python3 -c "
import re
with open('<srt_path>', 'r') as f:
    content = f.read()
blocks = re.split(r'\n\n+', content.strip())
out = []
for i, block in enumerate(blocks, 1):
    lines = block.strip().split('\n')
    if len(lines) >= 2:
        lines[0] = str(i)
        out.append('\n'.join(lines))
with open('<srt_path>', 'w') as f:
    f.write('\n\n'.join(out) + '\n')
"

수정된 SRT를 사용자에게 보여주고 굽기 전에 추가 편집이 필요한지 묻습니다.

6단계: 자막 굽기

올바른 ffmpeg 바이너리를 결정합니다(일반 ffmpeg에 libass가 없으면 ffmpeg-full 선호):

FFMPEG="ffmpeg"
if ! ffmpeg -filters 2>&1 | grep -q subtitles; then
  if [ -x /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg ]; then
    FFMPEG="/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg"
  fi
fi

그런 다음 굽기:

$FFMPEG \
  -i "<video_path>" \
  -vf "subtitles=<srt_path>:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,MarginV=30'" \
  -c:v libx264 -preset medium -crf 23 \
  -c:a aac -b:a 128k \
  -pix_fmt yuv420p \
  "<output_dir>/<basename>_subtitled.mp4" -y

force_style 옵션:

매개변수기본값설명
FontSize24글꼴 크기
PrimaryColour&H00FFFFFF흰색 텍스트
OutlineColour&H00000000검은색 윤곽선
Outline2윤곽선 두께
MarginV30아래쪽 여백

중요: SRT 파일 경로에 ffmpeg 필터 파서를 혼동시키는 특수 문자가 없어야 합니다. 필요한 경우 상대 경로나 심볼릭 링크를 사용하세요.

7단계: 완료

출력 파일 경로와 크기를 보고합니다. open <path>로 미리 보기를 제안합니다. 중간 파일인 _audio.wav를 삭제할 수 있음을 알립니다.


문제 해결

문제원인해결책
No such filter: 'subtitles'ffmpeg에 libass 없음ffmpeg-full 사용 또는 libass 설치
No such filter: 'drawtext'ffmpeg에 libfreetype 없음ffmpeg-full 사용
중복/빈 SRT 항목Whisper 환각5단계에서 정리
한글이 네모로 표시됨CJK 글꼴 없음macOS: 자동으로 Apple SD Gothic Neo로 대체. Linux: apt install fonts-noto-cjk
Error parsing filterchainSRT 경로에 특수 문자상대 경로 사용, 공백 피하기

품질 규칙

  • 충실한 변환: 실제로 말한 내용만 변환 — 의미를 추가하거나 다시 쓰지 않음
  • 고유명사 수정: 일반적인 Whisper 오인식을 수정하지만, 사용자와 확인
  • 자막 리듬: 항목당 최대 두 줄, 줄당 최대 ~20자(한국어 기준)
  • 정리: 완료 후 중간 파일(_audio.wav) 삭제를 사용자에게 알림

관련 스킬