|
<# |
|
.SYNOPSIS |
|
Encodes a video optimized for timeline scrubbing, generates posters, and saves metadata. |
|
|
|
.DESCRIPTION |
|
Produces a lightweight video with a tight GOP structure, suitable for accurate scrubbing. |
|
Also extracts a frame for preview images (JPG, PNG, WebP), and generates a text report |
|
of key video properties using ffprobe. Allows control of FFmpeg quality and compression settings. |
|
|
|
.PARAMETER InputFile |
|
Input video file (.mp4, .mov, etc.) |
|
|
|
.PARAMETER OutputFile |
|
Optional. Output video filename. Defaults to {input}_scrub_{timestamp}.mp4 |
|
|
|
.PARAMETER MaxHeight |
|
Scales video height (width is automatic). Default: 1080 |
|
|
|
.PARAMETER KeyframeInterval |
|
Keyframe interval in frames. Lower = more accurate scrubbing. Default: 6 |
|
|
|
.PARAMETER CRF |
|
Constant Rate Factor for FFmpeg (lower is higher quality). Range: 0–51. Default: 20 |
|
|
|
.PARAMETER Preset |
|
Encoding speed/efficiency tradeoff. E.g., veryslow, slow, medium. Default: slow |
|
|
|
.PARAMETER Tune |
|
Content tuning hint. E.g., animation, film, stillimage. Optional. |
|
|
|
#> |
|
|
|
param ( |
|
[Parameter(Mandatory = $true)] |
|
[string]$InputFile, |
|
|
|
[string]$OutputFile = "", |
|
|
|
[int]$MaxHeight = 1080, |
|
|
|
[int]$KeyframeInterval = 6, |
|
|
|
[ValidateRange(0, 51)] |
|
[int]$CRF = 20, |
|
|
|
[ValidateSet("ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow")] |
|
[string]$Preset = "slow", |
|
|
|
[string]$Tune = "animation" |
|
) |
|
|
|
# Timestamp |
|
$timestamp = Get-Date -Format "yyyyMMdd_HHmm" |
|
$inputBase = [System.IO.Path]::GetFileNameWithoutExtension($InputFile) |
|
$outputName = "${inputBase}_scrub_${timestamp}.mp4" |
|
$outputDir = "${inputBase}_scrub_${timestamp}" |
|
|
|
# Create folder |
|
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null |
|
|
|
# Fallback if no output provided |
|
if ([string]::IsNullOrWhiteSpace($OutputFile)) { |
|
$OutputFile = Join-Path $outputDir $outputName |
|
} |
|
$posterBase = Join-Path $outputDir "${inputBase}_poster_${timestamp}" |
|
$reportFile = Join-Path $outputDir "${inputBase}_metadata_${timestamp}.txt" |
|
|
|
# --------------------- |
|
# STEP 1: Encode Video |
|
# --------------------- |
|
$ffmpegArgs = @( |
|
"-i", "`"$InputFile`"", |
|
"-vf", "`"format=yuv420p,scale=-1:$MaxHeight`"", |
|
"-c:v", "libx264", |
|
"-profile:v", "main", |
|
"-level:v", "5.1", |
|
"-crf", "$CRF", |
|
"-preset", "$Preset" |
|
) |
|
|
|
if (-not [string]::IsNullOrWhiteSpace($Tune)) { |
|
$ffmpegArgs += @("-tune", "$Tune") |
|
} |
|
|
|
$ffmpegArgs += @( |
|
"-movflags", "+faststart", |
|
"-g", "$KeyframeInterval", |
|
"-keyint_min", "$KeyframeInterval", |
|
"-sc_threshold", "0", |
|
"-an", |
|
"`"$OutputFile`"" |
|
) |
|
|
|
Write-Host "`n[Encode] Scrub-optimized video:" |
|
Write-Host "ffmpeg $($ffmpegArgs -join ' ')`n" |
|
ffmpeg @ffmpegArgs |
|
|
|
# --------------------- |
|
# STEP 2: Generate Posters |
|
# --------------------- |
|
$posterTime = "00:00:01" |
|
$posterFormats = @("jpg", "png", "webp") |
|
|
|
foreach ($ext in $posterFormats) { |
|
$posterFile = "$posterBase.$ext" |
|
$posterArgs = @( |
|
"-i", "`"$InputFile`"", |
|
"-ss", $posterTime, |
|
"-vframes", "1", |
|
"`"$posterFile`"" |
|
) |
|
Write-Host "[Poster] Generating: $posterFile" |
|
ffmpeg @posterArgs |
|
} |
|
|
|
# --------------------- |
|
# STEP 3: Write Metadata Report |
|
# --------------------- |
|
$ffmpegCmdLine = "ffmpeg " + ($ffmpegArgs -join " ") |
|
|
|
$ffprobeArgs = @( |
|
"-v", "error", |
|
"-select_streams", "v:0", |
|
"-show_entries", "stream=codec_name,codec_type,bit_rate,profile,width,height,level,r_frame_rate,nb_frames,duration,avg_frame_rate", |
|
"-of", "default=noprint_wrappers=1:nokey=0", |
|
"`"$OutputFile`"" |
|
) |
|
|
|
Write-Host "[Metadata] Generating report: $reportFile" |
|
$reportHeader = "FFmpeg command:`n$ffmpegCmdLine`n`n--------------------------`nFFprobe Metadata:`n--------------------------`n" |
|
|
|
$reportContent = $reportHeader + (& ffprobe @ffprobeArgs | Out-String) |
|
$reportContent | Out-File -Encoding UTF8 $reportFile |
|
|
|
# --------------------- |
|
# Done |
|
# --------------------- |
|
Write-Host "`n✅ Done." |
|
Write-Host " Encoded video : $OutputFile" |
|
Write-Host " Poster images : $posterBase.jpg, $posterBase.png, $posterBase.webp" |
|
Write-Host " Metadata file : $reportFile" |