Skip to content

Instantly share code, notes, and snippets.

@yujinlin0224
Created October 1, 2022 08:04
Show Gist options
  • Save yujinlin0224/b239b552add72ca0b58dbbc49e87877f to your computer and use it in GitHub Desktop.
Save yujinlin0224/b239b552add72ca0b58dbbc49e87877f to your computer and use it in GitHub Desktop.
VideoTrumbnailMaker.ps1 (2018/07/22)
param (
[Parameter(Mandatory=$True)] [String] $InputPath,
[Parameter(Mandatory=$True)] [String] $OutputDir = [System.IO.Path]::GetDirectoryName("$InputPath"),
[Parameter(Mandatory=$False)] [String] $OutputType = "png",
[Parameter(Mandatory=$True)] [Int] $XCount,
[Parameter(Mandatory=$True)] [Int] $YCount,
[Parameter(Mandatory=$True)] [Int] $Width,
[Parameter(Mandatory=$True)] [Int] $Height
)
$TempFloder = ($env:temp -Replace "\\$") + "\ffmpeg_montage\"
$FFmpegPath = "D:\Program Files\Video Tools\ffmpeg\bin\ffmpeg.exe"
$FFprobePath = "D:\Program Files\Video Tools\ffmpeg\bin\ffprobe.exe"
$MontagePath = "C:\Program Files\ImageMagick-7.0.7-Q16-HDRI\montage.exe"
$InputFileTypes = (
"*.3g2", "*.3gp", "*.avi", "*.flv", "*.mkv", "*.mov", "*.mp4", "*.ogv", "*.swf", "*.ts", "*.webm", "*.wmv"
)
$OutputType = $OutputType -Replace "^\."
# Get-ChildItem -Path $TempFloder -Recurse -ErrorAction 'Ignore' | Remove-Item -Force -Recurse
# Remove-Item $TempFloder -Force -ErrorAction 'Ignore' | Out-Null
New-Item $TempFloder -Type Directory -Force | Out-Null
Function RunProcess($ExecPath, $ExecArgs) {
$ProcessStartInfo = New-Object System.Diagnostics.ProcessStartInfo
$ProcessStartInfo.RedirectStandardOutput = $True
$ProcessStartInfo.UseShellExecute = $False
$ProcessStartInfo.FileName = $ExecPath
$ProcessStartInfo.Arguments = $ExecArgs
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessStartInfo
$Process.Start() | Out-Null
Write-Output $Process
}
Function GetVideoInfo($FilePath) {
Write-Host "Getting video infomation . . . " -ForegroundColor "Yellow"
$ExecArgs = "-v ""warning"" ""$FilePath"" -show_entries ""format"" -show_streams -select_streams ""v"" -print_format ""json"""
Write-Host "$ ""$FFprobePath"" $ExecArgs" -ForegroundColor "Green"
$Process = RunProcess $FFprobePath $ExecArgs
# $Process.WaitForExit()
$OutputJson = $Process.StandardOutput.ReadToEnd() | ConvertFrom-Json
If ($OutputJson.format.duration -Eq $Null) {
Write-Host "Error get video duration." -ForegroundColor Red
return $Null
} Else {
$Duration = $OutputJson.format.duration.ToDecimal($Null)
}
If ($OutputJson.streams[0].avg_frame_rate -Eq $Null) {
Write-Host "Error get video fps." -ForegroundColor Red
return $Null
} Else {
$FPSStrings = $OutputJson.streams[0].avg_frame_rate -Split "/"
if ($FPSStrings[1].ToDecimal($Null) -Eq 0) {
$FPSStrings = $OutputJson.streams[0].r_frame_rate -Split "/"
}
$FPS = $FPSStrings[0].ToDecimal($Null) / $FPSStrings[1].ToDecimal($Null)
}
If ($OutputJson.streams[0].display_aspect_ratio -Eq $Null) {
Write-Host "Error get video ratio." -ForegroundColor Red
return $Null
} Else {
$RatioStrings = $OutputJson.streams[0].display_aspect_ratio -Split ":"
$Ratio = $RatioStrings[0].ToDecimal($Null) / $RatioStrings[1].ToDecimal($Null)
If (($Ratio -Eq $Null) -Or ($Ratio -Le 0)) {
$Ratio = $OutputJson.streams[0].width.ToDecimal($Null) / $OutputJson.streams[0].height.ToDecimal($Null)
}
}
return $Duration, $FPS, $Ratio
}
Function MakeVideoTrumbnail($FilePath, $Duration, $FPS, $Ratio) {
$FileName = [System.IO.Path]::GetFileName("$FilePath")
$TrumbnailTempFloder = $TempFloder + $FileName + "\"
New-Item $TrumbnailTempFloder -Type Directory -Force | Out-Null
Write-Host ("Getting video trumbnail per {0} . . . " -F ("{0:HH:mm:ss.fff}" -F
[datetime]([TimeSpan]::FromSeconds($Duration / ($XCount * $YCount))).Ticks)) -ForegroundColor Yellow
If (($Width -Gt 0) -And ($Height -Le 0)) {
$Height = [Math]::Round($Width / $Ratio)
} ElseIf (($Width -Le 0) -And ($Height -Gt 0)) {
$Width = [Math]::Round($Height * $Ratio)
} ElseIf (($Width -Le 0) -And ($Height -Le 0)) {
Write-Host "Error arguments ""width"" or ""height""." -ForegroundColor Red
return $Null
}
$Time = ($Duration / ($XCount * $YCount)) / 2
While ($Time -lt $Duration) {
$TimeString = "{0:HH:mm:ss.fff}" -F [DateTime]([TimeSpan]::FromSeconds($Time)).Ticks
$OutputPath = "$TrumbnailTempFloder{0}.$OutputType" -F (($TimeString -Replace ":", ".") -Replace "\.", "-")
$ExecArgs = "-v ""warning"" -y -ss $TimeString -i ""$FilePath"" -vf scale=${Width}:${Height} -frames:v 1 ""$OutputPath"""
Write-Host "$ ""$FFmpegPath"" $ExecArgs" -ForegroundColor Green
$Process = RunProcess $FFmpegPath $ExecArgs
$Process.WaitForExit()
$Time += $Duration / ($XCount * $YCount)
}
Write-Host "Merge trumbnails to one image . . . " -ForegroundColor Yellow
$ExecArgs = "-tile ${XCount}x${YCount} -geometry +0+0 ""$TrumbnailTempFloder*.$OutputType"" ""$OutputDir\$FileName.$OutputType"""
Write-Host "$ ""$MontagePath"" $ExecArgs" -ForegroundColor Green
$Process = RunProcess $MontagePath $ExecArgs
$Process.WaitForExit()
# Get-ChildItem -Path $TrumbnailTempFloder -Recurse | Remove-Item -Force -Recurse
# Remove-Item $TrumbnailTempFloder -Force | Out-Null
}
$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
$FileCount = 0
If (($InputPath[$InputPath.Length - 1] -Eq "\") -Or ($InputPath[$InputPath.Length - 1] -Eq "/")) {
Get-ChildItem -Path $InputPath -Include $InputFileTypes -Recurse | ForEach-Object {
Write-Host ("Start making trumbnail form file ""{0}"" at dictionary ""$InputPath""" -F $_.FullName) -ForegroundColor Cyan
$Duration, $FPS, $Ratio = GetVideoInfo $_.FullName
Write-Host ("Getted => Duration: {0}; FPS: $FPS; Ratio: $Ratio;" -F ("{0:HH:mm:ss.fff}" -F
[DateTime]([TimeSpan]::FromSeconds($Duration)).Ticks)) -ForegroundColor Yellow
if (($Duration -Eq $Null) -Or ($FPS -Eq $Null) -Or ($Ratio -Eq $Null)) {
Write-Host "Fail to load file ""{0}"" at dictionary ""$InputPath""." -F $_.FullName -ForegroundColor Red
Return
}
MakeVideoTrumbnail $_.FullName $Duration $FPS $Ratio
$FileCount += 1
}
} Else {
Write-Host "Start making trumbnail form file {0}" -F $InputPath -ForegroundColor Cyan
$Duration, $FPS, $Ratio = GetVideoInfo $InputPath
if (($Duration -Eq $Null) -Or ($FPS -Eq $Null) -Or ($Ratio -Eq $Null)) {
Write-Host "Fail to load file ""$InputPath""." -ForegroundColor Red
Return
}
MakeVideoTrumbnail $InputPath $Duration $FPS $Ratio
$FileCount += 1
}
$Stopwatch.Stop()
Write-Host ("Completed $FileCount files. Total spent {0} second(s), average {1} second(s)" -F
$Stopwatch.Elapsed.TotalSeconds, ($Stopwatch.Elapsed.TotalSeconds / $FileCount)) -ForegroundColor Cyan
# Remove-Item $TempFloder -Force | Out-Null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment