Inital push

This commit is contained in:
2026-05-19 14:55:09 -04:00
commit 7f2f0754b3
29 changed files with 3190 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
<#
.SYNOPSIS
Extracts a specific frame or the last frame of a video file to a PNG image using ffmpeg.
.PARAMETER Video
Path to the input video file. Can be absolute or relative to current directory.
.PARAMETER Image
Path to the output PNG image file. Can be absolute or relative to current directory.
.PARAMETER Frame
0-based frame index to extract. Negative values count from the end:
-1 extracts the last frame (default), -2 extracts second-to-last, etc.
The resulting frame index is clamped to the valid range (0 to total frames - 1).
.DESCRIPTION
Extracts a specific frame of a video file to a PNG image using ffmpeg.
Supports negative frame indices to count from the end of the video.
Supports -WhatIf and -Confirm for safe execution.
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory = $true)]
[string]$Video,
[Parameter(Mandatory = $true)]
[string]$Image,
[Parameter(Mandatory = $false)]
[int]$Frame = -1
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$VideoPath = $Video
if (-not (Test-Path $VideoPath)) {
Write-Error ('Video file not found: {0}' -f $VideoPath)
exit 1
}
$PSNativeCommandUseErrorActionPreference = $false
$totalFrames = & ffprobe -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -of csv=p=0 $VideoPath 2>&1 | Select-Object -First 1
if (-not $totalFrames -or $totalFrames -notmatch '^\d+$') {
Write-Error ('Could not determine frame count for: {0}' -f $VideoPath)
exit 1
}
$totalFramesInt = [int]$totalFrames
$maxFrameIndex = $totalFramesInt - 1
$frameToExtract = if ($Frame -lt 0) {
# Negative values count from the end
$calculatedFrame = $totalFramesInt + $Frame
# Clamp to valid range [0, maxFrameIndex]
[Math]::Max(0, [Math]::Min($calculatedFrame, $maxFrameIndex))
} else {
# Positive values are direct indices
if ($Frame -gt $maxFrameIndex) {
Write-Error ('Frame index {0} is out of range. Valid range: 0 to {1}' -f $Frame, $maxFrameIndex)
exit 1
}
$Frame
}
Write-Host ('Total frames: {0} - extracting frame index {1}' -f $totalFramesInt, $frameToExtract)
if ($PSCmdlet.ShouldProcess($Image, ('Extract frame {0} to PNG' -f $frameToExtract))) {
$videoFilter = 'select=eq(n\,{0})' -f $frameToExtract
$ffmpegStderr = & ffmpeg -y -i $VideoPath -vf $videoFilter -vsync vfr -frames:v 1 -q:v 1 $Image 2>&1
if ($LASTEXITCODE -ne 0) {
$ffmpegStderr | ForEach-Object { Write-Error $_ }
Write-Error 'ffmpeg failed to extract the last frame.'
exit 1
}
Write-Host ('Frame saved to: {0}' -f $Image)
}