Okay here is a script that uses ffprobe
to read the bitrate used in a video file. It takes a video as input, reads the video bitrate, and then proceeds to encode a (cropped) copy of the video using the same bitrate and x265 codec (as far as I can tell recoding is the only way to remove black boarders from videos from showing up in Icaros thumbnailer).
The script is executed from the windows explorer by right-clicking a video and choosing Transcode (command: cmd /k d:\utils\transcode.cmd "%1"). Everything else it does automatically.
@echo off
cd /d "%~dp0"
set "manifest=%~dpn0.txt"
set "temporary=%temp%\%~n0.tmp"
:: input must exist and be no duplicate
if exist "%~1" findstr /c:"%~1" "%manifest%" >nul || echo "%~1">>"%manifest%"
:: exit all but first instance
tasklist /fi "imagename eq handbrakecli.exe" | find /i "handbrakecli" && exit
:manifest
for /f "delims=" %%f in (%manifest%) do (
set "in=%%~ff"
set "out=%%~dpnf-2.mkv"
call :transcode )
for %%a in ("%manifest%") do if not %%~za lss 4 goto :manifest
exit /b
:transcode
if not exist "%in%" goto :cleanup
if exist "%out%" goto :cleanup
ffprobe "%in%" -v 0 -select_streams v:0 -show_entries stream=bit_rate -print_format compact=p=0:nokey=1 >"%temporary%"
set /p bitrate=<%temporary%
if not defined bitrate echo failed to fetch bitrate & goto :cleanup
:: reduce to full kilobytes
set "bitrate=%bitrate:~0,-3%"
if %bitrate% gtr 7000 set bitrate=7000
HandBrakeCLI -i "%in%" -o "%out%" --encoder x265_10bit --vb %bitrate% --two-pass --turbo --audio 1-9 --aencoder copy --audio-copy-mask aac,ac3,mp2,mp3,opus --audio-fallback opus --ab 160 --drc 2.0
:cleanup
findstr /v /c:"%in%" "%manifest%">"%temporary%"
move /y "%temporary%" "%manifest%">nul
The command is solid, but it constantly keeps getting broken according to me working on the rest of the script. Please note that the ffprobe
command itself, the variables etc has been constantly the same, but it still breaks every now and then. I suspect it has to do with "
quotes or something similar somewhere else in the script. Currently, instead of a number representing the video track bitrate I get a N/A
. And yes this has been tested on videos that have already been proven to work well with earlier script version, passing the bitrate info via ffprobe
.
The %~n0.txt file looks like this
"D:\VIDEOS\SCOPITONE\Dario - Big Bang.mkv"
"D:\VIDEOS\SCOPITONE\Rossi - BB (edit).mp4"
See, instead of every launch of the script creating a separate encoding instance, a file is queued in this file. Only the first instance of the script is allowed to continue, and files added later will be processed from the end of the queue.
The file %temporary% is supposed to include the bitrate 2534533
and gets reduced to kilos by dropping the last three digits so 2534
would mean the new video will be coded with 2534k/s
Processing lots of video files can take hours. It could happen that a shutdown of the PC or a restart of Windows must be done while the processing of one or more video files according to one or more existing list files is currently in progress. The list files with file or folder names not completely processed remain in the directory for temporary files on processing is interrupted and stopped for whatever reason. It should be possible to force a restart of the processing of the remaining video files according to the still existing list files later on processor time and power is available again for this video files processing task.
Below is the batch file from my initial answer with some enhancements.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "OutputNameExt=_2.mkv"
set "ExeFFProbe="
set "ExeHandBrake="
if not "%~1" == "" goto GetFFProbe
echo(
echo ERROR: "%~nx0" must be executed with at least one video file name!
echo(
if not defined NoPausePrompt set /P "=Press any key to exit ... " 0<nul & pause 1>nul
exit /B 2
:GetFFProbe
if defined ExeFFProbe if exist "%ExeFFProbe%" goto GetHandBrakeCLI
if exist "%~dp0ffprobe.exe" set "ExeFFProbe=%~dp0ffprobe.exe" & goto GetHandBrakeCLI
if exist ffprobe.exe for %%I in (ffrobe.exe) do set "ExeFFProbe=%%~fI" & goto GetHandBrakeCLI
for %%I in (ffprobe.exe) do set "ExeFFProbe=%%~$PATH:I"
if defined ExeFFProbe goto GetHandBrakeCLI
set "ExeMissing=ffprobe"
goto MissingEXE
:GetHandBrakeCLI
if defined ExeHandBrake if exist "%ExeHandBrake%" goto AddListFile
if exist "%~dp0HandBrakeCLI.exe" set "ExeHandBrake=%~dp0HandBrakeCLI.exe" & goto AddListFile
if exist HandBrakeCLI.exe for %%I in (HandBrakeCLI.exe) do set "ExeHandBrake=%%~fI" & goto AddListFile
for %%I in (HandBrakeCLI.exe) do set "ExeHandBrake=%%~$PATH:I"
if defined ExeHandBrake goto AddListFile
set "ExeMissing=HandBrakeCLI"
:MissingEXE
echo(
echo ERROR: "%~nx0" could not find the executable %ExeMissing%.exe!
echo(
echo Please make sure the program %ExeMissing%.exe is in the current directory or
echo can be found using the environment variable PATH or is in the directory:
echo(
echo "%~dp0"
echo(
if not defined NoPausePrompt set /P "=Press any key to exit ... " 0<nul & pause 1>nul
exit /B 3
:AddListFile
set "RetryCount=0"
set "ListFileName=%~n0"
set "ListFileName=%ListFileName:_= %"
set "ListFileName=%ListFileName:.= %_"
set "ListFullName=%TEMP%\%ListFileName%"
if /I "%~1" == "/ForceRestart" echo INFO: Force a restart of video files processing.& goto ProcessFiles
:GetFileNumber
set "FileNumber=0"
setlocal EnableDelayedExpansion
for /F "eol=| tokens=2 delims=_." %%I in ('dir "!ListFullName!*.tmp" /A-D-H-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R "_[0123456789][0123456789]*\.tmp$"') do if %%I GTR !FileNumber! set "FileNumber=%%I"
endlocal & set "FileNumber=%FileNumber%"
set /A FileNumber+=1
((for %%I in (%*) do echo("%~f1") 1>"%ListFullName%%FileNumber%.tmp") 2>nul
if not errorlevel 1 goto QueueTask
set /A RetryCount+=1
if not %RetryCount% == 50 goto GetFileNumber
echo(
echo ERROR: "%~nx0" could not create the temporary list file:
echo(
echo "%ListFullName%%FileNumber%.tmp"
echo(
if not defined NoPausePrompt set /P "=Press any key to exit ... " 0<nul & pause 1>nul
exit /B 1
:QueueTask
if not %FileNumber% == 1 exit /B
set "RetryCount=0"
:ProcessFiles
set "OneMoreList="
for /F "eol=| delims=" %%G in ('dir "%ListFullName%*.tmp" /A-D-H-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R "_[0123456789][0123456789]*\.tmp$"') do (
set "OneMoreList=1"
set "LinesProcessed="
(for /F "usebackq eol=| delims=" %%H in ("%TEMP%\%%G") do (
if exist "%%~H\" (
echo Processing *.mkv and *.mp4 in: %%H
for /F "eol=| delims=" %%I in ('dir "%%~H\*.mkv" "%%~H\*.mp4" /A-D-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /V /C:"%OutputNameExt%"') do set "VideoFile=%%~H\%%I" & call :ProcessVideo
) else if exist "%%~H" set "VideoFile=%%~H" & call :ProcessVideo
set "LinesProcessed=1"
)) 2>nul
if defined LinesProcessed (del "%TEMP%\%%G") else set /A RetryCount+=1
)
if not defined OneMoreList exit /B 0
if %RetryCount% LSS 50 goto ProcessFiles
echo(
echo ERROR: "%~nx0" could not process all the temporary list files:
echo(
echo "%ListFullName%*.tmp"
echo(
if not defined NoPausePrompt set /P "=Press any key to exit ... " 0<nul & pause 1>nul
exit /B 1
:ProcessVideo
for %%J in ("%VideoFile%") do (
if exist "%%~dpnJ%OutputNameExt%" echo INFO: Skipping file: "%VideoFile%"& goto :EOF
set "OutputFile=%%~nJ%OutputNameExt%"
set "TempFile=%%~dpnJ.tmp"
)
echo Processing video: "%VideoFile%"
set "BitRate="
for /F %%J in ('^""%ExeFFProbe%" "%VideoFile%" -v 0 -select_streams v:0 -show_entries stream^=bit_rate -print_format compact^=p^=0:nokey^=1 2^>nul^"') do set "BitRate=%%J"
if not defined BitRate echo ERROR: "%VideoFile%" is not a video file!& goto :EOF
set /A BitRate/=1000
if %BitRate% GTR 7000 set "BitRate=7000"
"%ExeHandBrake%" -i "%VideoFile%" -o "%TempFile%" --encoder x265_10bit --vb %BitRate% --two-pass --turbo --audio 1-9 --aencoder copy --audio-copy-mask aac,ac3,mp2,mp3,opus --audio-fallback opus --ab 160 --drc 2.0
if errorlevel 1 del "%TempFile%" 2>nul & goto :EOF
ren "%TempFile%" "%OutputFile%"
The third command line in the batch file is now:
set "OutputNameExt=_2.mkv"
This line defines the string which is appended to the source video file name without file extension to the output video file name. That makes it easily possible changing the output file names to *_x265.mkv
or whatever seems to be best without doing a search and replace on entire batch file.
The string value of the environment variable OutputNameExt
is referenced three times in the entire batch file.
There is added in the command block below the label :AddListFile
the command line:
if /I "%~1" == "/ForceRestart" echo INFO: Force a restart of video files processing.& goto ProcessFiles
That extension makes it possible running the batch file with the case-insensitive interpreted command line option /ForceRestart
for restarting the processing of the video files according to the still existing list files in the directory for temporary files after a restart of Windows.
Running the batch file with the option /ForceRestart
should be done only if there is no command process running which is already processing this batch file.
The following command line is added to the batch file for informing the user about the processing of videos in a directory.
echo INFO: Processing *.mkv and *.mp4 in: %%H
The batch file could be started with one or more directory names which contain already several output videos created some time before. That can especially occur on stopping the video processing due to a necessary shutdown or restart of Windows and later force a restart of the video processing and one or more existing list files contain one or more directory names instead of just video file names.
It is also possible that a directory has multiple videos processed already before and later are added additional videos into the same directory which need to be processed too. This extension makes it possible to run the batch file with just the directory name to get processed now only all added video files and skipping the output videos created some time before in same directory.
This enhancement was done by extending the command line
for /F "eol=| delims=" %%I in ('dir "%%~H\*.mkv" "%%~H\*.mp4" /A-D-L /B 2^>nul') do set "VideoFile=%%~H\%%I" & call :ProcessVideo
to the command line
for /F "eol=| delims=" %%I in ('dir "%%~H\*.mkv" "%%~H\*.mp4" /A-D-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /V /C:"%OutputNameExt%"') do set "VideoFile=%%~H\%%I" & call :ProcessVideo
FINDSTR is used now for getting the list of video file names in the directory to process without the video file names ending case-insensitive with the output name extension as defined in the third line in the batch file.
It is nevertheless possible to process a video of which name ends with the string assigned to the environment variable OutputNameExt
. But it is necessary to run the batch file with the name of such a video file as argument instead of the name of the directory containing such a video file.
There is added below the label :ProcessVideo
the following command block:
for %%J in ("%VideoFile%") do (
if exist "%%~dpnJ%OutputNameExt%" echo INFO: Skipping file: "%VideoFile%"& goto :EOF
set "OutputFile=%%~nJ%OutputNameExt%"
set "TempFile=%%~dpnJ.tmp"
)
This command block replaces the former last but one command line:
for %%J in ("%VideoFile%") do set "OutputFile=%%~dpnJ_2.mkv"
For each video file to process is checked now first if there is in the same directory already a video file with the output name extension as defined in the third command line. There is just output an information message about skipping this video file if there is already a matching output video file for the file to process next.
This enhancement is necessary as addition to the fourth enhancement to avoid processing of videos in a directory for which a matching output video already exists. It is also necessary for the use case of an interrupted and later restarted video processing on which multiple file names are stored in a list file and some of them have been processed already before interrupting the video files processing.
An already existing output video file must be explicitly deleted if a source video file has been modified somehow and there should be created the output video file once again using this batch file.
The fourth argument string passed to the program HandBrakeCLI
is now a temporary file name.
There are appended also two more command lines at the bottom of the batch file.
if errorlevel 1 del "%TempFile%" 2>nul & goto :EOF
ren "%TempFile%" "%OutputFile%"
This enhancement deletes the temporary file created by HandBrakeCLI
on HandBrakeCLI
exited with an exit code greater or equal 1 indicating an error and the subroutine ProcessFile
is exited without running the last command. That modified behavior is also useful if an error occurs on processing the source video file.
The last command line renames the created output file with the temporary file name to the correct output video file name as defined by the source file name and the string value assigned to the environment variable OutputNameExt
.
That enhancement makes it possible to interrupt the video processing even while HandBrakeCLI
is currently running resulting in a just partly done video processing task of the currently processed source video file. The just partly processed source video file is processed most likely first on restarting later the video processing by running the batch file with its option /ForceRestart
.