Rename -Scene parameter to -Level in Create-Scenes.ps1, add -Scenes parameter for automatic level search to detect exact scene count with binary search algorithm, update documentation across Create-Scenes.md, SKILL.md, README.md and index.md to explain search behavior and exit code 1 on failure, fix agent skills directory paths to use Windows environment variables and add VS Code location

This commit is contained in:
guru committed 2026-11-02 16:42:36 -05:00
1 parent 60feb778d3
commit 4378e3fd99
5 files changed
+103 -30

No files matched your search

+62 -14
View File
@@ -2,7 +2,7 @@
.SYNOPSIS
Detects scenes in a video file with ffmpeg and extracts each scene as a separate video clip file.
.DESCRIPTION
Analyzes the input video with ffmpeg scene-change detection, using the -Scene threshold, and computes
Analyzes the input video with ffmpeg scene-change detection, using the -Level threshold, and computes
the first and last frame (0-based) of each detected scene. Each scene is then extracted by calling
Create-Clip.ps1 (located in the same directory as this script) with the scene frame range, which in
turn calls Clone-Video.ps1.
@@ -18,6 +18,9 @@
The list of scenes (index, start frame, end frame, frame count, start time, end time) is always displayed.
If no scene change is detected, the whole video is treated as a single scene.
With -Scenes, the level is adjusted automatically until the requested number of scenes is detected; every
attempt is displayed. If that number cannot be reached, the script stops with exit code 1 and creates or
deletes nothing.
Unless -List is specified, existing scene clip files from a previous run (same directory, same source
name, same suffix pattern and same extension) are deleted before the new clips are created. Existing
@@ -29,9 +32,12 @@
.PARAMETER Video
Path to the input video file. Can be absolute or relative to current directory. If the path has no
extension, .mp4, .webm and .mkv are tried in turn.
.PARAMETER Scene
Threshold value between 0 and 1.0 to determine scene changes. Lower values mean more sensitive
detection (more scenes). Default is 0.3.
.PARAMETER Level
Threshold level value between 0 and 1.0 to determine scene changes. Lower values mean more sensitive
detection (more scenes). Default is 0.3. The value is rounded to 2 decimals.
.PARAMETER Scenes
Target number of scenes (a positive integer). The level is searched automatically, starting from -Level,
until exactly this many scenes are detected. Stops with exit code 1 if the number cannot be reached.
.PARAMETER Suffix
Scene suffix to use for the output video clip files. Must contain a printf-style number placeholder
such as %02d, which is replaced by the scene number starting at 1. By default, "-Scene-%02d" is used.
@@ -39,13 +45,16 @@
Only displays the list of scenes. No video clip file is created and no existing file is deleted.
.PARAMETER ExtraArgs
Additional parameters passed as-is to Create-Clip.ps1 and from there to Clone-Video.ps1
(ex: -Size 720p -NoAudio -CRF 18 -LTX). The parameters -Video, -Frames, -Suffix and -Target are
managed by this script and must not be repeated.
(ex: -Size 720p -NoAudio -CRF 18 -LTX). The parameters -Video, -Frames, -Suffix, -Target, -Level and
-Scenes are managed by this script and must not be repeated.
.EXAMPLE
.\Create-Scenes.ps1 -Video P01.mp4 -Scene 0.4 -List
.\Create-Scenes.ps1 -Video P01.mp4 -Level 0.4 -List
Lists the scenes detected in P01.mp4 without creating or deleting any file.
.EXAMPLE
.\Create-Scenes.ps1 -Video P01 -Scene 0.3 -Size 720p -NoAudio
.\Create-Scenes.ps1 -Video P01.mp4 -Scenes 4 -List
Searches the level automatically and lists the scenes once exactly 4 scenes are detected.
.EXAMPLE
.\Create-Scenes.ps1 -Video P01 -Level 0.3 -Size 720p -NoAudio
Creates P01-Scene-01.mp4, P01-Scene-02.mp4, ... scaled to 720p and without audio.
.EXAMPLE
.\Create-Scenes.ps1 -Video P01.mp4 -Suffix "-Shot-%03d" -WhatIf
@@ -59,7 +68,11 @@ param(
[Parameter(Mandatory = $false)]
[ValidateRange(0.0, 1.0)]
[double]$Scene = 0.3,
[double]$Level = 0.3,
[Parameter(Mandatory = $false)]
[ValidateRange(1, [int]::MaxValue)]
[int]$Scenes,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
@@ -234,16 +247,51 @@ $videoPath = Resolve-VideoPath -Path $Video
[object[]]$tokens = @()
if ($null -ne $ExtraArgs) { $tokens = @($ExtraArgs) }
$extraParams = ConvertTo-ClipArgument -Tokens $tokens
foreach ($reserved in 'Video', 'Frames', 'Suffix', 'Target') {
foreach ($reserved in 'Video', 'Frames', 'Suffix', 'Target', 'Level', 'Scenes') {
if ($extraParams.ContainsKey($reserved)) {
throw "-$reserved is managed by Create-Scenes.ps1 and must not be passed as an extra parameter."
}
}
$info = Get-VideoInfo -Path $videoPath
$changeTimes = @(Get-SceneChangeTime -Path $videoPath -Threshold $Scene)
$scenes = @(Get-SceneList -Info $info -ChangeTimes $changeTimes -Template $Suffix)
$scenes | Format-Table -AutoSize | Out-Host
# Level rounded to 2 decimals. The search rounds each new level to 2 decimals too; the step is not rounded.
$sceneLevel = [Math]::Round($Level, 2, [MidpointRounding]::AwayFromZero)
if ($PSBoundParameters.ContainsKey('Scenes')) {
$sceneStep = 0.1
$sceneDirection = 0
$pass = 0
while ($true) {
$pass++
$changeTimes = @(Get-SceneChangeTime -Path $videoPath -Threshold $sceneLevel)
$sceneList = @(Get-SceneList -Info $info -ChangeTimes $changeTimes -Template $Suffix)
'Pass {0}: level {1} -> {2} scene(s)' -f $pass, $sceneLevel, $sceneList.Count | Out-Host
$sceneList | Format-Table -AutoSize | Out-Host
if ($sceneList.Count -eq $Scenes) { break }
if ($sceneList.Count -lt $Scenes) {
# Fewer scenes than requested: a lower level detects more scenes.
if ($sceneDirection -eq 0) { $sceneDirection = -1 }
elseif ($sceneDirection -eq 1) { $sceneDirection = -1; $sceneStep = $sceneStep / 2.0 }
}
else {
# More scenes than requested: a higher level detects fewer scenes.
if ($sceneDirection -eq 0) { $sceneDirection = 1 }
elseif ($sceneDirection -eq -1) { $sceneDirection = 1; $sceneStep = $sceneStep / 2.0 }
}
if ($sceneStep -lt 0.01) {
throw "The number of scenes -Scenes $Scenes could not be found - Search stopped at scene level $sceneLevel."
}
$sceneLevel = [Math]::Round($sceneLevel + ($sceneDirection * $sceneStep), 2, [MidpointRounding]::AwayFromZero)
if ($sceneLevel -lt 0 -or $sceneLevel -gt 1) {
throw "The number of scenes -Scenes $Scenes could not be found - Search stopped at scene level $sceneLevel, which is outside the range 0 to 1.0."
}
}
}
else {
$changeTimes = @(Get-SceneChangeTime -Path $videoPath -Threshold $sceneLevel)
$sceneList = @(Get-SceneList -Info $info -ChangeTimes $changeTimes -Template $Suffix)
$sceneList | Format-Table -AutoSize | Out-Host
}
'Scene level used: {0}' -f $sceneLevel | Out-Host
if ($List) { return }
$confirm = [bool]$PSBoundParameters['Confirm']
@@ -251,7 +299,7 @@ $pattern = Get-SceneFilePattern -VideoPath $videoPath -Template $Suffix
Remove-ExistingScene -VideoPath $videoPath -Pattern $pattern -WhatIf:$WhatIfPreference -Confirm:$confirm
$failures = 0
foreach ($clipScene in $scenes) {
foreach ($clipScene in $sceneList) {
$frames = '{0}-{1}' -f $clipScene.StartFrame, $clipScene.EndFrame
Write-Verbose ('Scene {0}: frames {1}, suffix {2}' -f $clipScene.Index, $frames, $clipScene.Suffix)
# Extra parameters are forwarded as the original token array, not as the hashtable: Create-Clip.ps1