2024年5月3日 星期五

DVD 轉開放的影片格式 mkv, 含字幕

用 vlc 播放含有三個字幕軌的 mkv 檔 難得有機會向老婆炫耀 linux 的厲害: 她想要把 DVD 備份成 mp4, 結果以前買的軟體已下架, 而 windows 又拒絕用檔案總管去開啟 DVD。 在 linux 底下, 看到的不過就是一個檔案系統, 備份、 播放當然都沒問題, 其實也並不需要轉檔啊。 那順便來研究一下 VIDEO_TS/ 底下的 VTS_*.VOB 好了, 特別是老婆交代的「字幕」部分。 我看到的大部分 DVD 都只有一個字幕軌, 只有一部 「史瑞克」 有多種語言。 那就拿其中一個較短, 又含字幕的影片檔 VTS_03_1.VOB 來實驗好了:

VOB_FILE=VTS_03_1.VOB
BASE_NAME=${VOB_FILE%.VOB}
echo $BASE_NAME

參考 這個 gist 的指令及範例輸出, 查看 VOB 檔案的基本資訊及所有軌的資訊: ffprobe -v quiet -print_format json -show_format -show_streams $VOB_FILE > ${BASE_NAME}.json 再用 zq 把各軌資訊摘要成 csv 格式: zq -f csv 'over streams | {index,codec_name,codec_tag_string}' ${BASE_NAME}.json , 我看到的輸出是:

index,codec_name,codec_tag_string
0,dvd_nav_packet,[0][0][0][0]
1,mpeg2video,[0][0][0][0]
2,ac3,[0][0][0][0]
3,dvd_subtitle,[0][0][0][0]
4,dvd_subtitle,[0][0][0][0]
5,dvd_subtitle,[0][0][0][0]

所以 track 1 是影像軌, 2 是聲音 (只有一種語言的配音), 3、4、5 是三種語言的字幕, 可是沒記載各別是哪種語言。

ffmpeg -fflags genpts -i $VOB_FILE -map 0:1 -map 0:2 -codec:v copy -codec:a copy ${BASE_NAME}.mkv
mencoder $VOB_FILE -nosound -ovc frameno -o /dev/null -vobsuboutindex 0 -sid 0 -vobsubout ${BASE_NAME}_zh_TW
mencoder $VOB_FILE -nosound -ovc frameno -o /dev/null -vobsuboutindex 0 -sid 1 -vobsubout ${BASE_NAME}_th
mencoder $VOB_FILE -nosound -ovc frameno -o /dev/null -vobsuboutindex 0 -sid 2 -vobsubout ${BASE_NAME}_zh_HK

接下來用 ffmpeg 指令把原始影片的影像軌 (0:1, 第 0 個輸入檔的第一軌) 跟聲音軌 (0:2) 抓出來變成 .mkv 檔, 又用 mencoder 把三個字幕軌抓出來, 分別命名為 VTS_03_1_zh_TW.*、 VTS_03_1_th.*、 VTS_03_1_zh_HK.*, 其中每種語言會產生 *.idx 跟 *.sub 兩個檔案。 選項 -sid 0 指的是第 0 個字幕軌, 也就是 ffprobe 查看原始影片所回報的第 3 軌。 語言名稱是事後看成果才知道該怎麼命名的; -sid 1 大概是泰文吧.. google 判斷的。

現在可以用 mplayer -vobsub ${BASE_NAME}_zh_TW ${BASE_NAME}.mkv 播放影片, 搭配台灣正體中文字幕。 用 -vobsub 指定字幕時, 不必寫副檔名, mplayer 會自動去找 .idx 跟 .sub 。 字幕顏色不清楚。 沒關係, 我們馬上把 「影音」 跟 「字幕」 合併起來: mkvmerge -o ${BASE_NAME}_ALL.mkv ${BASE_NAME}.mkv *.idx *.sub 再查看一下新產生的 ${BASE_NAME}_ALL.mkv 的資訊: ffprobe -v quiet -print_format json -show_format -show_streams ${BASE_NAME}_ALL.mkv > ${BASE_NAME}_mkv.json 以及 zq -f csv 'over streams | {index,codec_name,codec_tag_string}' ${BASE_NAME}_mkv.json 果然內含 0-4 影、音及三個字幕軌共五軌。 但是! 字幕軌的順序可能跟原來的不同, 可以用 vlc 播放並選不同的字幕軌來確認一下; 而且字幕顏色變正常囉!

既然已變成開放的 matroska (mkv) 影片格式, 當然也就可以用 ffmpeg 進一步做格式轉換等等其他處理。 但是! 來自 DVD 的字幕軌是圖片而不是文字, 所以沒有任何指令可以把它抓出來變成 .srt 字幕檔。 如果想轉成 .mp4 格式, 就必須選定一個 (圖片) 字幕軌, 把它 "壓" 進影像軌裡面: ffmpeg -i ${BASE_NAME}_ALL.mkv -filter_complex "[0:v:0][0:s:2]overlay[vid]" -map [vid] -map 0:1 -codec:v libx264 -codec:a copy ${BASE_NAME}_zh_TW.mp4 (這裡的 0:s:2 選第二個字幕軌, 是根據剛剛在 vlc 裡面觀察的結果。) 產生的 ${BASE_NAME}_zh_TW.mp4 就只有影、音共兩軌, 而字幕是 "黏" 在影像軌裡面的。 這一題, linux 上的自由軟體的彈性再度大勝 windows 世界的專屬軟體!

(本篇的精華部分主要是從 這個問答 學來的。)

沒有留言:

張貼留言

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。