PCM文件:模拟音频信号经模数转换(A/D变换)直接形成的二进制序列,该文件没有附加的文件头和文件结束标志。Windows的Convert工具能够把PCM音频格式的文件转换成Microsoft的WAV格式的文件。    
          将音频数字化。事实上就是将声音数字化。最常见的方式是透过脉冲编码调制PCM(Pulse Code Modulation) 。

运作原理例如以下:首先我们考虑声音经过麦克风,转换成一连串电压变化的信号。例如以下图所看到的。这张图的横座标为秒。纵座标为电压大小。要将这种信号转为 PCM 格式的方法,是使用三个參数来表示声音。它们是:声道数採样位数採样频率

採样频率:即取样频率,指每秒钟取得声音样本的次数。採样频率越高,声音的质量也就越好,声音的还原也就越真实,但同一时候它占的资源比較多。因为人耳的分辨率非常有限,太高的频率并不能分辨出来。

在16位声卡中有22KHz、44KHz等几级,当中,22KHz相当于普通FM广播的音质,44KHz已相当于CD音质了,眼下的经常使用採样频率都不超过48KHz。 
        採样位数:即採样值或取样值(就是将採样样本幅度量化)。它是用来衡量声音波动变化的一个參数。也能够说是声卡的分辨率。

它的数值越大,分辨率也就越高。所发出声音的能力越强。
         声道数:非常好理解,有单声道和立体声之分,单声道的声音仅仅能使用一个喇叭发声(有的也处理成两个喇叭输出同一个声道的声音)。立体声的PCM 能够使两个喇叭都发声(一般左右声道有分工) ,更能感受到空间效果。

以下再用图解来看看採样位数和採样频率的概念。让我们来看看这几幅图。图中的黑色曲线表示的是PCM 文件录制的自然界的声波,红色曲线表示的是PCM 文件输出的声波。横坐标便是採样频率;纵坐标便是採样位数。

这几幅图中的格子从左到右,逐渐加密,先是加大横坐标的密度,然后加大纵坐标的密度。显然,当横坐标的单位越小即两个採样时刻的间隔越小。则越有利于保持原始声音的真实情况,换句话说,採样的频率越大则音质越有保证;同理,当纵坐标的单位越小则越有利于音质的提高。即採样的位数越大越好。

在计算机中採样位数一般有8位和16位之分。但有一点请大家注意,8位不是说把纵坐标分成8份,而是分成2的8次方即256份; 同理16位是把纵坐标分成2的16次方65536份; 而採样频率一般有11025HZ(11KHz),22050HZ(22KHz)、44100Hz(44KHz)三种。

那么,如今我们就能够得到PCM文件所占容量的公式:存储量 = (採样频率*採样位数*声道)*时间/8(单位:字节数).
比如,数字激光唱盘(CD-DA。红皮书标准)的标准採样频率为44.lkHz。採样数位为16位,立体声(2声道),能够差点儿无失真地播出频率高达22kHz的声音,这也是人类所能听到的最高频率声音。

激光唱盘一分钟音乐须要的存储量为:     

(44.1*1000*l6*2)*60/8=10。584。000(字节)=10.584MBytes

这个数值就是PCM声音文件在硬盘中所占磁盘空间的存储量。
计算机音频文件的格式决定了其声音的品质,日常生活中电话、收音机等均为模拟音频信号。即不存在採样频率和採样位数的概念,我们能够这样比較一下:

  • 44KHz,16BIT的声音称作:CD音质;
  • 22KHz、16Bit的声音效果近似于立体声(FM Stereo)广播。称作:广播音质;
  • 11kHz、8Bit的声音,称作:电话音质。

G711格式

G711编码的声音清晰度好,语音自然度高,但压缩效率低,数据量大常在32Kbps以上。常用于电话语音(推荐使用64Kbps),sampling rate为8K,压缩率为2,即把S16格式的数据压缩为8bit,分为a-law和u-law。

a-law也叫g711a,输入的是13位(其实是S16的高13位),使用在欧洲和其他地区,这种格式是经过特别设计的,便于数字设备进行快速运算。

运算过程如下:

(1)      取符号位并取反得到s,

(2)      获取强度位eee,获取方法如图所示

(3)      获取高位样本位wxyz

(4)      组合为seeewxyz,将seeewxyz逢偶数为取补数,编码完毕

示例:

输入pcm数据为3210,二进制对应为(0000 1100 1000 1010)

二进制变换下排列组合方式(0 0001 1001 0001010)

(1)      获取符号位最高位为0,取反,s=1

(2)      获取强度位0001,查表,编码制应该是eee=100

(3)      获取高位样本wxyz=1001

(4)      组合为11001001,逢偶数为取反为10011100

编码完毕。

u-law也叫g711u,使用在北美和日本,输入的是14位,编码算法就是查表,没啥复杂算法,就是基础值+平均偏移值,具体示例如下:

pcm=2345

(1)取得范围值

+4062 to +2015 in 16 intervals of 128

 

(2)得到基础值0x90,

(3)间隔数128,

(4)区间基本值4062,

(5)当前值2345和区间基本值差异4062-2345=1717,

(6)偏移值=1717/间隔数=1717/128,取整得到13,

(7)输出为0x90+13=0x9D

代码如下:

g711codec.h

/** G711 encode decode HEADER.*/#ifndef  __G711CODEC_H__
#define __G711CODEC_H__/*
* u-law, A-law and linear PCM conversions.
*/
#define SIGN_BIT    (0x80)      /* Sign bit for a A-law byte. */
#define QUANT_MASK  (0xf)       /* Quantization field mask. */
#define NSEGS       (8)         /* Number of A-law segments. */
#define SEG_SHIFT   (4)         /* Left shift for segment number. */
#define SEG_MASK    (0x70)      /* Segment field mask. */
#define BIAS        (0x84)      /* Bias for linear code. */int PCM2G711a( char *InAudioData, char *OutAudioData, int DataLen, int reserve );
int PCM2G711u( char *InAudioData, char *OutAudioData, int DataLen, int reserve );int G711a2PCM( char *InAudioData, char *OutAudioData, int DataLen, int reserve );
int G711u2PCM( char *InAudioData, char *OutAudioData, int DataLen, int reserve );int g711a_decode(short amp[], const unsigned char g711a_data[], int g711a_bytes);int g711u_decode(short amp[], const unsigned char g711u_data[], int g711u_bytes);int g711a_encode(unsigned char g711_data[], const short amp[], int len);int g711u_encode(unsigned char g711_data[], const short amp[], int len);#endif  /* g711codec.h */
g711codec.c
#include "g711codec.h"static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};static int search(int val, short    *table, int size)
{int    i;for (i = 0; i < size; i++) {if (val <= *table++)return (i);}return (size);
}/*
* alaw2linear() - Convert an A-law value to 16-bit linear PCM
*
*/
static int alaw2linear( unsigned char a_val )
{int    t;int   seg;a_val ^= 0x55;t = (a_val & QUANT_MASK) << 4;seg = ( (unsigned)a_val & SEG_MASK ) >> SEG_SHIFT;switch (seg) {case 0:t += 8;break;case 1:t += 0x108;break;default:t += 0x108;t <<= seg - 1;}return ((a_val & SIGN_BIT) ? t : -t);
}/*
* ulaw2linear() - Convert a u-law value to 16-bit linear PCM
*
* First, a biased linear code is derived from the code word. An unbiased
* output can then be obtained by subtracting 33 from the biased code.
*
* Note that this function expects to be passed the complement of the
* original code word. This is in keeping with ISDN conventions.
*/
static int ulaw2linear(unsigned char u_val)
{int    t;/* Complement to obtain normal u-law value. */u_val = ~u_val;/** Extract and bias the quantization bits. Then* shift up by the segment number and subtract out the bias.*/t = ((u_val & QUANT_MASK) << 3) + BIAS;t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
}/** linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law**/
unsigned char linear2alaw(int pcm_val)  /* 2's complement (16-bit range) */
{int        mask;int        seg;unsigned char   aval;if (pcm_val >= 0) {mask = 0xD5;       /* sign (7th) bit = 1 */} else {mask = 0x55;      /* sign bit = 0 */pcm_val = -pcm_val - 8;}/* Convert the scaled magnitude to segment number. */seg = search(pcm_val, seg_end, 8);/* Combine the sign, segment, and quantization bits. */if (seg >= 8)        /* out of range, return maximum value. */return (0x7F ^ mask);else {aval = seg << SEG_SHIFT;if (seg < 2)aval |= (pcm_val >> 4) & QUANT_MASK;elseaval |= (pcm_val >> (seg + 3)) & QUANT_MASK;return (aval ^ mask);}
}/** linear2ulaw() - Convert a linear PCM value to u-law**/
unsigned char linear2ulaw(int pcm_val)  /* 2's complement (16-bit range) */
{int        mask;int        seg;unsigned char   uval;/* Get the sign and the magnitude of the value. */if (pcm_val < 0) {pcm_val = BIAS - pcm_val;mask = 0x7F;} else {pcm_val += BIAS;mask = 0xFF;}/* Convert the scaled magnitude to segment number. */seg = search(pcm_val, seg_end, 8);/** Combine the sign, segment, quantization bits;* and complement the code word.*/if (seg >= 8)      /* out of range, return maximum value. */return (0x7F ^ mask);else {uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);return (uval ^ mask);}
}int g711a_decode( short amp[], const unsigned char g711a_data[], int g711a_bytes )
{int i;int samples;unsigned char code;int sl;for ( samples = i = 0; ; ){if (i >= g711a_bytes)break;code = g711a_data[i++];sl = alaw2linear( code );amp[samples++] = (short) sl;}return samples*2;
}int g711u_decode(short amp[], const unsigned char g711u_data[], int g711u_bytes)
{int i;int samples;unsigned char code;int sl;for (samples = i = 0;;){if (i >= g711u_bytes)break;code = g711u_data[i++];sl = ulaw2linear(code);amp[samples++] = (short) sl;}return samples*2;
}int g711a_encode(unsigned char g711_data[], const short amp[], int len)
{int i;for (i = 0;  i < len;  i++){g711_data[i] = linear2alaw(amp[i]);}return len;
}int g711u_encode(unsigned char g711_data[], const short amp[], int len)
{int i;for (i = 0;  i < len;  i++){g711_data[i] = linear2ulaw(amp[i]);}return len;
}

decode.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "g711codec.h"int main( int argc, char *argv[] )
{if(argc < 3){printf("==> Usage:\n\tdecode [src.g711a] [dest.pcm]\n");    //printf("==> Usage:\n\tdecode [src.g711u] [dest.pcm]\n");   return 0;}FILE *pInFile = fopen(argv[1], "rb");FILE *pOutFile = fopen(argv[2], "wb");if (NULL == pInFile || NULL == pOutFile){printf("open file failed\n");return 0;}struct stat s_buf;int status = 0;status = stat( argv[1], &s_buf );printf("file_size = %d\n", s_buf.st_size);int Ret = 0;int Read = 0;int DataLen = s_buf.st_size;printf("datalen = %d, %s, %d\n", DataLen, __func__, __LINE__);unsigned char ucInBuff[ DataLen + 1 ];unsigned char ucOutBuff[ 2*DataLen + 1 ];memset( ucInBuff, 0, sizeof(ucInBuff) );memset( ucOutBuff, 0, sizeof(ucOutBuff) );Read = fread( ucInBuff, 1, DataLen, pInFile );printf("Read = %d, Ret = %d\n", Read, Ret);if (Read){Ret = G711a2PCM( (char *)ucInBuff, (char *)ucOutBuff, Read, 0 );//Ret = G711u2PCM( (char *)ucInBuff, (char *)ucOutBuff, Read, 0 );printf("Read = %d, Ret = %d, %s, %d\n", Read, Ret, __func__, __LINE__);fwrite( ucOutBuff, 1, Ret, pOutFile );memset( ucInBuff, 0, sizeof(ucInBuff) );memset( ucOutBuff, 0, sizeof(ucOutBuff) );}else{printf("fread error !\n");return -1;}fclose(pInFile);fclose(pOutFile);return 0;
}

encode.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "g711codec.h"int main(int argc, char *argv[])
{if(argc < 3){printf("==> Usage:\n\tencode [src.pcm] [dest.g711a]\n");    //printf("==> Usage:\n\tencode [src.pcm] [dest.g711u]\n");   return 0;}FILE *pInFile = fopen(argv[1], "rb");FILE *pOutFile = fopen(argv[2], "wb");if (NULL == pInFile || NULL == pOutFile){printf("open file failed\n");return 0;}struct stat s_buf;int status = 0;status = stat( argv[1], &s_buf);    printf("file_size = %d\n", s_buf.st_size);int Ret = 0;int Read = 0;int Len = s_buf.st_size;printf("datalen = %d\n", s_buf.st_size);unsigned char ucInBuff[ Len +1 ];unsigned char ucOutBuff[ Len + 1 ];memset(ucInBuff, 0, sizeof(ucInBuff));memset(ucOutBuff, 0, sizeof(ucOutBuff));Read = fread(ucInBuff, 1, Len, pInFile);printf("Read = %d, Ret = %d\n", Read, Ret);if (Read){Ret = PCM2G711a( (char *)ucInBuff, (char *)ucOutBuff, Read, 0 );//Ret = PCM2G711u( (char *)ucInBuff, (char *)ucOutBuff, Read, 0 );printf("Read = %d, Ret = %d, %s, %d\n", Read, Ret, __func__, __LINE__);fwrite(ucOutBuff, 1, Ret, pOutFile);memset(ucInBuff, 0, sizeof(ucInBuff));memset(ucOutBuff, 0, sizeof(ucOutBuff));}else{printf("fread error !\n");return -1;}fclose(pInFile);fclose(pOutFile);return 0;
}

g711.c

#include <stdio.h>
#include "g711codec.h"/** function: convert PCM audio format to g711 alaw/ulaw.(zqj)*  InAudioData:   PCM data prepared for encoding to g711 alaw/ulaw.*   OutAudioData:  encoded g711 alaw/ulaw.*   DataLen:     PCM data size.*   reserve:      reserved param, no use.*//*alaw*/
int PCM2G711a( char *InAudioData, char *OutAudioData, int DataLen, int reserve )
{   //check params.if( (NULL == InAudioData) && (NULL == OutAudioData) && (0 == DataLen) ){printf("Error, empty data or transmit failed, exit !\n");    return -1;}printf("DataLen = %d, %s, %d\n", DataLen, __func__, __LINE__);int Retaen = 0; printf("G711a encode start......\n");Retaen = g711a_encode( (unsigned char *)OutAudioData, (short*)InAudioData, DataLen/2 );printf("Retaen = %d, %s, %d\n", Retaen, __func__, __LINE__);return Retaen; //index successfully encoded data len.
}/*ulaw*/
int PCM2G711u( char *InAudioData, char *OutAudioData, int DataLen, int reserve )
{   //check params.if( (NULL == InAudioData) && (NULL == OutAudioData) && (0 == DataLen) ){printf("Error, empty data or transmit failed, exit !\n");    return -1;}printf("DataLen = %d, %s, %d\n", DataLen, __func__, __LINE__);int Retuen = 0; printf("G711u encode start......\n");Retuen = g711u_encode( (unsigned char *)OutAudioData, (short*)InAudioData, DataLen/2 );printf("Retuen = %d, %s, %d\n", Retuen, __func__, __LINE__);return Retuen;
}/** function: convert g711 alaw audio format to PCM.(zqj)*  InAudioData:   g711 alaw data prepared for encoding to PCM.*   OutAudioData:   encoded PCM audio data.*   DataLen:     g711a data size.*   reserve:        reserved param, no use.*//*alaw*/
int G711a2PCM( char *InAudioData, char *OutAudioData, int DataLen, int reserve )
{//check param.if( (NULL == InAudioData) && (NULL == OutAudioData) && (0 == DataLen) ){printf("Error, empty data or transmit failed, exit !\n");    return -1;}printf("DataLen = %d, %s, %d\n", DataLen, __func__, __LINE__);int Retade = 0;printf("G711a decode start......\n");Retade = g711a_decode( (short*)OutAudioData, (unsigned char *)InAudioData, DataLen );printf("Retade = %d, %s, %d\n", Retade, __func__, __LINE__);return Retade;  //index successfully decoded data len.
}/*ulaw*/
int G711u2PCM( char *InAudioData, char *OutAudioData, int DataLen, int reserve )
{//check param.if( (NULL == InAudioData) && (NULL == OutAudioData) && (0 == DataLen) ){printf("Error, empty data or transmit failed, exit !\n");    return -1;}printf("DataLen = %d, %s, %d\n", DataLen, __func__, __LINE__);int Retude = 0;printf("G711u decode start......\n");Retude = g711u_decode( (short*)OutAudioData, (unsigned char *)InAudioData, DataLen );printf("Retude = %d, %s, %d\n", Retude, __func__, __LINE__);return Retude;
}

关于PCM音频和g711音频编码的转换。相关推荐

  1. 【Android RTMP】安卓直播推流总结 ( 直播服务器搭建 | NV21 图像采集 | H.264 视频编码 | PCM 音频采集 | AAC 音频编码 | RTMP 包封装推流 )

    文章目录 一. 安卓直播推流专栏博客总结 二. 相关资源介绍 三. GitHub 源码地址 四. 整体 Android 直播推流数据到服务器并观看直播演示过程 Android 直播推流流程 : 手机采 ...

  2. MP3、PCM、WAV等音频基础格式编码总结与代码分析

    MP3文件在生活中可以说非常熟悉了,几乎每天豆豆它本身是一种二进制文件,本篇文章就来看看它内部是如何编码的. 本项目用到的代码可以参考(其实核心的都在下边,最多不用移植了而已): https://gi ...

  3. RTP打包G711音频数据发送

    前面博客讲过G711编码,有两种G711A/G711U,主要在安防中应用,是一帧波形编码的音频数据,只是将PCM压缩一半数据量.一般G711,采样率8000,通道数1.所以G711中1B就是一个样本数 ...

  4. G711音频编码格式

      最近工作中遇到了G711a音频编码,之前只用到wav和pcm,特写此文对G711格式了解一番. 文章目录 采样和量化 G711简介 二进制文件格式 参考来源 采样和量化   首先需要明确的两个概念 ...

  5. ffmpeg实现g711音频和H264,H265封装mp4(整理,非原创)

    效果:实现G711和H264,H265存为mp4,录像文件VLC和暴风影音可播放 注:播放mp4音视频没问题,但使用mp4分析工具分析 Sample size有问题(待解决) 修改1: (资料来自:g ...

  6. EasyPlayer:安卓播放器Android MediaMuxer录像(支持G711音频)支持MP4、音视频同步

    Android平台的MediaMuxer是个非常好的录像库,它能将H.264视频+AAC音频存储成.mp4格式的文件,而且稳定性.同步效果都非常好.MediaMuxer在安卓版的EasyPlayer和 ...

  7. 利用ffmpeg提供的库(API)进行音频与视频的编码并生成文件

    Output example.c 目录 [隐藏] 1 概述 2 音频输出 2.1 add_audio_stream 2.2 open_audio 2.3 get_audio_frame 2.4 wri ...

  8. 音频之WAV格式编码解析

    学习目标: 音频之WAV格式编码解析 学习内容: 介绍 WAV是最常见的声音文件格式之一,wav文件分为两个部分,第一个部分是wav头文件,第二个部分是PCM编码的音频数据部分.是微软公司专门为Win ...

  9. 【Audio音频开发】音频基础知识及PCM技术详解

    个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享高质量嵌入式文章,让大家读有所得! 文章目录 1.前言 2.概念 3. PCM介绍 4. PCM原理 5.PCM相关概念 5.1 ...

最新文章

  1. EEPW单片机C语言程序设计,基于CH340T的STC89C52RC编程器设计
  2. ROS 不能再详细的安装教程
  3. 5、Makefile基础知识汇总(转自陈皓总述)
  4. 使用Git 管理heroku的项目(windows)
  5. 基于pytorch开发CNN提取全连接层作为特征
  6. 函数指针,以及用函数指针的好用之处(回调函数)
  7. matlab仿真图片png,Simulink仿真入门到精通(六) Simulink模型保存为图片
  8. php smarty安装,【php】smarty安装
  9. 如何把很多照片拼成一张照片_一张现场照片引发的中韩之争
  10. Win7和Ubuntu14.10双系统
  11. vuex:弄懂mapState、mapGetters、mapMutations、mapActions
  12. 计算机一级2016版本ms,2016计算机等级一级《MS Office》试题与答案
  13. android 获取cpu型号_当贝投影带你认识投影仪CPU芯片有哪些?网友:真详细
  14. TX2017秋招笔试题之编码
  15. snr matlab,cal snr - MATLAB 论坛讨论区 - EETOP 创芯网论坛 (原名:电子顶级开发网) -...
  16. python中字符串(二)-访问值、更新、转义、运算
  17. Tomcat的部署+第一个Servlet
  18. Java同步组件之CyclicBarrier,ReentrantLock
  19. js Maximum call stack size exceeded
  20. Parts of a URL

热门文章

  1. 区块链知识系列 - 区块链大事记
  2. 行业大咖到访众美集团 共话众美定制广场十大价值点
  3. Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo
  4. Argo CD系列视频图文版之手把手教你搭建Argo CD 实验环境
  5. 2022 全球网络黑客常用攻击方法 Top10
  6. 通讯录怎么恢复?在 手机上检索找回已删除的电话号码的3种方式
  7. k8s dashboard安装
  8. java入门到秃路线导航,元芳你怎么看?【教学视频+博客+书籍整理】
  9. 某系统采用基于优先权的非抢占式进程调度策略,完成一次进程调度和进程切换的系统时间开销为 1μs。
  10. 怎么看虚拟机服务器ip,虚拟主机的ip怎么看 查看主机ip的方法