Add Video_Length field to Get-VideoInfo.ini mapping to frames_count for reading actual encoded frame count directly from ffprobe instead of JSON metadata, with duration calculation using real fps

This commit is contained in:
2026-07-03 10:17:50 -04:00
parent 84811de486
commit f69f9b367c
2 changed files with 71 additions and 53 deletions
+70 -53
View File
@@ -9,7 +9,9 @@
When present, outputs the parsed comment metadata as JSON.
.DESCRIPTION
This script uses ffprobe to extract video format metadata, parses the comment tag as JSON,
and outputs the structured information with proper error handling.
and outputs the structured information with proper error handling. Fields configured as
'frames_count' in the INI file are read directly from ffprobe (actual encoded frame count)
rather than from the JSON metadata.
#>
param(
[Parameter(Mandatory = $true)]
@@ -148,63 +150,78 @@ try {
$displayNameFormatted = $displayName -replace '_', ' '
$fieldExists = $parsedComment.PSObject.Properties.Name -contains $jsonFieldName
if (-not $fieldExists) {
$valueDisplay = 'Not found'
}
else {
$fieldValue = $parsedComment.$jsonFieldName
if ($null -eq $fieldValue) {
$valueDisplay = 'Not found'
}
elseif ($jsonFieldName -eq 'generation_time') {
$totalSeconds = [int]$fieldValue
$minutes = [Math]::Floor($totalSeconds / 60)
$seconds = $totalSeconds % 60
$valueDisplay = ('{0}s ({1}m {2}s)' -f $totalSeconds, $minutes, $seconds)
}
elseif ($jsonFieldName -eq 'creation_date') {
try {
$dateTime = [DateTime]::Parse($fieldValue)
$valueDisplay = $dateTime.ToString('yyyy-MM-dd HH:mm:ss')
}
catch {
$valueDisplay = $fieldValue -replace 'T', ' '
}
}
elseif ($jsonFieldName -eq 'video_length') {
# 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
if ($jsonFieldName -eq 'frames_count') {
# frames_count is read directly from ffprobe (actual encoded frame count)
# rather than from the JSON comment metadata.
$fps = if ($actualFps) { $actualFps } else { 24.0 }
$ffFrames = & ffprobe -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -of csv=p=0 -- "$VideoPath" 2>&1 | Select-Object -First 1
if ($ffFrames -and $ffFrames -match '^\d+$') {
$frames = [int]$ffFrames
$durationSeconds = [Math]::Round($frames / $fps, 1)
$valueDisplay = ('{0} frames ({1}s, {2} fps)' -f $frames, $durationSeconds, $fps)
} else {
$valueDisplay = 'Not found'
}
elseif ($fieldValue -is [array]) {
if ($fieldValue.Count -gt 1) {
# Pretty-print array values as JSON, prefixed with a newline so the
# multi-line output starts cleanly under the field label.
$jsonArray = $fieldValue | ConvertTo-Json -Depth 10
$valueDisplay = [Environment]::NewLine + $jsonArray
}
else {
$jsonArray = $fieldValue | ConvertTo-Json -Depth 10 -Compress
$valueDisplay = $jsonArray
}
}
else {
$fieldExists = $parsedComment.PSObject.Properties.Name -contains $jsonFieldName
if (-not $fieldExists) {
$valueDisplay = 'Not found'
}
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)"
$fieldValue = $parsedComment.$jsonFieldName
if ($null -eq $fieldValue) {
$valueDisplay = 'Not found'
}
elseif ($jsonFieldName -eq 'generation_time') {
$totalSeconds = [int]$fieldValue
$minutes = [Math]::Floor($totalSeconds / 60)
$seconds = $totalSeconds % 60
$valueDisplay = ('{0}s ({1}m {2}s)' -f $totalSeconds, $minutes, $seconds)
}
elseif ($jsonFieldName -eq 'creation_date') {
try {
$dateTime = [DateTime]::Parse($fieldValue)
$valueDisplay = $dateTime.ToString('yyyy-MM-dd HH:mm:ss')
}
catch {
$valueDisplay = $fieldValue -replace 'T', ' '
}
}
elseif ($jsonFieldName -eq 'video_length') {
# 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
$durationSeconds = [Math]::Round($frames / $fps, 1)
$valueDisplay = ('{0} frames ({1}s, {2} fps)' -f $frames, $durationSeconds, $fps)
}
elseif ($fieldValue -is [array]) {
if ($fieldValue.Count -gt 1) {
# Pretty-print array values as JSON, prefixed with a newline so the
# multi-line output starts cleanly under the field label.
$jsonArray = $fieldValue | ConvertTo-Json -Depth 10
$valueDisplay = [Environment]::NewLine + $jsonArray
}
else {
$jsonArray = $fieldValue | ConvertTo-Json -Depth 10 -Compress
$valueDisplay = $jsonArray
}
}
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)"
}
}
}
}