This batch file isn't working and I know the ffmpeg commands work when the command is on its own.
I am using a WAV file that's exactly the length of the video (it was extracted from the video I am trying to add it back to).
The NOAUDIO and NOVIDEO labels work properly if I delete the wav and/or video file from the folder where ffmpeg.exe and the batch file are.
When the batch file is run with a wav audio and mp4 video file there, it just flashes up a command window. I tried putting pause after every single command but, still no joy.
Is there a mistake here somewhere?
Cheers folks...
:: --------------------
::
:: 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
:: --------------------
I just tested this and it does work, using the exact same commands as in the above batch file just with all the labels removed...
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
So I know the reason it's not working is something to do with the order the batch file runs. It's odd because I have another batch file just like it for extracting the WAV in the first place and that does work, with labels set out just like the first batch file above. Perplexing.
If I reduce it to just this, it works...
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
The main problem is that the command line
For %%a IN ("*.wav") DO Set "FILEWAV=%%~na"
is not executed ever on any video file found because of command goto
on the four if
conditions above. So one of the ffmpeg.exe
command lines is executed with environment variable FILEWAV
most likely not defined at all, at least not by the batch file.
The batch file can be improved to:
@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
The command FOR supports searching for file names using multiple wildcards like also command DIR. Therefore it is not necessary to use nearly the same code for each type of video file format to support by the batch file. The modification results in processing all video files in current directory and not just the last one, except the video file name ends already case-insensitive with -NEW
.
The character a
is a modifier for the loop variable. It can be used nevertheless as loop variable, but it is better to use as loop variable a character which is never interpreted as modifier. The batch file above uses once I
and once #
as loop variable to demonstrate that.
start /wait
is not necessary at all. Windows command processor cmd.exe
waits by default for self-termination of any executable started from within a batch file as otherwise the execution of timeout.exe
would not work as expected. Therefore ffmpeg.exe
can be run without usage of command start
and its option /wait
.
The command exit
at end of a batch file is always useless. It makes it just more difficult to debug the batch file for the developer of the batch file and its existence at end of the batch file without any parameter is counter-productive for batch file users executing the batch file from within a command prompt window or for users which want to call the batch file from another batch file multiple times, for example in a loop.
It is good practice to specify a Windows Command with full qualified file name in a batch file to make the batch file independent on PATH
and PATHEXT
as much as possible. Then Windows command processor does not need to search for the executables and the batch file works even if a user has somehow corrupted the value of environment variable PATH
.
The executable timeout.exe
does not exist by default on Windows XP and older versions of Windows. Therefore an IF condition is used to use either timeout.exe
on Windows Vista and newer versions of Windows or pause
on older versions of Windows.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
cls /?
color /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
timeout /?
title /?
where /?
See also:
Read the Microsoft documentation about Using command redirection operators for an explanation of >nul
, 2>nul
and |
. The redirection operators >
and |
must be escaped with caret character ^
on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir
command line with using a separate command process started in background with %ComSpec% /c
and the command line within '
appended as additional arguments.