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

news2024/9/21 14:42:40

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

音视频入门基础: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命令:

ffprobe -of json -show_packets XXX.aac

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

这个“size”实际是AVPacket结构体中的成员变量size,为AVPacket的成员变量data指向的缓冲区的大小,也就是AAC裸流中某个packet的大小(单位为字节)。该值通过fftools/ffprobe.c中的show_packet函数打印出来:

static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...
    print_val("size",             pkt->size, unit_byte_str);
//...
}

本文讲述这个“size”值是怎样被计算出来的。如果想直接看结论,可以跳到本文的最后,直接看“总结”。对于AAC裸流,size值是通过adts_aac_read_packet函数计算出来的。

二、adts_aac_read_packet函数的定义

adts_aac_read_packet函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/aacdec.c中:

static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    int ret, fsize;

retry:
    ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE);
    if (ret < 0)
        return ret;

    if (ret < ADTS_HEADER_SIZE) {
        return AVERROR(EIO);
    }

    if ((AV_RB16(pkt->data) >> 4) != 0xfff) {
        // Parse all the ID3 headers between frames
        int append = ID3v2_HEADER_SIZE - ADTS_HEADER_SIZE;

        av_assert2(append > 0);
        ret = av_append_packet(s->pb, pkt, append);
        if (ret != append) {
            return AVERROR(EIO);
        }
        if (!ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) {
            av_packet_unref(pkt);
            ret = adts_aac_resync(s);
        } else
            ret = handle_id3(s, pkt);
        if (ret < 0)
            return ret;

        goto retry;
    }

    fsize = (AV_RB32(pkt->data + 3) >> 13) & 0x1FFF;
    if (fsize < ADTS_HEADER_SIZE) {
        return AVERROR_INVALIDDATA;
    }

    ret = av_append_packet(s->pb, pkt, fsize - pkt->size);

    return ret;
}

该函数的作用是:获取一个ADTS音频帧的数据,赋值给形参pkt指向的packet。

形参s:既是输入型参数也是输出型参数,指向一个AVFormatContext对象。

形参pkt:输出型参数,指向一个AVPacket对象。执行adts_aac_read_packet函数后,pkt->data指向的的缓冲区会得到整个ADTS音频帧的数据,pkt->size会增至该ADTS音频帧的大小。

三、adts_aac_read_packet函数的内部实现分析

宏定义ADTS_HEADER_SIZE的值为7,表示不包含CRC校验的ADTS Header的长度:

#define ADTS_HEADER_SIZE 7

adts_aac_read_packet函数内部,首先通过av_get_packet函数从AVIOContext输入缓冲区或文件描述符中总共读取ADTS_HEADER_SIZE(7)个字节数据,也就是读取该音频帧的Header,追加到原来pkt->data指向的的缓冲区的尾部。关于av_get_packet函数的用法可以参考 《FFmpeg源码:append_packet_chunked、av_get_packet、av_append_packet函数分析》。如果实际读取到的大小小于7个字节,返回AVERROR(EIO)表示IO错误:

    ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE);
    if (ret < 0)
        return ret;

    if (ret < ADTS_HEADER_SIZE) {
        return AVERROR(EIO);
    }

由《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》可以知道,ADTS音频帧的adts_fixed_header中的syncword属性占12位,每个位都必须被设置为1。通过下面的if语句判断syncword属性的值是否正确,如果不正确,执行大括号内解析id3v2 header的流程。ID3v2是一系列元数据,里面存储了一些跟歌曲相关的信息(比如:演唱者、歌曲名、备注等)。关于AV_RB16宏定义的用法可以参考:《FFmpeg源码:AV_RB32、AV_RB16、AV_RB8宏定义分析》:

    if ((AV_RB16(pkt->data) >> 4) != 0xfff) {
        // Parse all the ID3 headers between frames
        //...

    }

获取adts_variable_header中的aac_frame_length属性,即该ADTS音频帧的总长度(包含ADTS Header、错误校验和AAC原始数据块,单位为字节),赋值给变量fsize。由《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》可以知道,ADTS Header至少占7个字节(当存在CRC校验时,ADTS Header占9字节;不存在CRC校验时,ADTS Header占7字节),所以如果从上面得到的该ADTS音频帧的总长度小于7,表示ADTS Header格式不正确,返回AVERROR_INVALIDDATA:

    fsize = (AV_RB32(pkt->data + 3) >> 13) & 0x1FFF;
    if (fsize < ADTS_HEADER_SIZE) {
        return AVERROR_INVALIDDATA;
    }

通过av_append_packet函数,增加形参pkt指向的packet的大小至aac_frame_length个字节,让pkt->data指向的的缓冲区得到整个ADTS音频帧的数据。关于av_append_packet函数的用法可以参考:《FFmpeg源码:append_packet_chunked、av_get_packet、av_append_packet函数分析》:

ret = av_append_packet(s->pb, pkt, fsize - pkt->size);

四、总结

1.AAC裸流每个packet的size值(该packet的大小,单位为字节)实际上是通过ADTS音频帧(adts音频压缩数据包)的adts_fixed_header中的aac_frame_length属性获取的。

2.如果仔细地观察,会发现AAC裸流每个packet的size值都不一样,这是因为ADTS音频帧存贮的是压缩后的音频数据。而WAV音频文件一般存贮的是PCM,也就是无压缩的原始音频数据,所以在存贮的是PCM数据的情况下,WAV音频文件每个packet的size值都是一样的。各位同学可以把本文跟《音视频入门基础:WAV专题(7)——FFmpeg源码中计算WAV音频文件每个packet的size值的实现》进行对比,以加深对音频帧size值的理解。

3.FFmpeg源码内部得到AAC裸流每个packet的size值是通过adts_aac_read_packet函数,但是解码ADTS Header获取里面信息(音频采样频率、声道数、采样位数等)是通过ff_adts_header_parse函数,关于ff_adts_header_parse函数可以参考:《音视频入门基础:AAC专题(6)——FFmpeg源码中解码ADTS格式的AAC的Header的实现》。可以看到这两个函数有部分功能是重复了,重复获取了ADTS音频帧的大小。FFmpeg对AAC裸流解封装时,会重复解码ADTS Header导致性能损失。也就是说:FFmpeg为了架构的通用性、扩展性、兼容性和代码的可读性造成了代码的冗余和重复,所以为了极致的性能,比如更快的解封装速度,很多开发者会选择不依赖任何第三方库自己写解析代码,或者改FFmpeg的源码实现优化。各位同学可以尝试改FFmpeg源码,使得对AAC裸流进行解复用时,只解码一次ADTS Header,从而提高解复用速度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2152600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零工市场小程序:推动零工市场建设

人力资源和社会保障部在2024年4月发布了标题为《地方推进零工市场建设经验做法》的文章。 零工市场小程序的功能 信息登记与发布 精准匹配、推送 在线沟通 权益保障 零工市场小程序作为一个找零工的渠道&#xff0c;在往后随着技术的发展和政策的支持下&#xff0c;功能必然…

自注意力与多头自注意力的区别

自注意力机制和多头自注意力机制在深度学习&#xff0c;尤其是Transformer模型中是核心组件。它们的主要区别在于如何处理输入信息和增强模型的表达能力。 1. 自注意力机制&#xff08;Self-Attention&#xff09; 自注意力机制的主要作用是让模型在处理每个输入元素时&#…

计算机人工智能前沿进展-大语言模型方向-2024-09-20

计算机人工智能前沿进展-大语言模型方向-2024-09-20 1. Multimodal Fusion with LLMs for Engagement Prediction in Natural Conversation Authors: Cheng Charles Ma, Kevin Hyekang Joo, Alexandria K. Vail, Sunreeta Bhattacharya, Alvaro Fern’andez Garc’ia, Kailan…

操作系统 | 学习笔记 | | 王道 | 5.1 I/O管理概述

5.1 I/O管理概述 5.1.1 I/O设备 注&#xff1a;块设备可以寻址&#xff0c;但是字符设备是不可寻址的 I/O设备是将数据输入到计算机中&#xff0c;或者可以接收计算机输出数据的外部设备&#xff0c;属于计算机中的硬件部件&#xff1b; 设备的分类 按使用特性分类&#xff…

新手爬虫er必刷!如何使用代理IP全攻略!

在爬虫开发中&#xff0c;代理IP&#xff08;也称为代理服务器&#xff09;是一个非常重要的工具。当爬虫访问网站时&#xff0c;可能会遭遇IP封锁或请求频率限制。通过使用代理IP&#xff0c;可以分散请求压力并规避特定对IP的限制&#xff0c;从而提高采集任务的持续性。同时…

Cassandra 5.0 Spring Boot 3.3 CRUD

概览 因AI要使用到向量存储&#xff0c;JanusGraph也使用到Cassandra 卸载先前版本 docker stop cassandra && docker remove cassandra && rm -rf cassandra/运行Cassandra容器 docker run \--name cassandra \--hostname cassandra \-p 9042:9042 \--pri…

SpringCloud Alibaba五大组件之——Sentinel

SpringCloud Alibaba五大组件之——Sentinel&#xff08;文末附有完整项目GitHub链接&#xff09; 前言一、什么是Sentinel二、Sentinel控制台1.下载jar包2.自己打包3.启动控制台4.浏览器访问 三、项目中引入Sentinel1.在api-service模块的pom文件引入依赖&#xff1a;2.applic…

【干货整理】什么软件能监控员工电脑?六大好用的电脑监控软件,抢手推荐!

什么软件能监控员工电脑&#xff1f; 电脑监控软件啦&#xff01; 要是能有一双无形的眼睛&#xff0c;既监督员工的工作状态&#xff0c;又保护着公司的数据安全&#xff0c;这无疑是企业管理者的福音。 今天&#xff0c;我们就来一起探索那些能够精准助力、高效护航的六大电…

张养浩,文坛政坛的双重巨匠

张养浩&#xff0c;字希孟&#xff0c;号云庄&#xff0c;又称齐东野人&#xff0c;生于元世祖至元七年&#xff08;公元1270年&#xff09;&#xff0c;卒于元英宗至治三年&#xff08;公元1329年&#xff09;&#xff0c;享年59岁。他是中国元代著名的文学家、政治家&#xf…

【Linux】解锁系统编程奥秘,高效文件IO的实战技巧

文件 1. 知识铺垫2. C文件I/O2.1. C文件接口2.2 fopen()与重定向2.3. 当前路径2.4. stdin、stdout、stderr 3. 系统文件I/O3.1. 前言3.2. open3.2.1. flags</h3>3.2.2. mode</h3>3.2.3. 返回值fd 3.3. write</h2>3.4. read3.5. close</h2>3.6. lseek&l…

快速响应:提升前端页面加载速度技巧的必知策略方案

在本文中&#xff0c;我们将深入探讨导致页面加载缓慢的常见原因&#xff0c;并分享一系列切实可行的优化策略&#xff0c;无论你是刚入门的新手&#xff0c;还是经验丰富的开发者&#xff0c;这些技巧都将帮助你提升网页性能&#xff0c;让你的用户体验畅快无阻。 相信作为前端…

【JavaEE精炼宝库】HTTP | HTTPS 协议详解

文章目录 一、HTTP 简介二、HTTP 协议格式&#xff1a;2.1 抓包工具的使用&#xff1a;2.2 HTTP 请求报文格式&#xff1a;2.3 HTTP 响应报文格式&#xff1a;2.4 HTTP 协议格式总结&#xff1a; 三、HTTP 请求详解&#xff1a;3.1 刨析 URL&#xff1a;3.2 方法(method)&#…

极度精简 Winows11 系统镜像!Tiny11 2311下载 - 支持苹果 M 芯片 Mac 安装 (ARM 精简版)!

最新推出的 Tiny11 是一款极端精简版 Windows 11 系统镜像&#xff0c;针对苹果 M 芯片 Mac 用户&#xff08;ARM 架构&#xff09;提供良好支持。Tiny11 内置了众多优化特性&#xff0c;如更小的安装体积和更快的启动速度&#xff0c;特别适合有特殊需求或老机型的用户。用户可…

centos 安装VNC,实现远程连接

centos 安装VNC&#xff0c;实现远程连接 VNC(Virtual Network Computing)是一种远程控制软件&#xff0c;可以实现通过网络远程连接计算机的图形界面。 服务器安装VNC服务 yum install -y tigervnc-server*启动VNC服务&#xff0c;过程中需要输入连接密码 vncserver :1查看…

2024华为杯研究生数学建模C题【数据驱动下磁性元件的磁芯损耗建模】思路详解

问题一 励磁波形分类 励磁波形作为影响磁芯性能的核心要素之一&#xff0c;其形态深刻影响着磁芯的损耗特性。励磁波形的独特形状直接塑造了磁芯内部磁通的动态行为&#xff0c;不同的波形轮廓影响了磁通密度随时间的变化速率&#xff0c;导致其损耗特性呈现出显著差异。因此&…

ESP32本地大模型对话机器人制作教程

整体架构 在本地电脑部署好Ollama服务&#xff0c;安装qwen大模型和llama3.1大模型。 ESP32接入局域网&#xff0c;用户通过串口给esp32发送问题&#xff0c;esp32打包json后向ollama服务发送请求&#xff0c;ollama返回响应&#xff0c;esp32解析结果并通过串口打印出来。 …

MavenMyBatis

Maven&MyBatis 目标 能够使用Maven进行项目的管理能够完成Mybatis代理方式查询数据能够理解Mybatis核心配置文件的配置 1&#xff0c;Maven Maven是专门用于管理和构建Java项目的工具&#xff0c;它的主要功能有&#xff1a; 提供了一套标准化的项目结构 提供了一套标准…

24最新Stable Diffusion 本地部署教程!

前言 1.前言&#xff1a; 最近看Stable Diffusion开源了&#xff0c;据说比Disco Diffusion更快&#xff0c;于是从git上拉取了项目尝试本地部署了&#xff0c;记录分享一下过程~ 这里是官网介绍&#xff1a;https://stability.ai/blog/stable-diffusion-public-release 嫌弃…

解决【WVP服务+ZLMediaKit媒体服务】加入海康摄像头后,能发现设备,播放/点播失败,提示推流超时!

环境介绍 每人搭建的环境不一样&#xff0c;情况不一样&#xff0c;但是原因都是下面几种&#xff1a; wvp配置不当网络端口未放开网络不通 我搭建的环境&#xff1a; WVP服务&#xff1a;windows下&#xff0c;用idea运行的源码 ZLM服务&#xff1a;虚拟机里 问题描述 1.…

计算机视觉的应用34-基于CV领域的人脸关键点特征智能提取的技术方法

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用34-基于CV领域的人脸关键点特征智能提取的技术方法。本文主要探讨计算机视觉领域中人脸关键点特征智能提取的技术方法。详细介绍了基于卷积神经网络模型进行人脸关键点提取的过程&#xff0c;包括使…