Reputation: 61
I'm trying to automate the subtitle addition to a folder with some videos so I wrote the following script:
forfiles /p "C:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess" /m *.mp4 /C "cmd /c set filename=@fname & ffmpeg -i @file -vf subtitles="C:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess\@fname.srt" -f mp4 "C:\Users\titos\Resilio_Sync\4K_Video_Downloader\donesubs\@fname_srt.mp4""
However, the script is throwing me the following error for each video:
[AVFormatContext @ 0000020c20220680] Unable to choose an output format for 'Der'; use a standard extension for the filename or specify the format manually.
[out#0 @ 0000020c20220580] Error initializing the muxer for Der: Invalid argument
Error opening output file Der.
Error opening output files: Invalid argument
In this case, "Der" is the second word of the video's title (And it does the same with each video where it throws the error with the second word). So I think it might be due to the videos containing spaces and ffmpeg not parsing it correctly? But why is the second word that it gets and not the first one in that case? And more importantly, what could I do to fix this issue?
I've honestly found some other threads that discuss similar issues, but quite frankly I'm still too newbie to understand any of the answers in order to adapt it to my script lol. I appreciate your help, thanks a lot in advance :)
Upvotes: 0
Views: 179
Reputation: 38708
The help information for the forfiles
utility, explains how to replace your nested doublequotes, "
with their hex equivalent, 0x22
.
Using that information, please change:
subtitles="C:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess\@fname.srt" -f mp4 "C:\Users\titos\Resilio_Sync\4K_Video_Downloader\donesubs\@fname_srt.mp4"
To
subtitles=0x22C:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess\@fname.srt0x22 -f mp4 0x22C:\Users\titos\Resilio_Sync\4K_Video_Downloader\donesubs\@fname_srt.mp40x22
You can replace any character which is causing you issues nested between the outer doublequotes with their hex equivalents. For instance &
->0x26
, =
->0x3D
.
With nested doublequotes, you also have the option of escaping them, rather than converting them to hex. You can do that with a backward slash, \
.
This would, in your case, mean using:
subtitles=\"C:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess\@fname.srt\" -f mp4 \"C:\Users\titos\Resilio_Sync\4K_Video_Downloader\donesubs\@fname_srt.mp4\"
However, there is yet another potential issue here; the forfiles
variables, @File
, @FName
, @Ext
, @Path
, and @RelPath
are each returned doublequoted. Those doublequotes are likely to confuse ffmpeg.exe
.
It would see:
subtitles="C:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess\"FileBaseName".srt" -f mp4 "C:\Users\titos\Resilio_Sync\4K_Video_Downloader\donesubs\"FileBaseName"_srt.mp4"
To solve that, you would need to somehow expand those variables to remove their surrounding doublequotes. That could be done by using a for
loop:
Hex converted doublequotes example:
@Echo Off
SetLocal EnableExtensions
%SystemRoot%\System32\forfiles.exe /P "%UserProfile%\Resilio_Sync\4K_Video_Downloader\videoprocess" /M *.mp4 /C "%SystemRoot%\System32\cmd.exe /Q /D /C 0x22If @IsDir==FALSE For /F 0x22Delims=0x22 %%G In (@FName) Do 0x22P:\athTo\ffmpeg.exe0x22 -i @File -vf subtitles=0x22%UserProfile%\Resilio_Sync\4K_Video_Downloader\videoprocess\%%~G.srt0x22 -f mp4 0x22%UserProfile%\Resilio_Sync\4K_Video_Downloader\donesubs\%%~G_srt.mp40x220x22"
Escaped doublequotes example:
@Echo Off
SetLocal EnableExtensions
%SystemRoot%\System32\forfiles.exe /P "%UserProfile%\Resilio_Sync\4K_Video_Downloader\videoprocess" /M *.mp4 /C "%SystemRoot%\System32\cmd.exe /Q /D /C \"If @IsDir==FALSE For /F \"Delims=\" %%G In (@FName) Do \"P:\athTo\ffmpeg.exe\" -i @File -vf subtitles=\"%UserProfile%\Resilio_Sync\4K_Video_Downloader\videoprocess\%%~G.srt\" -f mp4 \"%UserProfile%\Resilio_Sync\4K_Video_Downloader\donesubs\%%~G_srt.mp4\"\""
The above, would ordinarily be the appropriate, and correct syntax for your shown task, but, there is another issue here, that you're likely to encounter. The value for cmd.exe
's /C
option cannot be more than 253
characters long, and I'd assume the above would exceed that and return an ERROR
message.
To overcome that, you may be best advised to change directory first, then use relative paths, rather than the repetition of C:\Users\titos\Resilio_Sync\4K_Video_Downloader\
, to see if it reduces that character number to something workable.
Hex converted doublequotes example:
@Echo Off
SetLocal EnableExtensions
CD /D "%UserProfile%\Resilio_Sync\4K_Video_Downloader" 2>NUL || Exit /B
%SystemRoot%\System32\forfiles.exe /P "videoprocess" /M *.mp4 /C "%SystemRoot%\System32\cmd.exe /Q /D /C 0x22If @IsDir==FALSE For /F 0x22Delims=0x22 %%G In (@FName) Do 0x22P:\athTo\ffmpeg.exe0x22 -i @File -vf subtitles=0x22videoprocess\%%~G.srt0x22 -f mp4 0x22donesubs\%%~G_srt.mp40x220x22"
Escaped doublequotes example:
@Echo Off
SetLocal EnableExtensions
CD /D "%UserProfile%\Resilio_Sync\4K_Video_Downloader" 2>NUL || Exit /B
%SystemRoot%\System32\forfiles.exe /P "videoprocess" /M *.mp4 /C "%SystemRoot%\System32\cmd.exe /Q /D /C \"If @IsDir==FALSE For /F \"Delims=\" %%G In (@FName) Do \"P:\athTo\ffmpeg.exe\" -i @File -vf subtitles=\"videoprocess\%%~G.srt\" -f mp4 \"donesubs\%%~G_srt.mp4\"\""
Only if the above fails to reduce the character count sufficiently, should you consider removing the full paths to your forfiles.exe
, cmd.exe
, and ffmpeg.exe
files, (after confirming that each do have their parent locations listed in the value of %Path%
):
Hex converted doublequotes example:
@Echo Off
SetLocal EnableExtensions
CD /D "%UserProfile%\Resilio_Sync\4K_Video_Downloader" 2>NUL || Exit /B
forfiles.exe /P "videoprocess" /M *.mp4 /C "cmd.exe /Q /D /C 0x22If @IsDir==FALSE For /F 0x22Delims=0x22 %%G In (@FName) Do ffmpeg.exe -i @File -vf subtitles=0x22videoprocess\%%~G.srt0x22 -f mp4 0x22donesubs\%%~G_srt.mp40x220x22"
Escaped doublequotes example:
@Echo Off
SetLocal EnableExtensions
CD /D "%UserProfile%\Resilio_Sync\4K_Video_Downloader" 2>NUL || Exit /B
forfiles.exe /P "videoprocess" /M *.mp4 /C "cmd.exe /Q /D /C \"If @IsDir==FALSE For /F \"Delims=\" %%G In (@FName) Do ffmpeg.exe -i @File -vf subtitles=\"videoprocess\%%~G.srt\" -f mp4 \"donesubs\%%~G_srt.mp4\"\""
As you can see, working with forfiles.exe
can throw many obstacles in front of you, notwithstanding that every matching .mp4
file it encounters runs in a new cmd.exe
instance, which is very inefficient for anything other than a small number of matches.
In my opinion this type of task is better suited to a standard For
/For /F
loop, (forfiles.exe
is better suited to those rare times that its @RelPath
variable is needed). You already have an answer which uses one of those, so I will not post my version here.
Upvotes: 2
Reputation: 80193
I set up a directory with some dummy files matching the problem name format and simply echo
ed the resultant ffmpeg
line. The result was of the form
set filename="1 der 1" _and_ ffmpeg -i "1 der 1.mp4" -vf
subtitles=subtitledir\"1 der 1".srt -f mp4 donesubsdir\"1 der 1"_srt.mp4
(OK - I've broken the line for ease of viewing and substituted subtitledir
and donesubsdir
for the directorynames.)
Observing that the quoted filename appears within a string and theorising that ffmpeg
may have difficulty with that structure, I suggest
SET "vpath=U:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess"
FOR /f "delims=" %%e IN ('dir /b /a-d "%vpath%\*.mp4" 2^>nul') DO ECHO ffmpeg -i "%vpath%\%%~ne" -vf subtitles="subtitledir\%%~ne.srt" -f mp4 "donesubsdir\%%~ne_srt.mp4"
Where you need to follow the bouncing ball for subtitledir
and donesubsdir
.
My results were:
ffmpeg -i "U:\Users\titos\Resilio_Sync\4K_Video_Downloader\videoprocess\1 der 1" -vf
subtitles="subtitledir\1 der 1.srt" -f mp4 "donesubsdir\1 der 1_srt.mp4"
(OK - I've broken the line for ease of viewing and substituted subtitledir
and donesubsdir
for the directorynames.)
Theory:
The command dir /b /a-d "%vpath%\*.mp4" 2^>nul
is executed and produces lines of the filename only (/b
) with no directorynames (/a-d
) which are applied to %%e
."delims=" tells for
that no tokenising is required, so the entire name appears in %%e
, The 2^>nul
suppresses error messages - the ^
tells cmd
that the >
is part of the dir
command, not the for
.
(there are hundreds, if not thousands, of similar applications posted on SO)
See for /?
or thousands of examples on SO for the use of metavariable-modifiers.
Then %%~ne
is the name-part only of the filename in %%e
.
Upvotes: 1