Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c79451b373 | ||
|
|
373efac4af |
No files matched your search
@@ -7,6 +7,7 @@
|
|||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This script creates a full subtitle file from a video file from three sources: a reference video and two SRT subtitle files.
|
This script creates a full subtitle file from a video file from three sources: a reference video and two SRT subtitle files.
|
||||||
The output file contains all subtitles from the first and second subtitle files with proper timing and numbering.
|
The output file contains all subtitles from the first and second subtitle files with proper timing and numbering.
|
||||||
|
An existing file at -Output is overwritten without a prompt. Its folder is created if it does not exist.
|
||||||
.PARAMETER Video
|
.PARAMETER Video
|
||||||
Path to the video file.
|
Path to the video file.
|
||||||
.PARAMETER Subtitle1
|
.PARAMETER Subtitle1
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Creates a short clip video file from a 16:9 video file using the specified plan.
|
Creates a short clip video file from a 16:9 video file using the specified plan.
|
||||||
See Create-ShortClip.ini for details about the INI format and supported entries for the plan file.
|
See Create-ShortClip.ini for details about the INI format and supported entries for the plan file.
|
||||||
|
Existing files: with the default -Images (the 'Frames' folder next to the video), files directly in that folder are
|
||||||
|
deleted before extraction (not with -Render, where they are the input). With an explicit -Images, existing frames matching that pattern are deleted before extraction,
|
||||||
|
and the Frames folder is not touched. An existing output video is overwritten. The temporary extraction directory is
|
||||||
|
always removed. The Frames folder is removed after the video is created unless -Keep is given.
|
||||||
Supports -WhatIf and -Confirm for safe execution.
|
Supports -WhatIf and -Confirm for safe execution.
|
||||||
#>
|
#>
|
||||||
[CmdletBinding(SupportsShouldProcess)]
|
[CmdletBinding(SupportsShouldProcess)]
|
||||||
@@ -498,7 +502,7 @@ try {
|
|||||||
if ($videoDir -eq '') { $videoDir = '.' }
|
if ($videoDir -eq '') { $videoDir = '.' }
|
||||||
$framesDir = Join-Path $videoDir 'Frames'
|
$framesDir = Join-Path $videoDir 'Frames'
|
||||||
if (Test-Path $framesDir) {
|
if (Test-Path $framesDir) {
|
||||||
if ($PSCmdlet.ShouldProcess($framesDir, 'Clear existing frames directory')) {
|
if (-not $Render -and $PSCmdlet.ShouldProcess($framesDir, 'Clear existing frames directory')) {
|
||||||
Get-ChildItem -Path $framesDir -File | Remove-Item -Force
|
Get-ChildItem -Path $framesDir -File | Remove-Item -Force
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -719,11 +723,11 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Clean up frames directory after video is successfully created
|
# Clean up frames directory after video is successfully created
|
||||||
if ((-not $Keep) -and (Test-Path $framesDir) -and ($PSCmdlet.ShouldProcess($framesDir, 'Remove frames directory'))) {
|
if ((-not $Keep) -and $framesDir -and (Test-Path $framesDir) -and ($PSCmdlet.ShouldProcess($framesDir, 'Remove frames directory'))) {
|
||||||
Remove-Item -Path $framesDir -Recurse -Force
|
Remove-Item -Path $framesDir -Recurse -Force
|
||||||
Write-Host "Frames directory removed: $framesDir"
|
Write-Host "Frames directory removed: $framesDir"
|
||||||
}
|
}
|
||||||
elseif ($Keep -and (Test-Path $framesDir)) {
|
elseif ($Keep -and $framesDir -and (Test-Path $framesDir)) {
|
||||||
Write-Host "Frames directory preserved: $framesDir"
|
Write-Host "Frames directory preserved: $framesDir"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-6
@@ -1,7 +1,7 @@
|
|||||||
<#
|
<#
|
||||||
.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 using Get-LastFrame.ps1, requiring -Video and -Frame parameters from that script.
|
||||||
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 (maximum of 4 digits) 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
|
||||||
@@ -73,9 +73,5 @@ $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|||||||
$getLastFrameScript = Join-Path $scriptDir 'Get-LastFrame.ps1'
|
$getLastFrameScript = Join-Path $scriptDir 'Get-LastFrame.ps1'
|
||||||
|
|
||||||
# Forward common parameters to Get-LastFrame.ps1
|
# Forward common parameters to Get-LastFrame.ps1
|
||||||
$passThrough = @()
|
& $getLastFrameScript -Video $VideoPath -Image $imagePath -Frame $frameToExtract -WhatIf:$WhatIfPreference -Confirm:([bool]$PSBoundParameters['Confirm'])
|
||||||
if ($PSBoundParameters.ContainsKey('WhatIf')) { $passThrough += '-WhatIf' }
|
|
||||||
if ($PSBoundParameters.ContainsKey('Confirm')) { $passThrough += '-Confirm' }
|
|
||||||
|
|
||||||
& $getLastFrameScript -Video $VideoPath -Image $imagePath -Frame $frameToExtract @passThrough
|
|
||||||
exit $LASTEXITCODE
|
exit $LASTEXITCODE
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
- 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.
|
||||||
|
An existing PNG file with the same name is replaced.
|
||||||
Supports -WhatIf and -Confirm for safe execution.
|
Supports -WhatIf and -Confirm for safe execution.
|
||||||
#>
|
#>
|
||||||
[CmdletBinding(SupportsShouldProcess)]
|
[CmdletBinding(SupportsShouldProcess)]
|
||||||
@@ -135,6 +136,7 @@ for ($frameIndex = $startFrame; $frameIndex -le $endFrame; $frameIndex++) {
|
|||||||
$videoFilter = 'select=eq(n\,{0})' -f $frameIndex
|
$videoFilter = 'select=eq(n\,{0})' -f $frameIndex
|
||||||
|
|
||||||
$ffmpegArgs = @(
|
$ffmpegArgs = @(
|
||||||
|
'-y'
|
||||||
'-i', $VideoPath
|
'-i', $VideoPath
|
||||||
'-vf', $videoFilter
|
'-vf', $videoFilter
|
||||||
'-vsync', 'vfr'
|
'-vsync', 'vfr'
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
---
|
||||||
|
name: video-processing-scripts
|
||||||
|
description: Operates a collection of PowerShell 7 scripts that process video and image files with ffmpeg, ffprobe, rife-ncnn-vulkan and upscayl-bin. Covers clipping frame ranges, scene-based clip extraction, frame extraction to PNG, frame counts and video metadata, cropping and resizing to standard, LTX-2, Kling and Wan resolutions, pillar-boxing, side-by-side comparison, turnaround sheets, subtitle merging, audio extraction, AI image upscaling and RIFE frame interpolation. Use this skill when the user asks about video clipping, frame extraction, scene detection, cropping, upscaling, frame interpolation, subtitles, ffmpeg or RIFE workflows, the PowerShell video scripts, or preparing clips for Wan2GP or LTX models.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Video Processing PowerShell Scripts
|
||||||
|
|
||||||
|
A collection of PowerShell 7 scripts that wrap ffmpeg and ffprobe for video and image processing. Some scripts also call rife-ncnn-vulkan (frame interpolation) and upscayl-bin (AI upscaling). Each script has its own page in this documentation, linked from the catalog below.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **PowerShell 7+** (`pwsh`). Required by every script.
|
||||||
|
- **ffmpeg** and **ffprobe** on `PATH`. Required by every video script.
|
||||||
|
- **rife-ncnn-vulkan** on `PATH`, with `RIFE_HOME` set. Required by [Stitch-InBetween.ps1](Stitch-InBetween.md). See [RIFE installation guide](RIFE.md).
|
||||||
|
- **upscayl-bin** on `PATH`, with `UPSCAYL_HOME` set. Required by [Clone-Image.ps1](Clone-Image.md) when `-Upscale` is used. See [Upscalers installation guide](Upscalers.md).
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
| Variable | Purpose | Accepted values | Required by |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `RIFE_HOME` | Install folder of rife-ncnn-vulkan (the same folder as its `PATH` entry). Models are read from `%RIFE_HOME%\rife-v4.26`. | Folder path, e.g. `C:\tools\rife-ncnn-vulkan\` | [Stitch-InBetween.ps1](Stitch-InBetween.md) |
|
||||||
|
| `UPSCAYL_HOME` | Install folder of upscayl-bin (the same folder as its `PATH` entry). Models are read from `%UPSCAYL_HOME%\models`. | Folder path | [Clone-Image.ps1](Clone-Image.md) with `-Upscale` |
|
||||||
|
| `NCNN_GPU_ID` | GPU device passed to the `-g` flag of rife-ncnn-vulkan and upscayl-bin. | `0`, `1`, `2`... (GPU index), `-1` (CPU only) | [Stitch-InBetween.ps1](Stitch-InBetween.md), [Clone-Image.ps1](Clone-Image.md) with `-Upscale` |
|
||||||
|
|
||||||
|
These must be persistent user or system variables. An agent shell may not inherit variables set only in an interactive session.
|
||||||
|
|
||||||
|
## Check the Environment
|
||||||
|
|
||||||
|
Run these once before the first use in a session:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh --version
|
||||||
|
ffmpeg -version
|
||||||
|
ffprobe -version
|
||||||
|
Get-Command rife-ncnn-vulkan
|
||||||
|
Get-Command upscayl-bin
|
||||||
|
"RIFE_HOME=$env:RIFE_HOME"
|
||||||
|
"UPSCAYL_HOME=$env:UPSCAYL_HOME"
|
||||||
|
"NCNN_GPU_ID=$env:NCNN_GPU_ID"
|
||||||
|
```
|
||||||
|
|
||||||
|
If anything is missing or empty, **stop**. Tell the user exactly what is missing and point to [index.md](index.md) (prerequisites), [RIFE.md](RIFE.md) or [Upscalers.md](Upscalers.md). Do not install software or change environment variables without the user's approval.
|
||||||
|
|
||||||
|
## Installation and Location
|
||||||
|
|
||||||
|
- 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`.
|
||||||
|
- The script folder must be on `PATH` so scripts can be called from any directory.
|
||||||
|
- `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
|
||||||
|
|
||||||
|
- Always call a script as `pwsh -NoProfile -File <script>.ps1 <parameters>`.
|
||||||
|
- The `.cmd` wrappers are Windows-only convenience files. Do not use them in agent commands.
|
||||||
|
- Quote every path that contains spaces.
|
||||||
|
- Paths can be absolute or relative to the current directory.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File .\Create-Clip.ps1 -Video "My Video.mp4" -Frames "100-200"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Frame indices are **0-based**: the first frame is `0`.
|
||||||
|
- If the extension is omitted, `.mp4`, `.webm` and `.mkv` are tried in that order (for example [Create-Clip.ps1](Create-Clip.md), [Create-Scenes.ps1](Create-Scenes.md)).
|
||||||
|
- Files ending in `.skip.mp4` (for example `P01.skip.mp4`) are excluded from batch processing. Batch scripts also skip `.bak.mp4` backups.
|
||||||
|
- A `.skip` marker stays last in derived output names: `P01.skip.mp4` gives `P01-Clip.skip.mp4` ([Create-Clip.ps1](Create-Clip.md)) and `P01-Scene-01.skip.mp4` ([Create-Scenes.ps1](Create-Scenes.md)).
|
||||||
|
|
||||||
|
## Safety Rules
|
||||||
|
|
||||||
|
- **Never pass `-Confirm`.** Scripts run without interaction. Only `-Confirm` makes them prompt. No script sets a `ConfirmImpact` of `High`, so none prompts by default. `Create-Scenes.ps1` sets `Medium`.
|
||||||
|
- Before any script that creates, overwrites or deletes files, run it with **`-WhatIf`**. Show the user the result, then run it for real only if the user agrees.
|
||||||
|
- Never run a script on files the user has not designated. Never delete source videos.
|
||||||
|
|
||||||
|
Scripts that replace or delete existing files:
|
||||||
|
|
||||||
|
| Script | Behavior |
|
||||||
|
| --- | --- |
|
||||||
|
| [Clone-Video.ps1](Clone-Video.md) | Overwrites the `-Target` file (ffmpeg `-y`). |
|
||||||
|
| [Create-Clip.ps1](Create-Clip.md) | Overwrites the derived clip, through Clone-Video. |
|
||||||
|
| [Create-Scenes.ps1](Create-Scenes.md) | Deletes earlier clips of the same source in the source folder, then overwrites them. |
|
||||||
|
| [Clone-Image.ps1](Clone-Image.md) | Overwrites the `-Target` image (ffmpeg `-y`). |
|
||||||
|
| [Compare-Videos.ps1](Compare-Videos.md) | Overwrites the `-Output` file (ffmpeg `-y`). |
|
||||||
|
| [Create-PillarBox.ps1](Create-PillarBox.md) | Removes an existing target before writing it. |
|
||||||
|
| [Create-Turnaround.ps1](Create-Turnaround.md) | Overwrites the `-Target` image. |
|
||||||
|
| [Crop-Clips.ps1](Crop-Clips.md) | In-place when source and target are the same folder, which is the default when both are omitted: writes a `.bak.mp4` backup, then removes the original after a successful crop. A separate target folder replaces same-named files. |
|
||||||
|
| [Create-FullSubtitle.ps1](Create-FullSubtitle.md) | Overwrites the `-Output` subtitle file without a prompt. |
|
||||||
|
| [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. |
|
||||||
|
| [Get-FramesRange.ps1](Get-FramesRange.md) | Overwrites existing PNG frames with the same name (ffmpeg `-y`). |
|
||||||
|
| [Get-LastFrame.ps1](Get-LastFrame.md) | Overwrites the output PNG (ffmpeg `-y`). [Get-Frame.ps1](Get-Frame.md) uses it. |
|
||||||
|
| [Get-VideoAudio.ps1](Get-VideoAudio.md) | Overwrites the output audio file. |
|
||||||
|
| [Stitch-InBetween.ps1](Stitch-InBetween.md) | Deletes an existing `-Video` output before generating. Deletes everything inside an existing `-TempDir`. Deletes intermediate PNG frames. |
|
||||||
|
|
||||||
|
Run `-WhatIf` first on every script in this table, and check the output paths before running it for real.
|
||||||
|
|
||||||
|
## Script Catalog
|
||||||
|
|
||||||
|
| Script | Purpose | Typical use |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [Clone-Image.ps1](Clone-Image.md) | Resize, convert and optionally AI-upscale images | `-Source small.jpg -Target big_4k.png -Upscale 4 -Size 4K` |
|
||||||
|
| [Clone-Video.ps1](Clone-Video.md) | Re-encode a video with frame range, size, FPS, audio and CRF options | `-Source in.mp4 -Target out.mp4 -Frames "0-100"` |
|
||||||
|
| [Compare-Videos.ps1](Compare-Videos.md) | Side-by-side or grid comparison of 2 to 4 videos at 1080p or 4K | `-S1 a.mp4 -S2 b.mp4 -Output cmp.mp4` |
|
||||||
|
| [Create-Clip.ps1](Create-Clip.md) | Clip a frame range; output name is the source name plus `-Suffix` (default `-Clip`) | `-Video P01.mp4 -Frames "100-200"` |
|
||||||
|
| [Create-FullSubtitle.ps1](Create-FullSubtitle.md) | Merge two SRT files into one with adjusted timing | `-Video v.mp4 -Subtitle1 a.srt -Subtitle2 b.srt -Output out.srt` |
|
||||||
|
| [Create-PillarBox.ps1](Create-PillarBox.md) | Wrap a video in a 16:9 frame with side-bar effects | `-Video v.mp4 -Effect black` |
|
||||||
|
| [Create-Scenes.ps1](Create-Scenes.md) | Detect scene changes and create one clip per scene | `-Video P01.mp4 -Scene 0.3 -List` |
|
||||||
|
| [Create-ShortClip.ps1](Create-ShortClip.md) | Build a vertical short clip from an INI plan | `-Video v.mp4 -Plan plan.ini` |
|
||||||
|
| [Create-Turnaround.ps1](Create-Turnaround.md) | Arrange same-named images into a turnaround sheet | `-Source "C:\renders\CharacterA" -Target sheet.png` |
|
||||||
|
| [Crop-Clips.ps1](Crop-Clips.md) | Batch crop LTX-2, Kling and Wan videos to standard sizes | `-Source in_dir -Target out_dir` |
|
||||||
|
| [Get-Frame.ps1](Get-Frame.md) | Extract one frame to PNG with an automatic name | `-Video P01.mp4 -Frame 10` |
|
||||||
|
| [Get-FramesCount.ps1](Get-FramesCount.md) | Print the total frame count of a video | `-Video P01.mp4` |
|
||||||
|
| [Get-FramesRange.ps1](Get-FramesRange.md) | Extract a range of frames to PNG files | `-Video P01.mp4 -Frames "0-50"` |
|
||||||
|
| [Get-LastFrame.ps1](Get-LastFrame.md) | Extract one frame (default: the last) to a chosen PNG name | `-Video P01.mp4 -Image last.png` |
|
||||||
|
| [Get-VideoAudio.ps1](Get-VideoAudio.md) | Extract audio as WAV (default) or MP3 | `-Video P01.mp4 -MP3` |
|
||||||
|
| [Get-VideoInfo.ps1](Get-VideoInfo.md) | Show metadata stored in video comment tags | `-Video *.mp4` |
|
||||||
|
| [Stitch-InBetween.ps1](Stitch-InBetween.md) | Generate in-between frames with RIFE and encode them to video | `-First a.png -Last b.png -Frames 30 -Video out.mp4` |
|
||||||
|
|
||||||
|
## Common Workflows
|
||||||
|
|
||||||
|
**Clip a frame range** (count frames, preview, then run):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File .\Get-FramesCount.ps1 -Video P01.mp4
|
||||||
|
pwsh -NoProfile -File .\Create-Clip.ps1 -Video P01.mp4 -Frames "100-200" -WhatIf
|
||||||
|
pwsh -NoProfile -File .\Create-Clip.ps1 -Video P01.mp4 -Frames "100-200"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Split a video into scenes** (list first, then create clips):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File .\Create-Scenes.ps1 -Video P01.mp4 -Scene 0.3 -List
|
||||||
|
pwsh -NoProfile -File .\Create-Scenes.ps1 -Video P01.mp4 -Scene 0.3 -WhatIf
|
||||||
|
pwsh -NoProfile -File .\Create-Scenes.ps1 -Video P01.mp4 -Scene 0.3
|
||||||
|
```
|
||||||
|
|
||||||
|
**Extract the last frame to a named PNG:**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File .\Get-LastFrame.ps1 -Video P01.mp4 -Image last.png
|
||||||
|
```
|
||||||
|
|
||||||
|
**Upscale an image** (needs `UPSCAYL_HOME`, `NCNN_GPU_ID` and the model files):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File .\Clone-Image.ps1 -Source small.jpg -Target big_4k.png -Upscale 4 -Size 4K
|
||||||
|
```
|
||||||
|
|
||||||
|
**Interpolate between two images with RIFE:**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
pwsh -NoProfile -File .\Stitch-InBetween.ps1 -First frame1.png -Last frame2.png -Frames 30 -Video output.mp4 -FPS 24 -WhatIf
|
||||||
|
pwsh -NoProfile -File .\Stitch-InBetween.ps1 -First frame1.png -Last frame2.png -Frames 30 -Video output.mp4 -FPS 24
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **"Video file not found"**: check the path. Use an absolute path if relative paths fail. See [index.md](index.md).
|
||||||
|
- **"ffmpeg failed" or "ffprobe failed"**: run `ffmpeg -version` and `ffprobe -version`. Check that the file is not corrupt and that the disk has space. See [index.md](index.md).
|
||||||
|
- **"Frame index out of range"**: run [Get-FramesCount.ps1](Get-FramesCount.md). Indices are 0-based.
|
||||||
|
- **`-Image` rejected by Get-Frame**: `-Image` is not a [Get-Frame.ps1](Get-Frame.md) parameter. Use [Get-LastFrame.ps1](Get-LastFrame.md) for custom names.
|
||||||
|
- **Missing `RIFE_HOME`, `UPSCAYL_HOME` or `NCNN_GPU_ID`**: set the persistent variable as described above. Then start a new shell.
|
||||||
|
- **Upscale fails with missing models**: the model files `<Model>.bin` and `<Model>.param` must be in `%UPSCAYL_HOME%\models`. See [Clone-Image.md](Clone-Image.md) and [Upscalers.md](Upscalers.md).
|
||||||
Reference in new issue
Block a user