Files
Video-Processing-Scripts/video-processing-scripts/SKILL.md
T

19 KiB

name, description
name description
video-processing-scripts 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).

The per-script pages sit in the same folder as this file. Load a page only when you need its details, using the links in the catalog below.

Prerequisites

Encoders and filters required

These encoders are used by the scripts. Check the ones a task needs before running it; see Check the Environment.

Encoder or filter Used by Needed for
libx264 Clone-Video.ps1, Compare-Videos.ps1, Create-PillarBox.ps1, Create-ShortClip.ps1, Crop-Clips.ps1 H.264 video in MP4 and MKV output
libx265 Create-ShortClip.ps1 Output of HEVC (H.265) sources
libvpx-vp9 Clone-Video.ps1 Video in WebM output
libopus Clone-Video.ps1 Audio in WebM output
libmp3lame Get-VideoAudio.ps1 MP3 extraction (-MP3)
libaom-av1 Clone-Image.ps1, Create-Turnaround.ps1 AVIF images
libwebp Clone-Image.ps1, Create-Turnaround.ps1 WebP images

The filters used (for example scale, crop, pad, hstack, vstack, select, concat) are built into ffmpeg. No script needs libass or libfreetype.

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
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 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, Clone-Image.ps1 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 the core checks once before the first use in a session:

pwsh --version
ffmpeg -version
ffprobe -version

Run the task-specific checks only when the task uses the script that needs them:

  • Stitch-InBetween.ps1: Get-Command rife-ncnn-vulkan, $env:RIFE_HOME and $env:NCNN_GPU_ID.
  • Clone-Image.ps1 with -Upscale: Get-Command upscayl-bin, $env:UPSCAYL_HOME and $env:NCNN_GPU_ID.
  • Encoder checks, only for the task that needs the encoder (see the table above). For example, before an MP3 extraction: ffmpeg -hide_banner -encoders | Select-String libmp3lame. A missing encoder stops only the task that needs it.

If a core check fails, or a check needed by the current task fails, stop. Tell the user exactly what is missing and point to index.md (prerequisites), RIFE.md or Upscalers.md. Do not install software or change environment variables without the user's approval. A missing optional tool must not block unrelated tasks such as clipping.

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 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.
  • 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 <full path to script>.ps1 <parameters>. pwsh -File does not search PATH, so a bare name fails from any other folder. Find the script folder once with Split-Path (Get-Command Create-Clip.ps1).Source.
  • In the examples below, .\ means the script folder. From any other folder, replace .\ with the full script path.
  • 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.
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:

pwsh -NoProfile -File "C:\path\to\Video Processing Scripts\Create-Clip.ps1" -Video "D:\clips\P01.mp4" -Frames "100-200"

Conventions

  • Frame indices are 0-based: the first frame is 0.

  • -Frames syntax for Clone-Video.ps1, Create-Clip.ps1 and Get-FramesRange.ps1:

    Form Meaning
    start-end Frames from start to end, e.g. 100-200. Both ends must be inside the video. A reversed range or an end past the last frame is rejected with exit code 1.
    N Frames 0 to N, not only frame N. A number past the last frame is clamped to the last frame.
    -N The last N frames. -1 is the last frame.
    % 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-%
  • Create-Scenes.ps1 takes no frame range. It finds scene boundaries itself.

  • -Frame syntax for Get-Frame.ps1 and Get-LastFrame.ps1: a single frame index. Negative values count from the end (-1 is the last frame). Get-Frame.ps1 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 clamps the same way.

  • If the extension is omitted, .mp4, .webm and .mkv are tried in that order by Clone-Video.ps1, Create-Clip.ps1 and Create-Scenes.ps1.

  • .skip marker: a file named <name>.skip.<ext> is excluded from batch processing, and the marker stays last in derived names.

    • Create-Clip.ps1 accepts .mp4, .webm and .mkv, case-insensitive. P01.skip.mp4 gives P01-Clip.skip.mp4.
    • Crop-Clips.ps1 processes only .mp4 files and skips *.skip.mp4 and *.bak.mp4.
    • Create-Scenes.ps1 gives P01-Scene-01.skip.mp4 for P01.skip.mp4.
  • On failure, scripts exit with 1, print an error message to the error stream, and create no files. Check $LASTEXITCODE after each call.

  • Forwarded parameters: Create-Clip.ps1 and Create-Scenes.ps1 accept the extra parameters of Clone-Video.ps1 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

  • 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.

  • Overwrite and delete behavior of every script, as stated on its page:

    Script Behavior, as documented
    Clone-Image.ps1 An existing -Target or -Keep file is replaced. Both folders must exist.
    Clone-Video.ps1 An existing -Target is replaced without a prompt. The folder of -Target must exist.
    Compare-Videos.ps1 An existing -Output is replaced. Its folder must exist.
    Create-Clip.ps1 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 Overwrites -Output without a prompt.
    Create-PillarBox.ps1 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 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 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 An existing -Target image is replaced without a prompt. The folder of -Target must exist.
    Crop-Clips.ps1 Works in place when -Source and -Target are omitted or equal. See the in-place rule below.
    Get-Frame.ps1 An existing PNG with the same name is replaced.
    Get-FramesCount.ps1 Reads only. Creates and deletes nothing.
    Get-FramesRange.ps1 An existing PNG frame with the same name is replaced.
    Get-LastFrame.ps1 An existing output PNG is replaced without a prompt. With a numbering token in -Image, the resolved name is replaced, not the pattern.
    Get-VideoAudio.ps1 The output file, default or from -Output, is replaced.
    Get-VideoInfo.ps1 Reads only. Creates and deletes nothing.
    Stitch-InBetween.ps1 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 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. Never pass the same folder for both.
    • 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.
    • Never delete .bak.mp4 files yourself unless the user asks.
  • Stitch-InBetween -TempDir rule. The script deletes everything inside an existing -TempDir. Never pass an existing folder. Omit -TempDir unless the user designates a dedicated empty folder.

Script Catalog

Script Purpose Typical use
Clone-Image.ps1 Resize (cover-scale then crop), convert formats, set quality and compression, copy metadata, AI-upscale with -Upscale and optionally keep the upscaled image with -Keep, use LTX-2 sizes with -LTX -Source small.jpg -Target big_4k.png -Upscale 4 -Size 4K
Clone-Video.ps1 Re-encode or convert video (.mp4, .webm, .mkv) with frame range, size, FPS, audio, CRF, -Crop, -Reverse, -LTX and metadata options. Also builds a video from one image plus -Audio, builds a video from a folder of PNG files, and extracts one frame to PNG with -Sequence -Source in.mp4 -Target out.mp4 -Frames "0-100"
Compare-Videos.ps1 Side-by-side or grid comparison of 2 to 4 videos at 1080p or 4K, with -Clip, -Sideways and -NoAudio -S1 a.mp4 -S2 b.mp4 -Output cmp.mp4
Create-Clip.ps1 Clip a frame range. The output name is the source name plus -Suffix (default -Clip). Forwards extra parameters to Clone-Video.ps1 -Video P01.mp4 -Frames "100-200"
Create-FullSubtitle.ps1 Merge two SRT files into one, with timing taken from the video duration -Video v.mp4 -Subtitle1 a.srt -Subtitle2 b.srt -Output out.srt
Create-PillarBox.ps1 Wrap a video in a 16:9 frame with side-bar effects (solid colours, or blurred backgrounds from the video). -Vertical gives a 9:16 frame for square sources -Video v.mp4 -Effect black
Create-Scenes.ps1 Detect scene changes and create one clip per scene. -List only shows the scenes. Forwards extra parameters to Create-Clip.ps1 and Clone-Video.ps1 -Video P01.mp4 -Scene 0.3 -List
Create-ShortClip.ps1 Build a vertical short clip from an INI plan, with optional overlay, colour, smoothing and speed. -Render builds the video from existing frames -Video v.mp4 -Plan plan.ini
Create-Turnaround.ps1 Arrange same-sized images into a row or grid turnaround sheet, with padding colour, quality and compression options -Source "C:\renders\CharacterA" -Target sheet.png
Crop-Clips.ps1 Batch crop LTX-2, Kling and Wan videos to standard sizes. -Size fits every video to a chosen size. Square videos become 1080x1080 -Source in_dir -Target out_dir
Get-Frame.ps1 Extract one frame to PNG with an automatic name (<video>-<frame>.png). Negative indices count from the end -Video P01.mp4 -Frame 10
Get-FramesCount.ps1 Print the total frame count of a video -Video P01.mp4
Get-FramesRange.ps1 Extract a frame range to PNG files, with a custom name pattern through -Images -Video P01.mp4 -Frames "0-50"
Get-LastFrame.ps1 Extract one frame (default: the last) to a chosen PNG name. -Image can include a numbering token -Video P01.mp4 -Image last.png
Get-VideoAudio.ps1 Extract audio as WAV (default) or MP3 (-MP3) -Video P01.mp4 -MP3
Get-VideoInfo.ps1 Show metadata stored in video comment tags. Accepts wildcards. -Full adds JSON output -Video *.mp4
Stitch-InBetween.ps1 Generate in-between frames between two images with RIFE, then 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):

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, with forwarded parameters (list first, then create clips scaled to 720p without audio):

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 -Size 720p -NoAudio -WhatIf
pwsh -NoProfile -File .\Create-Scenes.ps1 -Video P01.mp4 -Scene 0.3 -Size 720p -NoAudio

Extract the last frame to a named PNG:

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):

pwsh -NoProfile -File .\Clone-Image.ps1 -Source small.jpg -Target big_4k.png -Upscale 4 -Size 4K

Interpolate between two images with RIFE (needs RIFE_HOME and NCNN_GPU_ID):

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.
  • "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.
  • "Frame index out of range": run Get-FramesCount.ps1. Indices are 0-based.
  • -Image rejected by Get-Frame: -Image is not a Get-Frame.ps1 parameter. Use Get-LastFrame.ps1 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 and Upscalers.md.