深圳网站公司制作,建设建材网站的目的,北京优化生育,网站服务器维护技术一、引言
从文章《音视频入门基础#xff1a;WAV专题#xff08;6#xff09;——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道#xff0c;通过FFprobe命令可以显示WAV音频文件每个packet#xff08;也称为数据包或多媒体包#xff09;的信息#xff0…一、引言
从文章《音视频入门基础WAV专题6——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道通过FFprobe命令可以显示WAV音频文件每个packet也称为数据包或多媒体包的信息这些信息包含该packet的duration和duration_time 这个“duration”实际是AVPacket结构体中的成员变量duration为该音频packet占用的以AVStream的time_base为单位的时间值。而“duration_time”为该音频packet占用的以秒为单位的时间值。这两个值通过fftools/ffprobe.c中的show_packet函数打印出来
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...print_duration_ts(duration, pkt-duration);print_duration_time(duration_time, pkt-duration, st-time_base);
//...
} 本文讲述“duration”和“duration_time”的值是怎样被计算出来的。如果想直接看结论可以跳到本文的最后直接看“总结”。 二、FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现
一得到每个packet的duration
FFmpeg对WAV音频文件进行解封装解复用时会调用avformat_find_stream_info函数而该函数底层会调用compute_pkt_fields函数
static void compute_pkt_fields(AVFormatContext *s, AVStream *st,AVCodecParserContext *pc, AVPacket *pkt,int64_t next_dts, int64_t next_pts)
{
//...if (pkt-duration 0) {compute_frame_duration(s, num, den, st, pc, pkt);if (den num) {duration (AVRational) {num, den};pkt-duration av_rescale_rnd(1,num * (int64_t) st-time_base.den,den * (int64_t) st-time_base.num,AV_ROUND_DOWN);}}
//...
} compute_pkt_fields函数内部由于AVPacket结构体被初始化后其成员变量duration会是0新版本的FFmpeg源码一般使用get_packet_defaults函数进行初始化具体可以参考《FFmpeg源码av_init_packet、get_packet_defaults、av_packet_alloc函数分析》所以会执行下面if语句为真时括号里的内容
if (pkt-duration 0) {
//...
} 通过compute_frame_duration函数让变量num被赋值为该音频packet占用的以AVStream的time_base为单位的时间值让变量den被赋值为该音频的采样频率单位为Hz
compute_frame_duration(s, num, den, st, pc, pkt); 从文章《FFmpeg源码compute_frame_duration函数分析》中可以知道compute_frame_duration函数内部调用了av_get_audio_frame_duration2函数。而从《FFmpeg源码get_audio_frame_duration、av_get_audio_frame_duration2函数分析》中可以知道av_get_audio_frame_duration2函数内部又通过get_audio_frame_duration函数来计算某个音频packet占用的时间值。计算公式是该音频packet占用的以AVStream的time_base为单位的时间值 packet的大小单位为字节×8÷音频的采样位数×声道数量比如某个音频packet的大小为16384字节、音频的采样位数为16位、声道数为2则该音频packet占用的时间值以AVStream的time_base为单位为16384×8÷16×2 4096。 关于av_rescale_rnd函数的用法可以参考《FFmpeg源码av_rescale_rnd、av_rescale_q_rnd、av_rescale_q、av_add_stable函数分析》。最后通过av_rescale_rnd函数得到AVPacket结构体的成员变量duration。下面语句相当于执行了pkt-duration 1 × num × st-time_base.den ÷ (den × st-time_base.num)
pkt-duration av_rescale_rnd(1,num * (int64_t) st-time_base.den,den * (int64_t) st-time_base.num,AV_ROUND_DOWN); 而从上面我们可以知道变量num为该音频packet占用的以AVStream的time_base为单位的时间值变量den为该音频的采样频率单位为Hz。根据《音视频入门基础WAV专题8——FFmpeg源码中计算WAV音频文件AVStream的time_base的实现》我们又可以知道WAV音频文件AVStream的time_basest-time_base为音频采样频率的倒数。
所以语句pkt-duration 1 × num × st-time_base.den ÷ (den × st-time_base.num)等价于
pkt-duration num。
从而让AVPacket结构体中的成员变量duration可以被赋值为该音频packet占用的以AVStream的time_base为单位的时间值。 二得到每个packet的duration_time
duration和duration_time是通过fftools/ffprobe.c中的show_packet函数打印出来
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...print_duration_ts(duration, pkt-duration);print_duration_time(duration_time, pkt-duration, st-time_base);
//...
} print_duration_time为宏定义
#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1) 而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函数的形参ts为该音频packet占用的以AVStream的time_base为单位的时间值形参time_base为AVStream的time_base。 关于av_q2d函数的用法可以参考《FFmpeg有理数相关的源码AVRational结构体和其相关的函数分析》。duration_time实际上是由writer_print_time函数中的下面语句计算出来的
double d ts * av_q2d(*time_base);
简单点来讲duration_time duration × time_base。 三、总结
对于WAV音频文件
AVPacket的“duration”为该音频packet占用的以AVStream的time_base为单位的时间值其值等于 packet的大小单位为字节×8÷音频的采样位数×声道数量比如某个音频packet的大小为16384字节、音频的采样位数为16位、声道数为2则该音频packet的duration等于16384×8÷16×2 4096。
而“duration_time”为该音频packet占用的以秒为单位的时间值其值等于duration × time_base。比如某个音频packet的duration为4096time_base为44100分之一其duration_time为4096乘以44100分之一等于0.092880。