以下是基于 PyAV Streams 模块整理的媒体流 (Streams) 核心速查手册。该文档聚焦于 StreamContainer 的灵活检索机制与 Stream 对象的元数据/时序属性,是进行多轨处理、格式探测和同步计算的基础。
1. StreamContainer:流的检索与选择
container.streams 是一个类元组容器,提供三种检索范式。优先使用 Typed Collections,仅在动态场景下使用 get()。
三种检索方式对比
Typed Collections(推荐默认使用)
video_streams = container.streams.video # tuple[VideoStream]
audio_streams = container.streams.audio # tuple[AudioStream]
sub_streams = container.streams.subtitles # tuple[SubtitleStream]
data_streams = container.streams.data # tuple[DataStream]
other_streams = container.streams.other # tuple[Stream] (未知类型)
💡 空安全:Typed Collections 返回空元组而非 None,可直接
for s in container.streams.video遍历而无需判空。
Dynamic get() 详解
# 按类型+索引组合选择
container.streams.get(video=0, audio=(0, 1)) # 第1路视频 + 前2路音频
# 按绝对索引选择(跨类型)
container.streams.get(0) # 第1个流(不论类型)
container.streams.get((0, 2)) # 第1和第3个流
# 传入 dict 等价于关键字参数
container.streams.get({'video': 0, 'audio': [0, 1]})
# ⚠️ 无参数 = 返回所有流
all_streams = container.streams.get()
⚠️ 检索陷阱
2. Stream 核心属性
基础标识
💡 属性透传机制:
stream.width、stream.pix_fmt、stream.options等实际来自codec_context。PyAV 做了透明代理,无需手动.codec_context.xxx。
时序系统(关键)
⚠️ 时序计算注意事项
# ✅ 安全的时长计算(秒)
if stream.duration is not None and stream.time_base is not None:
duration_sec = float(stream.duration * stream.time_base)
else:
# 降级方案:用 container.duration 或解码计数
duration_sec = float(container.duration) / av.time_base if container.duration else 0
# ✅ 考虑 start_time 偏移的精确 PTS
actual_pts = frame.pts - (stream.start_time or 0)
3. 常见工作流示例
多轨音频选择(按语言)
target_audio = None
for s in container.streams.audio:
if s.language == 'zho':
target_audio = s
break
if target_audio is None and container.streams.audio:
target_audio = container.streams.audio[0] # fallback to first
流信息摘要打印
for stream in container.streams:
print(f"[{stream.index}] {stream.type} | "
f"codec={stream.codec_context.name} | "
f"profile={stream.profile} | "
f"lang={stream.language} | "
f"tb={stream.time_base} | "
f"dur={stream.duration}")
安全获取主视频流
video = container.streams.video[0] if container.streams.video else None
if video is None:
raise ValueError("No video stream found")
print(f"{video.codec_context.width}x{video.codec_context.height} "
f"{video.codec_context.pix_fmt} @ {float(video.average_rate):.2f}fps")
4. Stream vs CodecContext 属性归属
💡 实践建议:日常使用无需区分,PyAV 透传机制让两者无缝衔接。仅在需要明确修改编码器参数时才显式访问
stream.codec_context。
5. 开发排查备忘
💡 核心记忆点
取流首选 Typed Collections:
streams.video[audio/subtitles],安全且可读get() 用于动态场景:运行时按类型+索引组合选择,无参返回全部
duration/frames/start_time 都可能为 None/0:防御性编程必不可少
跨流时间运算必须先 rescale:各流 time_base 独立,不可直接加减
Stream 透明代理 CodecContext:日常无需区分,改编码参数时才显式访问