尝试使用 ffmpeg 将 wav 与视频文件合并

Trying to merge wav with video file using ffmpeg

这个批处理文件不工作,我知道当命令独立时 ffmpeg 命令工作。

我使用的是与视频长度完全相同的 WAV 文件(它是从我试图将其添加回的视频中提取的)。

如果我从 ffmpeg.exe 和批处理文件所在的文件夹中删除 wav and/or 视频文件,NOAUDIO 和 NOVIDEO 标签将正常工作。

当批处理文件 运行 有一个 wav 音频和 mp4 视频文件时,它只是闪现一个命令 window。我尝试在每个命令后暂停,但仍然不开心。

这里哪里有错误吗?

大家好...

:: --------------------
::
:: This will put any included WAV file with any included
:: video file, assuming the video file type exists:
::
:: - AVI
:: - MKV
:: - MP4
:: - WEBM
::
:: --------------------

@echo off
title Replace Video Audio with WAV
color 0f

:: --------------------

if not exist *.wav goto NOAUDIO
if not exist *.avi if not exist *.mkv if not exist *.mp4 if not exist *.webm goto NOVIDEO

:: --------------------

if exist *.avi goto AVIFILE
if exist *.mkv goto MKVFILE
if exist *.mp4 goto MP4FILE
if exist *.webm goto WEBMFILE

:: --------------------

For %%a IN ("*.wav") DO Set "FILEWAV=%%~na"

:: --------------------

:AVIFILE
For %%a IN ("*.avi") DO Set "FILEAVI=%%~na"
start /wait ffmpeg.exe -i "%FILEAVI%.avi" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEAVI%-NEW.mp4"
goto FINISHED

:MP4FILE
For %%a IN ("*.mp4") DO Set "FILEMP4=%%~na"
start /wait ffmpeg.exe -i "%FILEMP4%.mp4" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEMP4%-NEW.mp4"
goto FINISHED

:WEBMFILE
For %%a IN ("*.webm") DO Set "FILEWEBM=%%~na"
start /wait ffmpeg.exe -i "%FILEWEBM%.webm" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEWEBM%-NEW.mp4"
goto FINISHED

:MKVFILE
For %%a IN ("*.mkv") DO Set "FILEMKV=%%~na"
start /wait ffmpeg.exe -i "%FILEMKV%.mkv" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEMKV%-NEW.mp4"
goto FINISHED

:: --------------------

:NOAUDIO
cls
echo.
echo.
echo    There is no audio to put with the video!
echo.
echo    Exiting...
timeout 6 >nul
goto FINISHED

:: --------------------

:NOVIDEO
cls
echo.
echo.
echo    There is no video to put audio with!
echo.
echo    Exiting...
timeout 6 >nul
goto FINISHED

:: --------------------

:FINISHED
exit

:: --------------------

我刚刚对此进行了测试,它确实有效,使用与上述批处理文件中完全相同的命令,只是删除了所有标签...

For %%a IN ("*.wav") DO Set FILEWAV=%%~na

:MP4FILE
For %%a IN ("*.mp4") DO Set FILEMP4=%%~na
start /wait ffmpeg.exe -i "%FILEMP4%.mp4" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEMP4%-NEW.mp4"
goto FINISHED

:FINISHED
exit

所以我知道它不起作用的原因与批处理文件 运行s 的顺序有关。这很奇怪,因为我有另一个批处理文件,就像它一样用于首先提取 WAV,并且确实有效,标签设置就像上面的第一个批处理文件一样。令人费解。

如果我将它简化为这个,它就可以工作...

For %%a IN ("*.wav") DO Set FILEWAV=%%~na

For %%a IN ("*.avi") DO Set FILEAVI=%%~na
start /wait ffmpeg.exe -i "%FILEAVI%.avi" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEAVI%-NEW.mp4"

For %%a IN ("*.mp4") DO Set FILEMP4=%%~na
start /wait ffmpeg.exe -i "%FILEMP4%.mp4" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEMP4%-NEW.mp4"

For %%a IN ("*.webm") DO Set FILEWEBM=%%~na
start /wait ffmpeg.exe -i "%FILEWEBM%.webm" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEWEBM%-NEW.mp4"

For %%a IN ("*.mkv") DO Set FILEMKV=%%~na
start /wait ffmpeg.exe -i "%FILEMKV%.mkv" -i "%FILEWAV%.wav" -c:v copy -map 0:v:0 -map 1:a:0 "%FILEMKV%-NEW.mp4"

exit

主要问题是命令行

For %%a IN ("*.wav") DO Set "FILEWAV=%%~na"

不会在任何视频文件上执行,因为命令 goto 在上述四个 if 条件下。因此 ffmpeg.exe 命令行之一是使用环境变量 FILEWAV 执行的,很可能根本没有定义,至少批处理文件没有定义。

批处理文件可以改进为:

@echo off
:: --------------------
::
:: This will put any included WAV file with any included
:: video file, assuming the video file type exists:
::
:: - AVI
:: - MKV
:: - MP4
:: - WEBM
::
:: --------------------

setlocal EnableExtensions DisableDelayedExpansion
title Replace Video Audio with WAV
color 0f

if not exist %SystemRoot%\System32\where.exe goto CheckAudio
%SystemRoot%\System32\where.exe ffmpeg.exe >nul 2>nul
if not errorlevel 1 goto CheckAudio
echo/
echo/
echo    There is ffmpeg.exe not found in current directory or
echo    any directory defined in environment variable PATH!
echo/
if exist %SystemRoot%\System32\timeout.exe (echo    Exiting...& %SystemRoot%\System32\timeout.exe 6 >nul) else pause
goto FINISHED

if exist *.wav goto ProcessVideo
cls
echo/
echo/
echo    There is no audio to put with the video!
echo/
if exist %SystemRoot%\System32\timeout.exe (echo    Exiting...& %SystemRoot%\System32\timeout.exe 6 >nul) else pause
goto FINISHED

:ProcessVideo
rem Get file name of (last) WAV file in current directory.
for %%I in (*.wav) do set "AudioFile=%%I"

rem Process all AVI, MKV, MP4 and WBEM video files in current directory.
set "NoVideo=1"
for /F "eol=| delims=" %%# in ('dir *.avi *.mkv *.mp4 *.webm /A-D /B /ON 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /E /L /V /C:"-new.mp4"') do ffmpeg.exe -i "%%#" -i "%AudioFile%" -c:v copy -map 0:v:0 -map 1:a:0 "%%~n#-NEW.mp4" & set "NoVideo="
if not defined NoVideo goto FINISHED

cls
echo/
echo/
echo    There is no video to put audio with!
echo/
if exist %SystemRoot%\System32\timeout.exe (echo    Exiting...& %SystemRoot%\System32\timeout.exe 6 >nul) else pause

:FINISHED
color
endlocal

命令 FOR 支持使用多个通配符搜索文件名,就像命令 DIR 一样。因此,没有必要为批处理文件支持的每种视频文件格式使用几乎相同的代码。修改会导致处理当前目录中的所有视频文件,而不仅仅是最后一个,除了视频文件名已经 case-insensitive 以 -NEW 结尾。

字符a是循环变量的修饰符。尽管如此,它仍可用作循环变量,但最好将永远不会被解释为修饰符的字符用作循环变量。上面的批处理文件使用一次 I 和一次 # 作为循环变量来证明这一点。

start /wait 根本没有必要。 Windows 命令处理器 cmd.exe 默认等待从批处理文件中启动的任何可执行文件的 self-termination,否则 timeout.exe 的执行将无法按预期工作。因此 ffmpeg.exe 可以是 运行 而无需使用命令 start 及其选项 /wait.

批处理文件末尾的命令exit总是没用的。对于批处理文件的开发人员来说, 变得更加困难,并且它在没有任何参数的情况下存在于批处理文件的末尾,对于从命令提示符中执行批处理文件的批处理文件用户来说,counter-productive window 或者对于想要多次从另一个批处理文件调用批处理文件的用户,例如在循环中。

最好在批处理文件中指定具有完整限定文件名的 Windows Command,以使批处理文件尽可能独立于 PATHPATHEXT。然后 Windows 命令处理器不需要搜索可执行文件,即使用户以某种方式破坏了环境变量 PATH.

的值,批处理文件也能正常工作

Windows XP 和 Windows 的旧版本默认不存在可执行文件 timeout.exe。因此,IF 条件用于在 Windows Vista 和更新版本的 Windows 上使用 timeout.exe 或在旧版本的 pause 上使用Windows.

为了了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • cls /?
  • color /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?
  • timeout /?
  • title /?
  • where /?

另请参阅:

阅读有关 Using command redirection operators 的 Microsoft 文档,了解 >nul2>nul| 的解释。重定向运算符 >| 必须在 FOR 命令行上使用脱字符 ^ 进行转义,以便在 [=141= 时将其解释为文字字符] 命令解释器在执行命令 FOR 之前处理此命令行,该命令在后台以 %ComSpec% /c 和命令行启动的单独命令进程中执行嵌入式 dir 命令行在 ' 内附加为附加参数。