鴥彼晚风
发布于 2026-07-01 / 2 阅读
0
0

PyAV 视频元数据 (SideData) 核心速查手册

以下是基于 PyAV Side Data 模块整理的视频元数据 (SideData) 核心速查手册。该文档聚焦于 av.sidedata 在视频处理中的 HDR 信息提取、运动向量分析及显示矩阵解析,是进行高质量视频转码、渲染和智能分析的关键。


1. 核心概念:什么是 SideData?

SideData 是附加在 Frame(偶尔也在 Packet)上的非像素元数据。它不直接参与画面渲染,但携带了正确显示、后处理或分析视频所必需的上下文信息。

特性

说明

载体

主要挂载于 Frame.side_data,部分类型也存在于 Packet.side_data

基类

继承自 Buffer,提供底层字节访问

枚举

通过 av.sidedata.Type 标识类型

生命周期

绑定到所属 Frame/Packet,不可独立持有

💡 黄金法则HDR 渲染必看 MASTERING_DISPLAY + CONTENT_LIGHT_LEVEL;自动旋转必看 DISPLAYMATRIX;AI 分析可挖 MOTION_VECTORS。


2. 视频关键 SideData 类型速查

🎨 HDR 相关(最重要)

Type

Flag

用途

关键字段

MASTERING_DISPLAY_METADATA

0xB

HDR 母版显示器色域与亮度范围

primaries, white_point, min/max_luminance

CONTENT_LIGHT_LEVEL

0xE

内容最大/平均亮度限制

MaxCLL, MaxFALL

ICC_PROFILE

0xF

色彩管理 ICC 配置文件

完整 ICC profile bytes

for sd in frame.side_data:
    if sd.type == av.sidedata.Type.MASTERING_DISPLAY_METADATA:
        print(f"Max Luminance: {sd.max_luminance}")
        print(f"Min Luminance: {sd.min_luminance}")
        print(f"Primaries: {sd.primaries}")
    elif sd.type == av.sidedata.Type.CONTENT_LIGHT_LEVEL:
        print(f"MaxCLL: {sd.MaxCLL}, MaxFALL: {sd.MaxFALL}")

📐 几何与显示

Type

Flag

用途

备注

DISPLAYMATRIX

0x6

视频旋转/翻转矩阵

移动端竖拍视频必备;9个int32组成的3×3矩阵

STEREO3D

0x2

3D 立体视频格式标记

左右/上下/交错等布局

SPHERICAL

0xD

VR/全景视频投影参数

equirectangular/cubemap + FOV

PANSCAN

0x0

Pan & Scan 裁切区域

旧式宽屏→4:3 适配

AFD

0x7

Active Format Description

广播标准中的有效画面区域

🤖 分析与编码辅助

Type

Flag

用途

备注

MOTION_VECTORS

0x8

编码器运动向量

返回 MotionVectors 序列对象

SEI_UNREGISTERED

0x14

私有 SEI 消息

厂商自定义元数据(如 DJI 无人机 GPS)

GOP_TIMECODE / S12M_TIMECODE

0xC/0x10

SMPTE 时间码

专业制作流程

A53_CC

0x1

CEA-608/708 隐藏字幕

北美广播字幕


3. MotionVectors 详解

MotionVectors 是唯一具有结构化高级 API 的 SideData 类型,继承自 Sequence,可直接迭代:

for sd in frame.side_data:
    if sd.type == av.sidedata.Type.MOTION_VECTORS:
        mvs = sd  # MotionVectors instance
        for mv in mvs:
            print(f"src={mv.src}, dst={mv.dst}, "
                  f"motion_x={mv.motion_x}, motion_y={mv.motion_y}, "
                  f"flags={mv.flags}")

MV 属性

说明

source / destination

参考帧索引

motion_x / motion_y

运动矢量分量

motion_scale

矢量精度因子

w / h

宏块尺寸

flags

方向/类型标志

💡 应用场景:视频稳像、插帧质量评估、编码效率分析、基于运动的显著性检测。需在解码时启用 export_side_data='motion_vectors'


4. 安全访问模式

防御性遍历

# ✅ 推荐:按类型过滤,避免索引越界
for sd in frame.side_data:
    match sd.type:
        case av.sidedata.Type.MASTERING_DISPLAY_METADATA:
            process_hdr_mastering(sd)
        case av.sidedata.Type.DISPLAYMATRIX:
            apply_rotation(sd)
        case _:
            pass  # 忽略未知类型,向前兼容

⚠️ 注意事项

陷阱

说明

解决方案

SideData 可能为空列表

并非所有帧都携带元数据

始终用 for 遍历,不要假设存在

仅特定帧携带

HDR metadata 通常只在首帧/IDR帧

缓存首次出现的值用于后续帧

Buffer 接口 vs 结构化字段

部分类型仅有 raw bytes

查阅 FFmpeg 对应 struct 定义手动解析

生命周期绑定

Frame 释放后 SideData 失效

需要持久化时立即提取并深拷贝

导出需显式启用

MotionVectors 默认不导出

codec_context.export_side_data = ['motion_vectors']


5. 常见工作流示例

HDR → SDR Tone Mapping 前置检查

has_hdr = False
max_cll = 0
for sd in frame.side_data:
    if sd.type == av.sidedata.Type.MASTERING_DISPLAY_METADATA:
        has_hdr = True
    if sd.type == av.sidedata.Type.CONTENT_LIGHT_LEVEL:
        max_cll = sd.MaxCLL

if has_hdr and max_cll > 1000:
    tonemap_filter = graph.add('tonemap', 'tonemap=hable:desat=0')

自动旋转校正

import numpy as np

for sd in frame.side_data:
    if sd.type == av.sidedata.Type.DISPLAYMATRIX:
        matrix = np.frombuffer(sd.to_memoryview(), dtype=np.int32).reshape(3, 3)
        rotation = extract_rotation(matrix)  # 0/90/180/270
        if rotation != 0:
            graph.add('transpose', f'{rotation // 90}')
        break

6. 开发排查备忘

症状

可能原因

诊断步骤

HDR 色调映射过曝/欠曝

未读取 CLL/Mastering metadata

遍历 side_data 确认是否存在

竖拍视频显示为横屏

忽略 DISPLAYMATRIX

检查并应用旋转矩阵

MotionVectors 为空

未启用导出

设置 export_side_data

AttributeError on sd.field

该类型无结构化字段

改用 to_bytes() / to_memoryview() 手动解析

仅首帧有 HDR 信息

正常行为,非每帧携带

缓存首次读取的值

SEI 数据乱码

私有协议未文档化

联系设备厂商获取解析规范

SideData 访问崩溃

Frame 已释放

确保在 Frame 生命周期内完成读取

💡 核心记忆点

  • HDR 双件套:MASTERING_DISPLAY_METADATA + CONTENT_LIGHT_LEVEL 缺一不可

  • 旋转靠矩阵:DISPLAYMATRIX 是移动端视频正确显示的唯一依据

  • MV 要导出:MotionVectors 默认关闭,需显式启用 export_side_data

  • 遍历优于索引:SideData 数量和顺序不固定,永远用 for + type 匹配

  • 缓存首帧元数据:HDR/ICC 等信息通常只出现一次,不要逐帧重复查找


评论