347 lines
12 KiB
Markdown
347 lines
12 KiB
Markdown
# Create-ShortClip.ps1
|
||
|
||
Creates a short clip video file from a 16:9 video file with dynamic cropping, padding, and optional overlay.
|
||
|
||
## Synopsis
|
||
|
||
Transforms landscape videos into portrait (9:16) or square (1:1) format clips by:
|
||
|
||
1. Extracting frames with optional vertical padding
|
||
2. Applying horizontal cropping with smooth transitions between keyframes
|
||
3. Optionally overlaying a PNG image with transparency
|
||
4. Encoding the final video with preserved quality settings
|
||
|
||
The output filename is automatically generated by appending `-ShortClip` before the file extension.
|
||
|
||
## Parameters
|
||
|
||
- **`-Video`** (required): Path to input video file (absolute or relative)
|
||
- **`-Plan`** (required): Path to INI plan file defining clip specifications and cropping behavior
|
||
- **`-Images`** (optional): Path to output PNG images file pattern. If not provided, frames are saved in subdirectory 'Frames' with video filename and 4-digit frame numbers
|
||
- **`-Keep`**: Preserve temporary and frames directories after processing
|
||
- **`-Render`**: Skip frame extraction/cropping and only create video from existing frames
|
||
- **`-Color`** (optional): Override INI file Color value for padding color name or RGB value (default: `black`)
|
||
- Named colors: `black`, `white`, `red`, `blue`, etc.
|
||
- Hex format: `#RRGGBB` (e.g., `#1a1a1a`)
|
||
- FFmpeg format: `0xRRGGBB`
|
||
- **`-Overlay`** (optional): Override INI file Overlay value for path to PNG file with transparency to overlay on each cropped frame
|
||
- **`-Smoothing`** (optional): Override INI file Smoothing value (`None`, `Up`, `Center`, `Down`)
|
||
- **`-Speed`** (optional): Override INI file Speed value (minimum: 1)
|
||
- **`-WhatIf`**: Simulate the operation without actually creating files. Shows what would be done.
|
||
- **`-Confirm`**: Prompt for confirmation before each state-changing operation (frame extraction, cropping, video creation).
|
||
|
||
## Plan File Format (INI)
|
||
|
||
### [Clip] Section
|
||
|
||
Defines output video specifications:
|
||
|
||
- **`Format`**: Output aspect ratio (default: `Portrait`)
|
||
- `Portrait`: 9:16 aspect ratio
|
||
- `Square`: 1:1 aspect ratio
|
||
- **`Height`**: Vertical height in pixels (default: `1920`). Width is computed based on format
|
||
- **`Padding`**: Vertical padding position when input height < output height (default: `Center`)
|
||
- `Top`: All padding at top
|
||
- `Bottom`: All padding at bottom
|
||
- `Center`: Padding split evenly top and bottom
|
||
- `None`: No padding; scale video to fill output height and crop horizontally to match format width
|
||
- **'Color'**: Padding color name or RGB value (default: `black`)
|
||
- Named colors: `black`, `white`, `red`, `blue`, etc.
|
||
- Hex format: `#RRGGBB` (e.g., `#1a1a1a`)
|
||
- FFmpeg format: `0xRRGGBB`
|
||
- **`Overlay`**: Path to PNG file with transparency to overlay on each cropped frame
|
||
- **`Audio`**: Copy audio from input video (default: `Yes`)
|
||
- `Yes`: Include audio
|
||
- `No`: Video only
|
||
- **`Position`**: Reference point for numeric cropping offset values (default: `Center`)
|
||
- `Left`: Numeric values represent absolute pixel offset from left edge
|
||
- `Center`: Numeric values represent pixel offset from center (value - output_width/2)
|
||
- `Right`: Numeric values represent pixel offset from right edge (value - output_width)
|
||
- **`Smoothing`**: Mode for adjusting cropping transition length to control speed (default: `None`)
|
||
- `None`: No smoothing, use calculated interpolation as-is
|
||
- `Up`: Extend transition by incrementing upper frame until speed limit is met
|
||
- `Center`: Extend transition by adjusting frame closest to center until speed limit is met
|
||
- `Down`: Extend transition by decrementing lower frame until speed limit is met
|
||
- **`Speed`**: Maximum cropping transition speed in pixels per frame (default: `10`, minimum: `1`)
|
||
- Controls how fast the crop position can change between frames
|
||
- If interpolated speed exceeds this value, smoothing extends the transition
|
||
|
||
### [Cropping] Section
|
||
|
||
Defines horizontal cropping keyframes with automatic interpolation:
|
||
|
||
**Format:** `frame_number=position`
|
||
|
||
**Position values:**
|
||
|
||
Each keyframe value is resolved to a **Left offset**: the X coordinate (in input-frame pixels) of the left edge of the crop window. The crop window has width `output_width` (or the intermediate width when downscaling).
|
||
|
||
- `Left`: Crop from left edge (Left offset = 0)
|
||
- `Center`: Crop from center (Left offset = (input_width - output_width) / 2)
|
||
- `Right`: Crop from right edge (Left offset = input_width - output_width)
|
||
- `number`: Absolute pixel offset, interpreted according to the `Position` setting in the `[Clip]` section (see `Position`). Result is clamped to `[0, input_width - output_width]`.
|
||
|
||
From the Left offset, the script also derives:
|
||
|
||
- **Center offset** = Left offset + output_width / 2 (X coordinate of the crop window's center)
|
||
- **Right offset** = Left offset + output_width (X coordinate of the crop window's right edge)
|
||
|
||
All three values are printed in the cropping offsets table at runtime to help diagnose framing.
|
||
|
||
**Behavior:**
|
||
|
||
- Frame numbers must be in ascending order
|
||
- Intermediate frames are automatically interpolated with smooth transitions
|
||
- Frames after the last keyframe use the last defined offset
|
||
- If section is empty or missing, defaults to `0=Center`
|
||
|
||
**Example:**
|
||
|
||
```ini
|
||
[Cropping]
|
||
0=Left
|
||
84=Left
|
||
85=Right
|
||
140=Right
|
||
159=Left
|
||
```
|
||
|
||
This creates:
|
||
|
||
- Frames 0-84: Crop from left
|
||
- Frame 84→85: Quick transition from left to right
|
||
- Frames 85-140: Crop from right
|
||
- Frames 140-159: Smooth pan from right to left
|
||
- Frames 159+: Crop from left
|
||
|
||
## Examples
|
||
|
||
**Basic portrait clip:**
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video input.mp4 -Plan plan.ini
|
||
# Creates: input-ShortClip.mp4 (9:16 format)
|
||
```
|
||
|
||
**Square format with white padding:**
|
||
|
||
```ini
|
||
# plan.ini
|
||
[Clip]
|
||
Format=Square
|
||
Height=1920
|
||
Padding=Center
|
||
Audio=Yes
|
||
[Cropping]
|
||
0=Center
|
||
```
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Color white
|
||
```
|
||
|
||
**With overlay graphic:**
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Overlay border.png
|
||
# Applies border.png (with transparency) over each cropped frame
|
||
```
|
||
|
||
**No padding (scale to fill height):**
|
||
|
||
```ini
|
||
# plan.ini
|
||
[Clip]
|
||
Format=Portrait
|
||
Height=1920
|
||
Padding=None
|
||
```
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini
|
||
# Scales video to fill 1920px height, crops horizontally to 1080px width
|
||
# No vertical padding bars added
|
||
```
|
||
|
||
**Keep frames for inspection:**
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Keep
|
||
# Preserves Frames/ directory for review
|
||
```
|
||
|
||
**Re-render with different encoding:**
|
||
|
||
```powershell
|
||
# First run: extract and crop frames
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Keep
|
||
|
||
# Modify encoding settings in script, then re-render
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Render
|
||
# Skips extraction/cropping, only creates video from existing frames
|
||
```
|
||
|
||
**Custom output location:**
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Images "C:\Output\frames\frame-%04d.png"
|
||
```
|
||
|
||
**Custom padding color:**
|
||
|
||
```powershell
|
||
# Dark gray padding
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Color #1a1a1a
|
||
|
||
# Navy blue padding
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Color navy
|
||
```
|
||
|
||
**Position parameter with numeric values:**
|
||
|
||
```ini
|
||
# plan.ini - Input: 1920x1088, Output: 1080x1920
|
||
[Clip]
|
||
Format=Portrait
|
||
Position=Center
|
||
[Cropping]
|
||
0=960
|
||
```
|
||
|
||
With `Position=Center` and output width 1080:
|
||
|
||
- Numeric value 960 is adjusted: 960 - (1080/2) = 960 - 540 = 420
|
||
- Final offset: 420 pixels from left edge (centered in 1920px input)
|
||
|
||
With `Position=Left`:
|
||
|
||
- Numeric value 960 is used directly: 960 pixels from left edge
|
||
|
||
With `Position=Right` and output width 1080:
|
||
|
||
- Numeric value 960 is adjusted: 960 - 1080 = -120 → clamped to 0
|
||
|
||
**Simulate without making changes:**
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -WhatIf
|
||
# Displays what would be done (cropping offsets, frame extraction, video creation) without actually processing
|
||
```
|
||
|
||
**Prompt before each operation:**
|
||
|
||
```powershell
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Confirm
|
||
# Will prompt for confirmation before frame extraction, each cropping operation, and video creation
|
||
```
|
||
|
||
**Smoothing fast transitions:**
|
||
|
||
```ini
|
||
# plan.ini - Control transition speed
|
||
[Clip]
|
||
Format=Portrait
|
||
Smoothing=Center
|
||
Speed=5
|
||
[Cropping]
|
||
0=Left
|
||
10=Right
|
||
```
|
||
|
||
Without smoothing, frames 0-10 would transition at 84 pixels/frame (too fast).
|
||
With `Smoothing=Center` and `Speed=5`, the transition extends to more frames, keeping speed ≤ 5 pixels/frame.
|
||
|
||
**Override INI settings via command-line:**
|
||
|
||
```powershell
|
||
# Override smoothing settings from command line
|
||
.\Create-ShortClip.ps1 -Video video.mp4 -Plan plan.ini -Smoothing Up -Speed 3
|
||
# Uses Up smoothing and speed limit of 3, ignoring INI file values
|
||
```
|
||
|
||
## Cropping Interpolation Example
|
||
|
||
Input: 1920x1088 video → Output: 1080x1920 (Portrait)
|
||
|
||
```ini
|
||
[Cropping]
|
||
0=Left
|
||
10=200
|
||
50=Center
|
||
91=Right
|
||
```
|
||
|
||
**Calculated Left offsets:**
|
||
|
||
- **Frame 0**: 0 (Left)
|
||
- **Frames 1-9**: Linear interpolation from 0 to 200
|
||
- Frame 1: 20, Frame 2: 40, ..., Frame 9: 180
|
||
- **Frame 10**: 200
|
||
- **Frames 11-49**: Linear interpolation from 200 to 420 (Center = (1920-1080)/2)
|
||
- Frame 11: 194.5, Frame 12: 189, ..., Frame 49: 425.5
|
||
- **Frame 50**: 420 (Center)
|
||
- **Frames 51-90**: Linear interpolation from 420 to 840 (Right = 1920-1080)
|
||
- Frame 51: 430.5, Frame 52: 441, ..., Frame 90: 829.5
|
||
- **Frame 91**: 840 (Right)
|
||
- **Frames 92+**: 840 (last known value)
|
||
|
||
All fractional values are rounded to nearest pixel.
|
||
|
||
**Runtime output** prints Left, Center (= Left + 540), and Right (= Left + 1080) offsets only at frames where the Left offset changes:
|
||
|
||
```text
|
||
Frame Left Center Right
|
||
----------------------------------------
|
||
0 0 540 1080
|
||
1 20 560 1100
|
||
2 40 580 1120
|
||
...
|
||
10 200 740 1280
|
||
...
|
||
50 420 960 1500
|
||
...
|
||
91 840 1380 1920
|
||
```
|
||
|
||
## Quality Preservation
|
||
|
||
The script automatically preserves video quality from the input:
|
||
|
||
- Detects and uses same codec (H.264 → libx264, H.265 → libx265)
|
||
- Preserves pixel format
|
||
- Uses input bitrate when available
|
||
- Falls back to CRF 8 (near-lossless) for VBR/CRF-encoded inputs
|
||
- Audio encoded as AAC at 192k bitrate
|
||
|
||
## Processing Workflow
|
||
|
||
1. **Validation**: Check video and plan file existence
|
||
2. **Analysis**: Extract video metadata (dimensions, frame count, FPS, codec)
|
||
3. **Offset Calculation**: Compute per-frame cropping offsets with interpolation and optional smoothing
|
||
4. **Frame Extraction**: Extract all frames with vertical padding applied
|
||
5. **Cropping**: Apply horizontal crop to each frame based on computed offsets
|
||
6. **Overlay** (optional): Apply PNG overlay during cropping step
|
||
7. **Encoding**: Create output video from processed frames
|
||
8. **Cleanup**: Remove temporary directories (unless `-Keep` specified)
|
||
|
||
> With `-WhatIf`, the workflow shows all planned operations without executing them.
|
||
|
||
## Existing Files and Folders
|
||
|
||
- **Default `-Images`** (the `Frames` folder next to the video): files directly in `Frames` are deleted before extraction. Subfolders are not touched. With `-Render`, nothing is deleted, because the existing frames are the input.
|
||
- **Explicit `-Images`**: existing frames that match the `-Images` pattern are deleted before extraction. The `Frames` folder is not used or deleted.
|
||
- **Output video**: an existing file at the output path is overwritten.
|
||
- **Temporary extraction directory** (in the system temporary folder): always removed when the run ends.
|
||
- **`Frames` folder** (default `-Images` only): removed after the video is created, unless `-Keep` is given.
|
||
|
||
## Notes
|
||
|
||
- Requires `ffmpeg` and `ffprobe` in system PATH
|
||
- Frame numbers in INI file are 0-based
|
||
- Overlay PNG should match output dimensions (width × height)
|
||
- Transparent areas in overlay allow video content to show through
|
||
- Use `-Render` to quickly re-encode with different settings without reprocessing frames
|
||
- Use `-WhatIf` to preview the full workflow (cropping offsets, frame operations, video creation) before committing to a full run
|
||
- Use `-Confirm` to be prompted before each state-changing operation
|
||
- `Smoothing` only takes effect when the interpolated speed between two keyframes exceeds the `Speed` limit; otherwise offsets are used unchanged
|