24 KiB
Clone-Video.ps1
Clones (copies) a video file using ffmpeg with optional frame range selection and sequence extraction. Reads MP4 (H.264), WebM and Matroska (MKV) sources — including YouTube/Google DASH downloads encoded as VP9 + Opus/AAC — and writes MP4, WebM, or MKV output depending on the -Target file extension. Also builds a video from a directory of sequentially-named PNG files (e.g. frame_0000.png) when -Source points to a folder, or from a single still image (.png, .jpg, .jpeg, .webp, .bmp, .tiff, .tif, .gif) for the duration of a provided audio file when -Source is an image and -Audio is specified.
Synopsis
When Source is a directory containing PNG files with sequence numbers:
- PNG files are sorted alphabetically (ascending) to form the frame list
-StartFrame/-EndFramefilter the list by 0-based index before encoding- If
-Reverseis set, the list is sorted descending after any frame range filtering - If
-Sizeis not specified, the dimensions of the first PNG are used - If
-FPSis not specified, 24 fps is used - If
-CRFis not specified, CRF 8 is used - If
-Audiois not specified, the output has no audio -LTXapplies the same closest-bucket logic as for video sources-Cropapplies the same crop rules as for video sources-Sequenceand-Metadataare not allowed in this mode and produce an error
When Source is a supported image file (.png, .jpg, .jpeg, .webp, .bmp, .tiff, .tif, .gif) and -Audio is provided:
- The image is looped as every frame for the duration of the audio file
-NoAudiois not allowed in this mode- If
-Sizeis not specified, the source image dimensions are used - If
-FPSis not specified, 24 fps is used - If
-CRFis not specified, CRF 8 is used -Size,-FPS,-CRF,-LTXand-Cropare honoured-StartFrame,-EndFrame,-Frames,-Sequence,-Metadataand-Reverseare ignored
When -Frames is provided, it defines a frame range using a flexible format and is mutually exclusive with -StartFrame, -EndFrame and -Sequence.
When Sequence is provided (video source mode):
- If
EndFrameis-1: Extracts the last frame to PNG, then clones video excluding the last frame - If
EndFrameis not-1: Extracts the frame atEndFrameto PNG, then clones video fromStartFrametoEndFrame-1
The output container is chosen from the -Target extension (.mp4, .webm, or .mkv; defaults to .mp4 when no recognised extension is given). Each container has its own codec profile — the script stream-copies streams that are already compatible and transcodes anything else to the container's preferred codecs. See Output containers for the full matrix.
Parameters
-Source(required): Path to an input video file or a directory containing PNG files with sequence numbers (e.g.frame_0000.png) or a supported image file. For video files — accepted containers:.mp4,.webm,.mkv; if the path has no extension the script tries.mp4,.webm, then.mkvin turn. For PNG sequence directories — see PNG Image Sequence Mode. For supported image files — see Image-to-Video Mode.-Target(required): Path to output video file. The extension picks the output container:.mp4(H.264/AAC),.webm(VP9/Opus), or.mkv(H.264/AAC, permissive stream-copy). If the extension is missing or unrecognised,.mp4is appended and the MP4 profile is used.-StartFrame(optional): 0-based frame index to start cloning from (default: 0). Mutually exclusive with-Frames.-EndFrame(optional): 0-based frame index to end cloning at, use -1 for end (default: -1). Mutually exclusive with-Frames.-Frames(optional): 0-based frame range to clone. Mutually exclusive with-StartFrame,-EndFrame, and-Sequence. Supported formats:start-end: Clone frames fromstarttoend(e.g.,"100-500")positive_number: Clone frames from 0 to that number (e.g.,"50")-N: Clone last N frames (e.g.,"-10")%: Represents the last frame index; can be used alone or in ranges (e.g.,"%","10-%","-%")all: Clone all frames (same as"0-%")
-Sequence(optional): Path to PNG file for extracted frame (.pngextension 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 formatwidth: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.-FPS(optional): Frames per second for the output video. Uses the input video's FPS if not specified. Forces a video re-encode, since changing frame rate requires re-encoding.-NoAudio: Exclude audio from cloned video. Forces a video re-encode, since removing the audio stream requires re-muxing the output file.-Audio(optional): Path to an alternate audio file to use for the target video. When specified, this audio replaces the source video's audio. Cannot be used with-NoAudio. When-Sourceis a supported image file,-Audiodetermines the output video duration.-CRF(optional): Constant Rate Factor for video encoding (0-51, lower is better quality). When specified, overrides both the video bitrate and the default-crf 8value. Only used when re-encoding is required-Metadata: Copy available JSON metadata from source video file to target video file-Reverse: Re-encode the video so it plays backward (last selected frame to first). Honours all other parameters (frame range,-Size,-FPS,-CRF, target container, etc.). Audio is not reversed — it is processed exactly as without-Reverse(trimmed/replaced/copied as applicable) and plays forward alongside the reversed video. Forces a video re-encode, since stream-copy is incompatible with thereversefilter.-LTX: Override the dimensions chosen by-Sizewith the closest LTX-2 (Wan2GP by DeepBeepMeep) canonical resolution for the source's aspect ratio. Only valid when-Sizeis one ofHD,1080p,720por480p. The script probes the source's width/height, computes its aspect ratio, and picks the bucket whose ratio is numerically closest. Forces a video re-encode (same as-Size). The buckets per-Sizeare:HD/1080p:1920x1088(16:9),1088x1920(9:16),1664x960(21:9),960x1664(9:21).720p:1280x704(16:9),704x1280(9:16),1088x576(21:9),576x1088(9:21).480p:832x448(16:9),448x832(9:16),896x512(4:3),512x896(3:4).
-Crop: Obtain the dimensions selected by-Size(including-LTXbuckets) by center-cropping the source instead of resizing it, so the original aspect ratio of the picture content is kept (no stretching or scaling). Requires-Size. Without-Cropthe source is resized (default behaviour). Honoured in all modes (video, PNG sequence and image-to-video). Forces a video re-encode (same as-Size). See Crop rules.
Crop rules
When -Crop is present, the requested output size is first computed exactly as without -Crop (named presets apply the short-side AR rule, custom width:height is used as given, -LTX picks its bucket). The source is then cropped around its center instead of being scaled:
- A dimension is cropped only when the source is bigger than the requested size in that dimension.
- A dimension where the source is equal or smaller is left untouched — no upscaling or padding is applied, so the output can be smaller than the requested size.
- Cropped dimensions are rounded down to an even number (required by
yuv420p).
| Source | -Size |
Without -Crop (resize) |
With -Crop |
|---|---|---|---|
1080x1080 |
960:1080 |
960x1080 (squeezed horizontally) |
960x1080 (cropped horizontally) |
1080x1080 |
720:720 |
720x720 (scaled down) |
720x720 (cropped horizontally and vertically) |
1080x1080 |
1920:720 |
1920x720 (stretched) |
1080x720 (cropped vertically only) |
Image-to-Video Mode
When -Source is a supported image file and -Audio is provided, the script builds a video of the static image lasting for the duration of the audio file, bypassing all video-probing logic.
Supported image formats
.png, .jpg, .jpeg, .webp, .bmp, .tiff, .tif, .gif
Defaults vs. overrides
| Parameter | Default when omitted | Can be overridden? |
|---|---|---|
-FPS |
24 | Yes — any positive value |
-CRF |
8 | Yes — any value 0-51 |
-Size |
Source image dimensions (even-padded) | Yes — any named or custom size |
Dimension rules
- If
-Sizeis a named preset (720p,1080p, etc.) without-LTX, the short-side AR rule from video mode applies using the source image's dimensions. - If
-Sizeis a customwidth:height, it is applied exactly. - If
-Sizeis omitted, the source image's width/height are used directly (padded to an even number if needed). -LTXpicks the closest LTX-2 bucket from the source image's aspect ratio. Only valid with-SizeHD,1080p,720por480p.-Cropcenter-crops the source image to the computed size instead of resizing it (see Crop rules).
Restrictions
-NoAudiois not allowed; audio is required in this mode.-StartFrame,-EndFrame,-Frames,-Sequence,-Metadataand-Reverseare ignored.
Output container
The output container is determined by the -Target extension (.mp4, .webm, .mkv), using the same codec profiles as for video sources. For libx264 targets (MP4/MKV), -tune stillimage is applied to optimise encoding for static content.
PNG Image Sequence Mode
When -Source is a directory the script builds a video from the PNG files found inside, bypassing all video-probing logic. The behaviour is fully driven by the parameters below.
Frame selection
-StartFrame and -EndFrame are 0-based indices into the alphabetically-sorted PNG list (not time-codes). The default range covers all PNG files. -Frames can be used instead of -StartFrame/-EndFrame to specify the range using the flexible format described in the Parameters section.
Ordering
The list is always built in ascending alphabetical order first. -Reverse then reverses it after the frame range has been applied, so the first frame in the output is list[EndFrame] and the last is list[StartFrame].
Defaults vs. overrides
| Parameter | Default when omitted | Can be overridden? |
|---|---|---|
-FPS |
24 | Yes — any positive value |
-CRF |
8 | Yes — any value 0-51 |
-Size |
First PNG dimensions (even-padded) | Yes — any named or custom size |
| Audio | No audio (-an) |
Yes — provide -Audio |
Dimension rules
- If
-Sizeis a named preset (720p,1080p, etc.) without-LTX, the short-side AR rule from video mode applies using the first PNG's dimensions. - If
-Sizeis a customwidth:height, it is applied exactly (as with video mode). - If
-Sizeis omitted, the first PNG's width/height are used directly (padded to an even number if needed). -LTXpicks the closest LTX-2 bucket from the first PNG's aspect ratio. Only valid with-SizeHD,1080p,720por480p.-Cropcenter-crops the PNG frames to the computed size instead of resizing them (see Crop rules).
Unsupported parameters
-Sequence and -Metadata are not valid in PNG sequence mode. Specifying either produces a terminating error before any file I/O occurs.
Output container
The output container is still determined by the -Target extension (.mp4, .webm, .mkv), using the same codec profiles as for video sources.
Examples
Clone entire video:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4
Clone specific frame range:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -StartFrame 100 -EndFrame 500
Clone frame range using -Frames:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -Frames "100-500"
Clone from frame 0 to frame 50:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -Frames "50"
Clone last 10 frames:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -Frames "-10"
Clone from frame 10 to last frame:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -Frames "10-%"
Extract last frame and clone without it:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Sequence last_frame.png
# Extracts last frame to last_frame.png
# Clones all frames except the last one
Extract specific frame and clone up to it:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -EndFrame 100 -Sequence frame100.png
# Extracts frame 100 to frame100.png
# Clones frames 0-99 (excluding frame 100)
Clone with resized output:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Size 720p
Clone with custom resolution:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Size 1280:720
Clone with cropped output (no resizing):
.\Clone-Video.ps1 -Source square.mp4 -Target output.mp4 -Size 960:1080 -Crop
# A 1080x1080 source is center-cropped horizontally to 960x1080.
Clone with output cropped on both dimensions:
.\Clone-Video.ps1 -Source square.mp4 -Target output.mp4 -Size 720:720 -Crop
# A 1080x1080 source is center-cropped horizontally and vertically to 720x720.
Clone with different FPS:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -FPS 24
Clone with resized output and different FPS:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Size 1080p -FPS 30
Clone without audio:
.\Clone-Video.ps1 -Source video.mp4 -Target silent.mp4 -NoAudio
Clone with alternate audio:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Audio music.mp3
# Replaces the video's audio with audio from music.mp3
Clone frame range with alternate audio:
.\Clone-Video.ps1 -Source video.mp4 -Target clip.mp4 -StartFrame 100 -EndFrame 500 -Audio soundtrack.wav
# Clones frames 100-500 and uses audio from soundtrack.wav (trimmed to match video duration)
Clone using the closest LTX-2 720p bucket:
.\Clone-Video.ps1 -Source video.mp4 -Target ltx720.mp4 -Size 720p -LTX
# A 16:9 source is rescaled to 1280x704, a 9:16 source to 704x1280,
# a 21:9 source to 1088x576, a 9:21 source to 576x1088.
Clone using the closest LTX-2 1080p bucket:
.\Clone-Video.ps1 -Source phone.mp4 -Target ltx1080.mp4 -Size 1080p -LTX
# A 1080x1920 (9:16) phone clip is rescaled to 1088x1920.
Clone with custom CRF value:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Size 1080p -CRF 18
# Uses CRF 18 instead of default CRF 8 or source bitrate
Clone with metadata:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Metadata
# Copies all available JSON metadata from source to target
Reverse the video (audio stays forward):
.\Clone-Video.ps1 -Source video.mp4 -Target reversed.mp4 -Reverse
# Video frames are played from last to first; audio plays forward as in the source.
Reverse a trimmed segment, rescaled and re-timed:
.\Clone-Video.ps1 -Source video.mp4 -Target clip_rev.mp4 -StartFrame 100 -EndFrame 500 -Size 720p -FPS 30 -Reverse
# Selects frames 100-500, scales to 720p, retimes to 30 fps, then reverses the video.
# Audio is trimmed to match the same segment but plays forward.
Build video from a still image with audio (image-to-video mode):
.\Clone-Video.ps1 -Source photo.jpg -Target output.mp4 -Audio soundtrack.mp3
# Creates a video of the static image for the duration of soundtrack.mp3
Build image-to-video at a specific resolution:
.\Clone-Video.ps1 -Source photo.png -Target output.mp4 -Audio narration.wav -Size 720p
Build image-to-video with LTX-2 resolution:
.\Clone-Video.ps1 -Source photo.jpg -Target ltx.mp4 -Audio narration.wav -Size 1080p -LTX
# Picks the closest LTX-2 1080p bucket for the image's aspect ratio
Build video from PNG sequence (all defaults):
.\Clone-Video.ps1 -Source frames\ -Target output.mp4
# All PNG files in frames\ sorted alphabetically, 24 fps, CRF 8, no audio
Build from a frame range:
.\Clone-Video.ps1 -Source frames\ -Target clip.mp4 -StartFrame 10 -EndFrame 49
# Uses frame_0010.png through frame_0049.png (0-based indices into the sorted list)
Build reversed sequence:
.\Clone-Video.ps1 -Source frames\ -Target reversed.mp4 -Reverse
# PNG files sorted descending: last frame plays first
Build reversed range:
.\Clone-Video.ps1 -Source frames\ -Target clip_rev.mp4 -StartFrame 10 -EndFrame 49 -Reverse
# Frames 10-49 selected first, then reversed: frame_0049.png plays first
Build with custom FPS and CRF:
.\Clone-Video.ps1 -Source frames\ -Target output.mp4 -FPS 30 -CRF 18
Build with scaled output:
.\Clone-Video.ps1 -Source frames\ -Target output.mp4 -Size 720p
# Scales to 720p preserving aspect ratio of first PNG
Build with audio:
.\Clone-Video.ps1 -Source frames\ -Target output.mp4 -Audio soundtrack.mp3
Build with LTX-2 canonical resolution:
.\Clone-Video.ps1 -Source frames\ -Target ltx.mp4 -Size 720p -LTX
# Picks the closest LTX-2 720p bucket for the first PNG's aspect ratio
Build as WebM:
.\Clone-Video.ps1 -Source frames\ -Target output.webm -FPS 24
# VP9 + no audio; use -Audio to add a soundtrack
Using absolute paths:
.\Clone-Video.ps1 -Source "C:\Videos\input.mp4" -Target "D:\Output\result.mp4"
Convert a YouTube/Google DASH download (VP9 + Opus in WebM) to standard H.264 MP4:
.\Clone-Video.ps1 -Source download.webm -Target download.mp4
# Video is transcoded from VP9 to H.264 (libx264, yuv420p, slow preset)
# Audio is transcoded from Opus to AAC 192k
Convert an MKV source (e.g. yt-dlp default) to MP4:
.\Clone-Video.ps1 -Source movie.mkv -Target movie.mp4
Convert and rescale a VP9 WebM in one step:
.\Clone-Video.ps1 -Source download.webm -Target download.mp4 -Size 720p
# Single re-encode pass: VP9 -> H.264 at 720p
Transcode an MP4 to WebM (VP9 + Opus):
.\Clone-Video.ps1 -Source video.mp4 -Target video.webm
# Video transcoded H.264 -> VP9 (libvpx-vp9)
# Audio transcoded AAC -> Opus (libopus, 160k)
Stream-copy a YouTube WebM into MKV (no re-encoding):
.\Clone-Video.ps1 -Source download.webm -Target download.mkv
# MKV accepts VP9 and Opus directly; both streams are stream-copied.
Output containers
The output container is selected from the -Target file extension. Each container has its own codec profile, stream-copy list, and encoder settings.
| Container | Target video codec | Target audio codec | Source video codecs stream-copied | Source audio codecs stream-copied |
|---|---|---|---|---|
.mp4 (default) |
libx264 (yuv420p, preset slow) |
aac 192k |
h264 |
aac, mp3, ac3, eac3, alac |
.webm |
libvpx-vp9 (yuv420p, deadline good, cpu-used 2, row-mt 1) |
libopus 160k |
vp8, vp9, av1 |
opus, vorbis |
.mkv |
libx264 (yuv420p, preset slow) |
aac 192k |
h264, hevc, vp8, vp9, av1, mpeg4 |
aac, mp3, ac3, eac3, alac, flac, opus, vorbis |
General rules
- A source stream that's on the container's stream-copy list is copied without re-encoding when no trimming, resizing, frame rate change, or audio removal is requested.
- A source stream that's not on the stream-copy list is transcoded to the container's target codec (e.g. VP9 → H.264 when the target is MP4, AAC → Opus when the target is WebM).
- Trimming (
-StartFrame/-EndFrameor-Frames) always forces an audio re-encode; in that case the audio is encoded with the target container's audio codec regardless of the source. -Sizealways forces a video re-encode (scaling requires re-encoding). For standard named sizes (320p,384p,480p,720p,900p,1080p/HD,1440p/2K,2160p/4K) the output preserves the source's aspect ratio — the reference height is the short-side target (landscape: computed width; portrait: computed height). Custom sizes (width:height) are used exactly.-Cropreplaces thescalefilter with a centeredcropfilter for the size computed from-Size/-LTX; it forces a video re-encode like-Size.-FPSalways forces a video re-encode (frame rate conversion requires re-encoding).-NoAudioalways forces a video re-encode (removing the audio stream requires re-muxing the output file).-Reversealways forces a video re-encode (thereverseffmpeg filter is appended at the end of the video filter chain). Audio is never reversed, so it plays forward over the reversed video and follows the same stream-copy/transcode rules it would have without-Reverse.-LTXonly takes effect when-SizeisHD,1080p,720por480p. Combining it with any other-Sizevalue (or omitting-Size) is rejected with an explicit error so the user is never silently downgraded to the regular preset. The chosen bucket replaces the dimensions that-Sizewould normally produce; everything else (re-encode logic, frame range, FPS, CRF, audio handling) behaves exactly as with a plain-Size.- Video bitrate priority is the same for every container:
-CRF(when specified) → source video bitrate (via-b:v) →-crf 14fallback. Forlibvpx-vp9,-b:v 0is automatically added alongside-crfso VP9's constant-quality mode is correctly enabled. - The
-Audioreplacement file is also probed; if its codec isn't on the target container's audio stream-copy list, it is transcoded to the container's audio codec. - If
-Targethas no extension (or an unrecognised one),.mp4is appended and the MP4 profile is used. This preserves the script's prior single-container behaviour. - The script logs the chosen target container, the detected source codecs, and any external
-Audiocodec, indicating whether each will be transcoded before running ffmpeg.
Notes
- WebM encoding is slow.
libvpx-vp9is much slower thanlibx264; the chosencpu-used 2 -row-mt 1settings strike a reasonable balance, but expect significantly longer rendering times than MP4. - MKV stream-copy is greedy. Because MKV accepts almost any codec, MKV output usually involves no re-encoding at all and is the fastest target for re-containerising downloads.
Safe Execution
This script supports -WhatIf and -Confirm for safe execution:
-WhatIf: Simulate the operation without actually creating files. Shows what would be done.-Confirm: Prompt for confirmation before each state-changing operation.
Simulate without making changes:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -WhatIf
Prompt before creating files:
.\Clone-Video.ps1 -Source video.mp4 -Target output.mp4 -Sequence frame.png -Confirm