返回> 网站首页
QQ语音slk文件格式转换及播放
yoours2021-07-27 19:36:37
简介一边听听音乐,一边写写文章。
一、QQ语音文件保存位置
/Android/data/com.tencent.mobileqq/Tencent/MobileQQ/[你的qq号]/ppt/
二、转换slk文件格式为pcm
见开源代码:https://kn007.net/topics/batch-convert-silk-v3-audio-files-to-mp3-in-windows/
可以使用Visual Studio编译:创建控制台程序,解压下载的源代码,拷贝silk文件夹下的src和interface文件夹,以及test文件夹下的Decoder.c文件。
删除asm汇编文件,将其他文件加入到工程,c文件修改为不使用编译头,以及删除创建的main函数后编译即可。
编译成功后,使用方法命令行输入: xxx.exe 1.slk 1.pcm
三、转换pcm为wav格式
转换方法为wav头信息 + pcm即可,见下:
typedef struct WaveHeader {
BYTE fileID[4];
DWORD fileLength;
BYTE wavTag[4];
BYTE FmtHdrID[4];
DWORD FmtHdrLeth;
WORD FormatTag;
WORD Channels;
DWORD SamplesPerSec;
DWORD AvgBytesPerSec;
WORD BlockAlign;
WORD BitsPerSample;
BYTE DataHdrID[4];
DWORD DataHdrLeth;
};
void convertAudioFiles(char* src, char* target)
{
FILE* fp = fopen(src, "rb");
fseek(fp, 0, SEEK_END);
long PCMSize = ftell(fp);
//填入参数,比特率等等。这里用的是16位单声道 8000 hz
WaveHeader header;
memcpy(header.fileID, "RIFF", 4);
memcpy(header.wavTag, "WAVE", 4);
memcpy(header.FmtHdrID, "fmt ", 4);
memcpy(header.DataHdrID, "data", 4);
//长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
header.fileLength = PCMSize + (44 - 8);
header.FmtHdrLeth = 16;
header.BitsPerSample = 16;
header.Channels = 1;
header.FormatTag = 0x0001;
header.SamplesPerSec = 24000;
header.BlockAlign = (short)(header.Channels * header.BitsPerSample / 8);
header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
header.DataHdrLeth = PCMSize;
FILE* fpwav = fopen(target, "wb");
fwrite(&header, sizeof(WaveHeader), 1, fpwav);
fseek(fp, 0, SEEK_SET);
BYTE buf[1024];
while(1)
{
int len = fread(buf, 1, 1024, fp);
if(len<=0)
break;
fwrite(buf, 1, len, fpwav);
}
fclose(fp);
fclose(fpwav);
}
调用方法:convertAudioFiles("1.pcm", "1.wav");
四、以内存数据的方式播放pcm
void PlayWav()
{
FILE* fp = fopen("1.pcm", "rb");
fseek(fp, 0, SEEK_END);
long PCMSize = ftell(fp);
BYTE* waveOut = new BYTE[PCMSize];
fseek(fp, 0, SEEK_SET);
fread(waveOut, 1, PCMSize, fp);
fclose(fp);
DWORD sampleRate=24000;
//确定音频数据的格式及内容
WAVEFORMATEX pFormat;
pFormat.wFormatTag=WAVE_FORMAT_PCM;
//simple,uncompressed format
pFormat.nChannels=1;//1=mono, 2=stereo
pFormat.nSamplesPerSec=sampleRate; // 44100
pFormat.nAvgBytesPerSec=sampleRate*2;
// = nSamplesPerSec * n.Channels * wBitsPerSample/8
pFormat.nBlockAlign=2; // = n.Channels * wBitsPerSample/8
pFormat.wBitsPerSample=16;
//16 for high quality, 8 for telephone-grade
pFormat.cbSize=0;
// 打开一个给定的波形音频输出装置
HWAVEOUT hWaveOut;
WAVEHDR WaveOutHdr;
MMRESULT result;
result = waveOutOpen(&hWaveOut, WAVE_MAPPER, &pFormat, 0L, 0L, WAVE_FORMAT_DIRECT);
if (result)
return;
// 准备波形数据块
WaveOutHdr.lpData = (LPSTR)waveOut;
WaveOutHdr.dwBufferLength = PCMSize;
WaveOutHdr.dwBytesRecorded=0;
WaveOutHdr.dwUser = 0L;
WaveOutHdr.dwFlags = 0L;
WaveOutHdr.dwLoops = 0L;
waveOutPrepareHeader(hWaveOut, &WaveOutHdr, sizeof(WAVEHDR));
// 向给定音频媒体中输出波形数据块:
result = waveOutWrite(hWaveOut, &WaveOutHdr, sizeof(WAVEHDR));
if (result)
return;
MMTIME mmTime;
//清除准备:
// Wait until finished sound play
do {
if(MMSYSERR_NOERROR==waveOutGetPosition(hWaveOut, &mmTime, sizeof(MMTIME)))
{
if(mmTime.wType==TIME_BYTES)
{
TRACE("%d%%\r\n", 100.0*mmTime.u.cb/PCMSize);
}
}
} while (waveOutUnprepareHeader(hWaveOut, &WaveOutHdr, sizeof(WAVEHDR))==WAVERR_STILLPLAYING);
// 关闭给定音频媒体:
waveOutClose(hWaveOut);
}
五、总结
该方法不需要ffmpeg、lame等辅助转换格式,直接自行依据开源代码修改编译没有原作者所说的杀毒软件会报毒问题。