如果不存在B帧,当然dts等于pts。
如果存在B帧呢,flv文件中dts和pts是如何体现的呢?
FLV的官方文档中对tag的定义,前半部分如下:
可以看到有两个字段涉及时间戳:
Timestamp(3字节)
时间戳,单位毫秒。
该时间戳是相对于首个Tag时间戳的相对时间戳。
首个Tag的时间戳一般为0。TimestampExtended(1字节)
扩展时间戳。
和Timestamp合在一起拼成一个32bit的时间戳。
该时间戳占高8位。
这个时间戳是什么呢? 是dts还是pts?
看一段ffmpeg中libavformat/flvdec.c的代码:
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
...
pos = avio_tell(s->pb);
type = (avio_r8(s->pb) & 0x1F);
orig_size =
size = avio_rb24(s->pb);
flv->sum_flv_tag_size += size + 11;
dts = avio_rb24(s->pb);
dts |= (unsigned)avio_r8(s->pb) << 24;
av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb));
if (avio_feof(s->pb))
return AVERROR_EOF;
avio_skip(s->pb, 3); /* stream id, always 0 */
flags = 0;
...
}
可以看到里边非常重要的两句:
dts = avio_rb24(s->pb);
dts |= (unsigned)avio_r8(s->pb) << 24;
可见Timestamp和TimestampExtended拼出来的是dts。
那么pts如何体现呢?
答案是用VideoTagHeader中有个Composition Time的字段来实现。
关于composition time的详细定义,文档说:
See ISO 14496-12, 8.15.3 for an explanation of composition times.
The offset in an FLV file is always in milliseconds. (单位也是毫秒)
Then look into the ISO 14496-12,8.15.3 , Page 24 and 26
8.15.3 Composition Time to Sample Box
8.15.3.1 Definition
Box Type: ‘ctts’
Container: Sample Table Box (‘stbl’)
Mandatory: No
Quantity: Zero or one
This box provides the offset between decoding time and composition time.
Since decoding time must be less than the composition time,
the offsets are expressed as unsigned numbers such thatCT(n) = DT(n) + CTTS(n)
where CTTS(n) is the (uncompressed) table entry for sample n.
由以上的文档可知,flv文档中的composition time表示PTS相对于DTS的偏移值。
参见一段ffmpeg中libavformat/flvdec.c的代码:
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
...
if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
// sign extension
int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
pts = dts + cts;
if (cts < 0) { // dts might be wrong
if (!flv->wrong_dts)
av_log(s, AV_LOG_WARNING,
"Negative cts, previous timestamps might be wrong.\n");
flv->wrong_dts = 1;
} else if (FFABS(dts - pts) > 1000*60*15) {
av_log(s, AV_LOG_WARNING,
"invalid timestamps %"PRId64" %"PRId64"\n", dts, pts);
dts = pts = AV_NOPTS_VALUE;
}
}
...
}
其中最重要的两句:
int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
pts = dts + cts;
总结一下:
1. flv文件中Timestamp和TimestampExtended拼出来的是dts。也就是解码时间。
Timestamp和TimestampExtended拼出来dts单位为ms。
2. CompositionTime 表示PTS相对于DTS的偏移值, 在每个视频tag的第14~16字节, 。
显示时间(pts) = 解码时间(tag的第5~8字节) + CompositionTime
CompositionTime的单位也是ms
注: 上文涉及到的ffmpeg的版本是4.0
ffmpeg version N-91445-g6cc6b61 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-11)
configuration: --enable-gpl --enable-debug=3 --enable-libmfx --disable-optimizations --disable-stripping
libavutil 56. 18.102 / 56. 18.102
libavcodec 58. 21.104 / 58. 21.104
libavformat 58. 17.101 / 58. 17.101
libavdevice 58. 4.101 / 58. 4.101
libavfilter 7. 25.100 / 7. 25.100
libswscale 5. 2.100 / 5. 2.100
libswresample 3. 2.100 / 3. 2.100
libpostproc 55. 2.100 / 55. 2.100
References:
http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
ISO 14496-12,8.15.3
https://stackoverflow.com/questions/7054954/the-composition-timects-when-wrapping-h-264-nalus
https://blog.csdn.net/cabbage2008/article/details/50402580
https://blog.csdn.net/leixiaohua1020/article/details/12678577