首页 > 其他分享 >音频demo:使用opencore-amr将PCM数据与AMR-NB数据进行相互编解码

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

时间:2024-07-08 21:29:02浏览次数:17  
标签:编解码 AMR opencore FRAME argv PCM amr define

1、README

a. 编译

编译demo

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

$ make

编译opencore-amr

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

#!/bin/bash

tar 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. 参考文章
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 	0


int 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/* 参数未使用 */);
#endif

		fwrite(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下载地址(任选一个)

标签:编解码,AMR,opencore,FRAME,argv,PCM,amr,define
From: https://blog.csdn.net/weixin_44498318/article/details/140272864

相关文章

  • MSAMRNBSource.dll文件丢失导致程序无法运行问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个MSAMRNBSource.dll文件(挑选合适的版本文件)......
  • C++ UTF-8编解码
    icu编解码数据:externconstUConverterSharedData  _MBCSData,_Latin1Data,  _UTF8Data,_UTF16BEData,_UTF16LEData,_UTF32BEData,_UTF32LEData,  _ISO2022Data,   _LMBCSData1,_LMBCSData2,_LMBCSData3,_LMBCSData4,_LMBCSData5,_LMBCSData6......
  • php如何实现amr转成mp3
    php实现amr转成mp3的方法:1、在服务器安装ffmpeg;2、使用“ffmpeg-i”指令来转换amr为mp3格式;3、在网页端使用html5的audio标签来播放mp3文件即可。思路服务器安装ffmpeg使用ffmpeg-i指令来转换amr为mp3格式(这个到时候写在PHP代码中,使用exec函数执行即可)一、服务器安装ffmp......
  • 基于Matlab的LDPC编解码算法实现的及LDPC码性能测试+源代码+文档说明
    文章目录源码下载地址@[toc]源码下载地址项目介绍项目功能界面预览项目备注源码下载地址项目介绍项目功能界面预览项目备注源码下载地址源码下载地址@[toc]源码下载地址点击这里下载代码项目介绍LDPC码背景及概要LDPC是LowDensityParityCheckCode英文缩写,意......
  • 自动移动机器人(AMR)技术详解
    自动移动机器人(AMR)技术是一种复杂的集成系统,它结合了多种技术来实现自主导航、感知环境和执行任务。以下是AMR技术的一些关键组件和功能:导航系统:定位技术:AMR通常使用GPS(在户外)和室内定位技术(如Wi-Fi、蓝牙、UWB或激光雷达SLAM)来确定其位置。路径规划:基于A*算法、Dijkstra......
  • 在不受支持的 Mac 上安装 macOS Sonoma (OpenCore Legacy Patcher v1.5.0)
    在不受支持的Mac上安装macOSSonoma(OpenCoreLegacyPatcherv1.5.0)InstallmacOSonunsupportedMacs请访问原文链接:https://sysin.org/blog/install-macos-on-unsupported-mac/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org历时两个月,OpenCoreLegacyPat......
  • .net中Base64编解码
    #region对字符串进行Base64编码///<summary>///对字符串进行Base64编码///</summary>///<paramname="source"></param>///<returns>string</returns>publicstaticstringBase......
  • FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
    ​AV1是一种新兴的免费视频编码标准,它由开放媒体联盟(AllianceforOpenMedia,简称AOM)于2018年制定,融合了GoogleVP10、MozillaDaala以及CiscoThor三款开源项目的成果。据说在实际测试中,AV1标准比H.265(HEVC)的压缩率提升了大约27%。由于AV1具有性能优势,并且还是免费授权,因此各大流......
  • 面试题剖析:Netty编解码如何解决拆包沾包问题?
    今天我们要聊的主题是Netty的编解码机制,特别是如何解决TCP的拆包和沾包问题。如果你曾在处理网络数据传输时遇到数据包混乱的情况,那么你已经体验过拆包和沾包的“乐趣”了。别担心,Netty提供了一系列强大的解码器,帮助我们轻松应对这些问题。本文将详细介绍这些解码器的工作原......
  • 题解:SP10232 AMR11E - Distinct Primes
    前话这咋人名都和HP一模一样了,SPOJ出题人里是不是全是哈迷啊。思路非常直观的一个思路:从前往后枚举每一个数,看是否满足条件,输出满足条件的第一个。CODE#include<bits/stdc++.h>usingnamespacestd;boolis(intn){//判断质数if(n<2)return0;for(inti=2;i<......