Functions/GenXdev.Media/StabilizeVideo.ps1
|
<# .SYNOPSIS Stabilizes the newest or specified .mp4 file using FFmpeg + vid.stab (no black borders). .DESCRIPTION Two-pass vid.stab stabilization with optzoom=1 (auto zoom/crop so borders never show) plus light sharpening. Works exactly like your Save-Video cmdlet — super simple. .LICENSE Copyright (C) 2026 René Vaessen / GenXdev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. .PARAMETER InputFile Optional: specific .mp4 to stabilize. If omitted, uses the newest .mp4 in the folder. .EXAMPLE Stabilize-Video # stabilizes the most recent .mp4 Stabilize-Video shaky.mp4 # specific file #> function StabilizeVideo { [CmdletBinding()] param ( [Parameter(Mandatory = $false, Position = 0)] [string]$InputFile ) # ------------------------------------------------------------------ # 1. Find the input file (newest .mp4 if not specified) # ------------------------------------------------------------------ if (-not $InputFile) { $InputFile = Microsoft.PowerShell.Management\Get-ChildItem *.mp4 | Microsoft.PowerShell.Utility\Sort-Object LastWriteTime -Descending | Microsoft.PowerShell.Utility\Select-Object -First 1 -ExpandProperty FullName if (-not $InputFile) { throw "No .mp4 file found in the current folder." } Microsoft.PowerShell.Utility\Write-Host "Using newest file: $(Microsoft.PowerShell.Management\Split-Path $InputFile -Leaf)" -ForegroundColor Cyan } if (-not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $InputFile)) { throw "File not found: $InputFile" } $file = Microsoft.PowerShell.Management\Get-Item $InputFile $dir = $file.DirectoryName $base = $file.BaseName $ext = $file.Extension $output = Microsoft.PowerShell.Management\Join-Path $dir "$base [stabilized]$ext" $trf = Microsoft.PowerShell.Management\Join-Path $dir "transforms.trf" # ------------------------------------------------------------------ # 2. Pass 1 – detect camera motion # ------------------------------------------------------------------ Microsoft.PowerShell.Utility\Write-Host "Pass 1/2: Analyzing shakiness..." -ForegroundColor Green ffmpeg -y -i $file -vf vidstabdetect=shakiness=8:accuracy=15 -f null NUL if ($LASTEXITCODE -ne 0) { throw "vidstabdetect failed" } # ------------------------------------------------------------------ # 3. Pass 2 – apply stabilization (no black borders!) # ------------------------------------------------------------------ Microsoft.PowerShell.Utility\Write-Host "Pass 2/2: Stabilizing & cropping (this may take a while)..." -ForegroundColor Green ffmpeg -y -i $file -vf " vidstabtransform=input=$trf:optzoom=1:crop=black:zoom=3:smoothing=20, unsharp=5:5:0.8:3:3:0.4" ` -c:v libx264 -preset slow -crf 23 -tune film ` -c:a copy ` "$output" if ($LASTEXITCODE -ne 0) { throw "vidstabtransform failed" } # ------------------------------------------------------------------ # 4. Cleanup & finish # ------------------------------------------------------------------ Microsoft.PowerShell.Management\Remove-Item $trf -ErrorAction SilentlyContinue Microsoft.PowerShell.Utility\Write-Host "Done! Stabilized video saved as:" -ForegroundColor Green Microsoft.PowerShell.Utility\Write-Host " $(Microsoft.PowerShell.Management\Split-Path $output -Leaf)" -ForegroundColor Yellow # Return the new file so you can pipe it (e.g. | Invoke-Item) Microsoft.PowerShell.Management\Get-Item $output } |