- 获取当前接入的声音设备,linux下的设别表示为“alsa”
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
extern"C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
}
int main() {
avdevice_register_all();
constAVInputFormat*input_format=av_find_input_format("alsa");
AVDeviceInfoList*device_list=NULL;
// Get the list of input sources
if (avdevice_list_input_sources(input_format, NULL, NULL, &device_list) >=0) {
// Iterate through the device list
for (inti=0; i<device_list->nb_devices; i++) {
AVDeviceInfo*device_info=device_list->devices[i];
printf("Device %d: %s%s\n", i, device_info->device_name, device_info->device_description);
}
// Free the device list
avdevice_free_list_devices(&device_list);
}
return0;
}
2. 读取麦克风音频数据并存为无损PCM文件
#include <stdio.h>
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h" //打开音频设备相关的头文件
#include "libavformat/avformat.h" //ffmpeg下的所有文件都是以格式来呈现的
void main(int argc, char **argv)
{
int ret = 0;
char errors[1024] = {0};
//context
AVFormatContext *fmt_ctx = NULL; //ffmpeg下的“文件描述符”
//paket
int count = 0;
AVPacket pkt;
//create file
char *out = "./audio_old.pcm";
FILE *outfile = fopen(out,"wb+");
char *devicename = "hw:1,0";
//register audio device
avdevice_register_all();
//get format
AVInputFormat *iformat = av_find_input_format("alsa");
//open audio
if( (ret = avformat_open_input(&fmt_ctx, devicename, iformat, NULL)) < 0)
{
av_strerror(ret, errors, 1024);
printf("Failed to open audio device, [%d]%s\n", ret, errors);
return;
};
av_init_packet(&pkt);
//read data form audio
while(ret = (av_read_frame(fmt_ctx, &pkt))== 0&&
count++ < 1000) {
av_log(NULL, AV_LOG_INFO, "pkt size is %d(%p), count=%d\n",
pkt.size,pkt.data, count);
fwrite(pkt.data, 1, pkt.size, outfile);
fflush(outfile);
av_packet_unref(&pkt);//release pkt
}
fclose(outfile);
avformat_close_input(&fmt_ctx);//releas ctx
return;
}
3. 将pcm数据编码成acc数据
#include <stdio.h>
#include <stdlib.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
// 只编码,不重采样
void audio_encode(const char *pcmfile, const char *aacfile) {
FILE *sfp = fopen(pcmfile, "r");
if (sfp == NULL) {
printf("fail to open pcmile\n");
goto _Error;
}
FILE *dfp = fopen(aacfile, "w+");
if (dfp == NULL) {
printf("failed to open aacfile\n");
goto _Error;
}
// 1. 初始化pcm_frame,保存每帧pcm数据
AVFrame *pcm_frame;
pcm_frame = av_frame_alloc();
pcm_frame->format = AV_SAMPLE_FMT_S16;
pcm_frame->channel_layout = AV_CH_LAYOUT_STEREO;
pcm_frame->sample_rate = 44100;
pcm_frame->channels = 2;
// nb_samples的值与具体的编码协议有关
pcm_frame->nb_samples = 1024; // 一帧中有多少个采样点
av_frame_get_buffer(pcm_frame, 0);
// 2. 找到合适的编码器
AVCodec *cod = avcodec_find_encoder_by_name("libfdk_aac");
if (cod == NULL) {
av_log(NULL, AV_LOG_ERROR, "fail to find codec\n");
goto _Error;
}
// 3. 设置其编码选项
AVCodecContext *cod_ctx = avcodec_alloc_context3(cod);
//cod_ctx->profile = FF_PROFILE_AAC_HE_V2; // 编码协议
cod_ctx->codec_type = AVMEDIA_TYPE_AUDIO; // 音频编码
cod_ctx->sample_fmt = pcm_frame->format;
cod_ctx->channel_layout = pcm_frame->channel_layout;
cod_ctx->channels = pcm_frame->channels;
cod_ctx->sample_rate = pcm_frame->sample_rate; // 采样率
// 4. 打开编码器
if (avcodec_open2(cod_ctx, cod, NULL) < 0) {
av_log(NULL, AV_LOG_ERROR, "fail to open codec\n");
goto _Error;
}
printf("frame_size:%d\n", cod_ctx->frame_size);
// 5. 初始化packet
int count = 0;
AVPacket *packet = av_packet_alloc();
int frame_size = pcm_frame->nb_samples * \
av_get_bytes_per_sample(pcm_frame->format) * pcm_frame->channels;
while (1) {
// AV_SAMPLE_FMT_S16是packed格式的, 声道数据LRLRLRLRLR...
// 所以pcm_frame->data[]是一维的
int ret = fread(pcm_frame->data[0], 1, frame_size, sfp);
if (ret < 0) {
printf("fail to read raw data\n");
goto _Error;
} else if (ret == 0) {
break;
}
pcm_frame->pts = count;
// 原始数据发送到编码器
if (avcodec_send_frame(cod_ctx, pcm_frame) < 0) {
printf("fail to send frame\n");
goto _Error;
}
// 获取编码数据
if (avcodec_receive_packet(cod_ctx, packet) >= 0) {
fwrite(packet->data, 1, packet->size, dfp);
count++;
av_packet_unref(packet);
printf("receive %d frame\n", count);
}
}
_Error:
if (sfp) {
fclose(sfp);
}
if (dfp) {
fclose(dfp);
}
if (cod_ctx) {
avcodec_close(cod_ctx);
avcodec_free_context(&cod_ctx);
}
if (pcm_frame) {
av_frame_free(&pcm_frame);
}
if (packet) {
av_packet_free(&packet);
}
}
int main(int argc, char const* argv[])
{
audio_encode("./test.pcm", "./output_test.aac");
return 0;
}
4. 读取麦克风音频数据并编码压缩成acc文件
#include <stdio.h>
#include <stdlib.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
// 只编码,不重采样
void audio_encode(const char *pcmfile, const char *aacfile, const char *originfile) {
FILE *pcmfp = fopen(pcmfile, "w+");
if (pcmfp == NULL) {
printf("failed to open pcmfile\n");
goto _Error;
}
FILE *dfp = fopen(aacfile, "w+");
if (dfp == NULL) {
printf("failed to open aacfile\n");
goto _Error;
}
FILE *originfp = fopen(originfile, "w+");
if (originfp == NULL) {
printf("failed to open pcmfile\n");
goto _Error;
}
// 1. 初始化pcm_frame,保存每帧pcm数据
AVFrame *pcm_frame;
pcm_frame = av_frame_alloc();
pcm_frame->format = AV_SAMPLE_FMT_S16;
pcm_frame->channel_layout = AV_CH_LAYOUT_STEREO;
pcm_frame->sample_rate = 44100;
pcm_frame->channels = 2;
// nb_samples的值与具体的编码协议有关
pcm_frame->nb_samples = 1024; // 一帧中有多少个采样点
av_frame_get_buffer(pcm_frame, 0);
// 2. 找到合适的编码器
AVCodec *cod = avcodec_find_encoder_by_name("libfdk_aac");
if (cod == NULL) {
av_log(NULL, AV_LOG_ERROR, "fail to find codec\n");
goto _Error;
}
// 3. 设置其编码选项
AVCodecContext *cod_ctx = avcodec_alloc_context3(cod);
//cod_ctx->profile = FF_PROFILE_AAC_HE_V2; // 编码协议
cod_ctx->codec_type = AVMEDIA_TYPE_AUDIO; // 音频编码
cod_ctx->sample_fmt = pcm_frame->format;
cod_ctx->channel_layout = pcm_frame->channel_layout;
cod_ctx->channels = pcm_frame->channels;
cod_ctx->sample_rate = pcm_frame->sample_rate; // 采样率
// 4. 打开编码器
if (avcodec_open2(cod_ctx, cod, NULL) < 0) {
av_log(NULL, AV_LOG_ERROR, "fail to open codec\n");
goto _Error;
}
printf("frame_size:%d\n", cod_ctx->frame_size);
// 5. 初始化packet
int count = 0;
AVPacket *packet = av_packet_alloc();
int frame_size = pcm_frame->nb_samples * \
av_get_bytes_per_sample(pcm_frame->format) * pcm_frame->channels;
// 6 注册设备
avdevice_register_all();
char *devicename = "hw:2,0";
// 获取输入(采集)格式
// AVInputFormat在FFmpeg中的作用是表示输入格式的数据结构,它包含了输入格式的相关信息,如名称、扩展名、MIME类型、解析函数
AVInputFormat * iformat = av_find_input_format("alsa"); //通过使用AVInputFormat,可以将特定格式的音视频文件读取到内存中,并对其进行解码、转码等操作
//打开输入设备
AVFormatContext* fmt_ctx=NULL; //AVFormatContext是FFmpeg中表示音视频格式的数据结构,它包含了音视频文件的所有信息,如文件名、流信息、时长、元数据
int ret = avformat_open_input(&fmt_ctx, devicename, iformat, NULL);
char errors[1024];
if(ret < 0){
av_strerror(ret, errors, 1024);
av_log(NULL,AV_LOG_ERROR,"Failed to open audio device,[%d]%s\n",ret,errors);
}
int buf_count = 0;
int count_in = 0;
AVPacket in_pkt;
int pcm_buffer_size = 4096;
while (count_in++ < 5000) {
// AV_SAMPLE_FMT_S16是packed格式的, 声道数据LRLRLRLRLR...
// 所以pcm_frame->data[]是一维的
//ret = fread(pcm_frame->data[0], 1, frame_size, sfp);
ret = av_read_frame(fmt_ctx, &in_pkt);
if (buf_count < pcm_buffer_size){
printf("[%d][%d][%d]\n", pcm_buffer_size, count_in, in_pkt.size);
memcpy(pcm_frame->data[0] + buf_count, in_pkt.data, in_pkt.size);
fwrite(in_pkt.data, 1, in_pkt.size, originfp);
buf_count += in_pkt.size;
continue;
}
if (buf_count == pcm_buffer_size){
buf_count = 0;
}
fwrite(pcm_frame->data[0], 1, pcm_buffer_size, pcmfp);
if (ret < 0) {
printf("fail to read raw data\n");
goto _Error;
}
// else if (ret == 0) {
// printf("ret == 0\n");
// break;
// }
pcm_frame->pts = count;
// 原始数据发送到编码器
if (avcodec_send_frame(cod_ctx, pcm_frame) < 0) {
printf("fail to send frame\n");
goto _Error;
}
// 获取编码数据
if (avcodec_receive_packet(cod_ctx, packet) >= 0) {
fwrite(packet->data, 1, packet->size, dfp);
count++;
av_packet_unref(packet);
printf("receive %d frame\n", count);
}
av_packet_unref(&in_pkt);//release pkt
}
_Error:
fflush(pcmfp);
if (pcmfp){
fclose(pcmfp);
}
fflush(originfp);
if (originfp){
fclose(originfp);
}
if (dfp) {
fclose(dfp);
}
if (cod_ctx) {
avcodec_close(cod_ctx);
avcodec_free_context(&cod_ctx);
}
if (pcm_frame) {
av_frame_free(&pcm_frame);
}
if (packet) {
av_packet_free(&packet);
}
}
int main(int argc, char const* argv[])
{
audio_encode("./encode_acc.pcm", "./encode_aac.aac", "origin.pcm");
return 0;
}