03 ffmpeg调用声卡录制wav文件

时间:2021-01-13 19:40:55
头文件:

#define __STDC_CONSTANT_MACROS
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
}

AVInputFormat类型表示一种输入文件/输入设备的数据格式
AVFormatContext类型表示音视频的格式内容
AVDictionary类型表示相关的配置项,如摄像头设备有图像大小的配置 
AVPacket类型用于装载一帧数据

1. av_register_all(); //注册能用的编解码器及文件格式

2. avdevice_register_all(); //注册能操作的输入输出设备


3. 准备参数
AVInputFormat *ifmt = av_find_input_format("alsa"); ///指定alsa接口的音频设备
AVFormatContext *fmtContxt = avformat_alloc_context();
AVDictionary *options = NULL;

av_dict_set(&options, "sample_rate", "44100", 0);
av_dict_set(&options, "channels", "1", 0);
    //声卡alsa接口可配置的选项,可参考ffmpeg源码/libavdevice/alsa_dec.c

4. 使用指定的参数, 打开指定的设备
if (avformat_open_input(&fmtContxt, "default", ifmt, &options) < 0)
{
perror("avformat open");
return 1;
}

5. 打开设备后, 可检查声音数据格式.
AVCodecID id = fmtContxt->streams[0]->codec->codec_id; //获取数据的格式ID
qDebug() << id << " " << avcodec_get_name(id);
// 显示是:pcm_s16le, 也就是pcm数据, 量化精度为小端16位



6. 准备一帧数据的空间,及读取数据:
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));

av_read_frame(fmtContxt, packet); //读取一帧数据
// packet->data指针指向声音数据缓冲区的首地址
// packet->size是当前帧数据的真实大小


7. 封装成一个wav文件. wav文件格式参考http://soundfile.sapp.org/doc/WaveFormat/
大概来说wav其实就一个文件头+pcm数据组成.
录制60秒的wav文件

WavHeader header(44100, 16, 1, 60);
FILE *fl = fopen("/my.wav", "w");
fwrite(&header, sizeof(header), 1, fl); // 写入文件头

int len = 44100*1*2*60; //60秒的数据长度
for (int n = 0; n < len;)
{
if (av_read_frame(fmtContxt, packet) < 0)
{
perror("read frame failed");
return 1;
}
qDebug() << packet->size;

n += packet->size;
fwrite(packet->data, packet->size, 1, fl); //写入pcm数据
}
fclose(fl);
附wav文件头的类型:
class WavHeader {
private:
unsigned char ChunkID[4]; // "RIFF"
unsigned int ChunkSize; // 36 + SubChunk2Size
unsigned char Format[4]; // "WAVE"

unsigned char Subchunk1ID[4]; // "fmt"
unsigned int Subchunk1Size; // 16 for pcm
unsigned short AudioFormat; // PCM=1
unsigned short NumChannels;
unsigned int SampleRate;
unsigned int ByteRate; // SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign; // NumChannels * BitsPerSample/8
unsigned short BitsPerSample; //8 bits = 8, 16 bits = 16

unsigned char Subchunk2ID[4]; // "data"
unsigned int Subchunk2Size; // NumSamples * NumChannels * BitsPerSample/8

public:
WavHeader (int rate, int bits, int channels, int sec)
{
strcpy((char *)ChunkID, "RIFF");
Subchunk2Size = (sec * rate * channels * bits)>>3;
ChunkSize = 36 + Subchunk2Size;
strcpy((char *)Format, "WAVE");

strcpy((char *)Subchunk1ID, "fmt ");
Subchunk1Size = 16;
AudioFormat = 1;
NumChannels = channels;
SampleRate = rate;
ByteRate = (rate * channels * bits)>>3;
BlockAlign = (channels * bits)>>3;
BitsPerSample = bits;

strcpy((char *)Subchunk2ID, "data");
Subchunk2Size = (sec * rate * channels * bits)>>3;
}
};

参考:
http://blog.csdn.net/leixiaohua1020