1.linux下使用alsa录音成pcm文件再使用lame转码为MP3
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#include <signal.h>
#include <lame/lame.h>
/*PCM文件转码成mp3文件*/
void ConvertPCM2MP3WithPath(const char *inputPath, const char *outputPath)
{
size_t readSize, writeSize;
/*打开pcm文件以及mp3文件*/
FILE *pcmFile = fopen(inputPath, "rb");
if (!pcmFile)
{
fprintf(stderr, "could not open %s\n", inputPath);
return;
}
FILE *mp3File = fopen(outputPath, "wb");
if (!mp3File)
{
fprintf(stderr, "could not open %s\n", outputPath);
return;
}
const int PCM_BUFF_SIZE = 8192;
const int MP3_BUFF_SIZE = 8192;
short int pcm_buffer[PCM_BUFF_SIZE * 2];
unsigned char mp3_buffer[MP3_BUFF_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do
{
readSize = fread(pcm_buffer, 2 * sizeof(short int), PCM_BUFF_SIZE, pcmFile);
printf("MP3::::::::::::: readSize: %ld \n", readSize);
if (readSize == 0)
{
writeSize = lame_encode_flush(lame, mp3_buffer, MP3_BUFF_SIZE);
}
else
{
writeSize = lame_encode_buffer_interleaved(lame, pcm_buffer, (int)readSize, mp3_buffer, MP3_BUFF_SIZE);
}
fwrite(mp3_buffer, writeSize, 1, mp3File);
} while (readSize != 0);
lame_close(lame);
fclose(mp3File);
fclose(pcmFile);
}
static int recording;
/*CTL+C 取消录音*/
void stop_recording(int param)
{
recording = 0;
}
/*开始录音*/
int StartRecode(const char *PcmFile)
{
FILE *pFile;
pFile = fopen(PcmFile, "wb");
if (pFile == NULL)
{
printf("open Pcmdfile err!\n");
return -1;
}
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/*打开PCM capture捕捉设备*/
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0)
{
printf("can't open pcm devecie\n");
exit(1);
}
/*分配一个硬件参数结构体*/
snd_pcm_hw_params_alloca(¶ms);
/*使用默认参数*/
snd_pcm_hw_params_any(handle, params);
/*Interleaved mode*/
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/*设置16小端采样精度*/
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/*双通道*/
snd_pcm_hw_params_set_channels(handle, params, 2);
/*采样率44100 CD级别音质*/
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/*一个周期32帧*/
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/*参数生效*/
rc = snd_pcm_hw_params(handle, params);
if (rc < 0)
{
printf("can't set hw params\n");
exit(0);
}
/*得到一个周期的数据大小*/
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
/* 16位采样精度 所以要*4*/
size = frames * 4;
buffer = (char *)malloc(size);
if (buffer == NULL)
{
printf("malloc buffer size err!\n");
return -2;
}
recording = 1;
while (recording)
{
/*捕捉数据*/
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
printf("over run occured\n");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
printf("err from read!\n");
}
else if (rc != (int)frames)
{
printf("short read frames\n");
}
rc = fwrite(buffer, sizeof(char), size, pFile);
if (rc != size)
{
printf("short write %d bytes\n", rc);
}
if (signal(SIGINT, stop_recording) == SIG_ERR)
{
printf("signal failed\n");
}
}
/*关闭文件句柄*/
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
fclose(pFile);
}
int main(int argc, char *argv[])
{
StartRecode("test.pcm");
ConvertPCM2MP3WithPath("test.pcm", "Goal.mp3");
const char *cmd = "rm -f test.pcm";
system(cmd);
return 0;
}
编译成可执行文件
gcc RecodePcm2Mp3.c -lasound -lmp3lame
2.linux下使用alsa收集音频流使用lame直接保存为MP3
代码1:
/*=============================================================================
# FileName: pcm_encoder_mp3.c
# Desc: use lame encode pcm data to mp3 format, the pcm data
# read from alsa
# Author: licaibiao
# LastChange: 2017-03-27
=============================================================================*/
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <lame/lame.h>
#define INBUFSIZE 128
#define MP3BUFSIZE (int) (1.25 * INBUFSIZE) + 7200
lame_global_flags *gfp;
short *input_buffer;
char *mp3_buffer;
char *outPath = "out.mp3";
FILE *infp;
FILE *outfp;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
snd_pcm_t *handle;
int size;
short *alsa_buffer;
void lame_init_set(void)
{
int ret_code;
gfp = lame_init();
if (gfp == NULL)
{
printf("lame_init failed/n");
}
ret_code = lame_init_params(gfp);
if (ret_code < 0)
{
printf("lame_init_params returned %d/n",ret_code);
}
outfp = fopen(outPath, "wb");
}
void lame_alloc_buffer(void)
{
input_buffer = (short*)malloc(INBUFSIZE*2);
mp3_buffer = (char*)malloc(MP3BUFSIZE);
}
void lame_release(void)
{
free(mp3_buffer);
free(input_buffer);
fclose(outfp);
lame_close(gfp);
}
void alsa_init(void){
unsigned int val;
int dir;
int ret;
ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (ret < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(ret));
exit(1);
}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
ret = snd_pcm_hw_params(handle, params);
if (ret < 0) {
fprintf(stderr,"unable to set hw parameters: %s\n", snd_strerror(ret));
exit(1);
}
}
void alsa_alloc_buffer(void){
int dir;
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 4;
alsa_buffer = (short *) malloc(size);
}
void alsa_release(void){
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(alsa_buffer);
}
void lame_encode(void)
{
int input_samples;
int mp3_bytes;
int status = 0;
int ret = 0;
int loop = 10000;
while(loop--){
ret = snd_pcm_readi(handle, alsa_buffer, frames);
if (ret == -EPIPE){
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}else if(ret == -EBADFD){
printf("PCM is not in the right state \n");
}
else if(ret == -ESTRPIPE){
printf("stream is suspended and waiting for an application recovery \n");
}
else if (ret < 0){
fprintf(stderr, "error from read: %s\n",snd_strerror(ret));
}
else if (ret != (int)frames){
fprintf(stderr, "short read, read %d frames\n", ret);
}
else if (ret == 0){
printf(" pcm read 0 frame deta \n ");
}
memcpy(input_buffer, alsa_buffer, size);
mp3_bytes = lame_encode_buffer_interleaved(gfp, input_buffer, size/4, mp3_buffer, MP3BUFSIZE);
if (mp3_bytes < 0)
{
printf("lame_encode_buffer_interleaved returned %d \n", mp3_bytes);
}
else if(mp3_bytes > 0)
{
fwrite(mp3_buffer, 1, mp3_bytes, outfp);
}
}
mp3_bytes = lame_encode_flush(gfp, mp3_buffer, sizeof(mp3_buffer));
if (mp3_bytes > 0)
{
printf("writing %d mp3 bytes\n", mp3_bytes);
fwrite(mp3_buffer, 1, mp3_bytes, outfp);
}
}
int main(int argc, char** argv)
{
lame_init_set();
lame_alloc_buffer();
alsa_init();
alsa_alloc_buffer();
lame_encode();
lame_release();
alsa_release();
}
代码2:
https://github.com/RichardoMrMu/alsa_lame_pcm_2_mp3?organization=RichardoMrMu&organization=RichardoMrMu