2
@echo off
set source="%1"

for %%a in (*.wav, *.aac, *.mp3,) do (
    ffmpeg -i "%1" -i "%%a" -c:v copy -map 0:v:0 -map 1:a:0 -shortest "%1_123.mov"
  )

I get DJI_0002.MOV_123.mov, but I need to get DJI_0002_123.mov.

Compo
  • 36,585
  • 5
  • 27
  • 39
becauseim
  • 21
  • 1

2 Answers2

1
@echo off
set source="%1"

for %%a in (*.wav, *.aac, *.mp3,) do (
    ffmpeg -i "%1" -i "%%a" -c:v copy -map 0:v:0 -map 1:a:0 -shortest "%~n1_123.mov"
  )

The ~n expands the substitution to equal only the filename, minus the extension. https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490909(v=technet.10)

LTPCGO
  • 448
  • 1
  • 4
  • 15
1

How to reference an argument of a batch file correct?

The environment variable source is not used at all in your batch file. It is additionally defined wrong. Better would be set "source=%~1". Open a command prompt, run call /? and read the output help from top of first page to bottom of last page.

In the command prompt window execute following two commands:

echo @set source="%1">Test.bat
echo @set source>>Test.bat

Those two command lines create a batch file Test.bat with the two lines:

@set source="%1"
@set source

Run next in command prompt window:

Test.bat "Test argument 1.txt"

Output is:

source=""Test argument 1.txt""

It can be seen what happened. The file name Test argument 1.txt passed with the required double quotes because of the spaces in file name to the batch file is assigned to the environment variable source with two additional double quotes.

Next run in command prompt window the command line:

Test.bat "Define & See argument 1.txt"

Now the Windows command processor outputs an error message on execution of the batch file because of & is not enclosed in a double quoted argument string in first line after parsing it. The first command line executed after parsing it is now:

@set source=""Define & See argument 1.txt""

The help output on running in command prompt window cmd /? explains on last page that a file name containing a space or one of these characters &()[]{}^=;!'+,`~ must be enclosed in double quotes as it is done on calling the batch file with the unusual file name Define & See argument 1.txt. But on execution of first line the ampersand is not anymore inside a double quoted argument string of command SET and for that reason interpreted as AND operator as explained in answer on single line with multiple commands using Windows batch file.

Next run the following three command lines in command prompt window:

echo @if "%~1" == "" echo %~nx0 must be called with a file name!^& pause ^& exit /B>Test.bat
echo @set "source=%~1">>Test.bat
echo @set source>>Test.bat

They recreate Test.bat with following content:

@if "%~1" == "" echo %~nx0 must be called with a file name!& pause & exit /B
@set "source=%~1"
@set source

This batch file first checks if it was called with at least one argument string and outputs a message and waits until the user presses any key to make sure the user has a chance to read it before leaving batch file processing with a jump to predefined end of file label. Test the first line by executing in command prompt window:

Test.bat

Now use multiple times the key UP ARROW to get back from command lines buffer the command line and execute this line with pressing key RETURN:

Test.bat "Define & See argument 1.txt"

This time no error message is output, just the line:

source=Define & See argument 1.txt

So it can be seen that this code is much better, isn't it. See also:
Why is no string output with 'echo %var%' after using 'set var = text' on command line?

Last run in command prompt window:

del Test.bat

Now it should be clear how to reference arguments of a batch file.


How to reference file name assigned to a loop variable with a modifier?

Run in command prompt window for /? to get output the help of Windows command FOR and read this help from top of first page to bottom of last page.

There is explained how to reference the loop variable with a modifier like %~nI to get for example just the file name of a file without path and without file extension. %~n references the substring of the string assigned currently to the loop variable between

  • last backslash of string assigned to the loop variable or beginning of string assigned to the loop on not containing a backslash at all to
  • last dot of string assigned to the loop variable or end of string assigned to loop variable on not containing a dot at all after last backlash/beginning of string.

So let us first create a batch file with following four lines:

@echo off
pushd "%~dp0"
for %%I in (*.wav *.aac *.mp3) do echo %%I
popd

This batch file is executed from within a command prompt window by typing its path and file name using key TAB as it was explained by help output on running cmd /?.

The second command line pushes current directory on stack and makes the directory of the batch file the current directory. Run in command prompt window pushd /? for help on this command. The third command line searches for non-hidden *.wav and *.aac and *.mp3 files in this directory and assigns the file name without path to loop variable I. For each iteration of the loop the string assigned to the loop variable I is just output without using any modifier. The fourth lines pops the previously pushed directory path from stack and sets this directory as current directory to restore initial current directory. Run in command prompt window popd /? for help on this command.

Next modify the third line in batch file to get finally:

@echo off
pushd "%~dp0"
for %%I in (*.wav *.aac *.mp3) do echo File name of %%I is %%~nI
popd

Run the batch file once again from the command prompt window by just pressing once key UP ARROW and next the key RETURN.

It can be seen how %%~nI modifies the string output unmodified with %%I.


What is the final batch file?

It is not written in question which file name is passed by argument to the batch file. It looks like one video file should be produced and the file name passed to the batch file is the name of the file containing the video data which should be merged with the audio file found in current directory which can be a *.wav or *.aac or *.mp3 file.

So finally modify the batch file once more to the command lines needed for this task:

@echo off
if "%~1" == "" echo %~nx0 must be called with a file name!& pause & exit /B
pushd "%~dp0"
for %%I in (*.wav *.aac *.mp3) do ffmpeg.exe -i "%~1" -i "%%I" -c:v copy -map 0:v:0 -map 1:a:0 -shortest "%~dpn1_123.mov" & goto MovieCreated
:MovieCreated
popd

It is of course also possible with multiple audio files in directory of the batch file to produce multiple video files with video and audio data in directory of the batch file with name of each audio file used for the created movie file.

@echo off
if "%~1" == "" echo %~nx0 must be called with a file name!& pause & exit /B
pushd "%~dp0"
for %%I in (*.wav *.aac *.mp3) do ffmpeg.exe -i "%~1" -i "%%I" -c:v copy -map 0:v:0 -map 1:a:0 -shortest "%%~nI_123.mov"
popd

It would be best to specify ffmpeg.exe with full qualified file name, i.e. drive + path + file name + file extension, enclosed in double quotes. Then cmd.exe would not need to search on each iteration of the loop for ffmpeg.exe in current directory and next in all directories of environment variable PATH.

Mofi
  • 46,139
  • 17
  • 80
  • 143