=================================================================
音视频入门基础:WAV专题系列文章:
音视频入门基础:WAV专题(1)——使用FFmpeg命令生成WAV音频文件
音视频入门基础:WAV专题(2)——WAV格式简介
音视频入门基础:WAV专题(3)——FFmpeg源码中,判断某文件是否为WAV音频文件的实现
音视频入门基础:WAV专题(4)——FFmpeg源码中获取WAV文件音频压缩编码格式、采样频率、声道数量、采样位数、码率的实现
音视频入门基础:WAV专题(5)——FFmpeg源码中解码WAV Header的实现
音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息
音视频入门基础:WAV专题(7)——FFmpeg源码中计算WAV音频文件每个packet的size值的实现
音视频入门基础:WAV专题(8)——FFmpeg源码中计算WAV音频文件AVStream的time_base的实现
音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现
音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现
音视频入门基础:WAV专题(11)——FFmpeg源码中计算WAV音频文件每个packet的pts_time、dts_time的实现
=================================================================
一、引言
从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts_time、dts_time:
打印出来的“pts_time”是以秒为单位的显示时间戳;“dts_time”是以秒为单位的解码时间戳。这两个值都是通过fftools/ffprobe.c中的show_packet函数打印出来的:
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...
print_time("pts_time", pkt->pts, &st->time_base);
//...
print_time("dts_time", pkt->dts, &st->time_base);
//...
}
本文讲述上述pts_time、dts_time的值是怎样被计算出来的。如果想直接看结论,可以跳到本文的最后,直接看“总结”。
二、FFmpeg源码中计算WAV音频文件每个packet的pts_time、dts_time的实现
从《音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现》中可以知道,pts是以AVStream->time_base为单位的显示时间戳;dts是以AVStream->time_base为单位的解码时间戳。
show_packet函数是通过print_time宏定义将pts和dts转换为pts_time和dts_time,并打印出来的:
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...
print_time("pts_time", pkt->pts, &st->time_base);
//...
print_time("dts_time", pkt->dts, &st->time_base);
//...
}
print_time宏定义如下,可以看到其实质是调用writer_print_time函数:
#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
而writer_print_time函数的定义为:
static void writer_print_time(WriterContext *wctx, const char *key,
int64_t ts, const AVRational *time_base, int is_duration)
{
char buf[128];
if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
} else {
double d = ts * av_q2d(*time_base);
struct unit_value uv;
uv.val.d = d;
uv.unit = unit_second_str;
value_string(buf, sizeof(buf), uv);
writer_print_string(wctx, key, buf, 0);
}
}
表达式writer_print_time(w, k, v, tb, 0)中,“v”为pts或dts,“tb”为AVStream的time_base。
关于av_q2d函数的用法可以参考:《FFmpeg有理数相关的源码:AVRational结构体和其相关的函数分析》。pts_time和dts_time是由writer_print_time函数中的下面语句计算出来的:
double d = ts * av_q2d(*time_base);
简单点来讲:
pts_time = pts × time_base,
dts_time = dts × time_base。
三、总结
“pts_time”是以秒为单位的显示时间戳;“dts_time”是以秒为单位的解码时间戳。
pts_time = pts × time_base,dts_time = dts × time_base。比如pts为4096,time_base为44100分之一,则pts_time等于4096乘以44100分之一 ,等于0.092880秒。