-
-
Save nyanshiba/47a5f0aae5a9e3ae2deab2f0ff411fb0 to your computer and use it in GitHub Desktop.
TSファイルをミリ秒単位でカットしてgif、mp4、avi、連番jpgにエンコードする汎用性の高いバッチ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@echo off | |
rem 180809 | |
rem 最早編集ソフトと化したTSファイルをD&Dでミリ秒単位でカットしてgif、mp4、avi、連番jpgにエンコードするバッチ | |
rem D&Dした複数ファイルを表示 | |
set cnt=0 | |
setlocal enabledelayedexpansion | |
for %%a in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do ( | |
if not %%a == "" ( | |
set /a cnt+=1 | |
echo !cnt!.%%a | |
) | |
) | |
setlocal disabledelayedexpansion | |
echo. | |
rem 複数ファイルD&Dでエンコ処理を呼ぶ | |
for %%a in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do ( | |
if not %%a == "" ( | |
title %~nx0:%%a | |
echo 処理対象:%%a | |
echo. | |
call :encode %%a | |
echo 処理終了:%%a | |
echo. | |
) | |
) | |
echo すべての処理終了 | |
pause | |
exit | |
:encode | |
rem ==========出力フォルダを作成========== | |
rem D&DしたTSファイルのあるディレクトリにその名前のフォルダを作成 | |
md "%~dpn1" | |
echo 出力ディレクトリ:"%~dpn1" | |
echo. | |
rem ==========カット時刻の計算方式========== | |
set /p hms_or_ffplay=カット時刻を入力する方式を選択[hms:hms表記、ff:ffplay等の秒数表記、Enter:カットしない]: | |
echo. | |
if "%hms_or_ffplay%" == "hms" ( | |
call :cutcal_hms %1 | |
) else if "%hms_or_ffplay%" == "ff" ( | |
call :cutcal_ffplay %1 | |
) else if "%hms_or_ffplay%" == "" ( | |
rem カット変数クリア | |
set SS= | |
set T= | |
) | |
rem ==========ビデオフィルタ========== | |
rem vfプリセット | |
set "vf0= " | |
set "vf1=-vf bwdif=0:-1:1,pp=ac" | |
set "vf2=-vf bwdif=0:-1:1,hqdn3d" | |
set "vf3=-vf bwdif=0:-1:1,pp=ac,unsharp=3:3:2:3:3:2:0,scale=1280:720" | |
set "vf4=-vf bwdif=0:-1:1,hqdn3d,unsharp=3:3:2:3:3:2:0,scale=1280:720" | |
set "vf5=-vf bwdif=0:-1:1,pp=ac,unsharp=3:3:1:3:3:1:0,scale=1920:1080" | |
set "vf6=-vf bwdif=0:-1:1,pp=ac,unsharp=3:3:1:3:3:1:0" | |
set "vf7=-vf pp=ac" | |
set "vf8=-vf pp=ac,scale=1280:720" | |
set "vf9=-vf pp=ac,scale=960:540" | |
set "vf10=-vf pp=ac,scale=720:480" | |
rem set "vf8=-vf pp7=16:0,scale=1280:720:sws_dither=none" | |
rem set "vf9=-vf pp7=16:0,scale=960:540:sws_dither=none" | |
rem set "vf10=-vf pp7=16:0,scale=720:480:sws_dither=none" | |
set "vf11=-vf scale=1280:720" | |
set "vf12=-vf framestep=50" | |
set "vf13=-vf framestep=100" | |
rem set "vf13=-vf select=eq^(pict_type^\,I^),framestep=50" | |
rem 疑似foreachループで変数を展開して引数を表示 | |
rem ループ用 | |
set i=0 | |
setlocal enabledelayedexpansion | |
:foreach | |
rem callで変数vfを遅延展開、!で巻き込まれないようにする | |
call set vfecho=%%vf!i!%% | |
rem 変数vfvarが定義されている場合のみ実行、gotoループでその間のみ実行 | |
if defined vfecho ( | |
echo vf!i!:!vfecho! | |
set /a i+=1 | |
goto :foreach | |
) | |
rem 聞く | |
set /p i=ビデオフィルタ選択:vf | |
rem callで変数内の変数を遅延展開 | |
call set vf=%%vf!i!%% | |
setlocal disabledelayedexpansion | |
echo vf:%vf% | |
echo. | |
rem ==========出力形式選択========== | |
echo ffplay:再生 | |
echo gif:ImageMagick、FFmpeg | |
echo mp4:h264_qsv LA-ICQ。品質、GOP長選択機能。 | |
echo avi:rawvideo、pcm_s16le出力。連番機能。 | |
echo jpg:コマ数かキーフレーム選択。 | |
echo png:コマ数かキーフレーム選択。 | |
set /p gif_or_mp4=出力形式を選択[gif、mp4、avi、jpg、png]: | |
echo. | |
call :%gif_or_mp4% %1 | |
exit /b | |
rem ==========カット時刻の計算サブルーチン========== | |
rem ----------hms表記のプレイヤ(秒単位)---------- | |
:cutcal_hms | |
set /p SS=カット開始時刻を入力[例:0時間1分23秒=000123]: | |
set /p TT=カット終了時刻を入力: | |
rem 秒になおす計算 | |
set /a SS=(%SS:~0,2%*3600+%SS:~2,2%*60+%SS:~4,2%) | |
set /a TT=(%TT:~0,2%*3600+%TT:~2,2%*60+%TT:~4,2%) | |
rem カット開始時刻と終了時刻の差を計算 | |
set /a T=(%TT%-%SS%) | |
rem カット開始秒と終了までの秒数を表示し、再入力するか聞く | |
set ask_again= | |
set /p ask_again=カット開始秒は%SS%、カット終了までの秒数は%T%ですが、よろしいですか[Enter/n]: | |
echo. | |
if not "%ask_again%" == "" ( | |
goto :cutcal_hms | |
) | |
rem ffmpegの引数を追加 | |
set "SS=-ss %SS%" | |
set "T=-t %T%" | |
exit /b | |
rem ----------ffplay等の秒数表記のプレイヤ(ミリ秒単位)---------- | |
rem tsファイルのptsズレに対応 | |
:cutcal_ffplay | |
rem カット開始時刻と終了時刻をffplayに表示されているミリ秒数で入力 | |
set /p SS=カット開始時刻を入力[例:0時間1分23秒4=000123.400s="000123400"ms]: | |
set /p TT=カット終了時刻を入力: | |
rem カット開始時刻と終了時刻の差を計算 | |
set /a T=(%TT%-%SS%) | |
rem ffprobeの-show_entriesスイッチを使ってformat=start_timeを出力し環境変数start_timeに設定 | |
for /f "delims=" %%a in ('ffprobe -v quiet -i %1 -show_entries format^=start_time -of default^=noprint_wrappers^=1:nokey^=1') do ( | |
set "start_time=%%a" | |
) | |
rem ffplayの表示から入力したカット開始時間-ffprobeで取得したstart_time(tsファイル等は開始時間がズレている場合があるため)(小数点を抜きミリ秒単位で計算) | |
rem 39533.817722 | |
set /a SS=(%SS%-%start_time:~0,-7%%start_time:~-6,-3%) | |
rem ミリ秒を秒に戻し桁揃え | |
set SS=%SS:~0,-3%.%SS:~-3% | |
set T=%T:~0,-3%.%T:~-3% | |
rem カット開始秒と終了までの秒数を表示し、再入力するか聞く | |
set ask_again= | |
set /p ask_again=カット開始秒は%SS%、カット終了までの秒数は%T%ですが、よろしいですか[Enter/n]: | |
echo. | |
if not "%ask_again%" == "" ( | |
goto :cutcal_ffplay | |
) | |
rem ffmpegの引数を追加 | |
set "SS=-ss %SS%" | |
set "T=-t %T%" | |
exit /b | |
rem ==========出力形式選択サブルーチン========== | |
rem ----------ffplay---------- | |
:ffplay | |
ffplay %SS% -i %1 %T% %vf% | |
exit /b | |
rem ----------gif---------- | |
:gif | |
rem フレームレートを入力 | |
set /p framerate=フレームレートを入力[5、10、24、30等]: | |
rem ffmpegでカット、インタレ解除、ノイズ除去、リサイズ、avi出力 | |
ffmpeg -y -hide_banner %SS% -i %1 %T% -an %vf% -c:v rawvideo "%~dpn1\temp.avi" | |
rem ffmpegでaviからpngを切り出し | |
ffmpeg -y -hide_banner -i "%~dpn1\temp.avi" -c:v png -r %framerate% "%~dpn1\%%05d.png" | |
rem imagemagickで複数のpngをgifに変換 | |
magick convert "%~dpn1\*.png" -layers Optimize "%~dpn1\%~n1.gif" | |
exit /b | |
rem ----------mp4---------- | |
:mp4 | |
rem 品質を入力 | |
set /p quality=crf又はglobal_qualityの値[LA-ICQ:27,x265:25]: | |
rem 入力された数値を元に音声オプションを選択し環境変数へ格納 | |
set /p audio_option=音声オプションを選択[128,256,320,copy,an]: | |
if "%audio_option%" == "128" ( | |
set audio_option=-c:a aac -b:a 128k | |
) else if "%audio_option%" == "256" ( | |
set audio_option=-c:a aac -b:a 256k | |
) else if "%audio_option%" == "320" ( | |
set audio_option=-c:a aac -b:a 320k | |
) else if "%audio_option%" == "copy" ( | |
set audio_option=-c:a copy -bsf:a aac_adtstoasc | |
) else if "%audio_option%" == "an" ( | |
set audio_option=-an | |
) | |
rem 入力された数値を元にGOPオプションを選択し環境変数へ格納 | |
set /p gop_option=GOPオプションを選択[p:保存用、s:ストリーミング用(closed gop)]: | |
if "%gop_option%" == "p" ( | |
set gop=30 | |
set bf=16 | |
) else if "%gop_option%" == "s" ( | |
set gop=15 | |
set bf=2 | |
) | |
rem PID | |
ffmpeg -hide_banner -i %1 | |
set /p pid_need=必要があればPIDを入力[-map i:0x140 -map i:0x141]: | |
rem ffmpegでカット、インタレ解除、ノイズ除去、リサイズ、mp4出力 | |
set /p encoder_option=エンコーダを選択[qsv,x265]: | |
:loop | |
if "%encoder_option%" == "qsv" ( | |
ffmpeg -y -hide_banner -analyzeduration 30M -probesize 100M -fflags +discardcorrupt %SS% -i %1 %T% %audio_option% %vf% -global_quality %quality% -c:v h264_qsv -preset:v veryslow -g %gop% -bf %bf% -refs 4 -b_strategy 1 -look_ahead 1 -look_ahead_depth 60 -pix_fmt nv12 -bsf:v h264_metadata=colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 %pid_need% -movflags +faststart "%~dpn1\%~n1.mp4" | |
) else if "%encoder_option%" == "x265" ( | |
ffmpeg -y -hide_banner -analyzeduration 30M -probesize 100M -fflags +discardcorrupt %SS% -i %1 %T% %audio_option% %vf% -c:v libx265 -preset:v fast -x265-params crf=%quality%:rc-lookahead=40:psy-rd=0.3:keyint=%gop%:no-open-gop:bframes=%bf%:rect=1:amp=1:me=umh:subme=3:ref=3:rd=3 -pix_fmt yuv420p -bsf:v hevc_metadata=colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 %pid_need% -movflags +faststart "%~dpn1\%~n1.mp4" | |
) | |
rem 稀にQSVのトランスコードに失敗すると"Error during encoding: device failed (-17)"が返されエンコに失敗してしまうので、ファイルサイズが0バイトなら失敗とみなしループさせて復旧を試みる | |
rem 終了コードが1且つループカウントが50以下までの間、エンコードを試みる | |
if "%errorlevel%" equ "1" ( | |
if "%cnt%" leq "50" ( | |
set /a cnt+=1 | |
timeout /t 10 | |
goto :encode | |
) else ( | |
goto :err | |
) | |
) | |
exit /b | |
rem ----------avi---------- | |
:avi | |
rem 同じ名前のファイルがあれば連番付け(編集向け機能) | |
set cnt=1 | |
if not exist "%~dpn1\%~n1_%cnt%.avi" ( | |
call :avienc %1 | |
) else if exist "%~dpn1\%~n1_%cnt%.avi" ( | |
:loop | |
set /a cnt+=1 | |
if not exist "%~dpn1\%~n1_%cnt%.avi" ( | |
call :avienc %1 | |
) else if exist "%~dpn1\%~n1_%cnt%.avi" ( | |
goto :loop | |
) | |
) | |
exit /b | |
:avienc | |
ffmpeg -hide_banner %SS% -i %1 %T% %vf% -c:v rawvideo -c:a pcm_s16le "%~dpn1\%~n1_%cnt%.avi" | |
exit /b | |
rem ----------jpg---------- | |
:jpg | |
rem キーフレームかコマ数出力か | |
set /p key_or_rate=キーフレームかコマ数出力か選択[k:キーフレーム、r:コマ数]: | |
if "%key_or_rate%" == "k" ( | |
ffmpeg -hide_banner -an -skip_frame nokey %SS% -i %1 %T% %vf% -f image2 -q:v 0 -vsync 0 "%~dpn1\%%05d.jpg" | |
) else if "%key_or_rate%" == "r" ( | |
ffmpeg -hide_banner -an %SS% -i %1 %T% %vf% -f image2 -q:v 0 -r 0.5 "%~dpn1\%%05d.jpg" | |
) | |
exit /b | |
rem ----------png---------- | |
:png | |
rem キーフレームかコマ数出力か | |
set /p key_or_rate=キーフレームかコマ数出力か選択[k:キーフレーム、r:コマ数]: | |
if "%key_or_rate%" == "k" ( | |
ffmpeg -hide_banner -an -skip_frame nokey %SS% -i %1 %T% %vf% -vsync 0 "%~dpn1\%%05d.png" | |
) else if "%key_or_rate%" == "r" ( | |
ffmpeg -hide_banner -an %SS% -i %1 %T% %vf% -c:v png -r 0.5 "%~dpn1\%%05d.png" | |
) | |
exit /b |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment