ffmpeg overwrites input files when called in a forfiles loop - windows

I need to join several mp4 and wav file pairs using ffmpeg.
When I run the command specifying the names of the files, it works well:
.\ffmpeg.exe -i file01.mp4 -i file01.wav -c:v copy -c:a aac -b:a 96k file01_new.mp4
But when I integrate this call in a forfiles loop, the source mp4 file is overwritten and the output mp4 file contains only the audio:
forfiles /M "*.mp4" /C ".\ffmpeg.exe -i #FNAME.mp4 -i #FNAME.wav -c:v copy -c:a aac -b:a 96k #FNAME_new.mp4"
I don't really understand what happens before the MP4 and WAV files are joined. Why is the source MP4 being overwritten?
How do I write this script to make it work? Thank you for your support.

Let me recommend to use for rather than forfiles, because the latter is quite slow and it expands its #-variables with surrounding quotes, which could be problematic:
rem // Create sub-directory for resulting files, so resulting files cannot become reprocessed:
2> nul md "result"
rem // Loop through `*.mp4` files:
for %%I in ("*.mp4") do (
rem /* Process current file, together with the related `*.wav` file,
rem and write the result into the new sub-directory: */
ffmpeg.exe -i "%%~I" -i "%%~nI.wav" -c:v copy -c:a aac -b:a 96k "result\%%~I"
)

Related

How to loop through my text file and call the name of picture

I need to take all audio files from a directory, and export them along with one of multiple pictures listed in a text file.
It's working to take all the audio files one by one, but I cannot make it have a different picture for each video. I have same picture all the time.
I don't know how to make the loop working for the pictures files.
Will be nice if someone can tell me how I can group pictures in order to export as a slideshow.
Thank you.
In .txt file my pictures are like this :
1.jpg
2.jpg
3.jpg
And my code looks like this:
#echo off
set "sourcedir=E:\test slideshow imagini"
set "outputdir=E:\test slideshow imagini\1"
PUSHD "%sourcedir%"
for /F "tokens=*" %%A in (poze3.txt) do (
echo %%A
:: pictures names
for %%F in (*.wav *.mp3) DO ffmpeg -loop 1 -i %%A -i "%%F" -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest -vf scale=1920:1080 "%outputdir%\%%F.mp4"
POPD
)
You need a trick to read the next line of a file with each run of the loop:
#echo off
setlocal enabledelayedexpansion
set "sourcedir=E:\test slideshow imagini"
set "outputdir=E:\test slideshow imagini\1"
PUSHD "%sourcedir%"
<"poze3.txt" (
for %%F in (*.wav *.mp3) DO (
set /p pic=
ffmpeg -loop 1 -i !pic! -i "%%F" -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest -vf scale=1920:1080 "%outputdir%\%%F.mp4"
)
)
(untested, but should work).
Btw: DO NOT use :: as comment. Use REM instead.
I know, :: is used often and behaves well outside of code blocks, but tends to hiccup when used within code blocks, leading to unexpected behaviour which is hard to troubleshoot.
I removed the popd in the loop. Repeatedly popd's without matching push's don't make sense. You do only one pushd before the loop, so the matching popd should be after the loop, where you can omit it, as the script ends anyway.

How to execute ffmpeg from with Batch For Loop

FOR %%A IN (%*) DO ffmpeg -y -i %%A -c:v prores_ks -profile:v 3 -c:a pcm_s16le "%%~dpA%%~nA.mov"
This batch file is intended to take multiple files which are dragged and dropped onto it, and transcode them with ffmpeg. The command results in a whole bunch of prinouts that are similar to the command, but it does not execute. I have also tried using start cmd.exe /c, but that causes numerous windows to open which necessitates a computer reboot.
Edit: squashman has made it clear that this solution would not work anyway (Thanks!). However, I have edited the script to act on only a single file at once and it still does not execute as intended and causes a looping printout.
ffmpeg -y -i %%1 -c:v prores_ks -profile:v 3 -c:a pcm_s16le "%%~dp1%%~n1.mov"
How can I modify this script to execute ffmpeg properly?
Edit 2: Resolved by dragging and dropping a folder onto the batch script.
cd /d %1
md output
FOR /F %%A IN ('dir /B %1') do ffmpeg -y -i %%A -c:v prores_ks -profile:v 3 -c:a pcm_s16le "output/%%~nA.mov"
pause
Expect all .mov files reside in current directory. if not, prepend path into both of "*.mov" and "%%~A.mov".
FOR /F "tokens=1,2 delims=." %%A IN ('dir /B *.mov') do ffmpeg -y -i %%A -c:v prores_ks -profile:v 3 -c:a pcm_s16le "%%~A.mov"
another way is to use PPX http://www.pirosa.co.uk/demo/wxargs/wxargs.html and speed-up whole process by utilizing all CPU cores
dir /b *.%required_file_extension% |ppx2 -P 4 -L 1 ffmpeg -y -i %%A -c:v prores_ks -profile:v 3 -c:a pcm_s16le "{}.mov"
Worth also considering using a build system like SCons.
I've coded up something similar here to transcode a directory's worth of video files all at once from the command-line:
https://github.com/nuket/Shrinkr#shrinkr-batch-transcode-scons-edition
Benefit of a build system is it tracks which source files have changed, so you can interrupt and re-run the batch transcode and it won't repeat already-completed work.

How to batch process a directory of mp4 files to remove their metadata?

I convert one mp4 file using ffmpeg to remove all metadata from the mp4 file with the following command:
ffmpeg -i test.mp4 -map_metadata -1 -c:v copy -c:a copy out.mp4
This works fine but I want a bash script that will automatically remove all metadata of a directory containing mp4 files, with minimum interaction.
How can I do that?
for f in *.mp4; do ffmpeg -i "$f" -map_metadata -1 -c:v copy -c:a copy "fixed_$f"; done
Bash replaces *.mp4 with names of all matching files in current directory. Each step the loop passes, f contains one of the file names.
Or use a subdirectory:
mkdir converted
for f in *.mp4; do ffmpeg -i "$f" -map_metadata -1 -c:v copy -c:a copy "converted/$f"; done
This lists all the files (and only the files) in the current directory:
for /r %i in (*) do echo %i
Also if you run that command in a batch file you need to double the % signs.
for /r %%i in (*) do echo %%i
It will go something like this. Create a file, call it test.cmd and copy this inside the file.
for %%f in (*.mp4) do (
ffmpeg -i %%f -map_metadata -1 -c:v copy -c:a copy %%~nf-out.mp4
)
The -n works as a substitution for only the name part.

Convert .MOD video files to .mp4 but maintain original file date

Windows 10,
ffmpeg
I'm very new to ffmpeg so I can't figure this out. I'm trying to use a command to copy then convert all .MOD video files in a directory to .mp4 files and keep the original date that the .MOD file was created. I don't understand how to map the current file in the loop to the map_metadata option. This command works but doesn't maintain the metadata (taken from this post)
FOR /F "tokens=*" %G IN ('dir /b *.MOD') DO ffmpeg -i "%G" -acodec copy "%~nG.mp4"
I've tried including the map in the above command but get various errors, mostly "invalid input file index: 1". The commands below will copy and convert but the new .mp4 files don't have the original file date so I must be using map_metadata incorrectly:
FOR /F "tokens=*" %G IN ('dir /b *.MOD') DO ffmpeg -i "%G" -acodec copy -map_metadata 0 "%~nG.mp4"
FOR /F "tokens=*" %G IN ('dir /b *.MOD') DO ffmpeg -i "%G" -map_metadata 0 -acodec copy "%~nG.mp4"
Any suggestions? Thanks
UPDATE
I got this with Powershell! (thanks to this post)
$oldvids = Get-ChildItem *.MOD -Recurse
foreach ($oldvid in $oldvids) {
$newvid = [io.path]::ChangeExtension($oldvid.LastWriteTime.toString("MMMddyyyy_HHmmss"), '.mp4')
ffmpeg.exe -i $oldvid.FullName -c:v libx264 -crf 18 -c:a aac -q:a 100 $newvid
}
input: MOV01E.MOD (Created date 4/1/2012 10:10 AM)
output: Apr012012_101005.mp4
ANOTHER UPDATE
The above command kind of works but I just realized all of the files are output to the root directory. I changed the command a bit but I'm not sure what's going on:
Get-ChildItem *.MOD -recurse | % {
$newvid = [io.path]::ChangeExtension($_.LastWriteTime.toString("MMMddyyyy_HHmmss"), '.mp4')
ffmpeg.exe -i $_.FullName -c:v libx264 -crf 50 -c:a aac -q:a 100 $newvid
}
I just needed to change the output file to include the directory path
Get-ChildItem *.MOD -recurse | % {
$newvid = [io.path]::ChangeExtension($_.LastWriteTime.toString("MMMddyyyy_HHmmss"), '.mp4')
ffmpeg.exe -i $_.FullName -c:v libx264 -crf 20 -c:a aac -q:a 100 ($_.DirectoryName + "\" + $newvid)
}

Windows Batch - Change the beginning of a path but keep the rest

I'm running FFMPEG for video encoding.
I have a batch file which will encode files you drop on it, keeping the file's original name and copy the encoded files to a specific directory.
I would like that script to "know" the original's file path and copy the encoded file to a path relative to it, meaning:
original file dropped on batch file is in C:\some\folder\show\season\episode\file.mov
encoded file should be encoded to D:\different\directory\show\season\episode\file.mp4
The part of the path up until \show is fixed.
This is what I have so far:
#echo on
set count=0
for %%a in (%*) do (<br>
if exist %%a (
md \\specific\path\"%%~na"
%MYFILES%\ffmpeg.exe -i "%%~a" -vcodec libx264 -preset medium -vprofile baseline -level 3.0 -b 500k -vf scale=640:-1 -acodec aac -strict -2 -ac 2 -ab 64k -ar 48000 "%%~na_500.mp4"
copy "%%~na_500.mp4" "\\specific\path\"%%~na"\%%~na_500.mp4"
copy "%%~na_500.mp4" "\\specific\path\"%%~na"\%%~na_500.mp4"
del "%%~na_500.mp4"
set /a count+=1
) else (
echo Skipping non-existent %%~a
Thank you,
Oren
#ECHO OFF
SETLOCAL
SET "MYFILES=MY_files"
SET "fixed_path=u:\destdir"
FOR %%a IN ("%*") DO IF EXIST "%%a" (
FOR /f "tokens=3*delims=\" %%b IN ("%%~dpa") DO (
ECHO(MD "%fixed_path%\%%c"
ECHO(%MYFILES%\ffmpeg.exe -i "%%~a" -vcodec libx264 -preset medium -vprofile baseline -level 3.0 -b 500k -vf scale=640:-1 -acodec aac -strict -2 -ac 2 -ab 64k -ar 48000 "%%~na_500.mp4"
ECHO(copy "%%~na_500.mp4" "%fixed_path%\%%c%%~na_500.mp4"
ECHO(del "%%~na_500.mp4"
)
) ELSE (ECHO(%%~a does NOT EXIST
)
GOTO :EOF
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
Similarly, the DEL and COPY commands are merely echoed.
I set myfiles to a constant - no doubt yours will be different and I set fixed _path to a constant for convenience of editing.
No idea whether the ffmpeg command is correct - just edited yours, and I'm puzzled by your use of two apparently identical copy commands in succession, but maybe my eyes are playing tricks...

Resources