ffmpeg学习九:音频编码前奏-ubuntu下录音和播放
来源:互联网 发布:潍坊行知中学李嘉辉 编辑:程序博客网 时间:2024/06/02 00:41
上一篇博客,我们把一个Yuv编码格式的视频文件编码为H264格式。那么接下来,自然要学习下音频编码了。在学习音频编码之前,我们先看看ubuntu下如何采集声音和播放声音。
录音
录制5秒钟的一段音频。
audio_recorder.c:
/*created by Jinwei Liu*/#define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> int main(int argc,char **argv) { long loops; 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; FILE * fd_out; if(argc!=2){ printf("usage:./a.out outfile\n"); } /* Open PCM device for recording (capture). */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); /* 11025 bits/second sampling rate (CD quality) */ val = 11025; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ //frames = 32; // snd_pcm_hw_params_set_period_size_near(handle, // params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * 4; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); loops = 5000000 / val; fd_out = fopen(argv[1],"w+"); while (loops > 0) { loops--; rc = snd_pcm_readi(handle, buffer, frames); if (rc == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short read, read %d frames\n", rc); } rc = fwrite(buffer,1, size,fd_out); if (rc != size) fprintf(stderr, "short write: wrote %d bytes\n", rc); } fclose(fd_out); snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); return 0; }
函数中已经有相关的注释了。录音可以认为有三部分组成:
第一:参数设置阶段。这一阶段需要设置波特率,帧率,通道数等。
第二:采集阶段。主要就是调用snd_pcm_readi都声音数据。
第三:保存阶段。把都出来的数据写入文件即可。
编译:
gcc -o recorder audio_recorder.c -lasound
运行:
./recorder audio.pcm
执行完成后生成audio.pcm文件。
播放原始音频数据
直接播放原始音频文件(注意,录制的参数和播放的参数要一致)
audio_palyer.c
/*created by Jinwei Liu*//* Use the newer ALSA API */ #define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> int main(int argc,char **argv) { long loops; 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; int fd; /* Open PCM device for playback. */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } else{ printf("open device sucess\n"); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); /* 11025 bits/second sampling rate (CD quality) */ val = 11025; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ // frames = 32; // snd_pcm_hw_params_set_period_size_near(handle, // params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); printf("frames = %ld\n",frames); size = frames * 4; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); fd = open(argv[1],O_RDONLY); if(fd<0){ printf("open error\n"); } while (1) { rc = read(fd, buffer, size); if (rc == 0) { fprintf(stderr, "end of file on input\n"); break; } else if (rc != size) { fprintf(stderr, "short read: read %d bytes\n", rc); } while((rc = snd_pcm_writei(handle, buffer, frames)<0)) { usleep(2000); if (rc == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); } } } close(fd); snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); return 0; }
函数中已经有相关的注释了。播放原始音频数据可以认为有三部分组成:
第一:参数设置阶段。这一阶段需要设置波特率,帧率,通道数等。
第二:读文件阶段。
第三:播放阶段。主要是snd_pcm_writei想pcm设备写入数据了。
编译:
gcc -o player audio_palyer.c -lasound
运行:
./player audio.pcm
播放的就是我们自己录制的音频数据,可以验证我们的录音程序是否正常。
播放wav格式的音频文件
这里要注意:wav是文件的格式,pcm是没有压缩的音频的编码格式。也就是说,一个是文件封装格式,一个是视频的编码格式,两个是有本质的区别的。在我们的例子中,wav文件的数据区,存储的正式pcm编码格式的音频数据。
头文件:palywav.h
#ifndef PLAY_WAV_H#define PLAY_WAV_H#include<stdio.h>#include<stdlib.h>#include <string.h>#include "alsa/asoundlib.h"struct WAV_HEADER{ char rld[4]; //riff 标志符号 int rLen; char wld[4]; //格式类型(wave) char fld[4]; //"fmt" int fLen; //sizeof(wave format matex) short wFormatTag; //编码格式 short wChannels; //声道数 int nSamplesPersec ; //采样频率 int nAvgBitsPerSample;//WAVE文件采样大小 short wBlockAlign; //块对齐 short wBitsPerSample; //WAVE文件采样大小 char dld[4]; //”data“ int wSampleLength; //音频数据的大小} ;int set_pcm_play(char * filename);#endif
源文件:playwav.c
#include "play_wav.h"int set_pcm_play(char * filename){ int rc; int ret; int size; snd_pcm_t* handle; //pcm文件句柄 snd_pcm_hw_params_t* params;//硬件参数结构体 unsigned int val; int dir=0; snd_pcm_uframes_t frames; struct WAV_HEADER wav_header; char *buffer; int channels; int frequency; int bit; int datablock; int nread; //unsigned char ch[100]; FILE *fp; //首先打开wav文件 fp=fopen(filename,"rb"); if(fp==NULL) { perror("open file failed:\n"); exit(1); } //读取头部信息 nread=fread(&wav_header,1,sizeof(wav_header),fp); printf("fread byte is:%d\n",nread); //通过读取到的头部信息,初始化硬件参数 channels=wav_header.wChannels; frequency=wav_header.nSamplesPersec; bit=wav_header.wBitsPerSample; datablock=wav_header.wBlockAlign; //打开pcm设备 rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if(rc<0) { perror("\nopen PCM device failed:"); exit(1); } //分配一个硬件参数结构体 snd_pcm_hw_params_alloca(¶ms); if(rc<0) { perror("\nsnd_pcm_hw_params_alloca:"); exit(1); } //使用默认值初始化 rc=snd_pcm_hw_params_any(handle, params); if(rc<0) { perror("\nsnd_pcm_hw_params_any:"); exit(1); } rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //交错模式 if(rc<0) { perror("\nsed_pcm_hw_set_access:"); exit(1); } //选择音频数据格式。 switch(bit/8) { case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8); break ; case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); break ; case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE); break ; } rc=snd_pcm_hw_params_set_channels(handle, params, channels); //设置通道数 if(rc<0) { perror("\nsnd_pcm_hw_params_set_channels:"); exit(1); } val = frequency; rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); //设置比特率 if(rc<0) { perror("\nsnd_pcm_hw_params_set_rate_near:"); exit(1); } //设置硬件参数 rc = snd_pcm_hw_params(handle, params); if(rc<0) { perror("\nsnd_pcm_hw_params: "); exit(1); } //获取帧率 rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir); if(rc<0) { perror("\nsnd_pcm_hw_params_get_period_size:"); exit(1); } //通过帧率计算缓冲区的大小 size = frames * datablock; buffer =(char*)malloc(size); fseek(fp,58,SEEK_SET); //定位到数据区 //一下的循环就是不断的从数据区读数据出来,然后写入pcm设备中,从而播放出来 while (1) { memset(buffer,0,sizeof(buffer)); ret = fread(buffer, 1, size, fp); if(ret == 0) { printf("song write in completed\n"); break; } else if (ret != size) { } while((ret = snd_pcm_writei(handle, buffer, frames)<0)) { usleep(2000); if (ret == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } else if (ret < 0) { fprintf(stderr, "error from writei: %s\n", snd_strerror(ret)); } } } fclose(fp); snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); return 0;}int main(int argc,char **argv){ if(argc !=2){ printf("usage:./playwav xxx.wav"); return -1; } set_pcm_play(argv[1]);return 0;}
函数中已经有相关的注释了。播放wav可以认为有四部分组成:
第一:解析文件头。
第二:参数设置阶段。这一阶段需要通过解析文件头得到的信息,来设置波特率,帧率,通道数等。
第二:读音频数据阶段。
第三:播放阶段。主要是snd_pcm_writei想pcm设备写入数据了。
编译:
gcc play_wav.c -lasound
执行:
./a.out song.wav
- ffmpeg学习九:音频编码前奏-ubuntu下录音和播放
- FFmpeg学习3:播放音频
- FFmpeg学习3:播放音频
- 简介录音和播放音频实现
- Android音频操作:录音和播放
- 录音,播放音频
- 录音/播放音频
- 音频播放\录音
- ubuntu下音频播放器
- FFmpeg学习5:多线程播放视音频
- 【iOS沉思录】:iOS多媒体音频(下)-录音及其播放
- ffmpeg--音频的解码和编码
- AVAudioRecord录音,AVAudioPlayer播放音频
- Android 音频 录音与播放
- ffmpeg播放视频音频
- FFmpeg:播放音频
- ffmpeg播放音频
- 四、FFMPEG播放音频
- Caffe学习系列(4):激活层(Activiation Layers)及参数
- 2016中国电信产业峰会,卓易科技再获大奖
- tableview的plain与group区别
- Android Context完全解析,你所不知道的Context的各种细节
- ts码流结构语法学习总结
- ffmpeg学习九:音频编码前奏-ubuntu下录音和播放
- 2017 年该学习的编程语言、框架和工具
- 扫码登陆 之我见
- java日常笔记2016-12-16
- EditText中输入信息的限制的方法
- RxJava学习笔记(三)自定义操作符
- Android内存优化---使用SparseArray和ArrayMap
- ngResource模块的服务
- could not read data from 'Configurat'/Info.plist': The file “plist” couldn’t be opened because there