Add printf-style numbering token support to Get-LastFrame.ps1 for -Image parameter (e.g. frame_%04d.png), resolving token to actual 0-based frame index before passing to ffmpeg to avoid image2 sequence counter behavior, with automatic output directory creation when path does not exist and updated documentation matching Get-FramesRange.ps1 functionality
This commit is contained in:
1 parent
c057f804bf
commit
9088022ef7
1 file changed
+41
-3
+41
-3
@@ -5,6 +5,10 @@
|
|||||||
Path to the input video file. Can be absolute or relative to current directory.
|
Path to the input video file. Can be absolute or relative to current directory.
|
||||||
.PARAMETER Image
|
.PARAMETER Image
|
||||||
Path to the output PNG image file. Can be absolute or relative to current directory.
|
Path to the output PNG image file. Can be absolute or relative to current directory.
|
||||||
|
Supports a printf-style numbering token (e.g. frame_%04d.png or C:\Output\frame_%04d.png), which is
|
||||||
|
replaced with the extracted 0-based frame index, zero-padded to the width given in the token
|
||||||
|
(%d = no padding, %04d = 4 digits). Without a token the path is used literally.
|
||||||
|
The output directory is created when it does not exist.
|
||||||
.PARAMETER Frame
|
.PARAMETER Frame
|
||||||
0-based frame index to extract. Negative values count from the end:
|
0-based frame index to extract. Negative values count from the end:
|
||||||
-1 extracts the last frame (default), -2 extracts second-to-last, etc.
|
-1 extracts the last frame (default), -2 extracts second-to-last, etc.
|
||||||
@@ -12,6 +16,7 @@
|
|||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Extracts a specific frame of a video file to a PNG image using ffmpeg.
|
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 negative frame indices to count from the end of the video.
|
||||||
|
Supports a printf-style numbering token in -Image, like Get-FramesRange.ps1.
|
||||||
Supports -WhatIf and -Confirm for safe execution.
|
Supports -WhatIf and -Confirm for safe execution.
|
||||||
#>
|
#>
|
||||||
[CmdletBinding(SupportsShouldProcess)]
|
[CmdletBinding(SupportsShouldProcess)]
|
||||||
@@ -64,9 +69,42 @@ $frameToExtract = if ($Frame -lt 0) {
|
|||||||
|
|
||||||
Write-Host ('Total frames: {0} - extracting frame index {1}' -f $totalFramesInt, $frameToExtract)
|
Write-Host ('Total frames: {0} - extracting frame index {1}' -f $totalFramesInt, $frameToExtract)
|
||||||
|
|
||||||
if ($PSCmdlet.ShouldProcess($Image, ('Extract frame {0} to PNG' -f $frameToExtract))) {
|
# Resolve any printf-style numbering token (%d, %04d) in -Image to the extracted frame
|
||||||
|
# index. The substitution is done here rather than left to ffmpeg: ffmpeg would treat the
|
||||||
|
# token as an image2 sequence counter starting at 1 instead of the actual video frame index.
|
||||||
|
$ImagePath = $Image
|
||||||
|
$tokenPattern = [regex]'%(\d*)d'
|
||||||
|
while ($ImagePath -match $tokenPattern) {
|
||||||
|
$padWidth = if ($Matches[1]) { [int]$Matches[1] } else { 0 }
|
||||||
|
$ImagePath = $tokenPattern.Replace($ImagePath, ([string]$frameToExtract).PadLeft($padWidth, '0'), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ImagePath -ne $Image) {
|
||||||
|
Write-Host ('Output pattern resolved to: {0}' -f $ImagePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
$outputDir = Split-Path -Parent $ImagePath
|
||||||
|
if ($outputDir -and -not (Test-Path -LiteralPath $outputDir)) {
|
||||||
|
if ($PSCmdlet.ShouldProcess($outputDir, 'Create output directory')) {
|
||||||
|
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
|
||||||
|
Write-Host ('Created output directory: {0}' -f $outputDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PSCmdlet.ShouldProcess($ImagePath, ('Extract frame {0} to PNG' -f $frameToExtract))) {
|
||||||
$videoFilter = 'select=eq(n\,{0})' -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
|
|
||||||
|
$ffmpegArgs = @(
|
||||||
|
'-y'
|
||||||
|
'-i', $VideoPath
|
||||||
|
'-vf', $videoFilter
|
||||||
|
'-vsync', 'vfr'
|
||||||
|
'-frames:v', '1'
|
||||||
|
'-q:v', '1'
|
||||||
|
'--', $ImagePath
|
||||||
|
)
|
||||||
|
|
||||||
|
$ffmpegStderr = & ffmpeg @ffmpegArgs 2>&1
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
$ffmpegStderr | ForEach-Object { Write-Error $_ }
|
$ffmpegStderr | ForEach-Object { Write-Error $_ }
|
||||||
@@ -74,5 +112,5 @@ if ($PSCmdlet.ShouldProcess($Image, ('Extract frame {0} to PNG' -f $frameToExtra
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host ('Frame saved to: {0}' -f $Image)
|
Write-Host ('Frame saved to: {0}' -f $ImagePath)
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user