使用 FFMPEG 自动连接(合并)DVD 中的 VOB 文件时出现问题

使用 FFMPEG 自动连接(合并)DVD 中的 VOB 文件时出现问题

我有一个解密 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 copy 输出.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 文件。然后可以使用自定义构造的“concat:”参数构建构造的 BAT 文件,该参数基于所需的 DVD 标题集和标题集中发现的文件数量。唯一美中不足的是,几乎不可能在包含管道 (|) 字符的变量中构建字符串。我通过在构建过程中替换“@”字符解决了这个问题,后来使用开源文件搜索和替换实用程序将“@”实例更改为“|”。它工作正常。注意我使用的是 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

相关内容