求基于分辨率、FPS、比特率的主观视频质量计算公式
现有基于每秒每像素比特数(BPPS)的视频质量评估公式,在跨分辨率、帧率对比时不符合主观感受。例如:
- 1080p60fps/10Mbit/s 视频主观画质优于 720p30fps/9Mbit/s
- 但原公式计算的BPPS:前者≈0.08,后者≈0.32,后者得分更高
原公式代码:
interface Video { width: number height: number fps: number bitrate: number } const computeVideoQualityScalar = (video: Video): number => { const pixelsPerFrame = video.width * video.height const pixelsPerSecond = pixelsPerFrame * video.fps const bitsPerPixelPerSecond = video.bitrate / pixelsPerSecond return bitsPerPixelPerSecond }
问题分析
原公式仅量化了静态像素的比特密度,但忽略了人眼的主观感知特性:
- 分辨率提升带来的细节感知是非线性的(高分辨率下,相同BPPS的细节表现力更强)
- 帧率提升带来的动态流畅度是主观质量的重要组成部分(60fps的流畅度感知远优于30fps,即使BPPS更低)
方案1:综合静态细节与动态流畅度的加权得分
通过结合分辨率、帧率的对数感知模型,给静态细节和动态流畅度赋予权重,得到更符合主观感受的综合得分。
公式设计
const computeSubjectiveVideoQuality = (video: Video, weightStatic: number = 0.5, weightDynamic: number = 0.5): number => { // 计算基础BPPS const pixelsPerFrame = video.width * video.height const pixelsPerSecond = pixelsPerFrame * video.fps const bpps = video.bitrate / pixelsPerSecond // 静态细节得分:结合分辨率的对数感知(基准像素数为640*480=307200) const basePixels = 640 * 480 const resolutionFactor = Math.log2((pixelsPerFrame / basePixels) + 1) const staticScore = bpps * resolutionFactor // 动态流畅度得分:结合帧率的对数感知(基准帧率为15fps) const baseFps = 15 const fpsFactor = Math.log2((video.fps / baseFps) + 1) const dynamicScore = fpsFactor // 综合加权得分 return (staticScore * weightStatic) + (dynamicScore * weightDynamic) }
示例计算
1080p60/10M:
staticScore ≈ 0.08 * Math.log2((2073600/307200)+1) ≈ 0.08 * 2.95 ≈ 0.236
dynamicScore ≈ Math.log2((60/15)+1) ≈ 2.32
综合得分(0.5/0.5权重)≈ 0.2360.5 + 2.320.5 ≈ 1.278720p30/9M:
staticScore ≈ 0.325 * Math.log2((921600/307200)+1) ≈ 0.325 * 2 ≈ 0.65
dynamicScore ≈ Math.log2((30/15)+1) ≈ 1.585
综合得分≈ 0.650.5 +1.5850.5 ≈1.117
结果符合主观感受:1080p60的得分更高。
权重调整建议
- 静态内容(如纪录片、照片视频):提高
weightStatic至0.6-0.7 - 动态内容(如运动、游戏视频):提高
weightDynamic至0.6-0.7
方案2:等效比特率转换法
将不同分辨率、帧率的视频转换为**基准参数(如720p30)**下的等效比特率,通过等效值对比主观质量。核心逻辑是:高分辨率/高帧率的视频,达到相同主观质量所需的比特率并非线性增长,而是存在压缩效率优势。
公式设计
// 基准参数:720p30 const BASE_WIDTH = 1280 const BASE_HEIGHT = 720 const BASE_FPS = 30 // 分辨率压缩效率系数(H.264取0.75,H.265取0.7) const RESOLUTION_COEFFICIENT = 0.75 // 帧率压缩效率系数(H.264取0.8,H.265取0.75) const FPS_COEFFICIENT = 0.8 // 反向转换:计算基准视频达到当前视频主观质量所需的比特率 const computeRequiredBaselineBitrate = (video: Video): number => { const resolutionRatio = (video.width * video.height) / (BASE_WIDTH * BASE_HEIGHT) const fpsRatio = video.fps / BASE_FPS return video.bitrate * (Math.pow(resolutionRatio, RESOLUTION_COEFFICIENT) * Math.pow(fpsRatio, FPS_COEFFICIENT)) }
示例计算
- 1080p60/10M:所需基准比特率≈10M*3.198≈32M
- 720p30/9M:所需基准比特率=9M
32M远高于9M,说明1080p60的主观质量要求更高,实际比特率能满足的质量更好,符合主观感受。
FFmpeg工具实现
可以通过FFprobe获取视频的width/height/fps/bitrate,再用脚本计算得分。以下是bash脚本示例:
#!/bin/bash # 输入视频路径 VIDEO_PATH="$1" # 用ffprobe提取视频参数 VIDEO_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate,bit_rate -of csv=p=0 "$VIDEO_PATH") # 分割参数 IFS=',' read -r WIDTH HEIGHT FPS_STR BITRATE <<< "$VIDEO_INFO" # 计算实际帧率(处理分数形式如30/1) FPS=$(echo "$FPS_STR" | awk -F '/' '{print $1/$2}') # 计算综合得分(方案1的0.5/0.5权重) BASE_PIXELS=$((640*480)) PIXELS=$((WIDTH*HEIGHT)) PPS=$(echo "$PIXELS * $FPS" | bc) BPPS=$(echo "scale=6; $BITRATE / $PPS" | bc) RESOLUTION_FACTOR=$(echo "scale=6; l($PIXELS / $BASE_PIXELS + 1) / l(2)" | bc -l) STATIC_SCORE=$(echo "scale=6; $BPPS * $RESOLUTION_FACTOR" | bc) FPS_FACTOR=$(echo "scale=6; l($FPS / 15 + 1) / l(2)" | bc -l) TOTAL_SCORE=$(echo "scale=6; $STATIC_SCORE * 0.5 + $FPS_FACTOR * 0.5" | bc -l) echo "视频参数:${WIDTH}x${HEIGHT} ${FPS}fps ${BITRATE}bps" echo "主观综合质量得分:$TOTAL_SCORE"
使用方式:
bash compute_video_quality.sh your_video.mp4
内容的提问来源于stack exchange,提问作者JamesK

