简体   繁体   中英

Trying to merge wav with video file using ffmpeg

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.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM