最近一周做一个ADPCM算法的调研工作,以前是做电视智能浏览器,所以对这个东西不了解,虽然给我了算法的接口,

使用intel的adpcm_coder/adpcm_decoder进行压缩和解压,参数也能看懂,但是还是不知道参数该如何传进去。

在网上查阅资料,大部分都是讲ADPCM算法的,还有讲把文件分离,以及给文件添加WAVE头的,跟我的需求还是很有出入。

我这边是一个PCM文件的裸流,里面没有文件头, 压缩、 解压,然后使用cooledit播放看看解压后的音频与原始音频是否有

差异。

ADPCM的原理,网上很多,我这里也不赘述, 代码里面要区分8位、16位单声道、16位双声道。

今天我写的代码是16位双声道。 在这里需要注意的是传进去和输出来的char的比例, 因为压缩的比例是1:4,所以我这里定义了一个FRAME_SIZE, 那些乘以4,除以2,千万不能少,不然就会出现问题。

使用cooledit播放音频流的时候,会有选择单声道还是双声道,以及选择多少bit,本程序要选择44100hz,双声道,16bit。

(关于cooledit的使用自己研究下,我也是刚研究一两天)

下面就上程序了(头文件路径自己修改吧,只需要把下面的代码复制粘贴,编译的时候带上adpcm.c文件即可):

1. 压缩PCM裸流,并且解压后把流再保存起来。(PCM裸流使用cooledit是可以播放的, 解压后的也是可以播放的,不然就是有问题)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "adpcm/adpcm.h"

static struct adpcm_state en_state_L,en_state_R,de_state_L,de_state_R;

#define FRAME_SIZE (1600)

// for encode, which includes left channel and right channel.
unsigned char inbuf[FRAME_SIZE*4];
short inencL[FRAME_SIZE];
short inencR[FRAME_SIZE];
unsigned char encbufL[FRAME_SIZE/2];
unsigned char encbufR[FRAME_SIZE/2];

// for decode
short decbufL[FRAME_SIZE];
short decbufR[FRAME_SIZE];
unsigned char outbufL[FRAME_SIZE*4];
unsigned char outbufR[FRAME_SIZE*4];

int main(int argc, char *argv[])
{
FILE *f, *f2;
char fname[64],fname2[64];

if (argc < 3 )
{
exit(-1);
}
strcpy(fname, argv[1]);
strcpy(fname2, argv[2]);

if (NULL == (f2=fopen(fname2,"wb")) )
{
exit(-1);
}
if (NULL == (f=fopen(fname,"rb")) )
{
exit(-1);
}
en_state_L.valprev = 0;
en_state_L.index = 0;
en_state_R.valprev = 0;
en_state_R.index = 0;
de_state_L.valprev = 0;
de_state_L.index = 0;
while(fread(inbuf, sizeof(unsigned char), sizeof(inbuf), f))
{
for(int i = 0; i < FRAME_SIZE * 4; i += 4)
{
//inencL[i/4] = inbuf[i] | (inbuf[i+1] << 8);
inencL[i/4] = inbuf[i] + inbuf[i+1] * 256;
inencR[i/4] = inbuf[i+2] + inbuf[i+2+1] * 256;
}
// encoder left channel and right channel
adpcm_coder(inencL, encbufL, FRAME_SIZE, &en_state_L);

adpcm_coder(inencR, encbufR, FRAME_SIZE, &en_state_R);

// decoder left channel and right channel

adpcm_decoder(encbufL, decbufL, FRAME_SIZE, &de_state_L);
adpcm_decoder(encbufR, decbufR, FRAME_SIZE, &de_state_R);

for(int i=0;i < FRAME_SIZE;i++){ 
outbufL[i*4] = decbufL[i] & 0xff; 
outbufL[i*4+1] = decbufL[i] >> 8; 
outbufL[i*4+2] = decbufR[i] & 0xff; 
outbufL[i*4+3] = decbufR[i] >> 8; 
}
fwrite(outbufL, sizeof(unsigned char), sizeof(outbufL), f2);
}
fclose(f);
fclose(f2);

return 0;
}

----------------------------------------

再说下, 左右声道一定要分离出来, 因为ADPCM算法就是根据前一个点预测下一个点, 如果左右声道不分离,那么就会右声道前一个点是左声道的,有可能左右声道波形图一样,那么问题不明显,但理论上,按我的理解需要分离出来。

以及存储的时候是左声道/右声道/左声道/右声道这样交叉的, 所以需要注意的是压缩和解压后保存文件的话,区分双声道。

单声道就无所谓了,没有左右之分。

2. adpcm_coder的调用(这个程序实现了PCM裸流的压缩,也就是编码的功能,会把压缩后的PCM流保存到文件)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "adpcm/adpcm.h"

static struct adpcm_state en_state_L,en_state_R,de_state_L,de_state_R;

#define FRAME_SIZE (1600)

// for encode, which includes left channel and right channel.
unsigned char inbuf[FRAME_SIZE*4];
short inencL[FRAME_SIZE];
short inencR[FRAME_SIZE];
unsigned char encbufL[FRAME_SIZE/2];
unsigned char encbufR[FRAME_SIZE/2];

int main(int argc, char *argv[])
{
FILE *f, *f2;
char fname[64],fname2[64];

if (argc < 3 )
{
exit(-1);
}
strcpy(fname, argv[1]);
strcpy(fname2, argv[2]);

if (NULL == (f2=fopen(fname2,"wb")) )
{
exit(-1);
}
if (NULL == (f=fopen(fname,"rb")) )
{
exit(-1);
}
en_state_L.valprev = 0;
en_state_L.index = 0;
en_state_R.valprev = 0;
en_state_R.index = 0;
while(fread(inbuf, sizeof(unsigned char), sizeof(inbuf), f))
{
for(int i = 0; i < FRAME_SIZE * 4; i += 4)
{
//inencL[i/4] = inbuf[i] | (inbuf[i+1] << 8);
inencL[i/4] = inbuf[i] + inbuf[i+1] * 256;
inencR[i/4] = inbuf[i+2] + inbuf[i+2+1] * 256;
}
printf("code\n");
adpcm_coder(inencL, encbufL, FRAME_SIZE, &en_state_L);
adpcm_coder(inencR, encbufR, FRAME_SIZE, &en_state_R);
for(int i=0;i < FRAME_SIZE/2;i++){ 
fwrite(&encbufL[i], sizeof(unsigned char), 1, f2);
fwrite(&encbufR[i], sizeof(unsigned char), 1, f2);
}
}
fclose(f);
fclose(f2);
return 0;

}

3. adpcm_decoder的调用(这个程序实现了PCM裸流的压缩后再解压,也就是解码的功能,会把解压出来的PCM流保存到文件)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "adpcm/adpcm.h"

static struct adpcm_state en_state_L,en_state_R,de_state_L,de_state_R;

#define FRAME_SIZE (1600)

// for encode, which includes left channel and right channel.
unsigned char inbuf[FRAME_SIZE];
short inencL[FRAME_SIZE/2];
short inencR[FRAME_SIZE/2];
unsigned char encbufL[FRAME_SIZE/2];
unsigned char encbufR[FRAME_SIZE/2];

// for decode
short decbufL[FRAME_SIZE];
short decbufR[FRAME_SIZE];
unsigned char outbufL[FRAME_SIZE*4];
unsigned char outbufR[FRAME_SIZE*4];

int main(int argc, char *argv[])
{
FILE *f, *f2;
char fname[64],fname2[64];

if (argc < 3 )
{
exit(-1);
}
strcpy(fname, argv[1]);
strcpy(fname2, argv[2]);

if (NULL == (f2=fopen(fname2,"wb")) )
{
exit(-1);
}
if (NULL == (f=fopen(fname,"rb")) )
{
exit(-1);
}
en_state_L.valprev = 0;
en_state_L.index = 0;
en_state_R.valprev = 0;
en_state_R.index = 0;
de_state_L.valprev = 0;
de_state_L.index = 0;
while(fread(inbuf, sizeof(unsigned char), sizeof(inbuf), f))
{
for(int i = 0; i < FRAME_SIZE; i += 2)
{
//inencL[i/4] = inbuf[i] | (inbuf[i+1] << 8);
encbufL[i/2] = inbuf[i];
encbufR[i/2] = inbuf[i+1];
}
printf("decode\n");
adpcm_decoder(encbufL, decbufL, FRAME_SIZE, &de_state_L);
adpcm_decoder(encbufR, decbufR, FRAME_SIZE, &de_state_R);

for(int i=0;i < FRAME_SIZE;i++){ 
outbufL[i*4] = decbufL[i] & 0xff; 
outbufL[i*4+1] = decbufL[i] >> 8; 
outbufL[i*4+2] = decbufR[i] & 0xff; 
outbufL[i*4+3] = decbufR[i] >> 8; 
}
fwrite(outbufL, sizeof(unsigned char), sizeof(outbufL), f2);
}
fclose(f);
fclose(f2);

return 0;

}

PCM裸流ADPCM算法压缩(调用adpcm_coder/adpcm_decoer接口)相关推荐

  1. C++ 採集音频流(PCM裸流)实现录音功能

    与上一篇的"C++ 播放音频流(PCM裸流)" 点击打开链接 相相应,本篇是关于用C++实现录音功能的.相同是直接建一个win32控制台程序然后将代码拷过去改个文件名称就能够用,也 ...

  2. PCM裸流数据的16进制格式以及左右声道分离c语言程序

    前言 本文讲解PCM裸流数据的存储格式. 本文PCM音频参数 声道数: 2采样位数: little endian signed 16 bits,小端有符号字 = short,表示范围 -32768~3 ...

  3. C++ 播放音频流(PCM裸流)

    直接上代码.假设有须要能够直接建一个win32控制台程序然后将代码拷过去改个文件名称就能够用了(注意将声道和频率与你自己的文件相应).当然我自己也用VS2008写了个样例上传了,假设有须要下载地址例如 ...

  4. FFmpeg系列(二)—— 音视频裸流转换:mp3转pcm、h264转YUV

    文章目录 1.总流程 2.解析流程 3.解码流程 4.完整代码 1.总流程 创建解析器.解码器.AVPacket和AVFrame 打开文件,将mp3数据读入缓冲区 解析mp3数据(在 main 函数中 ...

  5. python:lzma --- 用 LZMA 算法压缩

    python:lzma --- 用 LZMA 算法压缩 读写压缩文件 在内存中压缩和解压缩数据 杂项 指定自定义的过滤器链 例子 此模块提供了可以压缩和解压缩使用 LZMA 压缩算法的数据的类和便携函 ...

  6. FFmpeg解码H264裸流并转换成opencv Mat

    感谢雷霄骅博士的在中文视频编解码的付出,http://blog.csdn.net/leixiaohua1020 最近要搞一些视频推流的事情,要解析H264裸流并且获取opencv格式的Mat数据给算法 ...

  7. 网络流——最大流EK算法讲解

    网络流--最大流EK算法讲解 好了,这是第二篇博客了,如第一篇所述,来讲一讲刚刚理解的网络流.因为本人只会EK算法,所以先讲这个算法.(我会去补知识点的!!!) 什么是网络流??? 读者们刚接触这个知 ...

  8. Linux ALSA驱动之三:PCM创建流程源码分析(基于Linux 5.18)

    1.基本概念及逻辑关系 如上图,通过上一节声卡的学习我们已经知道PCM是声卡的一个子设备,或者表示一个PCM实例. 每个声卡最多可以包含4个pcm的实例,每个pcm实例对应一个pcm设备文件.pcm实 ...

  9. Android Socket 连接设备接收H264裸流数据并解码播放 Demo

    最近在做视频流相关的项目,发现 网上很少这方面的demo,很多都是长篇大论的理论知识,研究的太深,不利于小白快速 上手.所以我提炼了自己项目中这一块的内容,打包个小 demo ,只要 拿去稍作修改基本 ...

最新文章

  1. 04 集成学习 - Boosting - AdaBoost算法构建
  2. python中write的用法_Python中操作文件之write()方法的使用教程
  3. pass4side IBM 000-M15
  4. Java HashMap原理及内部存储结构
  5. 计算机动漫设计VR主要学什么,动漫设计专业学什么 要学什么软件
  6. 【10月17日】2020年十月蓝桥杯A组题目【感想与总结】(热乎的)
  7. centos7 配置虚拟交换机(物理交换机truckport设置)(使用brctl)
  8. Centos7 开启端口
  9. fabric canvas 清空并重置画布
  10. c 程序设计语言第1 3部分,《C程序设计语言(第2版新版)典藏版》 —1.3 for语句...
  11. 2020年最全Python常用爬虫代码就这些了(附爬虫教程)
  12. 快应用如何避免JSON.parse()解析出错
  13. 初学python100例-案例23 python输出菱形图案 青少年python编程 少儿编程案例讲解
  14. 最新:2021年7月全国程序员平均薪资出炉!你还坐得住吗?
  15. 港股相关交易规则与业务知识
  16. ubuntu里解决Firefox登陆12306问题
  17. java程序 jnlp,使用JNLP文件启动应用程序
  18. Matlab蒙特卡罗模拟
  19. ElasticSearch之 ik分词器详解
  20. 拼接模型坐标系的理解(五)

热门文章

  1. python 三菱plc读写_小说python操作PLC
  2. 利用武稀松版HtmlParser解析Html,使用CSS选择器定位节点
  3. vue中路由实现的原理?
  4. 跟沐风晓月一起玩转数据库之MySQL数据库表操作技巧与实用方法解析
  5. elementUI——表格单元格合并——技能提升
  6. 6.DesignForPlacement\3.AutoPlacementAll
  7. 装饰企业论江湖:十二大门派风起云涌,你是哪一派?
  8. radioml2018数据集_7 Papers Radios | CVPR 2020获奖论文;知识蒸馏综述
  9. 何为Access token
  10. lisp点坐标x轴可以乘除吗_cad建筑图上下水符号怎么表示