I have written a simple batch file to convert movies in a folder. The problem is, it never stops running. It keeps processing the next movie (which it just created). Here is the code:
#echo off & setlocal
FOR /r %%# in (*.mkv) DO IF NOT EXIST "%%~dpn#_265.mkv" (Title %~nx0 Processing: %%~f#
ffmpeg -i "%%~f#" -c:v libx265 -vtag hvc1 -map_metadata 0 -max_muxing_queue_size 1000 "%%~dpn#_265.mkv")
PAUSE
The file to convert is c:\tmp\c.mkv.
The code creates the first file c:\tmp\c_265.mkv, then creates a second file from that one called c:\tmp\c_265_265.mkv, and so on.
Your main issue with your code is likely to be that you're checking for the existence of every mkv file in the same directory, but with _265 appended to the basename. So in your example %%# would resolve to c:\tmp\c_265.mkv and you'd be checking for the existence of c:\tmp\c_265_265.mkv, which probably isn't the only check you needed to make. You probably wanted to check to ensure that the last four characters of %%# were not already _265 too.
Without changing your for /r methodology, (I'd go with a for /f with findstr idea similar to Gerhard's comment), you could do it like this:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /R "." %%G In (
"*.mkv"
) Do If /I "%%~xG" == ".mkv" If Not Exist "%%~dpnG_265%%~xG" (
Set "FileBaseName=%%~nG"
SetLocal EnableDelayedExpansion
If Not "!FileBaseName:~-4!" == "_265" (
"ffmpeg.exe" -i "%%G" -c:v libx265 -vtag hvc1 -map_metadata 0 -max_muxing_queue_size 1000 "%%~dpnG_265%%~xG"
)
EndLocal
)
Pause
Related
I'm creating a batch script to daily convert screen captures to video
Its all working except I cant get the screen caps to start at 0001 each day,so my current script fails.
Is there a way within FFMPEG to just read all the files in a folder (e.g. if I have one folder with 500 files starting with 01234.jpg and another folder with files starting at 87654.jpg)?
If not, can I use the batch script to find the start and finish points and send that to ffmpeg?
my script
#echo off
setlocal enabledelayedexpansion
rem Check if a new folder has been added to the watched folder
for /f "tokens=*" %%a in ('dir "Y:\fastone_timelapse" /B /AD') do (
set "new_folder=%%a"
rem Check if jpeg files are present in the new folder
if exist "Y:\ft\!new_folder!\*.jpg" (
ffmpeg.exe -f image2 -framerate 25 -pattern_type sequence -start_number 00001 -i "Y:\ft\!new_folder!\%%05d.jpg" -c:v libx265 -b:v 5000k -g 100 "Y:\ft\!new_folder!.mp4"
)
)
endlocal
if exist "Y:\ft\!new_folder!\*.jpg" (
set "first="
for /f %%y in ('dir /on /b /a-d "Y:\ft\!new_folder!\*.jpg"') do set "last=%%~ny"&if not defined first set "first=%%~ny"
echo First=!first! Last=!last!
ffmpeg.exe -f image2 -framerate 25 -pattern_type sequence -start_number 00001 -i "Y:\ft\!new_folder!\%%05d.jpg" -c:v libx265 -b:v 5000k -g 100 "Y:\ft\!new_folder!.mp4"
BTW, you don't appear to need new_folder as each appearance of !new_folder! can be replaced by %%a.
I compress a video with FFMPEG by means of a batch scripting one-liner with a FOR LOOP. After compressing I want to remove the original file.
This code perfectly makes the compressing job, but the original file is not being removed:
for %%i in (*.mp4) do ffmpeg -i "%%i" -vcodec libx265 -crf 28 "%%~ni"-small.mp4&&del "%%i"
pause
What have I missed?
By the way, this is a near to perfect compression ratio for any kinds of educational videos, tutorials, etc. which have occupied your hard drive.
I would assume that this methodology will serve you better:
#For /F "EOL=? Delims=" %%G In ('Dir /B /A:-D "*.mp4" ^| ^
"%__AppDir__%findstr.exe" /IR "\.mp4$" ^| ^
"%__AppDir__%findstr.exe" /IRV "\-small\.mp4$"'
) Do #If Not Exist "%%~nG-small%%~xG" (
ffmpeg.exe -i "%%G" -vcodec libx265 -crf 28 "%%~nG-small%%~xG"
If Not ErrorLevel 1 If Exist "%%~nG-small%%~xG" Del /A /F "%%G")
The idea is to get a directory listing of all files with an .mp4 extension. Using the first findstr to exclude any files which match the short, (8.3), names. It then pipes those through another findstr search, to exclude any of those files which already have -small appended to their basename. Next it checks to make sure that there are no existing files within that directory, with the same basename plus the -small basename suffix, (preventing possible overwrites). If all of those pass, ffmpeg.exe should be invoked, (subject to ffmpeg.exe being in the current directory, within %PATH%, or registered as executable with its location in the registry). Once the conversion has completed, the script checks the returned ErrorLevel was less than 1, (to ensure it was successful), and if so, whether the new file, (with the -small basename suffix) exists. If so it will proceed with the deletion, using the Del command.
If you wanted to try it again using conditional operators instead of the ErrorLevel, then it would look like this:
#For /F "EOL=? Delims=" %%G In ('Dir /B /A:-D "*.mp4" ^| ^
"%__AppDir__%findstr.exe" /IR "\.mp4$" ^| ^
"%__AppDir__%findstr.exe" /IRV "\-small\.mp4$"'
) Do #If Not Exist "%%~nG-small%%~xG" (
ffmpeg.exe -i "%%G" -vcodec libx265 -crf 28 "%%~nG-small%%~xG" && (
If Exist "%%~nG-small%%~xG" Del /A /F "%%G"))
I just put the '/f' after DEL and it perfectly does the job. I don't know if there are any shortcomings of the forced deletion but it works.
A final line:
for %%i in (*.mp4) do ffmpeg -i "%%i" -vcodec libx265 -crf 28 "%%~ni"-small.mp4&&del /f "%%i"
pause
I'm trying to remove the first chapter of a TV show rip. The idea is to have something similar to netflix, where the first episode will show the intro then the consecutive episodes don't.
I've been getting the chapter time with ffprobe then doing it manually with this
for %%A IN (*.mp4) DO ffmpeg -ss <CHAPTERTIME> -i "%%A" -vcodec copy -acodec copy "tmp.mp4" && DEL "%%A" && RENAME "tmp.mp4" "%%A"
How do I pass the first chapter time code value so ffmepg knows where to seek to?
Also hoping to use the same the same value to offset the subtitles so they align after the cut.
Note: The machine I've doing the cutting on is windows but I can use my FreeBSD server if that's easier.
It's probably the worst way to do it, but atleast it works, still cant get it to work in batch.
#setlocal enableextensions enabledelayedexpansion
#echo off
for %%A IN (*.mp4) DO ffprobe -show_chapters -print_format flat "%%A" > out.txt
for /f "tokens=* delims=" %%a in ('findstr /C:"chapters.chapter.1.start_time=" out.txt') do (
set S=%%a
set S=!S:~30,20!
echo !S!
)
for %%A IN (*.mp4) DO ffmpeg -ss !S! -i "%%A" -vcodec copy -acodec copy "tmp.mp4" && DEL "%%A" && RENAME "tmp.mp4" "%%A"
endlocal
If a source has 'eng' as an audio track, use that, otherwise use the default or audio track zero?
Is this possible?
I have tried:
-map 0:m:language:eng? -map 0:a:0?
But that ends up always using the default one.
Good question. I don't think ffmpeg has this feature, so I ended up writing a .bat script to mimic it. The script uses ffprobe to probe the media file. For each stream, if there's a language attribute set and that language != "eng", omit it. Otherwise, map all streams without language + those with "eng" language, and copy to basename-fixed.ext.
It's probably more complicated than it ought to be, but you might find it useful. *shrug*
#echo off
for %%I in (*.mkv *.mp4) do (
setlocal
for /f "delims=" %%x in (
'ffprobe -v quiet -show_entries "stream=codec_name:stream_tags=language" -of flat "%%~I"'
) do set "%%~x"
for /f "tokens=1* delims==" %%a in ('set streams') do (
echo(%%a | find /i "language" >NUL && if /i not "%%~b"=="eng" (
for /f "tokens=1-3 delims=." %%p in ("%%a") do (
for /f "tokens=1 delims==" %%s in ('set %%p.%%q.%%r') do set "%%~s="
)
)
)
setlocal enabledelayedexpansion
for /f "tokens=3 delims=." %%x in ('set streams ^| find "codec_name"') do (
if not defined map (
set "map=-map 0:%%x"
) else set "map=!map! -map 0:%%x"
)
echo ffmpeg -i "%%~I" !map! -c:v copy -c:a copy -c:s copy "%%~nI-fixed%%~xI"
ffmpeg -i "%%~I" !map! -c:v copy -c:a copy -c:s copy "%%~nI-fixed%%~xI"
endlocal
endlocal
)
ffmpeg can resize a video/image file .. first is input_file .. parameters .. output_file ..
ffmpeg -i input.avi -vf scale=320:240 output.avi
or
ffmpeg -i 20140724_071746.mp4 -vf scale=640:-1 20140724_071746_LOW_640.mp4
more info here: https://trac.ffmpeg.org/wiki/Scaling%20%28resizing%29%20with%20ffmpeg
I want it to downscale all the videos on my microSD card to create space (I have originals backed-up)
So I want it to go throw all the files in all the sub-directories overnight and resize all the files. Chances are that the script might stop or crash and I would need to run it again, or if I add new files I would want to run it again.
So I would want it to skip processing all the files that have been processed AND their resized versions.
In my case if a FILE_NAME.mp4 also has FILE_NAME_LOW_640.mp4 SKIP it
AND
if a FILE_NAME_LOW_640.mp4 has *640 SKIP it
Here is my Windows batch script so far
REM #echo off
REM just save as "DOS"
REM cd /d C:\s
setlocal enabledelayedexpansion
for %%j in (*.mp4) do (
set filename=%%~nj
echo %%j
ffmpeg -i %%j -vf scale=640:-1 %%j_LOW_640.mp4
REM but now I want to add the two checks to skip files that have been resized .. or if they are the resized version
REM if not "!filename!"=="%%j_LOW_640.mp4" AND IF FILE !COINTAIN *640* THEN ffmpeg -i %%j -vf scale=640:-1 %%j_LOW_640.mp4
)
pause
REM AND I would also want it to process all the sub-directories
In other words my questions for help are:
How can I do a check for a string if it contains a string match?
How can I have my script also process all the subdirectories?
I hope the method be simple enough so it don't needs explanations. You may read further details on FOR parameter modifiers at HELP FOR
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%a in ('dir /S /B *.mp4') do (
set "name=%%~Na"
if "!name:~-3!" neq "640" if not exist "%%~DPNa_LOW_640.mp4" (
ffmpeg -i "%%a" -vf scale=640:-1 "%%~DPNa_LOW_640.mp4"
)
)
for /f "delims=" %A in ('dir /b /s c:\somewhere\*.mp4') do (findstr /c:"_640" %A || Echo ffeg etc %A)
|| means run command if findstr returns an errorlevel of not 0, which it does if the string isn't found. /s in dir does subfolders.
Use %%A in batch and %A when typing.
See Novice Batch Issue- Creating Files for a list of command punctuation.
And a vbs script walking the tree. Run it with cscript in a command prompt(cscript //nologo "c:\some path\script.vbs". Change starting folder for your machine (replace the c:\users\david candy\documents).
On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
ProcessFolder "c:\users\david candy\documents"
Sub ProcessFolder(FolderPath)
Set fldr = fso.GetFolder(FolderPath)
Set Fls = fldr.files
For Each thing in Fls
wscript.echo thing.name
Next
Set fldrs = fldr.subfolders
For Each thing in fldrs
wscript.echo thing.name
ProcessFolder thing.path
Next
End Sub