1. 核心概念区分
类 | 角色 | 关键职责 |
|---|
InputContainer
| 解封装器 (Demuxer) | 读取文件 → 产出 Packet / Frame,支持 Seek |
OutputContainer
| 封装器 (Muxer) | 接收 Packet → 写入文件,管理流与头部 |
ContainerFormat
| 格式描述符 | 查询容器固有能力(是否支持时间戳、全局头等) |
Container
| 基类 | 提供通用 options、flags、超时配置 |
💡 核心原则:PyAV 中"容器"仅负责打包/拆包,不涉及编解码。视频数据以 Packet 形式进出容器,Frame 由 CodecContext 处理。
核心方法
方法 | 返回值 | 说明 |
|---|
demux(video=0)
| Generator[Packet]
| 产出原始 Packet,末尾自动附带 flush dummy packet |
decode(video=0)
| Generator[Frame]
| 内部 demux + decode,直接产出 Frame |
seek(offset, ...)
| - | 跳转到指定时间点附近的关键帧 |
close()
| - | 释放资源(推荐用 with 语句自动管理) |
Seek 参数详解(视频关键)
container.seek(offset, backward=True, any_frame=False, stream=None)
参数 | 默认值 | 视频处理建议 |
|---|
backward
| True
| 保持 True:向前找关键帧,确保解码起点正确 |
any_frame
| False
| 保持 False:仅定位到关键帧,避免花屏;定位后再逐帧解码到目标位置 |
stream
| None
| 传入视频流时 offset 使用该流 time_base;否则使用 av.time_base |
⚠️ Seek 黄金法则:backward=True, any_frame=False → demux 到目标位置 → 逐帧 decode 直到 PTS ≥ 目标时间。这是保证视频不花屏、不丢帧的唯一可靠方式。
关键属性
属性 | 说明 |
|---|
duration
| 容器总时长(time_base 单位) |
start_time
| 起始时间偏移 |
bit_rate
| 容器码率 |
size
| 文件大小(字节) |
3. OutputContainer:视频封装
核心工作流
with av.open('output.mp4', 'w') as out:
# 1. 添加视频流(指定编码器或复制模板)
stream = out.add_stream('libx264', rate=30)
# 或从输入流复制参数: out.add_stream(template=input_stream)
# 2. 写入 Packet(自动调用 start_encoding 写头部)
for packet in encoded_packets:
out.mux(packet)
# 3. with 退出时自动 close() + 写尾部
核心方法
方法 | 说明 |
|---|
add_stream(codec_name, rate, template, options)
| 创建视频流,rate 为帧率(支持 Fraction) |
mux(packets)
| 批量写入 Packet(自动交织排序) |
mux_one(packet)
| 写入单个 Packet |
start_encoding()
| 手动写文件头(通常自动调用) |
close()
| 写尾部并关闭 |
实用查询属性
属性 | 用途 |
|---|
default_video_codec
| 获取该容器推荐的默认视频编码器 |
supported_codecs
| 获取该容器支持的所有编码器集合 |
4. Container Flags(容器运行时标志)
通过 container.flags 设置,影响解封装/封装行为:
Flag | 值 | 视频场景用途 |
|---|
GENPTS
| 0x1 | 生成缺失的 PTS(即使需解析未来帧),修复时间戳异常 |
IGNDTS
| 0x8 | 忽略 DTS,仅信任 PTS,适用于某些 TS 流 |
NOFILLIN
| 0x10 | 禁止推断元数据,返回容器原始存储值 |
NOPARSE
| 0x20 | 禁用 AVParser,必须同时设 NOFILLIN;Seek 将失效 |
DISCARD_CORRUPT
| 0x100 | 丢弃标记为损坏的帧,防止解码崩溃 |
FLUSH_PACKETS
| 0x200 | 每写一个 Packet 立即刷盘,用于直播/实时录制防丢数据 |
BITEXACT
| 0x400 | 输出确定性比特流(无随机 ID/时间戳),用于测试比对 |
FAST_SEEK
| 0x80000 | 启用快速但不精确的 Seek,适合预览/缩略图 |
SHORTEST
| 0x100000 | 最短流结束时停止封装,防止音视频长度不一致 |
AUTO_BSF
| 0x200000 | 自动添加比特流过滤器,转封装时强烈推荐开启 |
通过 format.flags 查询,决定容器能否承载特定视频特性:
Flag | 含义 | 视频处理影响 |
|---|
GLOBALHEADER
| 需要全局头 | 编码时必须设 `CodecContext.flags |
NOTIMESTAMPS
| 不支持时间戳 | 无法做精确 Seek 和同步,仅适合裸流 |
VARIABLE_FPS
| 支持可变帧率 | VFR 视频可原样封装,无需插帧 |
TS_DISCONT
| 允许时间戳不连续 | 拼接多段视频时无需重排 PTS |
TS_NEGATIVE
| 允许负时间戳 | 保留原始负 PTS,否则被自动偏移到 0 |
ALLOW_FLUSH
| 支持 Flush | 编码器可发送 NULL Packet 触发尾部写出 |
SEEK_TO_PTS
| Seek 基于 PTS | 而非 DTS,影响 Seek 精度 |
NO_BYTE_SEEK
| 不支持字节 Seek | 只能按时间 Seek,HTTP Range 请求受限 |
6. 开发排查备忘
问题 | 原因 | 解决方案 |
|---|
Seek 后花屏/绿屏 | 定位到了非关键帧或未从关键帧开始解码 | 使用 backward=True, any_frame=False + 逐帧解码到目标 PTS |
转封装后播放器无法识别 | 缺少全局头或 BSF 未应用 | 检查 format.flags.GLOBALHEADER;开启 AUTO_BSF |
直播录制断电丢大量数据 | 未实时刷盘 | 设置 `flags |
拼接视频时间戳跳变 | 容器不允许 TS 不连续 | 检查 TS_DISCONT;或重排 PTS 使其单调递增 |
VFR 视频播放加速/卡顿 | 容器不支持可变帧率 | 检查 VARIABLE_FPS;不支持时需 CFR 重采样 |
demux 循环提前结束 | 未处理末尾 flush dummy packet | demux() 已自动包含,手动 demux 时勿过滤空 Packet
|
输出文件每次哈希不同 | 包含随机元数据 | 设置 BITEXACT flag |
add_stream 报错 | 编码器不被容器支持 | 先查 supported_codecs 或用 default_video_codec |
💡 最佳实践总结
解封装:始终用 with 语句;Seek 遵循"关键帧+逐帧逼近"模式;demux 产出的末尾 dummy packet 不要丢弃。
封装:优先用 template= 复制输入流参数;开启 AUTO_BSF 让容器自动适配比特流格式;实时写入必加 FLUSH_PACKETS。
格式选择:写入前检查 ContainerFormat.flags,确认目标容器支持所需视频特性(VFR、负 PTS、全局头等),避免运行时失败。