
我有一個解密 DVD 庫,所有這些 DVD 的影片都位於通常的 VIDEO_TS 資料夾中的一系列 VOB 檔案中。我想知道是否可以使用 FFMPEG 將它們組合成一個 MPEG 檔案。所以首先我從一個舊的非堆疊交換帖子中找到了這個(示例假設有 2 個 VOB 檔案),並且它有效...
ffmpeg -i "concat:VTS_01_1.VOB|VTS_01_2.VOB" -f DVD -c copy output.mpg
ffmpeg 有時會抱怨可能丟失時間戳,但我沒有在視訊、音訊或同步中看到任何問題。對於略有不同的投訴,這也適用
ffmpeg -i "concat:VTS_01_1.VOB|VTS_01_2.VOB" -f mpeg -c copy output.mpeg
所以我編寫了一個批次檔(Windows 10)來收集我想要處理的 VOB 檔案的數量。我當時希望做的是創建“concat”字串供 FFMPEG 處理。但我手工製作只是為了嘗試這樣......
set concat="concat: VTS_01_1.VOB|VTS_01_2.VOB|VTS_01_3.VOB|VTS_01_4.VOB|VTS_01_5.VOB"
然後我嘗試在批次文件中將該字串傳遞給 FFMPEG
ffmpeg -i %concat% -f DVD -c 複製輸出.mpg
好吧,這根本不起作用。我猜 FFMPEG 無法識別字串變數作為替代。所以我查找了有關“concat”主題的 ffmpeg 文檔,他們建議使用儲存在文字文件中的文件列表,如下所示...
file 'VTS_01_1.VOB'
file 'VTS_01_2.VOB' (etc...)
然後,將檔案儲存為“mylist.txt”,並像這樣呼叫 FFMPEG...
ffmpeg -f concat -safe 0 -i mylist.txt -c 複製輸出.mpg
嗯,我嘗試過,但效果不太好。在第一個 VOB 檔案之後,我不斷收到有關緩衝區下溢和時間戳記的警告,並且通常快速的串聯過程變得緩慢。警告通常看起來像這樣...
[mpeg @ 00000185e32b4200] buffer underflow st=1 bufi=1466 size=1998
[mpeg @ 00000185e32b4200] Non-monotonous DTS in output stream 0:1; previous: 328415794, current: 9265348; changing to 328415795. This may result in incorrect timestamps in the output file.
那麼,任何人都可以建議一種與我的第一個範例一樣有效的方法,但是從輸入文字檔案中獲取文件清單嗎?
答案1
經過大量的實驗和研究,我發現最好的方法是製作一個 BAT 檔案腳本,在變數中建立第二個 BAT 檔案腳本並將其儲存為臨時 BAt 檔案。然後,可以根據所需的 DVD 標題集以及標題集中發現的檔案數量,使用自訂構造的「concat:」參數來建立建構的 BAT 檔案。唯一美中不足的是,幾乎不可能在包含管道 (|) 字元的變數中建構字串。我透過在建置過程中取代「@」字元解決了這個問題,後來使用開源檔案搜尋和取代實用程式將「@」實例變更為「|」。效果很好。注意我使用的是 Windows 10,FFMPEG 版本為 git-2020-06-26-7447045,於 2020 年 6 月下載並安裝。下面是我創建的帶有註釋的批次文件,因此如果有人想做類似的事情,他們可以從這裡開始。我知道它可以改進,但它有效(總是一個好的開始)!
::
:: Batch file to automate conversion of a series of VOB files in a DVD
:: titleset into a single MPG file, via FFMPEG.
:: Pass a name you'd like for the final output movie file in param 1
:: This script needs a a file search and replace utility, and I'm useing
:: SKF (Swiss Army Knife), which is open source and free ...
:: https://sourceforge.net/projects/swissfileknife/
:: Whatever search/replace util you use, you'll have to put it in a
:: 'utilities' folder somewhere in your C: drive, and make sure
:: your system (or USER) PATH variable includes it.
:: Also, unless you have unencrytpted DVD copies to work with, OR a
:: Decryptor that automatically works in the background (like DVD43),
:: you'll have to start with a program like "1-Click DVD Copy (Pro)".
:: In that case you can put the Resulting VIDEO_TS folder in a temp
:: area on your HD. This will make this batch process run faster,
:: and eliminate the needs to waste a blank DVD.
echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: Set a path where converted ouptput videos will go
:: Temporary files created by this script will also go here.
set outPath="C:\Users\Public\Videos\Temp"
:: set a path to your DVD. Playable DVDs always have aVIDEO_TS folder
set inPathDVD="Q:\VIDEO_TS"
:: In the event you are making unencrypted copies (maybe with 1-Click),
:: set that software to put its output files here. In that case,
:: the parameter you pass this script should match the folder name
:: created by that software!
set inPathHD="C:\Users\Public\Videos\Temp\%1\Video_TS"
:: some variables to construct expecteed files to seach for and gather
set inpTitleSet=VTS_
set inpExt=.VOB
set output=%outPath%\%1.mpg
set outTemp=%outPath%\%1%inpExt%
:: choose whether files come directly from DVD (must be unencrypted!)
:: or defined location on HD
choice /M "Choose Source 1 = DVD 2 = HD Temp Area" /C 12
if ERRORLEVEL 1 set inPath=%inPathDVD%
if ERRORLEVEL 2 set inPath=%inPathHD%
echo input path is: %inPath%
cd /D %inPath%
echo .
echo VOB files from %inpath%...
echo .
:: create filespec for search "VTS_01_*.vob"
set inputFileSpec=%inpTitleSet%*%inpExt%
dir %inputFileSpec%
echo .
:: select desired titleset. Usually the group with the
:: biggest file sizes is the main movie titleset.
:: You'll be entering the digit after "VTS_0"
choice /M "Select Desired Titleset (digit after VTS_): " /C 12345678
echo you picked %ERRORLEVEL%
set inpTitleSet=%inpTitleSet%0%ERRORLEVEL%_
set inputFileSpec=%inpTitleSet%*%inpExt%
:: use a brute force loop to calculate number of
:: files matching %inputFileSpec% and display them.
:: Note that the '0' file is usually title/menu information,
:: and is skipped by making the %start% var '1'
echo files selected...
echo .
set start=1
:loop0
set tmp=%inpTitleSet%%start%%inpExt%
IF EXIST %tmp% (
echo %tmp%
set /A start=start+1
GOTO loop0
)
set /A count=%start%-1
echo .
:: confirm total files
echo Total Files = %count%
:: safety exit, in odd event where no movie files found
if %count% NEQ 0 GOTO continue1
echo .
echo Must Exit... no Files Found.
goto exit
:continue1
:: Build string containing of file names for FFMPEG "concat:" parameter.
:: Another Brute force loop. Again file *0.VOB will be skipped,
:: by making loop start=1::
:: set an 'empty' variable
set cc=
set start=1
:: create a temp substitute for the pipe "|" character,
:: because | can't be cant be used in a script (^| or similar
:: constructs just won't work here). So I'll use '@' and change it
:: later with a file search/replace utility.
set mypipe=@
:loop1
set tmp=%inpTitleSet%%start%%inpExt%
if %start% EQU %count% set mypipe=
IF EXIST %tmp% (
set cc=%cc%%inp%%tmp%%mypipe%
set /A start=start+1
GOTO loop1
)
:: create whole FFMPEG command as a string
set ffm=ffmpeg -i "concat:%cc%" -f DVD -c copy %output%
:: put it in a tmp batch file
set cmdfile=tmp.bat
echo %ffm% > %outPath%\%cmdfile%
:: now use SKF to replace the @ chars with |
:: if you have another search/replace utility, feel free to use it.
sfk replace %outPath%\%cmdfile% "/@/|/" -yes -quiet
:: prove string in batch file looks right. You can delete
:: these two lines if you want.
echo Final command...
type %outPath%\%cmdfile%
:: run the new batch file... Give user chance to start process
@pause
call %outPath%\%cmdfile%
:: delete batch file?
del %outPath%\%cmdfile%
echo .
echo .
echo %output% converted file should be ready
ENDLOCAL
:exit