ffmpeg时间戳和时间基

本文详细解释了时间戳的概念,包括PTS和DTS的区别,以及在视频编码和播放中的作用。重点讲解了如何处理不同时间基的转换,如ffmpeg中的tbn、tbc和tbr。介绍了关键API如av_rescale_q_rnd()用于提高精度。涉及封装格式、编码过程中的时间基一致性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间戳

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

定义:当前时刻,单位是时间基。

PTS(Presentation TimeStamp)是渲染用的时间戳,播放器会根据这个时间戳进行渲染播放

DTS(Decoding TimeStamp)解码时间戳,在视频packet进行解码成frame的时候会使用到

编码时一个GOP示例: I P P B P P B P P..

由于有B帧双向参考,在编码之后的帧的时间顺序就会发生变化,导致PTS和DTS不一致。没有B帧时,两者相同。

视频时间戳:一般这个值依赖于帧率,1000/fps为帧间间隔,相当于一个个间隔时间加上去了。

pts = inc++ * (1000/fps); //其中inc是一个静态的,初始值为0,每次打完时间戳加1。

音频时间戳:依赖于音频的sample rate来计算,(1000 / sample_rate)是每个采样多长时间,(frame_size * 1000 / sample_rate)计算出来一个frame_size长度的音频帧的时长:

pts = inc++ * (frame_size * 1000 / sample_rate);

音频pts计算

音频 sample_rate : samples per second,即采样率,表示每秒采集多少采样点。 比如44100HZ,就是一秒采集44100个sample。即每个sample的时间是1/44100秒。

一个音频帧的AVFrame有nb_samples个sample,所以一个AVFrame耗时是nb_samples*(1/44100)秒

时间基

时间基表示每个刻度是多少秒,比如(1/25)秒,(1/1M)秒

时间基在ffmpeg中不是统一的,在各层中都不相同,分为:封装层时间基、编解码层时间基

封装层时间基为AVStream->time_base;编解码层时间基为AVCodecContext->time_base

定义:基本时间单位,同常用的时、分、秒、毫秒、微秒本质一样的基本时间单位

时间基的不统一,带来了时间戳之间的转换,为了提高计算精度,ffmpeg中的时间基都是以分数形式表示的有理数类型,即AVRational类型

除了上述封装层和编解码层的时间基,ffmepg还定义了一个内部时间基,AV_TIME_BASE_Q,这是一个极小的值,1微秒

有了时间戳之后,还需要将PTS的时间戳转成以秒为单位的时间。这里就需要用到ffmpeg的时间基来进行计算了。FFmepg中有三种时间基,命令⾏中tbr、tbn和tbc的打印值就是这三种时间基的倒数:
tbn:    对应容器中的时间基。         值是AVStream.time_base的倒数
tbc:    对应编解码器中的时间基。    值是AVCodecContext.time_base的倒数
tbr:    从视频流中猜算得到,可能是帧率或场率(帧率的2倍)


在ffmpeg中,不同的时间戳对应不同的时间基。一般在视频进行渲染的时候渲染的时候用到的就是视频流的时间基tbn,视频流的时间基和帧率有关,每秒30帧,代表一帧需要1/30秒。

// ffmpeg中内部的时间基

define AV_TIME_BASE 1000000
// ffmpeg中分数所表示法

define AV_TIME_BASE_Q (AVRatonal){1, AV_TIME_BASE}

时间戳的转换
存在原因:因为时间基不统一,所以当时间基变化时,需要对时间戳进行转换

不同的封装格式的timebase是不一样的。另外,整个转码过程中,不同数据状态对应的时间基也是不一致的。例如视频MPEG-TS封装格式25fps,非压缩时候的数据AVFrame,它的时间基为AVCodecContext 的time_base,AVRational{1,25}。 压缩后的数据AVPacket对应的时间基为AVStream的time_base,AVRational{1,90000}。

转换思路很简单:先将原时间戳以某一中间时间单位(这里取国际通用时间单位:秒)为单位进行转换,然后再以新的时间基为单位进行转换,即得到新的时间戳

具体转换API:由转换思路可知,转换过程即先做个乘法再做个除法,涉及到除法就有除不尽的情况,就有舍入问题,ffmpeg专门为时间戳转换提供了API,即av_rescale_q_rnd(),一定要使用该API,提高转换精度,以免给片源未来的播放带来问题。

时间戳转换为秒
要用到的API:av_q2d(time_base),先将有理数类型的时间基转为double类型

具体转换过程:time_in_second = timestamp * av_q2d(time_base)

### FFmpeg 时间戳校正方法及参数设置 在使用 FFmpeg 进行多媒体处理时,时间戳的校正是一个常见的需求。以下是关于如何通过 FFmpeg 实现时间戳校正的方法及其相关参数设置。 #### 1. 基本原理 FFmpeg 中的时间戳主要涉及 `PTS` (Presentation Time Stamp) `DTS` (Decoding Time Stamp),它们用于描述媒体数据包播放解码的时间顺序。当遇到不连续或错误的时间戳时,可以通过调整这些值来实现校正[^4]。 #### 2. 使用命令行工具进行时间戳校正 FFmpeg 提供了一些内置选项可以用来修复时间戳问题: - **`-fflags +genpts`**: 自动生成新的 PTS 值以解决时间戳不一致的问题。 ```bash ffmpeg -i input.mp4 -vf "setpts=N/FRAME_RATE/TB" -c:v libx264 -preset ultrafast -fflags +genpts output.mp4 ``` - **`-vsync` 参数**: 控制视频同步模式,帮助修正帧率异常引起的时间戳错乱。 ```bash ffmpeg -i input.mp4 -vsync vfr -c:v copy -c:a copy output.mp4 ``` - **`-async` 参数**: 调整音频流的速度使其与视频保持同步。 ```bash ffmpeg -i input.mp4 -async 1 -c:v copy -c:a aac output.mp4 ``` 以上命令适用于简单的文件级操作场景,能够有效应对大多数常见的时间戳问题[^4]。 #### 3. 编程接口下的时间戳校正逻辑 如果需要更精细控制,则可通过编程调用 FFmpeg 的 API 来完成自定义的时间戳校正逻辑。下面是一个基于 C++ 的简单例子展示如何手动修改时间戳: ```cpp #include <libavformat/avformat.h> #include <libavutil/timestamp.h> void rescaleTimestamps(AVFormatContext* fmtCtx){ for(int i=0;i<fmtCtx->nb_streams;i++){ AVStream *in_stream = fmtCtx->streams[i]; while(av_read_frame(fmtCtx,&packet)>=0){ packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base); // Write packet to output... } } } ``` 此代码片段展示了如何利用 `av_rescale_q_rnd()` 函数重新缩放每个数据包的时间戳至目标容器所需的时间基数[^1]^。 #### 4. 特殊情况处理 对于某些特殊情况下(如直播流),可能还需要额外考虑延迟补偿等因素。例如,在实时应用中可采用如下策略: - 记录每一帧的实际接收时刻; - 对比理想播放时间实际到达时间差异; - 动态调整缓冲区大小或者引入适当的人工等待期以平滑过渡[^5]^。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步基

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值