音视频入门基础:AAC专题(9)——FFmpeg源码中计算AAC裸流每个packet的duration和duration_time的实现

=================================================================

音视频入门基础:AAC专题系列文章:

音视频入门基础:AAC专题(1)------AAC官方文档下载

音视频入门基础:AAC专题(2)------使用FFmpeg命令生成AAC裸流文件

音视频入门基础:AAC专题(3)------AAC的ADTS格式简介

音视频入门基础:AAC专题(4)------ADTS格式的AAC裸流实例分析

音视频入门基础:AAC专题(5)------FFmpeg源码中,判断某文件是否为AAC裸流文件的实现

音视频入门基础:AAC专题(6)------FFmpeg源码中解码ADTS格式的AAC的Header的实现

音视频入门基础:AAC专题(7)------FFmpeg源码中计算AAC裸流每个packet的size值的实现

音视频入门基础:AAC专题(8)------FFmpeg源码中计算AAC裸流AVStream的time_base的实现

音视频入门基础:AAC专题(9)------FFmpeg源码中计算AAC裸流每个packet的duration和duration_time的实现

音视频入门基础:AAC专题(10)------FFmpeg源码中计算AAC裸流每个packet的pts、dts、pts_time、dts_time的实现

=================================================================

一、引言

通过FFprobe命令:

cpp 复制代码
ffprobe -of json -show_packets XXX.aac

可以显示AAC裸流每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的duration和duration_time:

这个"duration"实际是AVPacket结构体中的成员变量duration,为该音频packet占用的以AVStream的time_base为单位的时间值。而"duration_time"为该音频packet占用的以秒为单位的时间值。这两个值通过fftools/ffprobe.c中的show_packet函数打印出来:

cpp 复制代码
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源码中计算AAC裸流每个packet的duration和duration_time的实现

(一)得到每个packet的duration

FFmpeg对AAC裸流进行解封装(解复用)时,会调用avformat_find_stream_info函数,而该函数底层会调用compute_pkt_fields函数:

cpp 复制代码
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语句为真时括号里的内容:

cpp 复制代码
if (pkt->duration <= 0) {
//...
}

通过compute_frame_duration函数,让变量num被赋值为该帧音频数据中采样的次数(对于规格为AAC LC和AAC LTP的AAC就是固定的1024),让变量den被赋值为该音频的采样频率(单位为Hz)。关于compute_frame_duration函数的用法可以参考:《FFmpeg源码:compute_frame_duration函数分析》:

cpp 复制代码
compute_frame_duration(s, &num, &den, st, pc, pkt);

最后通过av_rescale_rnd函数得到AVPacket结构体的成员变量duration。关于av_rescale_rnd函数的用法可以参考:《FFmpeg源码:av_rescale_rnd、av_rescale_q_rnd、av_rescale_q、av_add_stable函数分析》。下面语句相当于执行了:pkt->duration = 1 × num × st->time_base.den ÷ (den × st->time_base.num):

cpp 复制代码
pkt->duration = av_rescale_rnd(1,
        num * (int64_t) st->time_base.den,
        den * (int64_t) st->time_base.num,
        AV_ROUND_DOWN);

而从上面我们可以知道,变量num为该帧音频数据中采样的次数(对于规格为AAC LC和AAC LTP的AAC就是固定的1024),变量den为该音频的采样频率(单位为Hz)。根据《音视频入门基础:AAC专题(8)------FFmpeg源码中计算AAC裸流AVStream的time_base的实现》我们又可以知道,AAC裸流AVStream的time_base(st->time_base)固定为28224000分之一。

所以对于规格为AAC LC和AAC LTP的AAC,

语句pkt->duration = 1 × num × st->time_base.den ÷ (den × st->time_base.num)等价于

pkt->duration = 1024 × 28224000 ÷ 该音频的采样频率(这里的计算公式跟WAV音频文件是不一样的)

从而让AVPacket结构体中的成员变量duration可以被赋值为该音频packet占用的以AVStream的time_base为单位的时间值。

(二)得到每个packet的duration_time

音频的duration_time的计算公式都是一样的:duration_time = duration × time_base。具体可以参考:《音视频入门基础:WAV专题(9)------FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现》。

三、总结

1.对于标准的MPEG-2/4 AAC,其samples(一帧音频数据中采样的次数)为1024或者960次;规格为AAC LC和AAC LTP的AAC,一帧音频数据中采样的次数固定为1024次。具体可以参考:《音视频入门基础:AAC专题(3)------AAC的ADTS格式简介》。

2.音频AVPacket的"duration"为该音频packet占用的以AVStream的time_base为单位的时间值。对于AAC裸流,duration等于:samples × 28224000 ÷ 该音频的采样频率。对于规格为AAC LC和AAC LTP的AAC,samples固定为1024,duration等于:1024 × 28224000 ÷ 该音频的采样频率。比如,某个规格为AAC LC或AAC LTP的AAC裸流,其采样频率为44100Hz,则其一帧音频packet的duration等于:1024 × 28224000 ÷ 44100 = 655360。这个计算方法跟WAV音频文件是不一样的,各位同学可以把本文跟《音视频入门基础:WAV专题(9)------FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现》进行对比,以加深对音频帧duration值的理解。

3."duration_time"为该音频packet占用的以秒为单位的时间值,其值等于:duration × time_base(这是对任何格式的音频都通用的一种计算方式)。比如,某个音频packet的duration为655360,time_base为28224000分之一,则其duration_time等于655360乘以28224000分之一,等于0.02322。关于AAC音频time_base的计算方式可以参考:《音视频入门基础:AAC专题(8)------FFmpeg源码中计算AAC裸流AVStream的time_base的实现》。

4.对于AAC格式的音频,"duration_time"还有另外一种计算方式:duration_time = samples ÷ 该音频的采样频率。比如,samples(一帧音频数据中采样的次数)为1024,采样频率为44100Hz,则duration_time = 1024 ÷ 44100 = 0.02322。

相关推荐
xcLeigh6 小时前
HTML5超酷响应式视频背景动画特效(六种风格,附源码)
前端·音视频·html5
韩曙亮8 小时前
【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )
ffmpeg·音视频·avpacket·av_packet_clone·av_packet_ref·ffmpeg内存结构
9527华安11 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
电子科技圈12 小时前
XMOS携手合作伙伴晓龙国际联合推出集成了ASRC等功能的多通道音频板
科技·嵌入式硬件·mcu·物联网·音视频·iot
oushaojun212 小时前
ubuntu中使用ffmpeg和nginx推流rtmp视频
nginx·ubuntu·ffmpeg·rtmp
码码哈哈0.012 小时前
免费的视频混剪综合处理工具介绍与下载
音视频
莫固执,朋友12 小时前
网络抓包工具tcpdump 在海思平台上的编译使用
网络·ffmpeg·音视频·tcpdump
深海呐13 小时前
Android 从本地选择视频,用APP播放或进行其他处理
android·音视频·从本地选择视频,用app播放·从本地选择视频,并拿到信息·跳转到本地视频列表
lxkj_202413 小时前
修改ffmpeg实现https-flv内容加密
网络协议·https·ffmpeg
cuijiecheng201813 小时前
音视频入门基础:MPEG2-TS专题(6)——FFmpeg源码中,获取MPEG2-TS传输流每个transport packet长度的实现
ffmpeg·音视频