影片 / 音訊文字提取
從本機多媒體檔案(.mp4、.m4s、.mkv、.m4a、.mp3)產出帶有時間戳記的轉錄稿或歌詞檔案。處理兩種常見情況:下載的影片沒有軟字幕軌但有內嵌(硬字幕)的畫面上文字,以及只有音訊的情況。
何時使用
- 「從這個影片提取歌詞/字幕,並標記每行的開始時間。」
- 「將此音訊轉錄成附帶時間戳記的文字。」
- 下載的 Bilibili/YouTube
.m4s/.m4a檔案;歌詞已渲染在畫面中的卡拉OK/AMV/音樂錄影帶。 - 任何要求輸出
.lrc或.srt格式的請求。
步驟 0 — 務必先檢查
ffprobe -v quiet -print_format json -show_streams -show_format FILE | python3 -m json.tool
需了解的重點:
- 存在的串流。 來自 Bilibili 的
.m4s通常是僅含視訊(音訊存在於另一個.m4s/.m4a檔案)。如果沒有音訊串流,請在同一個資料夾中尋找持續時間相符的同伴音訊檔。 - 軟字幕?
ffprobe ... -select_streams s— 如果存在字幕串流,直接提取(ffmpeg -i FILE -map 0:s:0 out.srt),跳過所有 OCR/Whisper 工作。這是最快的路徑。 - 持續時間。 當視訊沒有音訊時,用它來匹配正確的音訊檔。
- 標題/演出者卡片不是字幕區域。 第 0 幀通常帶有大型標題和演出者疊加,位置和字體都與實際歌詞字幕不同。從它推導出的裁切區域會錯過所有歌詞。改為從歌曲中間(顯示長歌詞行)取樣一幀;如果需要歌曲/演出者名稱,再另外讀取標題卡。
- 在轉錄前確認歌曲。 檔名和標題卡可能與使用者所稱的曲目不一致。如果音訊/歌詞與您預期的名稱不符,請在產出完整轉錄稿前先說明;如果影片是數首歌曲之一,請指明您實際轉錄的是哪一首。
步驟 1 — 決定文字來源(優先順序)
- 軟字幕串流 → 直接提取。完成。
- 內嵌的畫面上文字(硬字幕) → OCR 辨識幀(步驟 3)。這會得到官方、正確拼寫的文字。每當影片明顯渲染歌詞/字幕時,優先使用這個方法。
- 僅音訊,無畫面上文字 → Whisper 轉錄(步驟 2)。
如果同時存在畫面上文字和音訊轉錄,請使用 OCR 取得文字,使用 Whisper 獲取時間/定向 — OCR 文字是權威拼寫,Whisper 能精準掌握時間網格,但對於歌唱的文字可能會誤聽(例如它把 "petals" 聽成 "pedophiles",把歌唱的母音聽成 "fry right")。互相交叉比對。
步驟 2 — 音訊轉錄(Whisper)
一次性安裝(關於中國大陸的 HF 鏡像修正,請參閱 references/whisper-setup.md):
uv venv /tmp/wvenv
/tmp/wvenv/bin/python -m pip install faster-whisper
提取 16 kHz 單聲道 WAV,可選擇正規化:
ffmpeg -y -i AUDIO -af "loudnorm=I=-16:TP=-1.5:LRA=11,highpass=f=80" -ar 16000 -ac 1 -c:a pcm_s16le /tmp/song.wav
轉錄(腳本位於 scripts/transcribe.py):
HF_HUB_DISABLE_XET=1 HF_ENDPOINT=https://hf-mirror.com \
/tmp/wvenv/bin/python scripts/transcribe.py /tmp/song.wav medium
- 模型
medium是甜蜜點;large-v3更準確但在 CPU 上慢。 medium在 CPU(int8)上轉錄一首約 2.5 分鐘的歌曲需要幾分鐘;載入模型時 RSS 低,然後在實際轉錄時跳到約 1.4 GB RSS — 不要在載入階段恐慌地殺死它,請檢查/proc/<pid>/status的 VmRSS。- 請勿對歌唱音樂使用 VAD 過濾。
vad_filter=True會捨棄安靜/帶迴音的人聲線條,可能將一首 3 分鐘的歌曲減少為少數段落。請轉錄整個音軌。 - 適用於「歌唱」的參數(無 VAD):
beam_size=5、condition_on_previous_text=True、溫度回退[0.0,0.2,0.4,0.6,0.8,1.0]、no_speech_threshold=0.8、log_prob_threshold=-1.5、compression_ratio_threshold=2.8、word_timestamps=True、hallucination_silence_threshold=1.5。(預設值會捨棄整個短語,並在樂器間隔中產出沉默幻覺。)
步驟 3 — 內嵌文字 OCR(高價值路徑)
完整操作手冊:references/hardsub-ocr.md。摘要:
- 安裝 tesseract 不使用 sudo,方法是將
.deb解壓縮到某個前綴目錄(詳情見參考文件)。文件中記錄了liblept.so.5和libarchive.so.13的符號連結修正。 - 尋找文字區域:用
vision_analyze讀取一幀,要求提供字幕區域的像素座標。在音樂錄影帶中,字幕通常位於左下角 — 請勿猜測。 - 密集提取幀:
ffmpeg -i SRC -vf fps=2 /tmp/frames/f_%04d.png(2 fps → 約 0.5 秒解析度;第 N 幀時間為 t = N/2 秒)。 - 裁切區域、放大 2–3 倍、轉灰階、對每一幀進行 OCR(
--psm 6或--psm 7)。 - 去除重複:連續幀重複同一行 = 一行歌詞;第一次清晰讀取即為其開始時間。
- 低對比度文字:使用
vision_analyze作為備援。 Tesseract 在淺色襯線字體搭配明亮/照片背景時會失敗。視覺模型可以可靠讀取 — 對 Tesseract 輸出亂碼的幀使用它。這種混合方式(Tesseract 大量處理 + 視覺模型填補)是生產模式。
輸出
當使用者要求歌詞和時間戳時產出 .lrc([mm:ss.xx]line),否則產出純文字 MM:SS 文字。儲存到使用者指定的路徑(通常是在 WSL 上的 Windows 桌面,例如 /mnt/c/Users/<user>/Desktop/)。
交接: 您在此產出的 .lrc 正是 guitar-tabs 技能進行 LRC 同步和絃譜/每行和絃對齊所需的輸入。當歌詞然後和絃譜的請求作為一個任務提出時,請保留 .lrc 並直接餵給 guitar-tabs(其 scripts/chord_analyze.py 接受 <音訊> <歌詞.lrc>,並為每一行歌詞印出一個和絃)。這兩個技能串聯:video-text-extraction → 時間同步歌詞 → guitar-tabs → 彈唱譜。
陷阱
.m4s通常只有視訊。 不要假設它有音訊。用持續時間匹配同伴音訊檔。- 不要相信 Whisper 對歌唱人聲的拼寫。 有畫面文字時請與之核對。
- VAD 會殺死安靜的人聲 — 見步驟 2。
- Tesseract 需要精確的裁切。 垂直方向偏移約 100 像素的文字區域就會產出雜訊。先用視覺分析取得座標。
- Tesseract 的共享庫相依性是一個一個出現的。 每次執行都會因不同的
error while loading shared libraries: X而失敗 — 先是liblept.so.5,然後libarchive.so.13,接著libgif.so.7,依此類推。不要放棄也不要逐個安裝:一次下載完整列表(見參考文件),解壓縮,然後用ldd … | grep "not found"一次查看所有仍然缺失的項目。兩個額外加分題:libarchive13在較新的 Ubuntu 上沒有候選套件(改使用libarchive13t64),而liblept5是攜帶真正liblept.so.5.0.4的套件 —-dev套件只提供懸空的符號連結。 - 短小/混亂的 OCR 讀取通常是裁切問題,而不是 OCR 問題。 在調整
--psm或閾值之前,先用vision_analyze分析裁切後的區域本身。如果視覺分析也看不到文字,那就是裁切錯了。這一步檢查可以省去很多無謂的濾波器調整。 - 帶有
export/ 管線的終端命令可能需要核准。 將 tesseract 的環境變數打包成.sh腳本,執行bash script.sh而不是內聯的export ...; tesseract ...。 - HuggingFace 在中國大陸很慢/被屏蔽。 務必設定
HF_ENDPOINT=https://hf-mirror.com和HF_HUB_DISABLE_XET=1(xet 後端對鏡像回傳 401)。 - 檢查模型下載是否確實進行中。 一個
faster-whisper執行若 RSS 約 5 MB 且 CPU 無活動,表示卡在抓取模型;真正執行時 RSS 會升到約 1.4 GB。檢查/proc/<pid>/status(VmRSS)而非殺死它或盲目等待。