音频demo:使用opencore-amr将PCM数据与AMR-NB数据进行相互编解码

1、README

a. 编译

编译demo

由于提供的.a静态库是在x86_64的机器上编译的,所以仅支持该架构的主机上编译运行。

$ make

编译opencore-amr

如果想要在其他架构的CPU上编译运行,可以使用以下命令(脚本)编译opencore-amr[下载地址]得到相应的库文件进行替换:

#!/bin/bashtar xzf opencore-amr-0.1.3.tar.gz
cd opencore-amr-0.1.3/
./configure --prefix=$PWD/_install # --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc
make -j96
make install
b. 使用

本示例是使用amr(nb)与pcm(8KHz,16bits,单/双声道)音频数据进行相互转化(编解码),使用如下:

$ ./pcm2amrnb ./audio/test_8000_16_1.pcm out.amr 	# 不管输入的PCM是单声道还是双声道,这里输出的amr都是单声道的
$ ./amrnb2pcm ./audio/test.amr out_8000_16_1.pcm 	# 解码出来的PCM都是8KHz单声道
编码参数要求

amr enc params

(截图来源:opencore-amr-0.1.3/test/amrnb-enc.c)
解码输出参数

amr dec params

(截图来源:opencore-amr-0.1.3/test/amrnb-dec.c)
c. 参考文章
  • https://blog.csdn.net/hanzhen7541/article/details/100932834

  • https://blog.csdn.net/dinggo/article/details/1966444

  • “Amr supports only 8000Hz sample rate and 4.75k, 5.15k, …”: https://stackoverflow.com/questions/2559746/getting-error-while-converting-wav-to-amr-using-ffmpeg#

d. 附录
$ tree
.
├── audio
│   ├── test_8000_16_1.pcm
│   ├── test_8000_16_2.pcm
│   └── test.amr
├── docs
│   ├── AMR文件格式分析_dinggo的专栏-CSDN博客_amr格式.mhtml
│   ├── AMR编码文件解析_hanzhen7541的博客-CSDN博客.mhtml
│   └── audio - getting error while converting wav to amr using ffmpeg - Stack Overflow.mhtml
├── include
│   ├── interf_dec.h
│   └── interf_enc.h
├── libs
│   └── libopencore-amrnb.a
├── main_amrnb2pcm.c
├── main_pcm2amrnb.c
├── Makefile
└── README.md

2、主要代码片段

main_pcm2amrnb.c
#include <stdio.h>
#include <stdlib.h>#include "interf_enc.h"/* PCM参数 */
#define PCM_SAMPLERATE 	(8000) 	/* 只能编码 8 khz */
#define PCM_SAMPLEBITS 	(16) 	/* 只支持16位 */
#define PCM_CHANNELS 	(1) 	/* 不管PCM输入是单声道还是双声道,这里输出的amr都是单声道的 *//* amr一帧数据是20ms,一秒50帧。8000,16,1 ==> 320 Bytes */
#define PCM_ONE_FRAME_SIZE  (PCM_SAMPLERATE/50 * PCM_SAMPLEBITS/8 * PCM_CHANNELS)/* AMR参数 */
#define AMR_ENCODE_MODE MR122
#define AMR_ONE_FRAME_SIZE (32) /* MR122格式是32字节一帧 *//* 是否使能背景噪声编码模式 */
#define DTX_DECODE_ENABLE 	1
#define DTX_DECODE_DISABLE 	0int main(int argc, char *argv[])
{int dtx = DTX_DECODE_ENABLE;void *vpAmr = NULL;FILE *fpAmr = NULL;FILE *fpPcm = NULL;/* 检查参数 */if(argc != 3){printf("Usage: \n""\t %s ./audio/test_8000_16_1.pcm out.amr\n", argv[0]);return -1;}printf("It will encode a PCM file as [sample rate: %d] - [sample bits: %d] - [channels: %d] !\n", PCM_SAMPLERATE, PCM_SAMPLEBITS, PCM_CHANNELS);/* 初始化编码器 */vpAmr = Encoder_Interface_init(dtx);if(vpAmr == NULL){printf("Encoder_Interface_init error!\n");return -1;}/* 打开pcm文件 */fpPcm = fopen(argv[1], "rb");if(fpPcm == NULL)   {   perror("argv[1]");return -1;}/* 打开amr文件 */fpAmr = fopen(argv[2], "wb");if(fpAmr == NULL){perror("argv[2]");return -1;}/* 先写入amr头部 */fwrite("#!AMR\n", 1, 6, fpAmr);/* 循环编码 */while(1){unsigned char acPcmBuf[PCM_ONE_FRAME_SIZE] = {0}; 	/* 保存在文件中一帧(20ms)PCM数据,8bit为单位,这里是unsigned */short asEncInBuf[PCM_ONE_FRAME_SIZE/2] = {0}; 		/* 编码需要的一帧(20ms)PCM数据,16bit为单位 */char acEncOutBuf[AMR_ONE_FRAME_SIZE] = {0};			/* 编码出来的一帧(20ms)AMR数据 */int iReadPcmBytes = 0; 								/* 从PCM文件中读取出的数据大小,单位:字节 */int iEncAmrBytes = 0; 								/* 编码出的AMR数据大小,单位:字节 *//* 读出一帧PCM数据 */iReadPcmBytes = fread(acPcmBuf, 1, PCM_ONE_FRAME_SIZE, fpPcm);if(iReadPcmBytes <= 0){break;}//printf("iReadPcmBytes = %d\n", iReadPcmBytes);#if 0/* 编码方式 1:像官方测试程序一样转换为short类型再进行编码 */for(int i = 0; i < PCM_ONE_FRAME_SIZE/2; i++){unsigned char *p = &acPcmBuf[2*PCM_CHANNELS*i];asEncInBuf[i] = (p[1] << 8) | p[0];}/* 编码 */iEncAmrBytes = Encoder_Interface_Encode(vpAmr, AMR_ENCODE_MODE, asEncInBuf, acEncOutBuf, 0/* 参数未使用 */);
#else/* 编码方式 2:传参时直接类型强制转换即可 *//* 编码 */iEncAmrBytes = Encoder_Interface_Encode(vpAmr, AMR_ENCODE_MODE, (short *)acPcmBuf, acEncOutBuf, 0/* 参数未使用 */);
#endif//printf("iEncAmrBytes = %d\n", iEncAmrBytes);/* 写入到AMR文件中 */fwrite(acEncOutBuf, 1, iEncAmrBytes, fpAmr);}/* 关闭文件 */fclose(fpAmr);fclose(fpPcm);/* 关闭编码器 */Encoder_Interface_exit(vpAmr);printf("%s -> %s: Success!\n", argv[1], argv[2]);return 0;
}
main_amrnb2pcm.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "interf_dec.h"/* amrnb解码出来的PCM就是这个参数 */
#define PCM_SAMPLERATE  (8000)
#define PCM_SAMPLEBITS  (16)
#define PCM_CHANNELS    (1)/* amr一帧数据是20ms,一秒50帧。8000,16,1 ==> 320 Bytes */
#define PCM_ONE_FRAME_SIZE  (PCM_SAMPLERATE/50 * PCM_SAMPLEBITS/8 * PCM_CHANNELS)/* AMR参数 */
#define AMR_ONE_FRAME_SIZE (32) /* 对于NB,一般占用字节最大的MR122格式是32字节一帧 */int main(int argc, char *argv[])
{void *vpDecoder = NULL;FILE *fpAmr = NULL;FILE *fpPcm = NULL;char acAmrHeader[6] = {0};int iReadBytes = 0;int iFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0};/* 检查参数 */if(argc != 3){printf("Usage: \n""\t %s ./audio/test.amr out_8000_16_1.pcm\n", argv[0]);return -1;}/* 初始化解码器 */vpDecoder = Decoder_Interface_init();if(vpDecoder == NULL){printf("Decoder_Interface_init() error!\n");return -1;}/* 打开文件 */fpPcm = fopen(argv[2], "wb");if(fpPcm == NULL){perror("test_enc.amr");return -1;}fpAmr = fopen(argv[1], "rb");if(fpAmr == NULL)   {   perror("argv[1]");return -1;}/* 判断是否为AMR文件 */iReadBytes = fread(acAmrHeader, 1, 6, fpAmr);if (iReadBytes != 6 || memcmp(acAmrHeader, "#!AMR\n", 6)) {printf("%s is not a amr file!\n", argv[1]);return -1;}/* 循环解码 */while(1){unsigned char acAmrBuf[AMR_ONE_FRAME_SIZE] = {0}; 	// 对于NB,一般最大是32字节,从amr文件读出一帧最大是32(31)字节unsigned char acPcmBuf[PCM_ONE_FRAME_SIZE] = {0}; 	// 解码出来的是以8bit为单位short asDecBuf[PCM_ONE_FRAME_SIZE/2] = {0}; 		// 解码出来的是以16bit为单位int iFrameSize = 0; 		// 根据AMR文件每帧的头部获取该帧数据大小/* 获取AMR规格 */iReadBytes = fread(acAmrBuf, 1, 1, fpAmr);if(iReadBytes <= 0)break;/* 获取一帧的大小, 对于 12.2 kbps 是 31 bytes */iFrameSize = iFrameSizes[(acAmrBuf[0] >> 3) & 0x0F];/* 读取一帧AMR数据,需要注意的是记得偏移一个地址存入31字节,而解码时需要32字节一起解码 */iReadBytes = fread(acAmrBuf + 1, 1, iFrameSize, fpAmr);if(iFrameSize != iReadBytes)break;#if 0/* 解码方式 1:像官方测试程序一样解码出来存到short类型的缓存里 *//* 将AMR数据解码 */Decoder_Interface_Decode(vpDecoder, acAmrBuf, asDecBuf, 0/* 参数未使用 */);char *p = acPcmBuf;for(int i = 0; i < 160; i++){*p++ = (asDecBuf[i] >> 0) & 0xff;*p++ = (asDecBuf[i] >> 8) & 0xff;		}
#else/* 解码方式2:传参时直接强制类型转换即可 *//* 将AMR数据解码 */Decoder_Interface_Decode(vpDecoder, acAmrBuf, (short *)acPcmBuf, 0/* 参数未使用 */);
#endiffwrite(acPcmBuf, 1, 320, fpPcm);}/* 关闭文件 */fclose(fpAmr);fclose(fpPcm);/* 关闭解码器 */Decoder_Interface_exit(vpDecoder);printf("%s -> %s : Success!\n", argv[1], argv[2]);return 0;
}

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

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

  • https://gitee.com/linriming/audio_pcm_amrnb_enc_dec.git

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hdu物联网硬件实验3 按键和中断

学院 班级 学号 姓名 日期 成绩 实验题目 按键和中断 实验目的 实现闪灯功能转换 硬件原理 无 关键代码及注释 /* Button Turns on and off a light emitting diode(LED) connected to digital pin 13, when pressing a pushbutton attached…

[图解]SysML和EA建模住宅安全系统-13-时间图

1 00:00:00,480 --> 00:00:02,280 首先&#xff0c;我们来看&#xff0c;图画在哪里 2 00:00:02,290 --> 00:00:04,380 这个图 3 00:00:04,390 --> 00:00:06,180 你看&#xff0c;它是描述&#xff0c;刚才讲的 4 00:00:06,190 --> 00:00:09,010 描述这个活动 …

ISO 20000认证:驱动企业IT服务管理变革的利器

在信息技术驱动商业发展的今天&#xff0c;企业对高效、可靠和安全的IT服务需求日益增长。ISO 20000作为国际公认的IT服务管理标准&#xff0c;能够帮助企业在竞争激烈的市场环境中脱颖而出&#xff0c;实现IT服务管理的全面提升。本文将深入探讨ISO 20000认证如何帮助企业优化…

Linux忘记密码重置root密码、重置普通用户密码

重启看到选项按e reboot 或 init 62、移动到Linux开头的行在末尾添加 rw init/bin/bash3、按下Ctrlx引导启动 mount -o remount,rw /输入命令回车更改密码,输入新密码&#xff0c;别用小键盘&#xff0c;容易出错 passwd输入两次校验&#xff0c;出现updated successfully就…

进程,进程的调度,进程的调度算法(详解)ฅ( ̳• · • ̳ฅ)

目录 &#x1f607;进程的概念&#xff1a; &#x1f61a;进程的组成&#xff1a; &#x1f970;进程的调度&#xff1a; 一.进程调度的概念&#xff1a; 二.进程调度的方式&#xff1a; 三.进程调度的时机&#xff1a; &#x1f92a;进程的调度算法&#xff1a; 一.先…

Python 中什么是局部变量和全局变量

在Python编程中&#xff0c;理解变量的作用域是非常重要的。变量的作用域决定了变量在程序中的可见性和生命周期。Python中有两种主要的变量作用域&#xff1a;局部变量和全局变量。 1. 局部变量 1.1 定义 局部变量是定义在函数内部的变量&#xff0c;只能在函数内部访问。局…

纯前端低代码开发脚手架 - daelui/molecule

daelui/molecule低代码开发脚手架&#xff1a;分子组件开发、预览、打包 页面代码示例、大屏代码示例预览 可开发页面组件 可开发大屏组件 项目git地址&#xff1a;https://gitee.com/daelui/molecule 在线预览&#xff1a;http://www.daelui.com/daelui/molecule/app/index.…

分布式一致性算法:Raft学习

分布式一致性算法&#xff1a;Raft学习 1 什么是分布式系统&#xff1f; 分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。这些节点可能位于不同的物理位置&#xff0c;但它们协同工作以提供一个统一的计算平台或服务。分布式系统…

Leetcode 295.数据流的中位数

295.数据流的中位数 问题描述 中位数是有序整数列表中的中间值。如果列表的大小是偶数&#xff0c;则没有中间值&#xff0c;中位数是两个中间值的平均值。 例如 arr [2,3,4] 的中位数是 3 。例如 arr [2,3] 的中位数是 (2 3) / 2 2.5 。 实现 MedianFinder 类: Media…

【笔记】太久不用redis忘记怎么后台登陆了

&#xff01;首先启动虚拟机linux的centos7 2.启动finalshell 我的redis启动在根目录用 redis-server redis.conf --启动 systemctl status redis --查看redis状态 是否active redis-cli -h centos的ip地址 -p 你要用的redis端口号&#xff08;默认为6379&#xff09; -a 你…

UDP通讯实现

服务器端&#xff1a; 1.获取套接字 int fd;fdsocket(AF_INET,SOCK_DGRAM,0);if(fd<0){perror("socket");exit(0);} #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); -domain: 指定通信域&…

LInux安装

目录 1. LInux优点 1.1 安全性高 1.2 稳定性和可靠性高 1.3 开源和免费 1.4 资源利用效率 2. Linux虚拟机下载 2.1 VMware安装 2.2 虚拟机安装 2.3 Centos7下载 2.4 简单设置Centors-7 2.4.1 首次进入 2.4.2 联网设置 2.4.3 自动联网设置 2.4.4 自动锁屏设置 Li…

Hadoop-15-Hive 元数据管理与存储 Metadata 内嵌模式 本地模式 远程模式 集群规划配置 启动服务 3节点云服务器实测

章节内容 上一节我们完成了&#xff1a; Hive中数据导出&#xff1a;HDFSHQL操作上传内容至Hive、增删改查等操作 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&am…

C++初学者指南-5.标准库(第一部分)--顺序容器

C初学者指南-5.标准库(第一部分)–顺序容器 文章目录 C初学者指南-5.标准库(第一部分)--顺序容器标准顺序容器常见特点规律性&#xff1a;复制&#xff0c;分配&#xff0c;比较类型推导(C17)常用接口部分 array<T,size>vector\<T>C 的默认容器快速回顾迭代器范围插…

【粉丝福利 | 第8期】值得收藏!推荐10个好用的数据血缘工具

⛳️ 写在前面参与规则&#xff01;&#xff01;&#xff01; ✅参与方式&#xff1a;关注博主、点赞、收藏、评论&#xff0c;任意评论&#xff08;每人最多评论三次&#xff09; ⛳️本次送书1~4本【取决于阅读量&#xff0c;阅读量越多&#xff0c;送的越多】 目前市面上绝…

文档图像处理:大模型的突破与新探索

前言 随着数字化时代的到来&#xff0c;文档图像处理技术在各行各业扮演着越来越重要的角色。在2023第十二届中国智能产业高峰论坛&#xff08;CIIS 2023&#xff09;的专题论坛上&#xff0c;合合信息智能技术平台事业部副总经理、高级工程师丁凯博士分享了当前文档图像处理面…

如何学习和提升SQL

资料来源于腾讯技术直播&#xff0c;只作为学习记录&#xff0c;如有侵权&#xff0c;请联系作者进行删除

4.1 操作系统

大纲 进程管理重点&#xff0c;占本章历年考试一半分数&#xff0c; 前趋图、信号量和PV操作、死锁和银行家算法 出计算题 作业管理历年考试从来没有考过 操作系统概述 进程管理 进程的组成和状态 前趋图 进程资源图 真题 1

实验一 MATLAB \ Python数字图像处理初步

一、实验目的&#xff1a; 1&#xff0e;熟悉及掌握在MATLAB\Python中能够处理哪些格式图像。 2&#xff0e;熟练掌握在MATLAB\Python中如何读取图像。 3&#xff0e;掌握如何利用MATLAB\Python来获取图像的大小、颜色、高度、宽度等等相关信息。 4&#xff0e;掌握如何在M…

java花店管理系统eclipse开发mysql数据库

1 绪论 1.1 系统开发目的 随着人们物质生活水平和经济水平的不断提高&#xff0c;室内绿化布置、家庭园艺装饰、礼仪鲜花等日益受到重视和青睐&#xff0c;以及送鲜花给亲朋好友来表达自己的情谊。传统的花店对于信息的管理的主要方式是基于文本、表格等纸质手工处理&#xf…