1. 程式人生 > >G711編解碼(G711與PCM型別互轉)【轉】

G711編解碼(G711與PCM型別互轉)【轉】

總結網上的G711編解碼, 將其一直到andorid系統上去, 通過jni的來進行G711和PCM 的互轉,  由於對於這兩種格式沒有深入的瞭解,, 所以如果想深入的瞭解他們可以百度, 在這裡只是實現這樣的功能罷了.

g711.c 包含編碼和解碼的方法

  1. //http://www.easydarwin.org/article/Streaming/38.html               參考文章  
  2. //https://github.com/EasyDarwin/EasyAACEncoder/blob/master/g711.cpp  
  3. //http://www.oschina.net/code/snippet_1173523_38946  
  4. //http://blog.csdn.net/rightorwrong/article/details/4209467  PCM 2 G711  G711 2 PCM   
  5. unsigned char encode(short pcm);  
  6. short decode(unsigned char alaw);  
  7. /** 個人理解  
  8.  * bitsize 應該為16, pBuffer(pcm資料) 兩個char 合成一個 short ,長度自然就是原來的一半(nBufferSize/2),  
  9.  * 通過編碼後short型別的資料變為char型別,讓後複製給pCodecBits  
  10.  */  
  11. int g711_encode(unsigned char* pCodecBits, const char* pBuffer, int nBufferSize)  
  12. {  
  13.     short* buffer = (short*)pBuffer;  
  14.     int i;  
  15.     for(i=0; i<nBufferSize/2; i++)  
  16.     {  
  17.         pCodecBits[i] = encode(buffer[i]);  
  18.     }  
  19.     return nBufferSize/2;  
  20. }  
  21. /** 個人理解  
  22.  * bitsize 應該為16, pcm 陣列的寬度變為原來兩倍(short *out_data = (short*)pRawData;),  
  23.  * 通過對pBuffer(g711資料)中char解碼轉為兩個位元組的short ,後複製給out_data陣列, 在使用的時候又轉為char型別, 則 解碼後的資料就是原來的兩倍(nBufferSize*2)  
  24.  */  
  25. int g711_decode(char* pRawData, const unsigned char* pBuffer, int nBufferSize)  
  26. {  
  27.     short *out_data = (short*)pRawData;  
  28.     int i;  
  29.     for(i=0; i<nBufferSize; i++)  
  30.     {  
  31.         out_data[i] = decode(pBuffer[i]);  
  32.     }  
  33.     return nBufferSize*2;  
  34. }  
  35. #define MAX 32635  
  36. unsigned char encode(short pcm)  
  37. {  
  38.     int sign = (pcm & 0x8000) >> 8;  
  39.     if (sign != 0)  
  40.         pcm = -pcm;  
  41.     if (pcm > MAX) pcm = MAX;  
  42.     int exponent = 7;  
  43.     int expMask;  
  44.     for (expMask = 0x4000; (pcm & expMask) == 0  
  45.         && exponent>0; exponent--, expMask >>= 1) { }  
  46.     int mantissa = (pcm >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0f;  
  47.     unsigned char alaw = (unsigned char)(sign | exponent <<4 | mantissa);  
  48.     return (unsigned char)(alaw^0xD5);  
  49. }  
  50. short decode(unsigned char alaw)  
  51. {  
  52.     alaw ^= 0xD5;  
  53.     int sign = alaw & 0x80;  
  54.     int exponent = (alaw & 0x70) >> 4;  
  55.     int data = alaw & 0x0f;  
  56.     data <<= 4;  
  57.     data += 8;  
  58.     if (exponent != 0)  
  59.         data += 0x100;  
  60.     if (exponent > 1)  
  61.         data <<= (exponent - 1);  
  62.     return (short)(sign == 0 ? data : -data);  
  63. }  

jni中實現編解碼,只貼出主要程式碼

G711 -> PCM

  1. JNIEXPORT void JNICALL Java_com_ff_aacdemo_jni_G711Coder_g711Topcm  
  2.   (JNIEnv *env, jobject obj){  
  3.     FILE* fpOut = fopen("/storage/emulated/0/t/pcm_to_g711.pcm", "wb");  
  4.     FILE* fpIn = fopen("/storage/emulated/0/t/pcm_to_g711.g711", "rb");//g711格式檔案在最後會給出連線  
  5.     int g711_BufferSize = 1024;  
  6.     char g711_Buffer[g711_BufferSize];  
  7.     int len;  
  8.     while((len = fread(g711_Buffer, 1, g711_BufferSize, fpIn)) > 0){  
  9.         LOGD("g711topcm length = %d", len);  
  10.         char pcmBuffer[len];  
  11.         int pcmbufsize = g711_decode(pcmBuffer, g711_Buffer, len);  
  12.         fwrite(pcmBuffer, 1, pcmbufsize, fpOut);  
  13.     }  
  14.     LOGD("g711topcm end");  
  15.     fclose(fpIn);  
  16.     fclose(fpOut);  
  17. }  

PCM -> G711

  1. JNIEXPORT void JNICALL Java_com_ff_aacdemo_jni_G711Coder_pcmTog711  
  2.   (JNIEnv *env, jobject obj){  
  3.     FILE* fpIn = fopen("/storage/emulated/0/t/pcm_to_g711.pcm", "rb");  
  4.     FILE* fpOut = fopen("/storage/emulated/0/t/pcm_to_g711.g711", "wb");  
  5.     LOGD("pcmTog711 1");  
  6.     int pcm_BufferSize = 1024;  
  7.     char pcm_Buffer[pcm_BufferSize];  
  8.     int len;  
  9.     while((len = fread(pcm_Buffer, 1, pcm_BufferSize, fpIn)) > 0){  
  10.         LOGD("pcmTog711 length = %d", len);  
  11.         char g711Buffer[len];  
  12.         int  g711BufSize = g711_encode(g711Buffer, pcm_Buffer, len);  
  13.         fwrite(g711Buffer, 1, g711BufSize, fpOut);  
  14.     }  
  15.     LOGD("pcmTog711 end");  
  16.     fclose(fpIn);  
  17.     fclose(fpOut);  
  18. }  

雖然能夠實現他們的相互轉換, 可是,不怎麼好找到播放器播放, 效果始終沒有驗證, 在下一章中, 將總結將 G711 轉換為 AAC , AAC這種格式將能夠使用常規的播放器進行播放

g711檔案 http://download.csdn.net/detail/yuanzhenhai/2693878