Functions/GenXdev.Media.ytdlp/StabilizeVideo.ps1
|
<##############################################################################
Part of PowerShell module : GenXdev.Media.ytdlp Original cmdlet filename : StabilizeVideo.ps1 Original author : René Vaessen / GenXdev Version : 2.3.2026 ################################################################################ Copyright (c) René Vaessen / GenXdev Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ################################################################################> <# .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. .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 $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 } |