这几天在单位研究使用libspeex对原始音频文件(PCM文件)进行编解码。在linux下原始音频文件可以通过arecord命令进行采集,使用的采样率是8kHz,量化位数为有符号16位整数(小端存储),单通道模式。在linux下播放原始音频文件可以通过使用aplay命令进行播放,在播放的时候需要给出量化位数参数,因为aplay默认使用8位无符号数进行量化取样。
下面分别是编码和解码的源代码,注意linux编译环境需要有speex(speex运行库包)和speex_devel(speex开发包)。
声音录制和编码源代码:
/*
* =====================================================================================
*
* Filename: record_spx.c
*
* Description:
*
* Version: 1.0
* Created: 12/01/2011 12:49:48 PM
* Revision: none
* Compiler: gcc
*
* Author: YOUR NAME (),
* Company:
*
* =====================================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <speex/speex.h>
#define DEFAULT_RATE 8000
#define DEFAULT_RECORD_DURING 60
#define DEFAULT_ALSA_REC_FILE "/tmp/xk_rec.wav"
#define FRAME_SIZE 160
#define RECORD_CMD_LENGTH 128
#define DEBUG_ON 1
#if DEBUG_ON
#define DEBUG_FILE "/tmp/xk_recorder.log"
#define DEBUG_TOOL(flag, fmt...) \
do { \
if (flag) { \
FILE *fp; \
fp = fopen(DEBUG_FILE, "a"); \
fprintf(fp, "%s[%d]", __FILE__, __LINE__); \
fprintf(fp, fmt); \
fclose(fp); \
} \
} \
while(0)
#else
#define DEBUG_TOOL(flag, fmt...)
#endif
static int flag = 0;
void print_usage(void)
{
printf("usage: speex_recorder <speex file(.spx)>\n");
return;
}
int run_command(const char *cmd)
{
int retval;
retval = system(cmd);
if (retval == 127) {
DEBUG_TOOL(DEBUG_ON, "command not available\n");
} else if (retval == -1) {
DEBUG_TOOL(DEBUG_ON, "system() error.\n");
} else if (retval != 0) {
DEBUG_TOOL(DEBUG_ON, "command return %d\n", retval);
} else {
DEBUG_TOOL(DEBUG_ON, "system(\"%s\") successful.\n", cmd);
}
return retval;
}
int record_alsa(const char *wave_file)
{
char cmd[RECORD_CMD_LENGTH];
int child, status, wait_child;
memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd), "arecord -t raw -f S16_LE -c 1 -r %d -d %d %s 1>/dev/null 2>&1",DEFAULT_RATE, DEFAULT_RECORD_DURING, wave_file);
if ((child = fork()) < 0 ) {
DEBUG_TOOL(DEBUG_ON, "fork() error.\n");
return -1;
} else if (child == 0) {
run_command(cmd);
return 0;
} else {
while(1) {
if (flag) {
DEBUG_TOOL(DEBUG_ON, "pause arecord process\n");
system("killall arecord");
break;
}
usleep(1000);
wait_child = waitpid(child, &status, WNOHANG||WUNTRACED);
if (wait_child == child) {
DEBUG_TOOL(DEBUG_ON, "arecord completed\n");
break;
}
}
return 0;
}
}
int build_spx_from_wave(const char *wave_file, const char *spx_file)
{
#if 0
char cmd[RECORD_CMD_LENGTH];
int retval;
memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd), "speexenc --wideband --vbr --rate %d --le --16bit %s %s 1>/dev/null 2>&1", DEFAULT_RATE, wave_file, spx_file);
retval = run_command(cmd);
return retval;
#else
const char *inFile, *outFile;
FILE *fin, *fout;
short in[FRAME_SIZE];
short input[FRAME_SIZE];
char cbits[200];
int nbBytes;
/*Holds the state of the encoder*/
void *state;
/*Holds bits so they can be read and written to by the Speex routines*/
SpeexBits bits;
int i, tmp;
/*Create a new encoder state in narrowband mode*/
state = speex_encoder_init(&speex_nb_mode);
/*Set the quality to 8 (15 kbps)*/
tmp=8;
speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp);
inFile = wave_file;
outFile = spx_file;
fin = fopen(inFile, "r");
fout = fopen(outFile, "w");
/*Initialization of the structure that holds the bits*/
speex_bits_init(&bits);
while (1)
{
/*Read a 16 bits/sample audio frame*/
fread(in, sizeof(short), FRAME_SIZE, fin);
if (feof(fin))
break;
/*Copy the 16 bits values to float so Speex can work on them*/
for (i=0;i<FRAME_SIZE;i++)
input[i]=in[i];
/*Flush all the bits in the struct so we can encode a new frame*/
speex_bits_reset(&bits);
/*Encode the frame*/
speex_encode_int(state, input, &bits);
/*Copy the bits to an array of char that can be written*/
nbBytes = speex_bits_write(&bits, cbits, 200);
/*Write the size of the frame first. This is what sampledec expects but
it's likely to be different in your own application*/
fwrite(&nbBytes, sizeof(int), 1, fout);
/*Write the compressed data*/
fwrite(cbits, 1, nbBytes, fout);
}
/*Destroy the encoder state*/
speex_encoder_destroy(state);
/*Destroy the bit-packing struct*/
speex_bits_destroy(&bits);
fclose(fin);
fclose(fout);
return 0;
#endif
}
int record_spx(const char *spx_file)
{
int retval;
retval = record_alsa(DEFAULT_ALSA_REC_FILE);
if (retval == 127 || retval < 0) {
DEBUG_TOOL(DEBUG_ON, "record_alsa() error.\n");
return -1;
}
retval = build_spx_from_wave(DEFAULT_ALSA_REC_FILE, spx_file);
if (retval == 127 || retval < 0) {
DEBUG_TOOL(DEBUG_ON, "build_spx_from_wave() error.\n");
return -2;
}
unlink(DEFAULT_ALSA_REC_FILE);
return 0;
}
void pause_record(int signal)
{
flag = 1;
return;
}
int main(int argc, char **argv)
{
int retval;
const char *speex_file;
if (argc != 2) {
print_usage();
return -1;
}
speex_file = argv[1];
signal(SIGTERM, pause_record);
retval = record_spx(speex_file);
return retval;
}
来源:oschina
链接:https://my.oschina.net/u/206258/blog/36751