Fix -Frames negative range calculation to extract last N frames correctly (off-by-one error), add validation to reject invalid '-%' and '-0' formats with exit code 1, change '%' alone to extract single last frame instead of range, remove duplicate last frame from PNG sequence concat list, update Get-LastFrame.ps1 and Get-Frame.ps1 to clamp out-of-range frame indices instead of erroring and improve error messages with inline stderr output, add -y flag and -- separator to ffprobe calls, replace deprecated
This commit is contained in:
1 parent
cf41fb0ce5
commit
1227c6e153
13 files changed
+100
-86
No files matched your search
+13
-6
@@ -36,7 +36,7 @@
|
|||||||
- start-end: Extract frames from start to end (e.g., "100-200")
|
- start-end: Extract frames from start to end (e.g., "100-200")
|
||||||
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
||||||
- -negative_number: Extract last N frames (e.g., "-10")
|
- -negative_number: Extract last N frames (e.g., "-10")
|
||||||
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%", "-%")
|
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%")
|
||||||
- all: Extract all frames (same as "0-%")
|
- all: Extract all frames (same as "0-%")
|
||||||
.PARAMETER Sequence
|
.PARAMETER Sequence
|
||||||
Path to PNG file for extracted frame. Can be absolute or relative to current directory. .png extension is added if not provided. If EndFrame is -1, extracts the last frame and excludes it from the cloned video. If EndFrame is not -1, extracts the frame at EndFrame index and excludes it from the cloned video.
|
Path to PNG file for extracted frame. Can be absolute or relative to current directory. .png extension is added if not provided. If EndFrame is -1, extracts the last frame and excludes it from the cloned video. If EndFrame is not -1, extracts the frame at EndFrame index and excludes it from the cloned video.
|
||||||
@@ -228,6 +228,14 @@ if (-not [string]::IsNullOrWhiteSpace($Frames)) {
|
|||||||
Write-Error '-Frames cannot be used together with -StartFrame, -EndFrame, or -Sequence'
|
Write-Error '-Frames cannot be used together with -StartFrame, -EndFrame, or -Sequence'
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
if ($Frames -match '^-.*%') {
|
||||||
|
Write-Error "Invalid Frames format '$Frames': '-%' is not supported. Use '%' for the last frame, or -N for the last N frames."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if ($Frames -match '^-0+$') {
|
||||||
|
Write-Error "Invalid Frames format '$Frames': a negative count must be at least 1. Use -1 for the last frame."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$AudioPath = $null
|
$AudioPath = $null
|
||||||
@@ -478,13 +486,13 @@ if (Test-Path -LiteralPath $SourcePath -PathType Container) {
|
|||||||
$maxPngIndex = $pngFiles.Count - 1
|
$maxPngIndex = $pngFiles.Count - 1
|
||||||
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($Frames)) {
|
if (-not [string]::IsNullOrWhiteSpace($Frames)) {
|
||||||
$framesPattern = $Frames -replace '%', $maxPngIndex
|
$framesPattern = if ($Frames -eq '%') { "$maxPngIndex-$maxPngIndex" } else { $Frames -replace '%', $maxPngIndex }
|
||||||
if ($framesPattern -ieq 'all') { $framesPattern = "0-$maxPngIndex" }
|
if ($framesPattern -ieq 'all') { $framesPattern = "0-$maxPngIndex" }
|
||||||
if ($framesPattern -match '^(\d+)-(\d+)$') {
|
if ($framesPattern -match '^(\d+)-(\d+)$') {
|
||||||
$StartFrame = [int]$Matches[1]
|
$StartFrame = [int]$Matches[1]
|
||||||
$EndFrame = [int]$Matches[2]
|
$EndFrame = [int]$Matches[2]
|
||||||
} elseif ($framesPattern -match '^-(\d+)$') {
|
} elseif ($framesPattern -match '^-(\d+)$') {
|
||||||
$StartFrame = [Math]::Max(0, $maxPngIndex - [int]$Matches[1])
|
$StartFrame = [Math]::Max(0, $maxPngIndex - [int]$Matches[1] + 1)
|
||||||
$EndFrame = $maxPngIndex
|
$EndFrame = $maxPngIndex
|
||||||
} elseif ($framesPattern -match '^\d+$') {
|
} elseif ($framesPattern -match '^\d+$') {
|
||||||
$StartFrame = 0
|
$StartFrame = 0
|
||||||
@@ -601,7 +609,6 @@ if (Test-Path -LiteralPath $SourcePath -PathType Container) {
|
|||||||
$concatLines += "file '$pfPath'"
|
$concatLines += "file '$pfPath'"
|
||||||
$concatLines += "duration $frameDuration"
|
$concatLines += "duration $frameDuration"
|
||||||
}
|
}
|
||||||
$concatLines += "file '$($pngFiles[-1].FullName.Replace('\', '/'))'"
|
|
||||||
[System.IO.File]::WriteAllLines($concatTempFile, $concatLines, [System.Text.UTF8Encoding]::new($false))
|
[System.IO.File]::WriteAllLines($concatTempFile, $concatLines, [System.Text.UTF8Encoding]::new($false))
|
||||||
|
|
||||||
$seqFfmpegArgs = @(
|
$seqFfmpegArgs = @(
|
||||||
@@ -718,13 +725,13 @@ $totalFramesInt = [int]$totalFrames
|
|||||||
$maxFrameIndex = $totalFramesInt - 1
|
$maxFrameIndex = $totalFramesInt - 1
|
||||||
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($Frames)) {
|
if (-not [string]::IsNullOrWhiteSpace($Frames)) {
|
||||||
$framesPattern = $Frames -replace '%', $maxFrameIndex
|
$framesPattern = if ($Frames -eq '%') { "$maxFrameIndex-$maxFrameIndex" } else { $Frames -replace '%', $maxFrameIndex }
|
||||||
if ($framesPattern -ieq 'all') { $framesPattern = "0-$maxFrameIndex" }
|
if ($framesPattern -ieq 'all') { $framesPattern = "0-$maxFrameIndex" }
|
||||||
if ($framesPattern -match '^(\d+)-(\d+)$') {
|
if ($framesPattern -match '^(\d+)-(\d+)$') {
|
||||||
$StartFrame = [int]$Matches[1]
|
$StartFrame = [int]$Matches[1]
|
||||||
$EndFrame = [int]$Matches[2]
|
$EndFrame = [int]$Matches[2]
|
||||||
} elseif ($framesPattern -match '^-(\d+)$') {
|
} elseif ($framesPattern -match '^-(\d+)$') {
|
||||||
$StartFrame = [Math]::Max(0, $maxFrameIndex - [int]$Matches[1])
|
$StartFrame = [Math]::Max(0, $maxFrameIndex - [int]$Matches[1] + 1)
|
||||||
$EndFrame = $maxFrameIndex
|
$EndFrame = $maxFrameIndex
|
||||||
} elseif ($framesPattern -match '^\d+$') {
|
} elseif ($framesPattern -match '^\d+$') {
|
||||||
$StartFrame = 0
|
$StartFrame = 0
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
- start-end: Extract frames from start to end (e.g., "100-200")
|
- start-end: Extract frames from start to end (e.g., "100-200")
|
||||||
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
||||||
- -negative_number: Extract last N frames (e.g., "-10")
|
- -negative_number: Extract last N frames (e.g., "-10")
|
||||||
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%", "-%")
|
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%")
|
||||||
- all: Extract all frames (same as "0-%")
|
- all: Extract all frames (same as "0-%")
|
||||||
.PARAMETER Suffix
|
.PARAMETER Suffix
|
||||||
Text inserted into the derived -Target name before the file extension. Defaults to "-Clip" and cannot be empty.
|
Text inserted into the derived -Target name before the file extension. Defaults to "-Clip" and cannot be empty.
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ function Get-SceneList {
|
|||||||
Frames = $end - $start + 1
|
Frames = $end - $start + 1
|
||||||
StartTime = [Math]::Round($start / $Info.Fps, 3)
|
StartTime = [Math]::Round($start / $Info.Fps, 3)
|
||||||
EndTime = [Math]::Round($end / $Info.Fps, 3)
|
EndTime = [Math]::Round($end / $Info.Fps, 3)
|
||||||
|
TotalTime = [Math]::Round(($end - $start + 1) / $Info.Fps, 3)
|
||||||
Suffix = Format-SceneSuffix -Template $Template -Number ($i + 1)
|
Suffix = Format-SceneSuffix -Template $Template -Number ($i + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-15
@@ -1,13 +1,14 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Extracts a specific frame of a video file to a PNG image using Get-LastFrame.ps1, requiring -Video and -Frame parameters from that script.
|
Extracts a specific frame of a video file to a PNG image. The extraction is done by Get-LastFrame.ps1, which this script calls with an image path derived from -Video and -Frame.
|
||||||
The image filename used for the -Image parameter is automatically derived from the -Video filename, with a "-" followed by the "-Frame" value padded with zeros (at least 4 digits, wider numbers are not truncated) inserted before the image file extension (e.g., P01.mp4 for frame 10 becomes P01-0010.png).
|
The image filename used for the -Image parameter is automatically derived from the -Video filename, with a "-" followed by the "-Frame" value padded with zeros (at least 4 digits, wider numbers are not truncated) inserted before the image file extension (e.g., P01.mp4 for frame 10 becomes P01-0010.png).
|
||||||
.PARAMETER Video
|
.PARAMETER Video
|
||||||
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 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, -2 extracts second-to-last, etc.
|
||||||
The resulting frame index is clamped to the valid range (0 to total frames - 1).
|
The resulting frame index is clamped to the valid range (0 to total frames - 1): a positive value past the last frame
|
||||||
|
gives the last frame, and a negative value before the first frame gives frame 0.
|
||||||
#>
|
#>
|
||||||
[CmdletBinding(SupportsShouldProcess)]
|
[CmdletBinding(SupportsShouldProcess)]
|
||||||
param(
|
param(
|
||||||
@@ -35,8 +36,7 @@ $totalFramesOutput = & ffprobe -v error -select_streams v:0 -count_frames -show_
|
|||||||
$ffprobeExit = $LASTEXITCODE
|
$ffprobeExit = $LASTEXITCODE
|
||||||
|
|
||||||
if ($ffprobeExit -ne 0) {
|
if ($ffprobeExit -ne 0) {
|
||||||
$totalFramesOutput | ForEach-Object { Write-Error $_ }
|
Write-Error ('ffprobe failed to read video file: {0}{1}{2}' -f $VideoPath, [Environment]::NewLine, ($totalFramesOutput -join [Environment]::NewLine))
|
||||||
Write-Error ('ffprobe failed to read video file: {0}' -f $VideoPath)
|
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,19 +48,15 @@ if (-not $totalFrames -or ([string]$totalFrames).Trim() -notmatch '^\d+$') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$totalFramesInt = [int]([string]$totalFrames).Trim()
|
$totalFramesInt = [int]([string]$totalFrames).Trim()
|
||||||
|
if ($totalFramesInt -lt 1) {
|
||||||
|
Write-Error ('Video has no frames: {0}' -f $VideoPath)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
$maxFrameIndex = $totalFramesInt - 1
|
$maxFrameIndex = $totalFramesInt - 1
|
||||||
|
|
||||||
# Resolve frame index (handles negative values that count from the end)
|
# Resolve frame index (handles negative values that count from the end)
|
||||||
$frameToExtract = if ($Frame -lt 0) {
|
$requestedFrame = if ($Frame -lt 0) { $totalFramesInt + $Frame } else { $Frame }
|
||||||
$calculatedFrame = $totalFramesInt + $Frame
|
$frameToExtract = [Math]::Max(0, [Math]::Min($requestedFrame, $maxFrameIndex))
|
||||||
[Math]::Max(0, [Math]::Min($calculatedFrame, $maxFrameIndex))
|
|
||||||
} else {
|
|
||||||
if ($Frame -gt $maxFrameIndex) {
|
|
||||||
Write-Error ('Frame index {0} is out of range. Valid range: 0 to {1}' -f $Frame, $maxFrameIndex)
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
$Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
# Derive the output image path: insert "-XXXX" (zero-padded resolved frame index) before .png extension
|
# Derive the output image path: insert "-XXXX" (zero-padded resolved frame index) before .png extension
|
||||||
$videoBase = [System.IO.Path]::GetFileNameWithoutExtension($VideoPath)
|
$videoBase = [System.IO.Path]::GetFileNameWithoutExtension($VideoPath)
|
||||||
|
|||||||
+12
-3
@@ -11,7 +11,7 @@
|
|||||||
- start-end: Extract frames from start to end (e.g., "100-200")
|
- start-end: Extract frames from start to end (e.g., "100-200")
|
||||||
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
||||||
- -negative_number: Extract last N frames (e.g., "-10")
|
- -negative_number: Extract last N frames (e.g., "-10")
|
||||||
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%", "-%")
|
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%")
|
||||||
- all: Extract all frames (same as "0-%")
|
- all: Extract all frames (same as "0-%")
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Extracts specific range of frames of a video file to PNG images using ffmpeg.
|
Extracts specific range of frames of a video file to PNG images using ffmpeg.
|
||||||
@@ -40,6 +40,15 @@ if (-not (Test-Path -LiteralPath $VideoPath)) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($Frames -match '^-.*%') {
|
||||||
|
Write-Error "Invalid Frames format '$Frames': '-%' is not supported. Use '%' for the last frame, or -N for the last N frames."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if ($Frames -match '^-0+$') {
|
||||||
|
Write-Error "Invalid Frames format '$Frames': a negative count must be at least 1. Use -1 for the last frame."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
$PSNativeCommandUseErrorActionPreference = $false
|
$PSNativeCommandUseErrorActionPreference = $false
|
||||||
|
|
||||||
$totalFramesOutput = & ffprobe -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -of csv=p=0 -- $VideoPath 2>&1
|
$totalFramesOutput = & ffprobe -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -of csv=p=0 -- $VideoPath 2>&1
|
||||||
@@ -65,7 +74,7 @@ $startFrame = 0
|
|||||||
$endFrame = 0
|
$endFrame = 0
|
||||||
|
|
||||||
# Replace % with actual last frame index, and handle 'all' keyword
|
# Replace % with actual last frame index, and handle 'all' keyword
|
||||||
$framesPattern = $Frames -replace '%', $maxFrameIndex
|
$framesPattern = if ($Frames -eq '%') { "$maxFrameIndex-$maxFrameIndex" } else { $Frames -replace '%', $maxFrameIndex }
|
||||||
if ($framesPattern -ieq 'all') {
|
if ($framesPattern -ieq 'all') {
|
||||||
$framesPattern = "0-$maxFrameIndex"
|
$framesPattern = "0-$maxFrameIndex"
|
||||||
}
|
}
|
||||||
@@ -76,7 +85,7 @@ if ($framesPattern -match '^(\d+)-(\d+)$') {
|
|||||||
}
|
}
|
||||||
elseif ($framesPattern -match '^-(\d+)$') {
|
elseif ($framesPattern -match '^-(\d+)$') {
|
||||||
$negativeCount = [int]$matches[1]
|
$negativeCount = [int]$matches[1]
|
||||||
$startFrame = [Math]::Max(0, $maxFrameIndex - $negativeCount)
|
$startFrame = [Math]::Max(0, $maxFrameIndex - $negativeCount + 1)
|
||||||
$endFrame = $maxFrameIndex
|
$endFrame = $maxFrameIndex
|
||||||
}
|
}
|
||||||
elseif ($framesPattern -match '^\d+$') {
|
elseif ($framesPattern -match '^\d+$') {
|
||||||
|
|||||||
+18
-19
@@ -12,7 +12,8 @@
|
|||||||
.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.
|
||||||
The resulting frame index is clamped to the valid range (0 to total frames - 1).
|
The resulting frame index is clamped to the valid range (0 to total frames - 1): a positive value past the last frame
|
||||||
|
gives the last frame, and a negative value before the first frame gives frame 0.
|
||||||
.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.
|
||||||
@@ -36,14 +37,14 @@ $ErrorActionPreference = 'Stop'
|
|||||||
|
|
||||||
$VideoPath = $Video
|
$VideoPath = $Video
|
||||||
|
|
||||||
if (-not (Test-Path $VideoPath)) {
|
if (-not (Test-Path -LiteralPath $VideoPath)) {
|
||||||
Write-Error ('Video file not found: {0}' -f $VideoPath)
|
Write-Error ('Video file not found: {0}' -f $VideoPath)
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
$PSNativeCommandUseErrorActionPreference = $false
|
$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
|
$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+$') {
|
if (-not $totalFrames -or $totalFrames -notmatch '^\d+$') {
|
||||||
Write-Error ('Could not determine frame count for: {0}' -f $VideoPath)
|
Write-Error ('Could not determine frame count for: {0}' -f $VideoPath)
|
||||||
@@ -51,21 +52,15 @@ if (-not $totalFrames -or $totalFrames -notmatch '^\d+$') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$totalFramesInt = [int]$totalFrames
|
$totalFramesInt = [int]$totalFrames
|
||||||
|
if ($totalFramesInt -lt 1) {
|
||||||
|
Write-Error ('Video has no frames: {0}' -f $VideoPath)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
$maxFrameIndex = $totalFramesInt - 1
|
$maxFrameIndex = $totalFramesInt - 1
|
||||||
|
|
||||||
$frameToExtract = if ($Frame -lt 0) {
|
# Negative values count from the end; the result is clamped to [0, maxFrameIndex]
|
||||||
# Negative values count from the end
|
$requestedFrame = if ($Frame -lt 0) { $totalFramesInt + $Frame } else { $Frame }
|
||||||
$calculatedFrame = $totalFramesInt + $Frame
|
$frameToExtract = [Math]::Max(0, [Math]::Min($requestedFrame, $maxFrameIndex))
|
||||||
# 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)
|
Write-Host ('Total frames: {0} - extracting frame index {1}' -f $totalFramesInt, $frameToExtract)
|
||||||
|
|
||||||
@@ -98,7 +93,7 @@ if ($PSCmdlet.ShouldProcess($ImagePath, ('Extract frame {0} to PNG' -f $frameToE
|
|||||||
'-y'
|
'-y'
|
||||||
'-i', $VideoPath
|
'-i', $VideoPath
|
||||||
'-vf', $videoFilter
|
'-vf', $videoFilter
|
||||||
'-vsync', 'vfr'
|
'-fps_mode', 'vfr'
|
||||||
'-frames:v', '1'
|
'-frames:v', '1'
|
||||||
'-q:v', '1'
|
'-q:v', '1'
|
||||||
'--', $ImagePath
|
'--', $ImagePath
|
||||||
@@ -107,8 +102,12 @@ if ($PSCmdlet.ShouldProcess($ImagePath, ('Extract frame {0} to PNG' -f $frameToE
|
|||||||
$ffmpegStderr = & ffmpeg @ffmpegArgs 2>&1
|
$ffmpegStderr = & ffmpeg @ffmpegArgs 2>&1
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
$ffmpegStderr | ForEach-Object { Write-Error $_ }
|
Write-Error ('ffmpeg failed to extract frame {0}: {1}' -f $frameToExtract, (($ffmpegStderr | Out-String).Trim()))
|
||||||
Write-Error 'ffmpeg failed to extract the last frame.'
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $ImagePath)) {
|
||||||
|
Write-Error ('ffmpeg reported success but no image was written for frame {0}: {1}' -f $frameToExtract, $ImagePath)
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,9 @@ The output container is chosen from the `-Target` extension (`.mp4`, `.webm`, or
|
|||||||
- **`-Frames`** (optional): 0-based frame range to clone. Mutually exclusive with `-StartFrame`, `-EndFrame`, and `-Sequence`. Supported formats:
|
- **`-Frames`** (optional): 0-based frame range to clone. Mutually exclusive with `-StartFrame`, `-EndFrame`, and `-Sequence`. Supported formats:
|
||||||
- `start-end`: Clone frames from `start` to `end` (e.g., `"100-500"`)
|
- `start-end`: Clone frames from `start` to `end` (e.g., `"100-500"`)
|
||||||
- `positive_number`: Clone frames from 0 to that number (e.g., `"50"`)
|
- `positive_number`: Clone frames from 0 to that number (e.g., `"50"`)
|
||||||
- `-N`: Clone last N frames (e.g., `"-10"`)
|
- `-N`: Clone the last N frames (e.g., `"-10"` clones frames 90 to 99 of a 100-frame video; `"-1"` clones the last frame only)
|
||||||
- `%`: Represents the last frame index; can be used alone or in ranges (e.g., `"%"`, `"10-%"`, `"-%"`)
|
- `%`: The last frame index. Alone (`"%"`) it selects only the last frame. In a range (e.g., `"10-%"`) it is the end of the range
|
||||||
|
- `-%` is not supported and is rejected with exit code `1`
|
||||||
- `all`: Clone all frames (same as `"0-%"`)
|
- `all`: Clone all frames (same as `"0-%"`)
|
||||||
- **`-Sequence`** (optional): Path to PNG file for extracted frame (`.png` extension added if missing)
|
- **`-Sequence`** (optional): Path to PNG file for extracted frame (`.png` extension added if missing)
|
||||||
- **`-Size`** (optional): Size of the output video. Uses the input video's size if not specified. Possible values: `320p`, `384p`, `480p`, `720p`, `900p`, `1080p`, `HD`, `1440p`, `2K`, `2160p`, `4K`, or custom size in format `width:height`. For standard named sizes the output **preserves the source aspect ratio**: the reference height is used as the short-side target and the other dimension is computed from the source AR — landscape/square sources use the reference as the output height (width computed), portrait sources use it as the output width (height computed). Custom sizes (`width:height`) are applied exactly as given. Forces a video re-encode, since scaling requires re-encoding.
|
- **`-Size`** (optional): Size of the output video. Uses the input video's size if not specified. Possible values: `320p`, `384p`, `480p`, `720p`, `900p`, `1080p`, `HD`, `1440p`, `2K`, `2160p`, `4K`, or custom size in format `width:height`. For standard named sizes the output **preserves the source aspect ratio**: the reference height is used as the short-side target and the other dimension is computed from the source AR — landscape/square sources use the reference as the output height (width computed), portrait sources use it as the output width (height computed). Custom sizes (`width:height`) are applied exactly as given. Forces a video re-encode, since scaling requires re-encoding.
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ Sources carrying a `.skip` marker keep that marker last: `P01.skip.mp4` becomes
|
|||||||
- **`-Frames`** (required): 0-based frame range to clip. Supported formats:
|
- **`-Frames`** (required): 0-based frame range to clip. Supported formats:
|
||||||
- `start-end`: Clip frames from `start` to `end` (e.g., `"100-200"`)
|
- `start-end`: Clip frames from `start` to `end` (e.g., `"100-200"`)
|
||||||
- `positive_number`: Clip frames from 0 to that number (e.g., `"50"`)
|
- `positive_number`: Clip frames from 0 to that number (e.g., `"50"`)
|
||||||
- `-N`: Clip last N frames (e.g., `"-10"`)
|
- `-N`: Clip the last N frames (e.g., `"-10"` clips frames 90 to 99 of a 100-frame video; `"-1"` clips the last frame only)
|
||||||
- `%`: Represents the last frame index; can be used alone or in ranges (e.g., `"%"`, `"10-%"`, `"-%"`)
|
- `%`: The last frame index. Alone (`"%"`) it selects only the last frame. In a range (e.g., `"10-%"`) it is the end of the range
|
||||||
|
- `-%` is not supported and is rejected with exit code `1`
|
||||||
- `all`: Clip all frames (same as `"0-%"`)
|
- `all`: Clip all frames (same as `"0-%"`)
|
||||||
- **`-Suffix`** (optional): Text inserted into the derived target name before the file extension. Defaults to `-Clip`, so `P01.mp4` becomes `P01-Clip.mp4`. Include any separator you want, such as the leading `-`. Must not be empty, because an empty suffix would produce a target with the same name as the source. For example, `-Suffix "-Clip-Shot-1"` turns `P01.mp4` into `P01-Clip-Shot-1.mp4`.
|
- **`-Suffix`** (optional): Text inserted into the derived target name before the file extension. Defaults to `-Clip`, so `P01.mp4` becomes `P01-Clip.mp4`. Include any separator you want, such as the leading `-`. Must not be empty, because an empty suffix would produce a target with the same name as the source. For example, `-Suffix "-Clip-Shot-1"` turns `P01.mp4` into `P01-Clip-Shot-1.mp4`.
|
||||||
- **Extra parameters**: Any additional parameters accepted by `Clone-Video.ps1` (e.g. `-Size`, `-FPS`, `-NoAudio`, `-Audio`, `-CRF`, `-Metadata`, `-Reverse`, `-LTX`) are forwarded directly. The parameters `-Video`, `-Frames`, `-Suffix` and `-Target` are handled by this script and must not be repeated.
|
- **Extra parameters**: Any additional parameters accepted by `Clone-Video.ps1` (e.g. `-Size`, `-FPS`, `-NoAudio`, `-Audio`, `-CRF`, `-Metadata`, `-Reverse`, `-LTX`) are forwarded directly. The parameters `-Video`, `-Frames`, `-Suffix` and `-Target` are handled by this script and must not be repeated.
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ Refer to [Clone-Video.ps1](Clone-Video.md) for a full description of the encodin
|
|||||||
Example scene list for a video with two hard cuts at frames 30 and 60:
|
Example scene list for a video with two hard cuts at frames 30 and 60:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Index StartFrame EndFrame Frames StartTime EndTime Suffix
|
Index StartFrame EndFrame Frames StartTime EndTime TotalTime Suffix
|
||||||
----- ---------- -------- ------ --------- ------- ------
|
----- ---------- -------- ------ --------- ------- --------- ------
|
||||||
1 0 29 30 0.00 0.97 -Scene-01
|
1 0 29 30 0.00 0.97 1.00 -Scene-01
|
||||||
2 30 59 30 1.00 1.97 -Scene-02
|
2 30 59 30 1.00 1.97 1.00 -Scene-02
|
||||||
3 60 89 30 2.00 2.97 -Scene-03
|
3 60 89 30 2.00 2.97 1.00 -Scene-03
|
||||||
```
|
```
|
||||||
|
|
||||||
`StartTime` and `EndTime` are in seconds, computed as frame index divided by frame rate.
|
`StartTime` and `EndTime` are in seconds, computed as frame index divided by frame rate. `EndTime` is the time of the last frame of the scene, so it is one frame before the next scene starts. `TotalTime` is the scene's duration in seconds: `Frames` divided by frame rate.
|
||||||
|
|
||||||
## Scene Threshold
|
## Scene Threshold
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ Extracts a specific frame of a video file to a PNG image by calling [Get-LastFra
|
|||||||
- **`-Frame`** (required): 0-based frame index to extract.
|
- **`-Frame`** (required): 0-based frame index to extract.
|
||||||
- Positive values: Direct frame index (e.g., `0` = first frame, `100` = frame 100)
|
- Positive values: Direct frame index (e.g., `0` = first frame, `100` = frame 100)
|
||||||
- Negative values: Count from the end (e.g., `-1` = last frame, `-2` = second-to-last)
|
- Negative values: Count from the end (e.g., `-1` = last frame, `-2` = second-to-last)
|
||||||
- Values are automatically clamped to the valid range (0 to total frames − 1)
|
- Values are automatically clamped to the valid range (0 to total frames − 1): a positive value past the last frame gives the last frame, and a negative value before the first frame gives frame 0
|
||||||
|
|
||||||
## Image Filename Derivation
|
## Image Filename Derivation
|
||||||
|
|
||||||
|
|||||||
+13
-20
@@ -12,11 +12,11 @@ Extracts a specific range of frames from a video file to PNG images.
|
|||||||
|
|
||||||
- **`start-end`**: Extract frames from start to end index (e.g., `100-200`)
|
- **`start-end`**: Extract frames from start to end index (e.g., `100-200`)
|
||||||
- **`positive_number`**: Extract frames from 0 to that number (e.g., `50` extracts frames 0-50)
|
- **`positive_number`**: Extract frames from 0 to that number (e.g., `50` extracts frames 0-50)
|
||||||
- **`-negative_number`**: Extract last N frames (e.g., `-10` extracts last 10 frames)
|
- **`-negative_number`**: Extract the last N frames (e.g., `-10` extracts frames 90 to 99 of a 100-frame video; `-1` extracts the last frame only)
|
||||||
- **`%`**: Represents the last frame index. Can be used alone or in ranges:
|
- **`%`**: The last frame index. Alone (`%`) it extracts only the last frame. In a range it is the end of the range:
|
||||||
- `%` - Extract only the last frame
|
- `%` - Extract only the last frame
|
||||||
- `10-%` - Extract from frame 10 to the last frame
|
- `10-%` - Extract from frame 10 to the last frame
|
||||||
- `-%` - Extract only the first frame (frame 0)
|
- `-%` is not supported and is rejected with exit code `1`
|
||||||
- **`all`**: Extract all frames (same as `0-%`)
|
- **`all`**: Extract all frames (same as `0-%`)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
@@ -24,63 +24,56 @@ Extracts a specific range of frames from a video file to PNG images.
|
|||||||
**Extract specific range:**
|
**Extract specific range:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "100-200"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "100-200"
|
||||||
# Creates: Frames/video_0100.png, Frames/video_0101.png, ..., Frames/video_0200.png
|
# Creates: Frames/video_0100.png, Frames/video_0101.png, ..., Frames/video_0200.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Extract first 50 frames:**
|
**Extract first 50 frames:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "50"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "50"
|
||||||
# Creates: Frames/video_0000.png through Frames/video_0050.png
|
# Creates: Frames/video_0000.png through Frames/video_0050.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Extract last 10 frames:**
|
**Extract last 10 frames:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "-10"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "-10"
|
||||||
# If video has 500 frames, creates: Frames/video_0490.png through Frames/video_0499.png
|
# If video has 500 frames, creates: Frames/video_0490.png through Frames/video_0499.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Extract only the last frame:**
|
**Extract only the last frame:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "%"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "%"
|
||||||
# If video has 500 frames, creates: Frames/video_0499.png
|
# If video has 500 frames, creates: Frames/video_0499.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Extract from frame 10 to the last frame:**
|
**Extract from frame 10 to the last frame:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "10-%"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "10-%"
|
||||||
# If video has 500 frames, creates: Frames/video_0010.png through Frames/video_0499.png
|
# If video has 500 frames, creates: Frames/video_0010.png through Frames/video_0499.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Extract only the first frame:**
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "-%"
|
|
||||||
# Creates: Frames/video_0000.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Extract all frames:**
|
**Extract all frames:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "all"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "all"
|
||||||
# If video has 500 frames, creates: Frames/video_0000.png through Frames/video_0499.png
|
# If video has 500 frames, creates: Frames/video_0000.png through Frames/video_0499.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Custom output pattern:**
|
**Custom output pattern:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "0-100" -Images "output_frame"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "0-100" -Images "output_frame"
|
||||||
# Creates: output_frame_0000.png through output_frame_0100.png
|
# Creates: output_frame_0000.png through output_frame_0100.png
|
||||||
```
|
```
|
||||||
|
|
||||||
**Full output path:**
|
**Full output path:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "50-150" -Images "C:\Output\frame_%04d.png"
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "50-150" -Images "C:\Output\frame_%04d.png"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** Frame numbers in output filenames reflect the actual video frame index (0-based).
|
**Note:** Frame numbers in output filenames reflect the actual video frame index (0-based).
|
||||||
@@ -99,11 +92,11 @@ This script supports `-WhatIf` and `-Confirm` for safe execution:
|
|||||||
**Simulate without extracting:**
|
**Simulate without extracting:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "100-200" -WhatIf
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "100-200" -WhatIf
|
||||||
```
|
```
|
||||||
|
|
||||||
**Prompt before each frame:**
|
**Prompt before each frame:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\Get-Frames.ps1 -Video video.mp4 -Frames "0-10" -Confirm
|
.\Get-FramesRange.ps1 -Video video.mp4 -Frames "0-10" -Confirm
|
||||||
```
|
```
|
||||||
@@ -9,7 +9,7 @@ Extracts a specific frame of a video file to a PNG image.
|
|||||||
- **`-Frame`** (optional): 0-based frame index to extract (default: -1)
|
- **`-Frame`** (optional): 0-based frame index to extract (default: -1)
|
||||||
- Positive values: Direct frame index (e.g., 0 = first frame, 100 = frame 100)
|
- Positive values: Direct frame index (e.g., 0 = first frame, 100 = frame 100)
|
||||||
- Negative values: Count from the end (e.g., -1 = last frame, -2 = second-to-last)
|
- Negative values: Count from the end (e.g., -1 = last frame, -2 = second-to-last)
|
||||||
- Values are automatically clamped to valid range (0 to total frames - 1)
|
- Values are automatically clamped to valid range (0 to total frames - 1): a positive value past the last frame gives the last frame, and a negative value before the first frame gives frame 0
|
||||||
|
|
||||||
## Filename Pattern
|
## Filename Pattern
|
||||||
|
|
||||||
|
|||||||
+17
-10
@@ -11,7 +11,7 @@ The per-script pages sit in the same folder as this file. Load a page only when
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- **Platform**: Windows 11 only. The scripts are tested on Windows 11 and nowhere else. Linux and WSL are not supported. Run them with Windows PowerShell 7 (`pwsh.exe`).
|
- **Platform**: Windows 11 only. The scripts are tested on Windows 11 and nowhere else. Linux and WSL are not supported. Run them with PowerShell 7 for Windows (`pwsh.exe`).
|
||||||
- **PowerShell 7+** (`pwsh`). Required by every script.
|
- **PowerShell 7+** (`pwsh`). Required by every script.
|
||||||
- **Core tools**: **ffmpeg** and **ffprobe** on `PATH`. Most scripts need both. [Stitch-InBetween.ps1](Stitch-InBetween.md) needs only ffmpeg. [Get-FramesCount.ps1](Get-FramesCount.md), [Get-VideoInfo.ps1](Get-VideoInfo.md) and [Create-FullSubtitle.ps1](Create-FullSubtitle.md) need only ffprobe.
|
- **Core tools**: **ffmpeg** and **ffprobe** on `PATH`. Most scripts need both. [Stitch-InBetween.ps1](Stitch-InBetween.md) needs only ffmpeg. [Get-FramesCount.ps1](Get-FramesCount.md), [Get-VideoInfo.ps1](Get-VideoInfo.md) and [Create-FullSubtitle.ps1](Create-FullSubtitle.md) need only ffprobe.
|
||||||
- **Optional tools**, needed only by specific scripts:
|
- **Optional tools**, needed only by specific scripts:
|
||||||
@@ -49,7 +49,7 @@ If a core check fails, or a check needed by the current task fails, **stop**. Te
|
|||||||
|
|
||||||
- Git: `git clone https://git.gurusushi.dyndns.org/guru/Video-Processing-Scripts.git` (repository `guru/Video-Processing-Scripts`).
|
- Git: `git clone https://git.gurusushi.dyndns.org/guru/Video-Processing-Scripts.git` (repository `guru/Video-Processing-Scripts`).
|
||||||
- SVN: `public-svn`, project `Video Processing Scripts`.
|
- SVN: `public-svn`, project `Video Processing Scripts`.
|
||||||
- The script folder must be on `PATH` so scripts can be called from any directory.
|
- The script folder should be on `PATH` so that `Get-Command` finds the scripts and the `.cmd` wrappers work. This does not make `pwsh -File <bare name>` work. See [How to Run the Scripts](#how-to-run-the-scripts).
|
||||||
- `Update-Video-Processing-Scripts.cmd` updates a Git copy to the latest version. Run it only with the user's approval.
|
- `Update-Video-Processing-Scripts.cmd` updates a Git copy to the latest version. Run it only with the user's approval.
|
||||||
|
|
||||||
## How to Run the Scripts
|
## How to Run the Scripts
|
||||||
@@ -64,6 +64,12 @@ If a core check fails, or a check needed by the current task fails, **stop**. Te
|
|||||||
pwsh -NoProfile -File .\Create-Clip.ps1 -Video "My Video.mp4" -Frames "100-200"
|
pwsh -NoProfile -File .\Create-Clip.ps1 -Video "My Video.mp4" -Frames "100-200"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
From any other folder, use the full script path and an absolute video path:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File "C:\path\to\Video Processing Scripts\Create-Clip.ps1" -Video "D:\clips\P01.mp4" -Frames "100-200"
|
||||||
|
```
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
- Frame indices are **0-based**: the first frame is `0`.
|
- Frame indices are **0-based**: the first frame is `0`.
|
||||||
@@ -73,18 +79,19 @@ pwsh -NoProfile -File .\Create-Clip.ps1 -Video "My Video.mp4" -Frames "100-200"
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `start-end` | Frames from `start` to `end`, e.g. `100-200` |
|
| `start-end` | Frames from `start` to `end`, e.g. `100-200` |
|
||||||
| `N` | Frames 0 to `N`, not only frame `N` |
|
| `N` | Frames 0 to `N`, not only frame `N` |
|
||||||
| `-N` | The last `N` frames |
|
| `-N` | The last `N` frames. `-1` is the last frame. |
|
||||||
| `%` | The last frame index, alone or in a range, e.g. `10-%` |
|
| `%` | The last frame index. Alone it selects only the last frame. In a range, e.g. `10-%`, it is the end of the range. |
|
||||||
|
| `-%` | Not supported. Rejected with exit code `1`. |
|
||||||
| `all` | All frames, same as `0-%` |
|
| `all` | All frames, same as `0-%` |
|
||||||
|
|
||||||
- **`-Frame` syntax** for [Get-Frame.ps1](Get-Frame.md) and [Get-LastFrame.ps1](Get-LastFrame.md): a single frame index. Negative values count from the end (`-1` is the last frame). Out-of-range values are clamped.
|
- [Create-Scenes.ps1](Create-Scenes.md) takes no frame range. It finds scene boundaries itself.
|
||||||
|
- **`-Frame` syntax** for [Get-Frame.ps1](Get-Frame.md) and [Get-LastFrame.ps1](Get-LastFrame.md): a single frame index. Negative values count from the end (`-1` is the last frame). [Get-Frame.ps1](Get-Frame.md) clamps values to the valid range: a positive value past the last frame gives the last frame, and a negative value before the first frame gives frame 0. [Get-LastFrame.ps1](Get-LastFrame.md) clamps the same way.
|
||||||
- If the extension is omitted, `.mp4`, `.webm` and `.mkv` are tried in that order by [Clone-Video.ps1](Clone-Video.md), [Create-Clip.ps1](Create-Clip.md) and [Create-Scenes.ps1](Create-Scenes.md).
|
- If the extension is omitted, `.mp4`, `.webm` and `.mkv` are tried in that order by [Clone-Video.ps1](Clone-Video.md), [Create-Clip.ps1](Create-Clip.md) and [Create-Scenes.ps1](Create-Scenes.md).
|
||||||
- **`.skip` marker**: a file named `<name>.skip.<ext>` is excluded from batch processing, and the marker stays last in derived names.
|
- **`.skip` marker**: a file named `<name>.skip.<ext>` is excluded from batch processing, and the marker stays last in derived names.
|
||||||
- [Create-Clip.ps1](Create-Clip.md) accepts `.mp4`, `.webm` and `.mkv`, case-insensitive. `P01.skip.mp4` gives `P01-Clip.skip.mp4`.
|
- [Create-Clip.ps1](Create-Clip.md) accepts `.mp4`, `.webm` and `.mkv`, case-insensitive. `P01.skip.mp4` gives `P01-Clip.skip.mp4`.
|
||||||
- [Crop-Clips.ps1](Crop-Clips.md) processes only `.mp4` files and skips `*.skip.mp4` and `*.bak.mp4`.
|
- [Crop-Clips.ps1](Crop-Clips.md) processes only `.mp4` files and skips `*.skip.mp4` and `*.bak.mp4`.
|
||||||
- [Create-Scenes.ps1](Create-Scenes.md) gives `P01-Scene-01.skip.mp4` for `P01.skip.mp4`.
|
- [Create-Scenes.ps1](Create-Scenes.md) gives `P01-Scene-01.skip.mp4` for `P01.skip.mp4`.
|
||||||
- Batch operations skip `.bak.mp4` backup files.
|
- On failure, scripts exit with `1`, print an error message to the error stream, and create no files. Check `$LASTEXITCODE` after each call.
|
||||||
- Scripts exit with `0` on success and `1` on failure. Check `$LASTEXITCODE` after each call.
|
|
||||||
- **Forwarded parameters**: [Create-Clip.ps1](Create-Clip.md) and [Create-Scenes.ps1](Create-Scenes.md) accept the extra parameters of [Clone-Video.ps1](Clone-Video.md) and forward them, for example `-Size`, `-FPS`, `-NoAudio`, `-Audio`, `-CRF`, `-Metadata`, `-Reverse` and `-LTX`. Each reserves `-Video`, `-Frames`, `-Suffix` and `-Target` for itself, so do not repeat them in the extra parameters.
|
- **Forwarded parameters**: [Create-Clip.ps1](Create-Clip.md) and [Create-Scenes.ps1](Create-Scenes.md) accept the extra parameters of [Clone-Video.ps1](Clone-Video.md) and forward them, for example `-Size`, `-FPS`, `-NoAudio`, `-Audio`, `-CRF`, `-Metadata`, `-Reverse` and `-LTX`. Each reserves `-Video`, `-Frames`, `-Suffix` and `-Target` for itself, so do not repeat them in the extra parameters.
|
||||||
|
|
||||||
## Safety Rules
|
## Safety Rules
|
||||||
@@ -102,7 +109,7 @@ pwsh -NoProfile -File .\Create-Clip.ps1 -Video "My Video.mp4" -Frames "100-200"
|
|||||||
| [Create-Clip.ps1](Create-Clip.md) | An existing derived clip is replaced without a prompt. The clip is written by Clone-Video.ps1, with the `.skip` marker kept last in the name. |
|
| [Create-Clip.ps1](Create-Clip.md) | An existing derived clip is replaced without a prompt. The clip is written by Clone-Video.ps1, with the `.skip` marker kept last in the name. |
|
||||||
| [Create-FullSubtitle.ps1](Create-FullSubtitle.md) | Overwrites `-Output` without a prompt. |
|
| [Create-FullSubtitle.ps1](Create-FullSubtitle.md) | Overwrites `-Output` without a prompt. |
|
||||||
| [Create-PillarBox.ps1](Create-PillarBox.md) | An existing `-Target` video is replaced without a prompt. If ffmpeg fails, the target is removed, including a file that existed before the run. |
|
| [Create-PillarBox.ps1](Create-PillarBox.md) | An existing `-Target` video is replaced without a prompt. If ffmpeg fails, the target is removed, including a file that existed before the run. |
|
||||||
| [Create-Scenes.ps1](Create-Scenes.md) | Only when `-List` is not given. Deletes earlier clips of the same source in the source folder, then creates the new ones, which replace the old ones. |
|
| [Create-Scenes.ps1](Create-Scenes.md) | Without `-List`, deletes the earlier scene clips of the same source in the source folder, then creates the new ones. `-List` creates and deletes nothing. |
|
||||||
| [Create-ShortClip.ps1](Create-ShortClip.md) | Overwrites the output video. With the default `-Images` and without `-Render`, clears the `Frames` folder. With explicit `-Images`, deletes only matching frames. Removes its temporary folders, and the `Frames` folder unless `-Keep` is given. |
|
| [Create-ShortClip.ps1](Create-ShortClip.md) | Overwrites the output video. With the default `-Images` and without `-Render`, clears the `Frames` folder. With explicit `-Images`, deletes only matching frames. Removes its temporary folders, and the `Frames` folder unless `-Keep` is given. |
|
||||||
| [Create-Turnaround.ps1](Create-Turnaround.md) | An existing `-Target` image is replaced without a prompt. The folder of `-Target` must exist. |
|
| [Create-Turnaround.ps1](Create-Turnaround.md) | An existing `-Target` image is replaced without a prompt. The folder of `-Target` must exist. |
|
||||||
| [Crop-Clips.ps1](Crop-Clips.md) | Works in place when `-Source` and `-Target` are omitted or equal. See the in-place rule below. |
|
| [Crop-Clips.ps1](Crop-Clips.md) | Works in place when `-Source` and `-Target` are omitted or equal. See the in-place rule below. |
|
||||||
@@ -114,8 +121,8 @@ pwsh -NoProfile -File .\Create-Clip.ps1 -Video "My Video.mp4" -Frames "100-200"
|
|||||||
| [Get-VideoInfo.ps1](Get-VideoInfo.md) | Reads only. Creates and deletes nothing. |
|
| [Get-VideoInfo.ps1](Get-VideoInfo.md) | Reads only. Creates and deletes nothing. |
|
||||||
| [Stitch-InBetween.ps1](Stitch-InBetween.md) | Deletes an existing `-Video` before generating. Deletes everything inside an existing `-TempDir`. |
|
| [Stitch-InBetween.ps1](Stitch-InBetween.md) | Deletes an existing `-Video` before generating. Deletes everything inside an existing `-TempDir`. |
|
||||||
|
|
||||||
- **Crop-Clips in-place rule.** Crop-Clips works on the current folder when `-Source` and `-Target` are omitted, and it backs up each file it crops to `<name>.bak.mp4`, replacing any existing backup without a prompt. Skipped files are not backed up and keep their backup. A re-run with a different `-Size` crops the already cropped files again, so the backup then holds the previous cropped output and the true original is lost. So:
|
- **Crop-Clips in-place rule.** Crop-Clips works on the current folder when `-Source` and `-Target` are omitted or equal, and it backs up each file it crops to `<name>.bak.mp4`, replacing any existing backup without a prompt. Skipped files are not backed up and keep their backup. A re-run with a different `-Size` crops the already cropped files again, so the backup then holds the previous cropped output and the true original is lost. So:
|
||||||
- Always pass explicit `-Source` and `-Target`, and prefer a separate `-Target` folder.
|
- Always pass explicit `-Source` and `-Target`, and prefer a separate `-Target` folder. Never pass the same folder for both.
|
||||||
- Use in-place mode only when the user asks for it.
|
- Use in-place mode only when the user asks for it.
|
||||||
- Warn the user before re-running in place with a different `-Size` on files that already have a `.bak.mp4`.
|
- Warn the user before re-running in place with a different `-Size` on files that already have a `.bak.mp4`.
|
||||||
- Never delete `.bak.mp4` files yourself unless the user asks.
|
- Never delete `.bak.mp4` files yourself unless the user asks.
|
||||||
|
|||||||
Reference in new issue
Block a user