FFmpeg内部有多种时间戳,基于不同的时间基准。理解这些时间概念,有助于通过FFmpeg进行音视频开发
在我看来,FFmpeg有两个时间基准:AV_TIME_BASE
和AVStream->time_base
内部时间基准:AV_TIME_BASE
AV_TIME_BASE
表示1S对应多长时间,AV_TIME_BASE_Q
则是对应的分数形式,如下所示:
/**
* Internal time base represented as integer
*/
#define AV_TIME_BASE 1000000
/**
* Internal time base represented as fractional value
*/
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
AVFormatContext
中的参数多是基于AV_TIME_BASE
的,如下所示:
/**
* Position of the first frame of the component, in
* AV_TIME_BASE fractional seconds.
* 第一帧的开始时间戳
*/
int64_t start_time;
/**
* Duration of the stream, in AV_TIME_BASE fractional
* seconds.
* 时长
*/
int64_t duration;
比如:通过AVFormatContext
计算出音视频文件的时长:
/**
* Convert an AVRational to a `double`.
*/
static inline double av_q2d(AVRational a){
return a.num /(double) a.den;
}
// 单位秒
AVFormatContext->duration * av_q2d(AV_TIME_BASE_Q)
所以,基于内部时间基准的时间戳转换很简单:
// 时间戳转换到秒
time_in_seconds = timestamp * av_q2d(AV_TIME_BASE_Q)
// 秒转换到时间戳
timestamp = time_in_seconds * AV_TIME_BASE
流时间基准:AVStream->time_base
AVStream
表示AVFormatContext
中一条具体的流结构,比如:音频流、视频流和字幕流等。AVStream->time_base也是分数结构AVRational
,只不过不再是固定值,而是依赖于具体流AVStream
、AVPacket
和AVFrame
中的时间戳多是基于对应的流时间基准例如:AVStream
中的帧开始时间戳和流时长:
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented.
* 表示一秒对应多长时间
*/
AVRational time_base;
/**
* Decoding: pts of the first frame of the stream in presentation order, in stream time base.
*/
int64_t start_time;
/**
* Decoding: duration of the stream, in stream time base.
*/
int64_t duration;
要计算出流时长信息(秒),如下所示:
//计算出AVStream多少秒
duration(秒) = AVStream->duration * av_q2d(AVStream->time_base);
比如:某视频流的time_base
是1/90000,即:90000表示1秒。那么2700000实际表示30秒再看一下AVFrame
中的时间戳:
/**
* frame timestamp estimated using various heuristics, in stream time base
*/
int64_t best_effort_timestamp;
/**
* Presentation timestamp in time_base units (time when frame should be shown to user).
*/
int64_t pts;
一般情况下,两者都可以表示PTS时间戳,且都是基于流时间基准
// 用秒表示PTS
timestamp(秒) = av_frame_get_best_effort_timestamp(AVFrame) * av_q2d(AVStream->time_base);
不同时间基准之间的转换
为了在不同时间基准间进行转换,FFmpeg提供了av_rescale_q
函数进行转换
/**
* Rescale a 64-bit integer by 2 rational numbers.
* The operation is mathematically equivalent to `a * bq / cq`.
* a表示原始值,bq表示原来的时间基准;cq表示要转换到的时间基准
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
例如:把流时间戳转换到内部时间戳:
// 把某个视频帧的pts转换成内部时间基准
av_rescale_q(AVFrame->pts, AVStream->time_base, AV_TIME_BASE_Q)
ffmpeg中进行seek时(av_seek_frame),时间戳必须基于流时间基准,比如:seek到第5秒
// 首先计算出基于视频流时间基准的时间戳
int64_t timestamp_in_stream_time_base = av_rescale_q(5* AV_TIME_BASE, AV_TIME_BASE_Q, video_stream_->time_base);
// 然后seek
av_seek_frame(av_format_context, video_stream_index, timestamp_in_stream_time_base, AVSEEK_FLAG_BACKWARD);
原文链接:
https://www.zybuluo.com/ltlovezh/note/1498037
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。