2022-03-31 Amr-nb格式字节对齐、非字节对齐的转换和解码处理(含源码)

这篇具有很好参考价值的文章主要介绍了2022-03-31 Amr-nb格式字节对齐、非字节对齐的转换和解码处理(含源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

常用音视频处理格式AMR-NB

AMR的格式分为AMR-NB、AMR-WB、AMR-WB+
三种格式的区分和差异可以自行百度,在这里就不做细分了。 我相信,找到这篇文章的基本已经是入门了。


这一次我们主要处理的是AMR-NB格式的数据。本文主要贴出了如何区分字节对齐、非字节对齐的方法,以及如何处理解码?(需要完整解决方案或者答疑的,可以私聊获取相关帮助)。


前言

解决什么问题:

这次,我们需要解决的是将AMRNB的UDP包数据,进行解码;这边涉及到的知识点是:

  1. opencore-amr-0.1.5,下载点击: https://download.csdn.net/download/shayueqing/85059816
  2. winpcap库,用于抓取网卡数据包。

提示:以下是本篇文章正文内容,下面案例可供参考

一、理论知识(熟悉可跳过)

摘自网络:原文链接:https://blog.csdn.net/runningya/article/details/6227384

  1. AMR编码介绍
    AMR编码是一种自适应多速率编码,根据传输信道的实际情况,调整编码模式、速率和纠错码位数来保证语音质量,在数据压缩和容错上面取得平衡。一般语音质量越高抗干扰能力越弱。在GSM网络,基站、基站控制器可根据网络质量和信号质量情况动态调整语音编码模式以提高不同网络状况下的语音质量。现在手机终端基本上都支持AMR编码,Nokia从2004年开始提供支持AMR的终端,目前所有的新型号终端都支持AMR。
  2. AMR在IP域中的净荷格式
    RFC3267/4867协议描述AMR编码在RTP中的载荷格式,是其在IP域的存在形式。
    对于每个RTP会话,AMR净荷有两种模式,分别为节省带宽模式和字节对齐模式,具体采用那种模式,由信令协商决定;采用后一模式可以后可以引入鲁棒排序、帧交叉编码和CRC校验等方式提高语音传输的质量。
  3. AMR NB/WB信令协商参数
    AMR常用如下
    octet-align,是节省带宽模式还是字节对节模式,一般取值为1表示字节对齐,为0或不带默认表示为节省带宽模式;
    mode-set,一旦请求带了模式集,之后AMR媒体流只选择属于这个模式集的模式来发送;
    mode-change-period,模式改变周期;
    maxptime,最大支持的打包时长(ms);
    crc,净荷是否进行CRC校验,一般为1表示需要,媒体流会携带校验位;
    robust-sorting,是否进行鲁棒排序;
    interleaving,定义交错帧块数;
    ptime,指包时长;
    channels,音频通道数,例如采用左右通道数值则为2;

二、我们要做哪些事?

如何提取AMR-NB,哪里有amr字节和采样率的对应,可以参考一些我的其他博文:https://blog.csdn.net/shayueqing/article/details/107319891

解决什么问题,对你是否有帮助?

  1. 从网卡上抓取rtp包,提取出payload;
  2. 根据playload,结合amr-nb的“采样率字节表”,解析出实际的数据长度,并且进行解码;

三、代码干货(底下附完整实现)

1.提取payload数据,并进行两步处理

  • 将amr-nb非字节对齐转成字节对齐;
  • 区分噪音帧和音频帧;

代码如下(示例):

//这一步是从RTP包获取payload
unsigned char*pbuffer = (u_char*)((u_char*)uh + sizeof(udp_header) + sizeof(rtp_header));
//这一步进行非字节对齐与字节对齐的转换
int size = 0;
unsigned char outbuf[400] = { 0 };
bool bRet = prase_amr(pbuffer, 32, outbuf, &size, &data.pData[0]);
if (bRet == false)
{
	//为噪音帧
	memset(data.pData, 0, 32);
	data.iBnoiseFrame = 1;			
}
else
{
	//为正常
	data.length = size + 1;
	memcpy(&data.pData[1], outbuf, size);
	data.iBnoiseFrame = 0;			
}		
//这一步将数据投递到解码队列
pRecordData->push(data);

2.核心函数 prase_amr

  • 这部分是非字节对齐与字节对齐转换的关键,参考了Pjmedia开源库;

	bool bNoise = false;		//是否为噪音帧
	unsigned cnt = 0;
	bool octet_aligned = true;		//默认字节对齐
	pj_uint8_t nFramSize = 0;
	/* Read cursor */
	pj_uint8_t r_bitptr = 0;
	pj_uint8_t *r = (pj_uint8_t*)data;
	pjmedia_codec_amr_bit_info info;
	/* env vars for AMR or AMRWB */
	pj_uint8_t				SID_FT;
	const pj_uint8_t	    *framelen_tbl;
	const pj_uint16_t	    *framelenbit_tbl;
	const pj_int16_t* const *order_maps;

	/* frame info */
	//pjmedia_codec_amr_bit_info *info;
	
	if (amr_nb) {
		SID_FT = 8;
		framelen_tbl = pjmedia_codec_amrnb_framelen;
		framelenbit_tbl = pjmedia_codec_amrnb_framelenbits;
		order_maps = pjmedia_codec_amrnb_ordermaps;
	}
	else {
		SID_FT = 9;
		framelen_tbl = pjmedia_codec_amrwb_framelen;
		framelenbit_tbl = pjmedia_codec_amrwb_framelenbits;
		order_maps = pjmedia_codec_amrwb_ordermaps;
	}

	

	/* Code Mode Request, 4 bits */
	pj_uint8_t cmr = (pj_uint8_t)((*r >> 4) & 0x0F);
	pj_uint8_t reserver = (pj_uint8_t)((*r) & 0x0F);
	if (reserver != 0)
	{
		//非字节对齐
		octet_aligned = false;
	}

	r_bitptr = 4;
	if (octet_aligned) {
		++r;
		r_bitptr = 0;
	}

	/* Table Of Contents, 6 bits each */
	for (;;) {
		pj_uint8_t TOC = 0;
		pj_uint8_t F, FT, Q;

		if (r_bitptr == 0) {
			TOC = (pj_uint8_t)(*r >> 2);
			r_bitptr = 6;
		}
		else if (r_bitptr == 2) {
			TOC = (pj_uint8_t)(*r++ & 0x3F);
			r_bitptr = 0;
		}
		else if (r_bitptr == 4) {
			TOC = (pj_uint8_t)((*r++ & 0x0f) << 2);
			TOC |= *r >> 6;
			r_bitptr = 2;
		}
		else if (r_bitptr == 6) {
			TOC = (pj_uint8_t)((*r++ & 0x03) << 4);
			TOC |= *r >> 4;
			r_bitptr = 4;
		}

		F = (pj_uint8_t)(TOC >> 5);
		FT = (pj_uint8_t)((TOC >> 1) & 0x0F);
		Q = (pj_uint8_t)(TOC & 1);

		if (FT > SID_FT && FT < 14) {
			
			cnt = 0;
			//解析错误
			break;
		}

		if (octet_aligned) {
			++r;
			r_bitptr = 0;
		}

		/* Set frame attributes */
		//info = (pjmedia_codec_amr_bit_info*)&frames[cnt].bit_info;
		info.frame_type = FT;
		info.mode = (pj_int8_t)((FT < SID_FT) ? FT : -1);
		info.good_quality = (pj_uint8_t)(Q == 1);
		info.start_bit = 0;
		info.STI = 0;
	
		if (!F)
			break;
	}
	//*nframes = cnt;

	if (info.frame_type == SID_FT)
		return true;


	/* Speech frames */
	
	pj_uint8_t FT;
	FT = info.frame_type;

	pj_uint8_t *buf = r;
	pj_uint8_t start_bit = r_bitptr;

	//if (FT == SID_FT) {
	//	unsigned sti_bitptr;
	//	sti_bitptr = r_bitptr + 35;
	//	info->STI = (pj_uint8_t)
	//		(r[sti_bitptr >> 3] >> (7 - (sti_bitptr % 8))) & 1;
	//}

	if (octet_aligned) {
		r += framelen_tbl[FT];
		nFramSize = framelen_tbl[FT];
	}
	else {
		if (FT == 14 || FT == 15) {
			/* NO DATA */
			//frames[cnt].size = 0;
		}
		else {
			unsigned adv_bit;

			adv_bit = framelenbit_tbl[FT] + r_bitptr;
			r += adv_bit >> 3;
			r_bitptr = (pj_uint8_t)(adv_bit % 8);

			nFramSize = adv_bit >> 3;
			if (r_bitptr)
			{
				++nFramSize;
			}
			//++frames[cnt].size;
		}
	}
	

	
	// d0 开始, start位=2,字节31

	pj_int8_t    amr_bits[477 + 7] = { 0 };
	pj_int8_t   *p_amr_bits = &amr_bits[0];

	unsigned char outbuf[1024] = { 0 };

	pj_uint8_t  *r1 = (pj_uint8_t*)buf;  /* read cursor */
	pj_uint8_t  *w = (pj_uint8_t*)outbuf; /* write cursor */

	/* env vars for AMR or AMRWB */




	unsigned i;

	//*out_info = *in_info;
	order_maps = pjmedia_codec_amrnb_ordermaps;
	if (amr_nb) {
		SID_FT = 8;
		framelen_tbl = pjmedia_codec_amrnb_framelen;
		framelenbit_tbl = pjmedia_codec_amrnb_framelenbits;
		//bitrate_tbl = pjmedia_codec_amrnb_bitrates;

	}
	else {
		SID_FT = 9;
		framelen_tbl = pjmedia_codec_amrwb_framelen;
		framelenbit_tbl = pjmedia_codec_amrwb_framelenbits;
		//bitrate_tbl = pjmedia_codec_amrwb_bitrates;
		//order_maps = pjmedia_codec_amrwb_ordermaps;
	}

	//PJ_UNUSED_ARG(bitrate_tbl);
	int  frame_type = info.frame_type;

	/* unpack AMR bitstream if there is any data */
	if (frame_type <= SID_FT) {
		i = 0;
		if (start_bit) {
			for (; i < (unsigned)(8 - start_bit); ++i)
				*p_amr_bits++ = (pj_uint8_t)
				((*r1 >> (7 - start_bit - i)) & 1);
			++r1;
		}
		for (; i < framelenbit_tbl[frame_type]; i += 8, ++r1) {
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 7) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 6) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 5) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 4) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 3) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 2) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1 >> 1) & 1);
			*p_amr_bits++ = (pj_uint8_t)((*r1) & 1);
		}
	}



	if (frame_type < SID_FT) {

		/* Speech */
		int mode = info.frame_type;
		// mode = 7, size = 31
		/*out_info->mode = in_info->frame_type;
		size = framelen_tbl[out_info->mode];*/

		//pj_bzero(out->buf, out->size);

		if (reorder)
		{
			const pj_int16_t *order_map = order_maps[mode];

			for (i = 0; i < framelenbit_tbl[mode]; ++i) {
				if (amr_bits[i]) {
					pj_uint16_t bitpos;
					bitpos = order_map[i];
					w[bitpos >> 3] |= 1 << (7 - (bitpos % 8));
				}
			}
		}
		else {
			for (i = 0; i < framelenbit_tbl[mode]; ++i) {
				if (amr_bits[i])
					w[i >> 3] |= 1 << (7 - (i % 8));
			}
		}
		*framesize = nFramSize;
		*byte0 = (info.frame_type << 3) | (info.good_quality << 2);
		memcpy(datsdata, outbuf, nFramSize);
		return true;
	}
	else
	{
		//memcpy(datsdata, outbuf, 31);
		*framesize = 0;
	}
	return false;

不理解程序原理的可以私聊我本人,获取帮助。下面附完整实现。

2.完整源码实现

附下载链接: 完整转换代码

四、amr分类

2022-03-31 Amr-nb格式字节对齐、非字节对齐的转换和解码处理(含源码)

五、一些参考资料

1.说明

RFC3267说明中讲到以下内容:

3.8节,介绍了 Bandwidth Efficient or Octet-aligned Mode,大家可以看下;

  1. 介绍了节省带宽或高效带宽传输模式、八位字节对齐模式;
  2. 使用何种模式,主要是由会话协商决定;
  3. 两种模式之间,八位字节对齐模式能够更好的处理丢包和比特错误;

2022-03-31 Amr-nb格式字节对齐、非字节对齐的转换和解码处理(含源码)

4.4节描述了octet-aligned Mode的详细内容
2022-03-31 Amr-nb格式字节对齐、非字节对齐的转换和解码处理(含源码)文章来源地址https://www.toymoban.com/news/detail-434545.html

到了这里,关于2022-03-31 Amr-nb格式字节对齐、非字节对齐的转换和解码处理(含源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CAP结构体之字节对齐

    🍅 我是 蚂蚁小兵 ,专注于车载诊断领域,尤其擅长于对CANoe工具的使用 🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】 🍅 玩转CANoe,博客目录大全,点击跳转👉 CAPL为什么也要理解字节对齐呢? 一般情况下,我们在定义/使用结构体的情

    2024年02月12日
    浏览(33)
  • 【FFmpeg】ffmpeg 命令行参数 ⑧ ( 使用 ffmpeg 转换封装格式 | 音视频编解码器参数设置 | 视频 帧率 / 码率 / 分辨率 设置 | 音频 码率 / 采样率 设置 )

    音视频 文件 从 采样 - 处理 - 得到原始数据帧队列 - 音视频编码 - 音视频包队列 - 格式封装 的过程如下 : 封装格式 参考 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装

    2024年04月17日
    浏览(63)
  • c/c++--字节对齐(byte alignment)

    在所有结构体成员的字节长度都 没有超出操作系统基本字节单位 (32位操作系统是4,64位操作系统是8)的情况下 按照结构体中字节最大的变量长度来对齐; 若结构体中某个变量字节 超出操作系统基本字节单位 那么就按照 系统字节单位来对齐 。 注意: 并不是32位就直接按照

    2024年02月07日
    浏览(27)
  • 为什么要做字节对齐 alignment?

    下面这段 C++ 代码的输出是什么?定义的 Type 占用的字节数(下面简称为字节数)是多少呢? 经过编译运行,在 x86-64 Linux 机器上输出的结果是 8 。如果将成员变量的字节数相加求和,等于 1 + 4 = 5 字节。那多出来的 3 字节做什么了? 一般,我们会把多出的 3 字节用来做字节

    2024年02月07日
    浏览(31)
  • STM32 大小端与字节对齐使用记录

    串口数据包解析 接收到的数据包: 其中数据内容为: 我们设计的结构体 使用内容复制函数 想要的数据: 实际的数据: 解决方法: CMSIS都已经给你写好的,请看core_cm3.h 执行完这个代码后 我们希望 实际上 解决方法:

    2024年02月07日
    浏览(27)
  • C/C++编译器的字节对齐方式

    C/C++编译器的缺省字节对齐方式为自然对界。即在缺省情况下,编译器为每一个变量或是数据单元按其自然对界条件分配空间。 在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插

    2024年01月19日
    浏览(22)
  • ()Android apk应用加固、字节对齐、二次签名全流程

    这篇博客主要是讲如何对apk应用进行加固、对齐和签名的,会有详细的步骤逐一介绍 随着各大加固工具都开始逐一收费后,个人开发中或者中小型企业如何对应用进行加固就成了一个问题。以前我常用的是360加固助手,虽然每天限制一定的免费次数,但起码能用。 可是最近

    2024年01月17日
    浏览(35)
  • 结构体占用内存大小如何确定?-->结构体字节对齐 | C语言

    目录 一、什么是结构体 二、为什么需要结构体 三、结构体的字节对齐 3.1、示例1 3.2、示例2 3.3、示例3  3.4、示例4 3.5、示例5 四、结构体字节对齐总结         结构体是将不同类型的数据按照一定的功能需 求进行整体封装,封装的数据类型与大小均可以由用户指定。 结

    2024年01月17日
    浏览(34)
  • C语言结构体字节对齐(内存对齐)之#pragma pack和__attribute__((packed)的使用

    在不使用 #pragma pack 和 __attribute__((packed) 等选项来自定义字节对齐大小的情况下,关于正常字节对齐的描述,可参考博文: C/C++计算类/结构体和联合体(union)所占内存大小(内存对齐问题)_联合体占用的内存空间_SOC罗三炮的博客-CSDN博客 同学可以尝试将char f 注释,最后将

    2024年02月12日
    浏览(33)
  • 1分钟了解C语言正确使用字节对齐及#pragma pack的方法

    ​ C/C++编译器的缺省字节对齐方式为自然对界。即在缺省情况下,编译器为每一个变量或是数据单元按其自然对界条件分配空间。 在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有

    2024年02月02日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包