From ad31100d64151761a869d534e4faece766181870 Mon Sep 17 00:00:00 2001 From: Claude Toupin Date: Sun, 31 May 2026 22:18:37 -0400 Subject: [PATCH] Add actual encoded resolution and frame rate detection from ffprobe video stream data --- Get-VideoInfo.ps1 | 65 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/Get-VideoInfo.ps1 b/Get-VideoInfo.ps1 index 03aea01..53da915 100644 --- a/Get-VideoInfo.ps1 +++ b/Get-VideoInfo.ps1 @@ -33,7 +33,7 @@ if (-not (Test-Path -LiteralPath $VideoPath)) { $PSNativeCommandUseErrorActionPreference = $false try { - $ffprobeOutput = & ffprobe -v quiet -print_format json -show_format -- $VideoPath 2>&1 + $ffprobeOutput = & ffprobe -v quiet -print_format json -show_format -show_streams -- $VideoPath 2>&1 $ffprobeExit = $LASTEXITCODE if ($ffprobeExit -ne 0) { @@ -56,6 +56,34 @@ try { $commentJson = $raw.format.tags.comment + # Extract the actual (encoded) resolution and frame rate from the first video + # stream reported by ffprobe. These may differ from the values stored in the + # JSON comment metadata (e.g. WanGP/LTX records "720x1280" but the file is + # actually encoded at 704x1280 after the model's internal padding/cropping). + $actualResolution = $null + $actualFps = $null + $get = { param($obj, $name) if ($obj -and ($obj.PSObject.Properties.Name -contains $name)) { $obj.$name } else { $null } } + + if ($raw.PSObject.Properties.Name -contains 'streams') { + $videoStream = $raw.streams | Where-Object { $_.codec_type -eq 'video' } | Select-Object -First 1 + if ($videoStream) { + $w = & $get $videoStream 'width' + $h = & $get $videoStream 'height' + if ($w -and $h) { + $actualResolution = '{0}x{1}' -f [int]$w, [int]$h + } + + $rfr = & $get $videoStream 'r_frame_rate' + if ($rfr -and $rfr -match '^(\d+)/(\d+)$') { + $num = [double]$matches[1] + $den = [double]$matches[2] + if ($den -ne 0) { + $actualFps = [Math]::Round($num / $den, 3) + } + } + } + } + try { $parsedComment = $commentJson | ConvertFrom-Json } @@ -123,33 +151,28 @@ try { } } elseif ($jsonFieldName -eq 'video_length') { - $fps = 24.0 - $fieldExists = $parsedComment.PSObject.Properties.Name -contains 'force_fps' - - if ($fieldExists) { - # force_fps may be a number (e.g. 30) or a non-numeric mode string - # (e.g. "control" in some WanGP/LTX presets). Only override the - # default when the value parses as a positive number. - $forceFpsRaw = $parsedComment.force_fps - $parsedFps = 0.0 - if ([double]::TryParse( - [string]$forceFpsRaw, - [System.Globalization.NumberStyles]::Float, - [System.Globalization.CultureInfo]::InvariantCulture, - [ref]$parsedFps) -and $parsedFps -gt 0) { - $fps = $parsedFps - } - } - + # Always use the real frame rate reported by ffprobe for the + # duration calculation. The JSON metadata's force_fps may be a + # non-numeric mode marker (e.g. "control") or simply not match + # the actual encoded frame rate. + $fps = if ($actualFps) { $actualFps } else { 24.0 } $frames = [int]$fieldValue - $secondsAt24fps = [Math]::Round($frames / $fps, 1) - $valueDisplay = ('{0} frames ({1}s, {2} fps)' -f $frames, $secondsAt24fps, $fps) + $durationSeconds = [Math]::Round($frames / $fps, 1) + $valueDisplay = ('{0} frames ({1}s, {2} fps)' -f $frames, $durationSeconds, $fps) } elseif ($fieldValue -is [array]) { $valueDisplay = ($fieldValue | ConvertTo-Json -Compress -Depth 10) } else { $valueDisplay = $fieldValue + # If the value looks like a WxH resolution string and ffprobe + # reports a different actual encoded resolution, surface both. + if ($actualResolution ` + -and ($fieldValue -is [string]) ` + -and ($fieldValue -match '^\d+x\d+$') ` + -and ($fieldValue -ne $actualResolution)) { + $valueDisplay = "$fieldValue (real: $actualResolution)" + } } }