#include <iostream>
extern "C"{
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/audio_fifo.h>
#include <libavutil/time.h>
#include <stdio.h>
}
using namespace std;
static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
uint64_t channel_layout,
int chnls,
int sample_rate,
int nb_samples)
{
AVFrame *frame = av_frame_alloc();
int ret;
if (!frame){
fprintf(stderr, "error allocating an audio frame
");
exit(1);
}
frame->format = sample_fmt;
// 声道
frame->channel_layout = channel_layout;
// 有几个声道
frame->channels = chnls;
// 采样率
frame->sample_rate = sample_rate;
// 可以装多少个数据
frame->nb_samples = nb_samples;
if(nb_samples){
ret = av_frame_get_buffer(frame, 1);
if (ret < 0){
fprintf(stderr, "error allocating an audio frame
");
exit(1);
}
}
return frame;
}
// 声音的采集
static int test2(){
// 创建一个文件管理器
AVFormatContext *formatCtx = avformat_alloc_context();
AVInputFormat *ifmt = av_find_input_format("avfoundation");
// 配置流的参数
AVDictionary *options = NULL;
// av_dict_set(&options, "video_size". "1920*1080",0);
// av_dict_set(&options, "framerate", "15", 0);
// 打开桌面流
if (avformat_open_input(&formatCtx, "2", ifmt, &options) != 0){
printf("open input device fail
");
return -1;
}
// 查找设个设备里面的媒体信息
if (avformat_find_stream_info(formatCtx, NULL)<0)
{
printf("找不到媒体流信息!
");
return -1;
}
if(formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
{
printf("流信息格式错误!");
}
// 找到解码器
AVCodec *codec = avcodec_find_decoder(formatCtx->streams[0]->codecpar->codec_id);
if (codec ==NULL){
printf("codec not found.
");
return -1;
}
AVCodecContext *ctx = avcodec_alloc_context3(codec);
// 进行解码
avcodec_parameters_to_context(ctx, formatCtx->streams[0]->codecpar);
if (avcodec_open2(ctx, codec, NULL)<0){
printf("不能打开解码器");
return -1;
}
// 初始化声音
AVFrame *frame = alloc_audio_frame(
(AVSampleFormat)formatCtx->streams[0]->codecpar->format,
formatCtx->streams[0]->codecpar->channel_layout,
formatCtx->streams[0]->codecpar->channels,
formatCtx->streams[0]->codecpar->sample_rate,
formatCtx->streams[0]->codecpar->frame_size
);
// 开始对声音部分算法优化
SwrContext *swr = swr_alloc();
av_opt_set_int(swr, "in_channel_count", ctx->channels, 0);
av_opt_set_int(swr, "in_channel_layout", ctx->channel_layout, 0);
av_opt_set_int(swr, "in_sample_rate", ctx->sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", ctx->sample_fmt, 0);
int des_channe_layout=3;
int des_channel_count=2;
int des_sample_rate=44100;
AVSampleFormat des_sample_fmt = AV_SAMPLE_FMT_S16;
av_opt_set_int(swr, "out_channel_layout", des_channe_layout, 0);
av_opt_set_int(swr, "out_channel_count", des_channel_count, 0);
av_opt_set_int(swr, "out_sample_rate", des_sample_fmt, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", (AVSampleFormat)des_sample_fmt, 0);
swr_init(swr);
printf("声道:%d, 采样率:%d, 数据格式为:%d -----> 声道:%d, 采样率:%d, 数据格式为:%d",
ctx->channels, ctx->sample_rate, ctx->sample_fmt,
des_channel_count, des_sample_rate, des_sample_fmt);
int DES_NB_SAMPLES = 1024;
AVFrame *outFrame = alloc_audio_frame(des_sample_fmt, des_channe_layout,
des_channel_count,des_sample_rate, DES_NB_SAMPLES);
AVFrame *newFrame = alloc_audio_frame(des_sample_fmt, des_channe_layout,des_channel_count,
des_sample_rate, 0);
AVFrame *newFrame2 = alloc_audio_frame(des_sample_fmt, des_channe_layout,des_channel_count,
des_sample_rate, 0);
AVAudioFifo *fifo = av_audio_fifo_alloc(des_sample_fmt, des_channel_count, 10240);
FILE *file=NULL;
// fopen_s(&file, "out.pcm", 'wb');
file = fopen("/Users/fandx/Desktop/out.pcm", "wb");
int framecout = 100;
while (framecout--){
int size = av_audio_fifo_size(fifo);
if(size >= DES_NB_SAMPLES){
size = DES_NB_SAMPLES;
av_audio_fifo_read(fifo, (void**)outFrame, size);
fwrite(outFrame->data[0], size, des_channel_count*av_get_bytes_per_sample(des_sample_fmt),file);
// 这里也是完整的数据
// fwrite(outFrame->data[0], av_get_bytes_per_sample(des_sample_fmt)*des_channel_count,
// size, file)
continue;
}
AVPacket packet = {0};
av_init_packet(&packet);
if(av_read_frame(formatCtx, &packet) >= 0){
// 发送包到解码器
avcodec_send_packet(ctx, &packet);
if (avcodec_receive_frame(ctx, frame)<0)
{
printf("Decode Error
");
} else{
printf("采集到音频
");
swr_convert_frame(swr, newFrame, frame);
av_audio_fifo_write(fifo, (void**)newFrame->data, newFrame->nb_samples);
int64_t dealy = swr_get_delay(swr, des_sample_rate);
if (dealy >0){
swr_convert_frame(swr, newFrame2, NULL);
}
// 在这里可以判断一下fifo里面的数量足够1024
int size = av_audio_fifo_size(fifo);
if(size < DES_NB_SAMPLES){
// 数据不够
av_packet_unref(&packet);
continue;
}
av_audio_fifo_read(fifo, (void**)newFrame2->data, newFrame2->nb_samples);
fwrite(outFrame->data[0], size, des_channel_count*av_get_bytes_per_sample(des_sample_fmt),file);
}
}
av_packet_unref(&packet);
}
// 资源释放
av_frame_free(&frame);
av_frame_free(&newFrame);
av_frame_free(&newFrame2);
avcodec_free_context(&ctx);
avformat_close_input(&formatCtx);
fclose(file);
return 0;
}
int main(){
int ver = avcodec_version();
avdevice_register_all();
test2();
}