Created
September 3, 2023 15:27
-
-
Save JonLevin25/7bc92baab754da6379aa538061e2637a to your computer and use it in GitHub Desktop.
Powershell / FFMPEG - multiple clips from multiple input videos. Configurable audio/video fade
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
#### | |
## Config | |
# FFMPEG | |
$ffmpegPath = "ffmpeg.exe" | |
$ffplayPath = "ffplay.exe" | |
#$isPreview = $true # Uncomment to preview (ffplay) instead of transcoding. | |
# OUTPUT | |
$outputFolder = "./transcoded_output" | |
# TIMES | |
$video_fade_in_secs = 0 | |
$video_fade_out_secs = 1.5 | |
$audio_fade_in_secs = 2 | |
$audio_fade_out_secs = 6 | |
#### | |
## DATA | |
# Helper path vars (REPLACE ME) | |
$color_corrected = "./One Long shot.mp4" | |
$no_color = "./One Long shot_no color.mp4" | |
$stabalizer = "./One Long shot_nocolor+_withstabalizer.mp4" | |
# Clip list (REPLACE ME) | |
$clips = @( | |
@{ 'start' = "00:08"; 'end' = "20"; 'file' = $color_corrected; } | |
@{ 'start' = "00:07"; 'end' = "1:20"; 'file' = $color_corrected; } | |
@{ 'start' = "01:30"; 'end' = "2:30"; 'file' = $color_corrected; } | |
@{ 'start' = "01:30"; 'end' = "2:30" ; 'file' = $no_color; } | |
@{ 'start' = "02:47"; 'end' = "4:06"; 'file' = $no_color; } | |
) | |
#### | |
## Helper functions | |
function parse_seconds($timestr) { | |
# Note: does not support fractions for now. | |
# check if int passed in (ParseExact with 's' fmt == doesn't work.) | |
[int]$secs = $null | |
if ([int32]::TryParse($a , [ref]$secs )) { | |
return $secs | |
} | |
$formats = @( | |
'ss', | |
'm\:s', | |
'h\:m\:s' | |
) | |
foreach ($fmt in $formats) { | |
try { | |
return [int][datetime]::ParseExact($timestr, "$fmt", $null).TimeOfDay.TotalSeconds | |
} | |
catch { } | |
} | |
throw "Could not parse_seconds from the timestamp $timestr !" | |
} | |
#### | |
## MAIN | |
New-Item -Path "$outputFolder" -ItemType Directory -Force | |
foreach ($clip in $clips) { | |
$inputFile = $clip['file'] | |
$startTime = $clip['start'] | |
$endTime = $clip['end'] | |
# Colons are problematic for filters + filenames. so get seconds. Also needed for fade calculations later. | |
$startTimeSecs = parse_seconds("$startTime") | |
$endTimeSecs = parse_seconds("$endtime") | |
$durationSecs = $endTimeSecs - $startTimeSecs | |
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($inputFile) | |
$outputFile = "$outputFolder/${baseName}_${startTimeSecs}-${endTimeSecs}.mp4" | |
$fadeOutStart = $endtimeSecs - $fade_in_secs | |
$fadeInStart = $startTimeSecs | |
#### | |
## build filters | |
$has_vfade_in = $video_fade_in_secs -gt 0 | |
$has_vfade_out = $video_fade_out_secs -gt 0 | |
$has_afade_in = $audio_fade_in_secs -gt 0 | |
$has_afade_out = $audio_fade_out_secs -gt 0 | |
$vfilter = "" | |
$afilter = "" | |
if ($has_vfade_in) { $vfilter += "fade=t=in:st=${startTimeSecs}:d=${video_fade_in_secs}" } | |
if ($has_afade_in -gt 0) { $afilter += "afade=t=in:st=${startTimeSecs}:d=${audio_fade_in_secs}" } | |
if ($has_vfade_in -and $has_vfade_out) { $vfilter += "," } | |
if ($has_afade_in -and $has_afade_out) { $afilter += "," } | |
if ($has_vfade_out) { $vfilter += "fade=t=out:st=$($endTimeSecs-$video_fade_out_secs):d=${video_fade_out_secs}" } | |
if ($has_afade_out) { $afilter += "afade=t=out:st=$($endTimeSecs-$audio_fade_out_secs):d=${audio_fade_out_secs}" } | |
#### | |
## Actual command | |
echo "Transcoding (time: $startTime -> $endTime, file: $inputFile -> $outputFile)" | |
echo "vfilter: $vfilter" | |
echo "afilter: $afilter" | |
echo "----------------------`n`n`n`n" | |
if ($isPreview) { | |
& $ffplayPath -i $inputFile -ss "$startTime" -t "$durationSecs" -vf "$vfilter" -af "$afilter" | |
} else { | |
& $ffmpegPath -i $inputFile -ss "$startTime" -to "$endTime" -vf "$vfilter" -af "$afilter" "$outputFile" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment