flv # 存在B帧情况下的dts和pts

如果不存在B帧,当然dts等于pts。
如果存在B帧呢,flv文件中dts和pts是如何体现的呢?

FLV的官方文档中对tag的定义,前半部分如下:

tag的前半部分

可以看到有两个字段涉及时间戳:


flv timestamp
  • 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的字段来实现

VideoTagHeader

Composition Time in VideoTagHeader

关于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 that CT(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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容