Use ffmpeg to cut out the first chapter - ffmpeg

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

Related

sending FFMPEG the start_number of image sequence in a batch script

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.

ffmpeg/for loop: How to make ffmpeg or cmd loop stops after it founds an error?

I'm trying to create a bat file to create multiple gifs from videos and I'm doing ok so far.
I managed to create this command
#echo off
FOR /L %%A IN (0,5,3600) DO (ffmpeg -ss %%A -t 3 -i "%~1" -vf "fps=10,scale=360:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 -fs 1000000 "output %%~nxA.gif")
The problem is that I use a command for 1h videos, which will create 720 gifs
The problem is that when the video is under 1h of duration the bat file continues to run and create empty gif files, until reaches 720 gif files
I need to know what command should I use.
I've tried -abort_on empty_output, -abort_on empty_output_stream, and -xerror
but none of this worked
Also I'm using the for to loop the command, therefore I don't know if this is a ffmpeg problem or a for loop problem
Help me!
Instead of using the fixed 3600, I suggest you use ffprobe to get the video's duration.
Either through another for-loop...
#ECHO off
FOR /F "delims=" %%A IN ('ffprobe -v 0 -show_entries format^=duration -of compact^=p^=0:nk^=1 "%~1"') DO ^
FOR /L %%B IN (0,5,%%A) DO ^
ffmpeg -ss %%B -t 3 -i "%~1" -vf "fps=10,scale=360:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" "%~n1_%%B.gif"
...or with a variable...
#ECHO off
FOR /F "delims=" %%A IN ('ffprobe -v 0 -show_entries format^=duration -of compact^=p^=0:nk^=1 "%~1"') DO SET dur=%%A
FOR /L %%A IN (0,5,%dur%) DO ^
ffmpeg -ss %%A -t 3 -i "%~1" -vf "fps=10,scale=360:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" "%~n1_%%A.gif"

Windows batch program NOT EXIST not functioning

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

How can I delete a file in FOR loop in batch scripting after another command?

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

ffmpeg - is there a way to -map 0:m:language:eng if it exists, otherwise use the default?

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
)

Resources