ffmpeg 问答系列-> mux 部分


author: hjjdebug

date: 2025年 08月 24日 星期日 09:47:08 CST

descrip: ffmpeg 问答系列-> mux 部分


文章目录

  • [1. frame->pts 和 packet->pts 是什么关系?](#1. frame->pts 和 packet->pts 是什么关系?)
  • [2 问pts 和 dts, 哪一个时间戳是严格递增的?](#2 问pts 和 dts, 哪一个时间戳是严格递增的?)
  • [3. av_interleaved_write_frame 的工作原理](#3. av_interleaved_write_frame 的工作原理)

mux 部分对frame 的pts, packet的pts, dts 要求十分严格,
这里对时间戳概念pts,dts进行一下辨析.
pts 是演播时间戳. dts 是解码时间戳. 时间戳的基准单位根据上下文可以自己设置.
frame中有时间戳pts,
packet中不仅有pts, 还有dts.

mpeg 音频frame 被编码为packet,

1. frame->pts 和 packet->pts 是什么关系?

一般是直接copy 的关系, 但也有可能差一个偏移.

对mpegaudio 而言, 其关系为:

参考代码: libavcodec/mpegaudioenc_template.c:773

if (frame->pts != AV_NOPTS_VALUE)

avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding)

其中avctx->initial_padding 是481, 所以pkt->pts 总是比frame->pts 小481

当frame->pts=0时, pkt->pts=-481

mpeg 视频frame 被编码为packet, packet有pts 和 dts,

2 问pts 和 dts, 哪一个时间戳是严格递增的?

首先frame->pts 是严格递增的,它就是frame的个数.

然后看一下实测结果. mpeg2 编码视频.

从实验中看出, pkt->dts 是严格递增的.

cpp 复制代码
vframe->pts:0    第一个frame, 被缓存,编不出pkt
--
vframe->pts:1    第2个frame, 被缓存,编不出pkt
--
vframe->pts:2    第2个frame, 得pkt->pts=0, pkt->dts=-1
只所以有dts, 解码时间戳,或者说为什么引入dts概念, 就是要你按解码时间戳来解码, 它是严格递增的.
pts 由于有b帧的存在, 呈现小幅波动, 例如测试的编码例子为0,3,1,2,6,4,5,9... 像喝醉酒一样往上长!

pkt before rescale, pts:0,dts:-1
--
vframe->pts:3
pkt before rescale, pts:3,dts:0
--
vframe->pts:4
pkt before rescale, pts:1,dts:1
--
vframe->pts:5
pkt before rescale, pts:2,dts:2
--
vframe->pts:6
pkt before rescale, pts:6,dts:3
--
vframe->pts:7
pkt before rescale, pts:4,dts:4
--
vframe->pts:8
pkt before rescale, pts:5,dts:5
--
vframe->pts:9
pkt before rescale, pts:9,dts:6
--
vframe->pts:10
pkt before rescale, pts:7,dts:7
--
vframe->pts:11
pkt before rescale, pts:8,dts:8
--
vframe->pts:12
pkt before rescale, pts:12,dts:9

3. av_interleaved_write_frame 的工作原理

ret = av_interleaved_write_frame(fmt_ctx, pkt);

  1. 检查并修正输入AVPacket的pts/dts
  2. 设置有pkt 的链表缓冲, 通过ff_interleave_packet_per_dts默认算法按解码时间戳(DTS)排序.
  3. 先缓存数据包,当时间戳满足连续性条件时批量写入. 例如音视频包都存在且满足连续性条件.开始写入.
  4. 由AVFormatContext->max_interleave_delta参数控制最大缓冲时长. 超过该容忍度强制写入.
    里边内容还是挺多的, 可以调试源码获得第一手资料.