移动设备很多都用的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; }
解析XML很常见的功能,网上库也很多,有的大有的小,有的用起来方便有的繁琐。博主测试了几个库,最后用这了这个库,分享出来。
TinyXML,能百度到很多使用的demo代码,用起来确实很方便,我附件里面的是单文件版,只有一个.hpp(就是.h),直接include后就能使用。
点击下载:tinyXML.hpp.gz
...
对于MFC逆向分析,过程略有麻烦,偶然发现一个小工具并分享了源码,这里也分享出来。
界面截图如下,可以很清晰的分析展示出来很多有意思的信息,省略了自已定位的麻烦。
工程下载:点击下载 MFC SPY源码
...