音频demo:使用faad2将AAC数据解码出PCM数据

1、README

前言

本demo是使用的开源项目faad2将aac数据解码成pcm数据。

a. 编译使用

faad2的编译:(faad2下载地址:https://sourceforge.net/projects/faac/files/faad2-src/faad2-2.8.0/)

tar xzf faad2-2.8.8.tar.gz
cd faad2-2.8.8/
./configure --prefix=$PWD/_install
make
make install

demo的编译使用:

$ make clean && make
$ 
$ ./aac2pcm 
Usage:
    ./aac2pcm <in aac file> <out pcm file>
Examples:
    ./aac2pcm ./audio/test1_44100_stereo.aac  out1_44100_16bit_stereo.pcm
    ./aac2pcm ./audio/test2_8000_mono.aac     out2_16000_16bit_stereo.pcm  # output [samplerate] and [channels] will be auto configured.
b. 参考文章
  • 用faad解码AAC(ADTS封装)_gavinr的博客-CSDN博客_faad解码aac
c. demo目录架构
$ tree
.
├── aac_adts.c
├── aac_adts.h
├── audio
│   ├── out1_44100_16bit_stereo.pcm
│   ├── out2_16000_16bit_stereo.pcm
│   ├── test1_44100_stereo.aac
│   └── test2_8000_mono.aac
├── docs
│   └── 用faad解码AAC(ADTS封装)_gavinr的博客-CSDN博客_faad解码aac.mhtml
├── include
│   ├── faad.h
│   └── neaacdec.h
├── lib
│   └── libfaad.a
├── main.c
├── Makefile
└── README.md

2、主要代码片段

aac_adts.c
#include "aac_adts.h"


int getAdtsFrame(FILE *fp, uint8_t *pAdtsFrameData, T_AdtsHeader *ptAdtsHeaderInfo)
{
	uint32_t readBytes = 0;

	if(!fp || !pAdtsFrameData || !ptAdtsHeaderInfo)
		return -1;

	// ADTS header size is AAC_ADTS_HEADER_SIZE(=7) bytes
	readBytes = fread(pAdtsFrameData, 1, AAC_ADTS_HEADER_SIZE, fp);
	if(readBytes <= 0)
		return -2;

	ptAdtsHeaderInfo->syncword              = (pAdtsFrameData[0] << 4 ) | (pAdtsFrameData[1]  >> 4);
	ptAdtsHeaderInfo->id                    = (pAdtsFrameData[1] & 0x08) >> 3;
	ptAdtsHeaderInfo->layer                 = (pAdtsFrameData[1] & 0x06) >> 1;
	ptAdtsHeaderInfo->protection_absent     =  pAdtsFrameData[1] & 0x01;
	ptAdtsHeaderInfo->profile               = (pAdtsFrameData[2] & 0xc0) >> 6;
	ptAdtsHeaderInfo->sampling_freq_index   = (pAdtsFrameData[2] & 0x3c) >> 2;
	ptAdtsHeaderInfo->private_bit           = (pAdtsFrameData[2] & 0x02) >> 1;
	ptAdtsHeaderInfo->channel_configuration = (((pAdtsFrameData[2] & 0x01) << 2) | ((pAdtsFrameData[3] & 0xc0) >> 6));
	ptAdtsHeaderInfo->original_copy         = (pAdtsFrameData[3] & 0x20) >> 5;
	ptAdtsHeaderInfo->home                  = (pAdtsFrameData[3] & 0x10) >> 4;
	ptAdtsHeaderInfo->copyright_identification_bit   = (pAdtsFrameData[3] & 0x08) >> 3;
	ptAdtsHeaderInfo->copyright_identification_start = (pAdtsFrameData[3] & 0x04) >> 2;
	ptAdtsHeaderInfo->aac_frame_length = ((pAdtsFrameData[3] & 0x03) << 11) |
										 ((pAdtsFrameData[4] & 0xFF) << 3) |
										 ((pAdtsFrameData[5] & 0xE0) >> 5);
	ptAdtsHeaderInfo->adts_buffer_fullness = ((pAdtsFrameData[5] & 0x1f) << 6 | (pAdtsFrameData[6] & 0xfc) >> 2);
	ptAdtsHeaderInfo->number_of_raw_data_blocks_in_frame = (pAdtsFrameData[6] & 0x03);

	if (ptAdtsHeaderInfo->syncword != 0xFFF)
		return -3;

	/* read the remaining frame of ADTS data outside the AAC_ADTS_HEADER_SIZE(=7) bytes header,
	 * and it should be written after offsetting the header by AAC_ADTS_HEADER_SIZE(=7) bytes
	 */
	readBytes = fread(pAdtsFrameData + AAC_ADTS_HEADER_SIZE, 1, ptAdtsHeaderInfo->aac_frame_length - AAC_ADTS_HEADER_SIZE, fp);
	if(readBytes <= 0)
		return -4;

	return 0;
}

aac_adts.h
#ifndef __AAC_ADTS_H__
#define __AAC_ADTS_H__

#include <stdio.h>
#include <stdint.h>


#define AAC_ADTS_HEADER_SIZE 	(7)

#define MAX_ADTS_SIZE 			(1024) /* 1K Bytes */


typedef enum{
    MPEG_4 = 0x0,
    MPEG_2 = 0x1,
}aac_id_t;


typedef enum{
    SFI_96000 = 0x0,
    SFI_88200 = 0x1,
    SFI_64000 = 0x2,
    SFI_48000 = 0x3,
    SFI_44100 = 0x4,
    SFI_32000 = 0x5,
    SFI_24000 = 0x6,
    SFI_22050 = 0x7,
    SFI_16000 = 0x8,
    SFI_12000 = 0x9,
    SFI_11025 = 0xa,
    SFI_8000  = 0xb,
    SFI_7350  = 0xc,
    SFI_ERROR = 0xd,
}sampling_freq_index_t;


/* AAC(ADTS) Header element member.
 * [Note: It is not stored as defined type size!!!]
 */
typedef struct{
	/* fixed header */
    uint32_t syncword;              // 12bit  '1111 1111 1111' is stand by ADTS frame
    uint32_t id;                    // 1 bit  0 for MPEG-4, 1 for MPEG-2
    uint32_t layer;                 // 2 bit  always '00'
    uint32_t protection_absent;     // 1 bit  1 not crc, 0 have crc 1
    uint32_t profile;               // 2 bit  AAC profile, '01' for AAC-LC
    uint32_t sampling_freq_index;   // 4 bit  reference to 'sampling_freq_index_t'
    uint32_t private_bit;           // 1 bit  always '0'
    uint32_t channel_configuration; // 3 bit  channels count
    uint32_t original_copy;         // 1 bit  always '0'
    uint32_t home;                  // 1 bit

    /* varible header */
    uint32_t copyright_identification_bit;   // 1 bit  always '0'
    uint32_t copyright_identification_start; // 1 bit  always '0'
    uint32_t aac_frame_length;               // 13bit  length of [adts header] + [adts data]
    uint32_t adts_buffer_fullness;           // 11bit  0x7FF stand by varible bit rate
    uint32_t number_of_raw_data_blocks_in_frame;  // 2 bit  always '00', number of AAC Frames(RDBs) in ADTS frame minus 1
}T_AdtsHeader, *PT_AdtsHeader;



/************************************************************************
 * function describe: get one frame aac(adts, include adts header) from
 *                    aac file.
 * params:
 *   [fp]: aac file handler.(in)
 *   [pAdtsFrameData]: the function will fill the aac data in it, must be
 *                     alloced memory before call this function.(out)
 *   [ptAdtsHeaderInfo]: AAC-ADTS header information in this frame.(out)
 * return: 0-success  other-error
 ************************************************************************/
int getAdtsFrame(FILE *fp, uint8_t *pAdtsFrameData, T_AdtsHeader *ptAdtsHeaderInfo);


#endif /*  __AAC_ADTS_H__ */

main.c
#include <stdio.h>
#include <stdlib.h>

#include "aac_adts.h"
#include "faad.h"


#define MAX_DEC_SIZE   (128 * 1024)


int main(int argc, char *argv[])
{
	int ret = -1;
	FILE *fpAAC = NULL;
	FILE *fpPCM = NULL;
	unsigned char *aacBuf = NULL;
	unsigned char *pcmPtr = NULL;
	unsigned char channels = 0;
	unsigned long sampleRate = 0;
	T_AdtsHeader adtsHeader = {};
	NeAACDecHandle aacDecHandler = 0;
	NeAACDecFrameInfo aacDecFrameInfo = {};
	uint32_t audioSampleRate = -1;

	if(argc != 3)
	{
		printf("Usage:\n"
			   "    %s <in aac file> <out pcm file>\n"
			   "Examples:\n"
			   "    %s ./audio/test1_44100_stereo.aac  out1_44100_16bit_stereo.pcm\n"
			   "    %s ./audio/test2_8000_mono.aac     out2_16000_16bit_stereo.pcm  # output [samplerate] and [channels] will be auto configured.\n",
			   argv[0], argv[0], argv[0]);
		return -1;
	}

	/* open file */
	fpAAC = fopen(argv[1], "rb");
	fpPCM = fopen(argv[2], "wb");
	if(!fpAAC || !fpPCM)
	{
		printf("[%s:%d] open <%s> or <%s> file failed!\n", __FUNCTION__, __LINE__, argv[1], argv[2]);
		goto exit;
	}

	/* alloc memory */
	aacBuf = (unsigned char *)malloc(MAX_DEC_SIZE);
	if(!aacBuf)
	{
		printf("[%s:%d] alloc memory for aacBuf failed!\n", __FUNCTION__, __LINE__);
		goto exit;
	}

	/* aac decode 1/4: open aac decoder */
	aacDecHandler = NeAACDecOpen();

	/* use to configure decoder params */
	ret = getAdtsFrame(fpAAC, aacBuf, &adtsHeader);
	if(ret < 0)
	{
		if(ret == -2)
		{
			printf("aac file end!\n");
			goto exit;
		}
		else
		{
			printf("[%s:%d] get adts frame failed with %d!\n", __FUNCTION__, __LINE__, ret);
			goto exit;
		}
	}
	else
	{
		fseek(fpAAC, 0, SEEK_SET); // reset

		/* aac decode 2/4: init aac decoder params */
		NeAACDecInit(aacDecHandler, aacBuf, adtsHeader.aac_frame_length, &sampleRate, &channels);
		printf("\e[32m>>> will be decoded output with [samplerate: %lu], [channels: %d]<<<\e[0m\n", sampleRate, channels);
	}

	while(1)
	{
		ret = getAdtsFrame(fpAAC, aacBuf, &adtsHeader);
		if(ret < 0)
		{
			if(ret == -2)
			{
				printf("aac file end!\n");
				break;
			}
			else
			{
				printf("[%s:%d] get adts frame failed with %d!\n", __FUNCTION__, __LINE__, ret);
				goto exit;
			}
		}
		//printf("get one adts frame with size: %d\n", adtsHeader.aac_frame_length);

		/* aac decode 3/4: decode */
		pcmPtr = (unsigned char*)NeAACDecDecode(aacDecHandler, &aacDecFrameInfo, aacBuf, adtsHeader.aac_frame_length/* include header */);
		if(aacDecFrameInfo.error > 0)
		{
			printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, NeAACDecGetErrorMessage(aacDecFrameInfo.error));
			goto exit;
		}
		else if(pcmPtr && aacDecFrameInfo.samples > 0)
		{
			printf("<in> [aac frame size: %lu] [header type: %s] "
                "[profile: %s]    |    <out> [samplerate: %lu] [samples cnt: %lu] [channels: %d] \n",
				aacDecFrameInfo.bytesconsumed, 
				aacDecFrameInfo.header_type == 2 ? "ADTS" : "Other", 
				aacDecFrameInfo.object_type == 2 ? "LC" : "Other", 
				aacDecFrameInfo.samplerate,
				aacDecFrameInfo.samples,
				aacDecFrameInfo.channels);

			fwrite(pcmPtr, 1, aacDecFrameInfo.samples * aacDecFrameInfo.channels, fpPCM);
		}
		else
		{
			printf("[%s:%d] Unknown decode error!\n", __FUNCTION__, __LINE__);
		}
	}

	/* aac decode 1/4: close aac decoder */
	NeAACDecClose(aacDecHandler);

	printf("\e[32mSuccess!\e[0m\n");

exit:
	if(fpAAC) fclose(fpAAC);
	if(fpPCM) {fflush(fpPCM); fclose(fpPCM);}
	if(aacBuf) free(aacBuf);

	return 0;
}

3、demo下载地址(任选一个)

  • https://download.csdn.net/download/weixin_44498318/89525143

  • https://gitee.com/linriming/audio_aac2pcm_with_faad2

  • https://github.com/linriming20/audio_aac2pcm_with_faad2.git

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度解析:当下流行的人工智能大模型生成逻辑

在过去的几年里&#xff0c;人工智能领域经历了前所未有的革新&#xff0c;其中最引人注目的就是大规模预训练模型的崛起。这些模型&#xff0c;如GPT系列、BERT、T5、DALLE和CLIP等&#xff0c;凭借其强大的语言理解和生成能力&#xff0c;已经在自然语言处理&#xff08;NLP&…

Springboot使用WebSocket发送消息

1. 创建springboot项目&#xff0c;引入spring-boot-starter-websocket依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>完整项目依赖 <?xml ver…

聊聊使用GROUP_CONCAT函数遇到的坑

问题现象 在工作中我们或多或少都会使用到函数group_concat&#xff0c;它可以合并多行的某列(或多列)数据为一行&#xff0c;默认以逗号分隔。 最近碰到了一个线上bug&#xff0c;查询DB时返回的结果信息mysql自动截取了&#xff0c;导致页面显示的时候只显示了前半段结果。 …

MATLAB环境下4种噪声生成

生成噪声包括: 1)粉红色(闪烁)噪声-功率谱密度斜率-3 dB/oct。&#xff0c; - 10db /dec 2)红色(布朗)噪声-功率谱密度斜率-6 dB/oct。&#xff0c; - 20db /dec 3)蓝色噪声-功率谱密度斜率3 dB/oct。&#xff0c; 10db /dec 4)紫色(紫色)噪声-功率谱密度斜率 6db /oct。&…

抖音商城自定义小程序源码系统 前后端分离 带完整的源代码包以及搭建教程

系统概述 在当今数字化时代&#xff0c;电商平台的便捷性和个性化体验成为了吸引用户的关键。随着短视频平台的兴起&#xff0c;抖音作为其中的佼佼者&#xff0c;其商城小程序成为了商家连接消费者的新阵地。为了帮助商家快速构建个性化、高效的小程序店铺&#xff0c;本文将…

Java线程的创建·启动和休眠

一.线程的创建和启动 Java中创建线程的两种方式 ◆继承java.lang.Thread类 ◆实现java.lang.Runnable接口 ◆使用线程的步骤 继承Thread类创建线程 ◆自定义线程类继承自Thread类 ◆重写run()方法&#xff0c;编写线程执行体 ◆创建线程对象&#xff0c;调用start()方法启动…

基于大数据的电商产品评论数据分析与可视化--Python

基于大数据的电商产品评论数据分析与可视化 1绪论 1.1研究背景与意义阐述 随着电子商务领域的迅猛扩张,电商平台累积了海量的用户评价信息。这些建议不只是包含了消费者对产品的评价和经验分享,更重要的是,它们包含了丰富且价值巨大的信息。深度分析在线用户反馈不仅揭示…

#数据结构 链表

单向链表 1. 概念 单向链表 单向循环链表 双向链表 双向循环链表 解决&#xff1a;长度固定的问题&#xff0c;插入和删除麻烦的问题 1、逻辑结构&#xff1a; 线性结构 2、存储结构&#xff1a; 链式存储 链表就是将 结点 用链串起来的线性表&#xff0c;链就是 结点 中的…

《C++20设计模式》命令模式思考

文章目录 一、前言二、分析 拆解1、经典命令模式2、撤销操作3、关于Invoker类 三、实现 一、前言 哎&#xff01;只要是书上写的和经典设计模式不同&#xff0c;我就会很伤脑筋。&#x1f629; 命令模式到底是干什么的&#xff1f; 答&#xff1a;命令的发送者和接收者完全解…

环境配置05——conda创建虚拟环境指定版本torch与python

版本选择&#xff1a; python版本3.11.8torch版本2.1.2 1.创建环境 conda create -n t212p311 python3.11.8 2.下载torch pytorch-wheels-cu121安装包下载_开源镜像站-阿里云 3. 安装torch 进入虚拟环境 activate t212p311 进入torch安装包所在目录&#xff0c;安装torc…

html+css+js随机验证码

随机画入字符、线条 源代码在图片后面 点赞❤️关注&#x1f60d;收藏⭐️ 互粉必回 图示 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"…

将QComboBox下拉项中的文本居中、居右

目录 1. 需求提出 2. 解决方法 1. 需求提出 QComboBox下拉项中的文本默认是居左的&#xff0c;如下&#xff1a; 有时需要将下拉项中的文本居中、居右。如何实现&#xff1f; 2. 解决方法 首先想到的是通过样式表来解决&#xff0c;但找遍Qt Assist和网络&#xff0c;都没这…

MySQL存储与优化 一、MySQL架构原理

1.MySQL体系架构 MySQL Server架构自顶向下大致可以分网络连接层、服务层、存储引擎层和系统文件层 (1)网络连接层 客户端连接器&#xff08;Client Connectors&#xff09;&#xff1a;提供与MySQL服务器建立的支持。目前几乎支持所有主流的服务端编程技术&#xff0c;例如常…

EE trade:市价建仓的优缺点是什么

在金融市场的复杂环境中&#xff0c;市价建仓策略作为一种常见的交易手段&#xff0c;其优缺点成为了投资者关注的焦点。通过深入分析&#xff0c;我们可以更全面地理解这一策略的利弊&#xff0c;从而在实际操作中做出更加明智的决策。 市价建仓优点分析 快速执行 市价建仓…

鸿蒙系统:未来智能生态的引领者

在当今这个日新月异的互联网领域&#xff0c;操作系统作为连接硬件与软件的桥梁&#xff0c;其重要性不言而喻。随着华为鸿蒙系统&#xff08;HarmonyOS&#xff09;的崛起&#xff0c;一场关于操作系统未来的讨论再次被推向高潮。 鸿蒙OS&#xff0c;华为的全新力作&#xff…

从nginx返回404来看http1.0和http1.1的区别

序言 什么样的人可以称之为有智慧的人呢&#xff1f;如果下一个定义&#xff0c;你会如何来定义&#xff1f; 所谓智慧&#xff0c;就是能区分自己能改变的部分&#xff0c;自己无法改变的部分&#xff0c;努力去做自己能改变的&#xff0c;而不要天天想着那些无法改变的东西&a…

2024年电脑监控软件排行榜(真实测评推荐七款电脑监控软件)

在信息化快速发展的今天&#xff0c;企业对员工电脑活动的监控变得尤为重要。有效的电脑监控软件不仅可以提升员工的工作效率&#xff0c;还能防止信息泄露&#xff0c;保障企业的数据安全。本文将介绍几款知名的电脑监控软件&#xff0c;并对其特点进行详细分析&#xff0c;帮…

JavaWeb系列二十三: web 应用常用功能(文件上传下载)

文章目录 5. 文件上传基本介绍5.1 文件上传-原理示意图5.2 文件上传页面5.3 走通Servlet5.4 表单项区别处理5.5 创建目录-保存文件5.6 中文编码问题5.7 文件上传注意事项和细节5.7.1 按照年月日目录存放5.7.2 文件覆盖问题5.7.3 封装一下 5.8 文件上传其他注意事项5.8.1 upload…

浅谈信息技术高效课堂管理:策略、技巧与实践

引言&#xff1a; 在信息化教育的浪潮中&#xff0c;信息技术课程正逐渐成为学校教育体系中的重要组成部分。然而&#xff0c;信息技术课堂的特殊性——高互动性、高度依赖电子设备&#xff0c;给课堂管理带来了前所未有的挑战。如何在保证教学效率的同时&#xff0c;维护良好…

go mod 依赖管理补充2

依赖包的版本问题&#xff0c;别的开发语言有没有类似的问题&#xff1f;是怎么解决的&#xff1f; 举例&#xff1a;java java的依赖包的版本问题&#xff0c;通过Maven模块来操作&#xff0c;可以指定依赖包版本号&#xff0c;如下&#xff1a; go.mod 文件 go.mod文件是G…