Communitygithub.com

localizing-video

Apple Silicon 기기에서 외국어 비디오(특히 중국어/일본어)를 영어로 현지화합니다. 신경망 더빙, 자막, 화면 내 텍스트 번역을 100% 로컬/무료로 제공합니다.

localizing-video란 무엇인가요?

이 스킬은 Apple Silicon Mac에서 외국어 비디오(주로 중국어/일본어 YouTube 튜토리얼, 강연)를 완전한 영어 버전으로 변환하는 로컬 파이프라인입니다. yt-dlp로 다운로드하고, Whisper로 음성 인식(ASR)을 수행하며, Kokoro-onnx TTS로 영어 더빙을 합성하고, libass를 사용해 하드서브 자막을 입히며, ocrmac(Apple Vision)으로 화면 내 텍스트를 OCR하여 번역합니다. 이 스킬이 존재하는 핵심 이유는 각 단계에서 발생할 수 있는 '숨은 함정(footgun)'을 해결하기 위해서입니다. 예를 들어, ffmpeg이 libass 없이 빌드된 문제, Kokoro의 espeak-ng 데이터 경로 문제, 영어-중국어 간 정보 밀도 차이로 인한 더빙 시간 지연 문제, 자막이 비디오 위에 거대하게 렌더링되는 문제, YouTube 자막 트랙을 먼저 확인하지 않고 불필요하게 Whisper를 실행하는 문제, 동음이의어 말장난이 ASR에서 사라지는 문제 등을 다룹니다. 특히 '앵커링(anchoring)' 기법으로 더빙의 시간적 드리프트를 제거하고, '정적 슬라이드 프리즈 확장' 등으로 시간 밀도 차이를 보정하는 고급 기법을 제공합니다. 이 스킬은 Claude Code, Cursor 등 AI 에이전트가 이 파이프라인을 안정적으로 재현할 수 있도록 안내합니다.

지원 대상~Claude Code✓Codex CLI✓Cursor✓Antigravity
npx skills add evnchn-agentic/localizing-video

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

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

문서

localizing-video은(는) 무엇을 하나요?

외국어 비디오를 영어로 변환합니다 — 동기화된 더빙 + 영어 자막 + 번역된 화면 내 텍스트 — Apple Silicon에서 100% 로컬/무료로 제공합니다. AI 에이전트가 yt-dlp, whisper, ffmpeg, scene-detect, mux 등의 도구를 사용하여 파이프라인을 구축할 수 있지만, 이 스킬은 재구축 시 잘못 선택하거나 간과하기 쉬운 도구 선택과 숨은 문제(footgun) 를 방지하기 위한 검증된 참조 구현체입니다.

참조 구현 (여기서 시작하세요)

이 저장소에는 작동하는 파이프라인이 포함되어 있습니다: engine/ 은 일반적인 실행 가능 엔진(build_dub.py — 청크 앵커링 기반, 드리프트 없음 (더빙 함정 참조), make_ass.py, dense_ocr.py, dedup_spans.py, render_overlay.py, run.sh)이고, example/ 은 완전한 작업 데이터셋입니다. engine/SETUP.md + example/README.md를 읽고 엔진을 실행하세요 — 처음부터 작성하지 마십시오. 비디오별로 새로 해야 할 작업은 en.srt + translations.json을 생성하는 것(번역 단계)뿐입니다. 엔진은 1920×1080 소스를 가정합니다.

파이프라인 및 각 단계의 결정

  1. 다운로드 yt-dlp (403 오류 시 --extractor-args "youtube:player_client=web_safari,ios,tv" 시도; DASH가 DRM인 경우 HLS 형식이 종종 작동).
  2. ASR — 하지만 yt-dlp --list-subs를 먼저 실행 (함정 참조): 수동/크리에이터 트랙이 무료로 Whisper보다 더 나은 결과를 낼 수 있고, -orig 태그는 실제 소스 언어를 알려줍니다(16분 동안 Whisper를 돌릴 필요 없이 "이미 대상 언어임"을 파악). -orig 자동 캡션은 무료 제2 ASR이므로 교차 검증에 사용할 수 있습니다. 이후 openai-whisper whisper source.mp4 --model large-v3-turbo --language <zh/ja> --word_timestamps True --output_format all (JSON 유지). 언어를 고정하세요. (torch는 py3.14 휠이 없으므로 py3.12 venv에서 whisper를 실행하세요.)
  3. 직접 (에이전트가 루프 내에서) TRANSLATE transcript — 무료, 톤 인식, 전문 용어 일관성 유지. 1:1 세그먼트↔타임스탬프 매핑을 유지하세요. 고유 명사는 지식을 바탕으로 수정하세요(ASR이 잘못 인식함). 말장난을 그대로 살리세요, 단어가 아닌 — 말장난은 직역으로 살아남는 경우가 드물기 때문에, 동일한 메커니즘을 지닌 영어 말장난을 트랜스-크리에이트하고, 그 효과를 자막에서 전달하세요(말장난의 주요 전달 매체 — 더빙은 원본 오디오 덕킹 위에 올라탐). 동음이의어 말장난은 ASR에서 보이지 않습니다 (함정 참조). 따라서 자막을 OCR하여 찾아내야 합니다.
  4. 더빙 — Kokoro-onnx TTS (함정 참조). 문장 단위 합성, 각 청크를 실제 타임스탬프에 앵커링(세그먼트별 드리프트 추적이 아님 — 누적 지연 발생), 시간 맞춤, 믹싱. 더빙을 따라가기 위해 시각적 타이밍을 조정합니다(더빙을 시계에만 맞추지 말고) — Time-density 참조.
  5. 자막 — 영어 자막을 레터박스 바에 입히고, 프레임 위에 겹치지 않도록 합니다 (함정 참조).
  6. 시각적 OCR — ocrmac (Apple Vision), 1fps 밀집 처리, 시간 범위로 중복 제거.
  7. 직접 시각적 문자열을 번역; 중국어 전용 박스 위에 영어를 오버레이.
  8. 먹싱 — ffmpeg-full (libass), 오버레이 → 레터박스 → 자막 버닝 → 더빙 오디오.

함정 — 이 스킬이 존재하는 실제 이유

함정현실 / 해결책
ffmpeg에 subtitles 필터 없음기본 brew ffmpeg는 libass가 없습니다. /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg를 사용하세요. (스킬: hardsubbing-video)
TTS = say는 평평하고 로봇 같음기본값으로 Kokoro-onnx (무료, 신경망, onnxruntime을 통해 py3.14 지원). 남성 am_michael 등.
Kokoro가 조용히 실패: phontab ... No such file번들된 espeak 데이터 경로가 깨짐. brew install espeak-ng를 실행한 후, 스크립트 내에서 espeakng_loader.get_data_path/get_library_path를 재정의하여 /opt/homebrew/share/espeak-ng-data + /opt/homebrew/lib/libespeak-ng.dylib를 사용하세요.
영어가 중국어/일본어보다 말하는 데 밀도가 낮음 → 더빙이 늦게 끝남atempo를 사용하지 마세요(>1.25×는 보코더 아티팩트 생성) — Kokoro의 네이티브 speed 로 재합성. 실행 커서로 드리프트를 추적하지 마세요(cursor-start catch-up): 경험적으로 밀집된 연속 음성의 경우 동영상 중간까지 ~+5초 누적. 대신: (a) 각 발화를 실제 시작점에 앵커링(=자막/비디오 타임라인)하여 드리프트가 누적될 수 없도록 함; (b) 인접한 ASR 세그먼트를 ~문장 단위 발화로 청킹하여 긴 영어 줄이 짧은 이웃에서 시간을 빌려올 수 있도록 함 — 세그먼트별 피팅은 1.9× 한도에서 59% 라인이 잘렸지만, 문장 청킹은 이를 ~0으로 줄였습니다. 앵커링은 드리프트를 잡지만, 오버런을 잡지 못합니다 — 오디오가 할당된 슬롯을 초과하는 청크는 여전히 다음 앵커와 충돌합니다. 오버플로우 폴백 순서: (1) 간결한 번역, (2) ~1.9× 한도 내에서 더 빠르게 재합성("압축" = 네이티브 speed 재합성 또는 더 짧은 텍스트 — atempo 아님), (3) 그 아래 슬라이드를 프리즈 확장(Time-density 참조), (4) 밀도가 낮은 이웃의 여유 시간을 빌림; 최후의 수단으로, 하드캡 + 30ms 페이드아웃(자막은 여전히 전체 줄을 전달).
영어 자막이 비디오 위에 크게 렌더링됨SRT→libass가 PlayResY=288로 기본 설정되어 글꼴/여백이 ~4.4배 확대됨. 명시적인 PlayResY가 있는 ASS를 생성해야 함 = 패딩된 높이. 그리고 레터박스(하단 막대 패딩, Alignment=2)를 사용하여 영어가 소스 자체의 내장 자막과 충돌하지 않도록 함(해당 자막은 제거할 수 없음).
Vision OCR "사용자 정의 스크립트가 필요함"아니요 — pip install ocrmac; ocrmac.OCR(f, language_preference=["zh-Hans","en-US"]).recognize()는 정규화된 (text, conf, (x,y,w,h))를 반환하며, 원점은 왼쪽 하단.
ASR 대 화면 자막 조정하단 자막은 내레이션에 대한 권위 있는 정답입니다(좋은 ASR 교차 검증). 하지만 제작자는 개그 자막을 넣습니다(횡설수설 ≠ 실제 대사); ASR을 OCR로 맹목적으로 대체하지 마세요. 차이점을 식별하고 각각 판단하세요.
ASR이 동음이의어 말장난을 조용히 평탄화함말장난 자체가 동음이의어일 수 있습니다: 人工智能(AI)를 人工痔能("치질 기술")로 발음하거나, 搁置("프로젝트 보류")를 割痔疮("치질 제거")로 발음. Whisper는 희귀한 말장난을 일반적인 단어로 "수정"하므로 개그가 대본에 도달하지 못함 — 고유 명사 수정으로는 복구할 수 없습니다. 제작자는 일반적으로 내장 자막에 말장난을 철자하므로, 여기서 OCR은 교차 검증이 아니라 일반적으로 유일한 신뢰할 수 있는 복구 경로입니다(철자된 동음이의어의 경우 자막이 우선하며, 위의 개그 자막 경우와 반대입니다). 징후: 한 줄이 이상하게 직역된 경우, 또는 반응/시각 효과가 단어와 일치하지 않는 경우 → 번역 전에 해당 자막을 OCR하세요.
YouTube 자막을 먼저 확인하지 않고 Whisper 실행yt-dlp --list-subs는 5초가 걸리며 세 가지 이점을 제공합니다. (1) <lang>-orig 태그 = 비디오의 실제 소스 언어; 이미 대상 언어라면(예: en-orig) 전체 파이프라인은 무효 — 다운로드+Whisper 전에 중단. (2) 수동/크리에이터 트랙(소스 언어)은 종종 Whisper보다 우수: 실제 구두점, 올바른 고유 명사, 삽입된 [음악] 없음. (3) -orig 자동 캡션은 무료 제2 ASR — Whisper와 비교하여 정확히 인간 수정이 필요한 줄을 찾을 수 있습니다. 16분 영어 강연에서 측정된 결과: 98.2% 단어 일치, 그러나 두 엔진은 Arthur Andersen(YT, 정답) vs Anderson(Whisper, 오답)에서 갈렸고 둘 다 브랜드명(Saily → "Saylite"/"Saley")을 잘못 처리함 — 교차 검증이 이를 식별; 어느 엔진 혼자서는 잡을 수 없습니다. 함정: --list-subs에 나오는 다른 100개 이상의 언어는 YouTube 자동 번역이며, 크리에이터 트랙이 아닙니다 — 거기에 zh-Hant 행이 있다고 해서 실제 중국어 소스로 착각하지 마세요.
모든 중국어 박스에 오버레이해설 비디오에서 화면상의 많은 "내용"(기사, 포함된 강연, 트윗)은 이미 영어이고 중국어가 위에 덧씌워져 있음 — 오버레이는 중복되어 지저분함. 중국어 전용 요소로 범위를 좁히세요.
스크롤 텍스트에 정적 오버레이스팬별(평균 위치) 오버레이는 연속 스크롤을 추적할 수 없음 — 중국어가 계속 가려짐. 프레임별 OCR + 박스 추적이 필요하며, 일반적으로 가치가 없음(해당 콘텐츠는 이미 영어 종류).
원본 영어 클립을 들리게 유지소스가 실제 영어 클립(인터뷰/데모)을 재생하는 경우, 원본 오디오를 전체 볼륨으로 그대로 전달하고 더빙 아래에서만 덕킹(약 0.1)하세요.
새로운 비디오에서 스크립트 재사용적응하되 하드코딩된 길이/경로가 있는지 확인하세요. render_overlay.py는 하드코딩된 프레임 수에서 오버레이 지속 시간을 파생함 — 더 긴 비디오에서 오버레이가 조용히 중간에 멈춤. len(glob('f1/f_*.png'))에서 지속 시간을 파생하고 상수는 사용하지 마세요. 비디오별로 en.srt + translations.json을 다시 번역하세요; 인덱스 페어링 어설션과 병렬 확인으로 번역/키 정렬 오류를 잡을 수 있음.

Time-density: 더빙뿐만 아니라 타임라인 재조정

영어는 중국어/일본어보다 초당 약 1.5~2배 적은 비트를 전달하므로, 충실한 더빙은 밀집된 소스에서 항상 시간과 싸우게 됩니다. 더빙을 압축하는 것(네이티브 speed)은 하나의 지렛대이며, ~1.9배 한도가 넘으면 서둘러 말하는 것처럼 들립니다. 더 큰 지렛대는: 시각적 타임라인은 탄력적입니다 — 더빙에 맞게 재조정하세요. 세 가지 지렛대, 비용이 적게 드는 순서:

  • 먼저 간결한 번역(밀집→더 짧게). 가장 밀집된 줄을 더 짧게 바꾸세요. 무료이며 시청자가 보는 것에 아무것도 잃지 않으며, 더빙이 조금 줄이더라도 자막은 여전히 전체 의미를 전달합니다. 이것이 talking-head 샷의 주요 지렛대입니다(움직이는 얼굴을 잡으면 떨림 발생; B-roll로 재편집은 일반적으로 제자리 현지화 작업 범위를 벗어남).
  • 정적 슬라이드 프리즈 확장(압박이 있는 곳에서 시간 확보). 내레이터가 스크린샷/슬라이드를 읽을 때 더빙이 가장 빨리 달리며 — 해당 프레임은 정적이므로, 자연스러운 일시 정지 지점에서 약간 더 길게 유지하여 시간을 확보하세요. 세 가지 조건을 지킨다면 거의 눈에 띄지 않습니다: (i) 타임라인 편집입니다 — 모든 다운스트림 항목이 유지 시간만큼 이동하므로, 프리즈를 삽입하고 유지된 타임라인에 대해 자막/더빙/오버레이 타이밍을 다시 생성하거나(또는 먹싱 시 모든 트랙을 함께 유지), 원래 시간에 앵커링하지 마세요; (ii) 오디오 배경음도 일시 정지하는 곳에서만 프리즈 — 연속 음악/룸톤/원본 오디오 위에서 유지하면 배경음이 동기화 해제됨(확장/크로스페이드하거나, 배경음이 덕킹/무음인 더빙 아래에서만 프리즈); (iii) "정적"은 진정으로 정적이어야 함 — 커서, 깜박이는 캐럿, 레이저 포인터 또는 프레임의 웹캠 인셋은 환상을 깨뜨립니다. 많은 작은 유지를 하고, 긴 드래그는 하지 마세요(몇 초 유지는 버퍼링/정지로 읽힘).
  • 밀도가 낮은 구간에서 여유 시간 회수(역방향 — 덜 밀집→밀집). 인트로, 사인오프, 느린 팬에는 여유 공간이 있습니다; 더빙이 거기서 숨을 쉬게 하거나, 그 여유를 밀집된 구간으로 앞당겨 빌리세요.

이것이 작동하는 이유: 밀도와 프리즈 가능성은 상관관계가 있습니다. 내레이션이 밀집된 이유는 슬라이드를 설명하기 때문이며 — 슬라이드는 정확히 프리즈 가능한 것입니다. 따라서 대부분의 시간 압박은 흡수할 수 있는 곳에 발생하는 경향이 있습니다. 추정하지 말고 측정하세요: 각 초를 프레임 간 움직임(평균|프레임 − 이전|을 다운스케일된 그레이스케일에서)으로 정적으로 표시하세요 — 그러나 임계값은 비디오별 보정이 필요합니다(코덱 노이즈, 비트레이트, fps, 그레인이 모두 영향을 줌; ≈4/255가 한 비디오의 값이었음), 그리고 전체 프레임 평균은 국지적 움직임을 놓칩니다(커서/캐럿/포인터) → 자막 대역을 마스킹하고 전체 프레임이 아닌 정적 영역을 확인하세요. 그런 다음 정적 마스크와 빠른 더빙 청크를 교차하여 압박이 얼마나 프리즈 가능한지 확인하세요. 한 10분 설명자 비디오에서 측정된 결과, 차분한 1.4× 한도는 ~14초를 회수해야 했고 74%가 프리즈 가능한 정적 슬라이드 위에 있었습니다(26%는 프리즈 불가능한 talking-head 위 → 간결한 표현) — 그러나 이 비율은 비디오마다 다릅니다. 소스 런타임을 초과하는 것은 독립 실행형 파일에는 괜찮습니다; 외부에서 동기화되는 것이 없기 때문입니다.

운영자와 논의할 결정 사항

  • 시각적 범위: 타겟팅(중국어 전용, 권장) vs 전체(기사 단락 포함 — 스크롤 시 저하).
  • 더빙 음성: 사용 가능한 무료 Kokoro 음성; 유료 (ElevenLabs)는 청구 제약을 완화하는 경우에만 제안.
  • 오디오: 전체 교체 vs 더빙 아래에 원본을 덕킹하여 유지.
  • 페이싱 노력: 빠른 더빙 수용(자막이 전체 의미 전달) vs 차분한 한도를 위한 시간 재조정(간결한 표현 + 슬라이드 프리즈 확장 — 측정 + 재먹싱 비용 발생). 결정할 수 있도록 측정값을 제공하세요.

검증 (신뢰하지 말고 — 확인하세요)

최종 mp4를 프레임 샘플링(JPG 읽기)하여 내레이션 순간, 슬라이드/오버레이 순간, 영어 클립 간격, 마지막 줄에서 확인하세요 — 자막 동기화, 오버레이 배치, 레터박스, A/V 지속 시간 일치를 확인하세요. 픽셀은 영구적으로 타버립니다. 특히 밀집된 슬라이드 순간을 샘플링하세요(더빙이 빨라지는 곳) — 그곳이 동기화/드리프트가 먼저 깨지는 곳입니다; 해당 타임스탬프의 번인된 중국어 자막이 동기화의 기준입니다. (오디오를 직접 듣고 확인할 수 없습니다 — 동기화는 앵커된 타임라인을 통해 구조적입니다; 그렇게 말하고 운영자에게 최종 청취를 요청하세요.)

다음과 함께 사용

hardsubbing-video (ffmpeg/libass 번인 함정 — 이 스킬의 8단계).

관련 스킬