BlackFeather'S Blog 我的技术小博 -- C/C++,Python,Golang

移动设备的amr音频解码 - VC

移动设备很多都用的AMR格式的编码来压缩语音,用于存储和传输。但是用代码播放时,需要先解码。


以下就是解码代码:

#define MMS_IO

#ifdef MMS_IO
#define AMR_MAGIC_NUMBER "#!AMR\n"
#define MAX_PACKED_SIZE (MAX_SERIAL_SIZE / 8 + 2)
#endif

/* frame size in serial bitstream file (frame type + serial stream + flags) */
#define SERIAL_FRAMESIZE (1+MAX_SERIAL_SIZE+5)


BOOL AMRNBDecode(BYTE *pbAmrBuffer, DWORD dwAmrLen, BYTE **bOut, DWORD *dwOutLen, BOOL IsHadHeader)
{
	Speech_Decode_FrameState *speech_decoder_state = NULL;
	Word16 serial[SERIAL_FRAMESIZE];   /* coded bits                    */
	Word16 synth[L_FRAME];             /* Synthesis                     */

	UWord8 packed_bits[MAX_PACKED_SIZE];
	Word16 packed_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 };

	enum RXFrameType rx_type = (enum RXFrameType)0;
	enum TXFrameType tx_type = (enum TXFrameType)0;
	enum Mode mode = (enum Mode)0;

	Word16 reset_flag = 0;
	Word16 reset_flag_old = 1;
	Word16 i;

	UWord8 toc, q, ft;

	if (NULL == pbAmrBuffer)
		return FALSE;

	BYTE *pbBuffer = pbAmrBuffer;
	BOOL bRet = FALSE;

	if (IsHadHeader)
	{
		/* read and verify magic number */
		if (memcmp(pbBuffer, AMR_MAGIC_NUMBER, strlen(AMR_MAGIC_NUMBER)))
		{
			return FALSE;
		}
		pbBuffer += strlen(AMR_MAGIC_NUMBER);
		dwAmrLen -= strlen(AMR_MAGIC_NUMBER);
	}

	BYTE *pbDecode = NULL;
	DWORD dwDeLen = 0;

	/*-----------------------------------------------------------------------*
	* Initialization of decoder                                             *
	*-----------------------------------------------------------------------*/
	if (Speech_Decode_Frame_init(&speech_decoder_state, "Decoder"))
		return FALSE;

	/*-----------------------------------------------------------------------*
	* process serial bitstream frame by frame                               *
	*-----------------------------------------------------------------------*/
	while (1 == GetBytesFromBuffer(&pbBuffer, &dwAmrLen, sizeof(UWord8), &toc))
	{
		/* read rest of the frame based on ToC byte */
		q = (toc >> 2) & 0x01;
		ft = (toc >> 3) & 0x0F;
		if (packed_size[ft] != GetBytesFromBuffer(&pbBuffer, &dwAmrLen, packed_size[ft], &packed_bits))
		{
			bRet = FALSE;
			break;
		}

		rx_type = UnpackBits(q, ft, packed_bits, &mode, &serial[1]);

		if (rx_type == RX_NO_DATA) {
			mode = speech_decoder_state->prev_mode;
		}
		else {
			speech_decoder_state->prev_mode = mode;
		}

		/* if homed: check if this frame is another homing frame */
		if (reset_flag_old == 1)
		{
			/* only check until end of first subframe */
			reset_flag = decoder_homing_frame_test_first(&serial[1], mode);
		}
		/* produce encoder homing frame if homed & input=decoder homing frame */
		if ((reset_flag != 0) && (reset_flag_old != 0))
		{
			for (i = 0; i < L_FRAME; i++)
			{
				synth[i] = EHF_MASK;
			}
		}
		else
		{
			/* decode frame */
			Speech_Decode_Frame(speech_decoder_state, mode, &serial[1], rx_type, synth);
		}

		/* write synthesized speech */
		pbDecode = (BYTE *)realloc(pbDecode, sizeof(Word16) * L_FRAME + dwDeLen);
		memcpy(&pbDecode[dwDeLen], synth, sizeof(Word16) * L_FRAME);
		dwDeLen += sizeof(Word16) * L_FRAME;

		/* if not homed: check whether current frame is a homing frame */
		if (reset_flag_old == 0)
		{
			/* check whole frame */
			reset_flag = decoder_homing_frame_test(&serial[1], mode);
		}
		/* reset decoder if current frame is a homing frame */
		if (reset_flag != 0)
		{
			Speech_Decode_Frame_reset(speech_decoder_state);
		}
		reset_flag_old = reset_flag;

		bRet = TRUE;
	}

	Speech_Decode_Frame_exit(&speech_decoder_state);

	if (bRet)
	{
		//建立文件头
		WAVFILEHEADER *pHeader = CreateWavFileHeader(dwDeLen, 1, 8000, 16);
		*dwOutLen = dwDeLen + sizeof(WAVFILEHEADER);
		*bOut = new BYTE[*dwOutLen];
		memcpy(*bOut, pHeader, sizeof(WAVFILEHEADER));
		memcpy(*bOut + sizeof(WAVFILEHEADER), pbDecode, dwDeLen);
		free(pHeader);
	}

	if (pbDecode)
		free(pbDecode);

	return bRet;
}


UINT GetBytesFromBuffer(BYTE **pBuffer, DWORD *dwOft, UINT dwRead, void *lpTarget)
{
	if (*dwOft < dwRead)
		return 0;

	memcpy(lpTarget, *pBuffer, dwRead);
	*dwOft -= dwRead;
	*pBuffer += dwRead;

	return dwRead;
}



WAVFILEHEADER *CreateWavFileHeader(int fileLength, short channel, int sampleRate, short bitPerSample)
{

	WAVFILEHEADER *header = (WAVFILEHEADER *)malloc(sizeof(WAVFILEHEADER));

	// RIFF
	header->riff[0] = 'R';
	header->riff[1] = 'I';
	header->riff[2] = 'F';
	header->riff[3] = 'F';

	// file length
	header->fileLength = fileLength + (44 - 8);

	// WAVE
	header->wavTag[0] = 'W';
	header->wavTag[1] = 'A';
	header->wavTag[2] = 'V';
	header->wavTag[3] = 'E';

	// fmt
	header->fmt[0] = 'f';
	header->fmt[1] = 'm';
	header->fmt[2] = 't';
	header->fmt[3] = ' ';

	header->size = 16;
	header->formatTag = 1;
	header->channel = channel;
	header->sampleRate = sampleRate;
	header->bitPerSample = bitPerSample;
	header->blockAlign = (short)(header->channel * header->bitPerSample / 8);
	header->bytePerSec = header->blockAlign * header->sampleRate;

	// data
	header->data[0] = 'd';
	header->data[1] = 'a';
	header->data[2] = 't';
	header->data[3] = 'a';

	// data size
	header->dataSize = fileLength;

	return header;
}


More...

2015年1月18日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

分享一个XML解析库 -- TinyXML

 

解析XML很常见的功能,网上库也很多,有的大有的小,有的用起来方便有的繁琐。博主测试了几个库,最后用这了这个库,分享出来。

 

TinyXML,能百度到很多使用的demo代码,用起来确实很方便,我附件里面的是单文件版,只有一个.hpp(就是.h),直接include后就能使用。

 

点击下载:tinyXML.hpp.gz

...

More...

2014年10月13日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

mfc spy源码 - VC

 

对于MFC逆向分析,过程略有麻烦,偶然发现一个小工具并分享了源码,这里也分享出来。

界面截图如下,可以很清晰的分析展示出来很多有意思的信息,省略了自已定位的麻烦。

 

工程下载:点击下载 MFC SPY源码

...

2014年6月24日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

undname 源码 - VC

 

用过的人都知道这玩意是干啥的。。。直接贴源码。

 

...

More...

2014年6月24日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

EAT的API Hook

 

IAT的API Hook都已经烂大街了,我丢一个非主流的EAT Hook函数。

就是不走寻常路。

 

 

...

More...

2014年5月26日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

音频播放库 libZPlay(c++)

 

最近开发过程中用到了语音播放,查了一下,写一篇总结。

功能很强大的,有一个bass24,不开源但是提供了各个语言的调用接口和例子,因为项目设计不想额外带一个DLL,所以放弃了,于是有了libZPlay这个库。

 

libZPlay库集成了所有支持格式(mp3, mp2, mp1, ogg, flac, ac3, aac, oga, wav and pcm )的编码解码器。库本身是由WINAPI编写,你无须额外的库,也不需要MFC / .NET的支持,只能在Windows下运行。

...

More...

2014年5月8日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

ring3层实现文件监控 - vc

 

文件/文件夹监控这个功能在某些项目中会用到,需要的就是监控而不是拦截,所以此代码作用就明显了。博主查找,总结了三种方法实现文件/文件夹监控,注意只是监控。

这里只是点一下关键函数,具体用法不贴出来了,自行搜索。

 

方法一:SHChangeNotifyRegister

Windows内部有两个未公开的函数,不过在最新的MSDN中,已经公开了,分别叫做SHChangeNotifyRegister和 SHChangeNotifyDeregister。这两个函数位于Shell32.dll中,是用序号方式导出的。

...

More...

2014年1月6日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

获取进程的启动时间和结束时间

 

不是博主原创,保留作者信息:

Author : YogaRamanan.T

 

此代码的主要功能是遍历所有进程,获取出来每个进程的启动时间和结束时间(进程结束后会显示)。此外还可以显示所有内核模块和地址。

利用此功能,可以做到很多有意思的事情。分享出来!

 

...

More...

2014年1月3日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

推荐两个UDP可靠传输库

 

可靠传输必然优先考虑TCP,但是不同人遇到不同问题,可能会有变态的情况,用UDP也要达到TCP那样保持发送顺序和可靠性,还要类似未连接的状态。

偶然间看到这两个库,测试了一下效果确实不错,分享一下。

 

1.ENet

ENet 是一个易用的、可移植的 UDP 网络开发包,主要功能包括连接管理、可靠的按顺序的多通道包传输机制、包分解和重新打包、避免堵塞机制等。

...

More...

2013年12月19日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0