FFMPEG で DVD からの VOB ファイルの連結 (マージ) を自動化する際の問題

FFMPEG で DVD からの VOB ファイルの連結 (マージ) を自動化する際の問題

私には、暗号化解除された DVD のライブラリがあります。そのすべてのビデオは、通常の VIDEO_TS フォルダ内の一連の VOB ファイルに格納されています。FFMPEG を使用して、それらを 1 つの 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

そこで、処理したい VOB ファイルの数を収集するバッチ ファイル (Windows 10) を作成しました。次に、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

多くの実験と調査を行った結果、変数に 2 番目の BAT ファイル スクリプトを作成し、それを一時 BAT ファイルとして保存する BAT ファイル スクリプトを作成することが最善の方法であることがわかりました。作成された BAT ファイルは、必要な DVD タイトルセットとタイトルセット内の検出されたファイル数に基づいて、カスタム作成された "concat: " パラメーターを使用して作成できます。唯一の難点は、パイプ (|) 文字を含む変数に文字列を作成することがほぼ不可能であることです。ビルド中に '@' 文字を置き換えてこの問題を解決し、後でオープン ソースのファイル検索および置換ユーティリティを使用して '@' インスタンスを "|" に変更しました。問題なく動作します。注: Windows 10 と、2020 年 6 月にダウンロードおよびインストールされた FFMPEG バージョン git-2020-06-26-7447045 を使用しています。以下は私が作成したコメント付きのバッチ ファイルです。同様のことをしたい場合は、ここから始めることができます。改善の余地があることはわかっていますが、うまく機能しています (常に良いスタートです)。

::
:: 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

関連情報