Skip to content

Instantly share code, notes, and snippets.

@JonLevin25
Created September 3, 2023 15:27
Show Gist options
  • Save JonLevin25/7bc92baab754da6379aa538061e2637a to your computer and use it in GitHub Desktop.
Save JonLevin25/7bc92baab754da6379aa538061e2637a to your computer and use it in GitHub Desktop.
Powershell / FFMPEG - multiple clips from multiple input videos. Configurable audio/video fade
####
## 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