#include "audio_capture_opus.h"
#include "gbk2utf8.h"
string GetError4(const int &index){
char buf[256] = { 0 };
av_strerror(index, buf, sizeof(buf));
return string(buf);
}
int audio_capture_opus() {
const char* outPath = "./captureOpus.opus";
/// 查找OPUS音频编码器
const char* codec_name = "libopus";
AVCodec *ACodec = avcodec_find_encoder_by_name(codec_name);
if (!ACodec)
{
cout << "avcodec_find_decoder - faild!" << endl;
return -1;
}
/// 创建音频编码器上下文
AVCodecContext *ACodecContext = avcodec_alloc_context3(ACodec);
if (!ACodecContext)
{
cout << "avcodec_alloc_context3 - faild!" << endl;
return -2;
}
// 设置音频参数
/// 比特率
ACodecContext->bit_rate = 48000;
/// 采样率
ACodecContext->sample_rate = 48000; //opus
/// 采样格式 假如源音频是AV_SAMPLE_FMT_S16,则用AV_SAMPLE_FMT_S16,我的pcm是AV_SAMPLE_FMT_FLT
ACodecContext->sample_fmt = AV_SAMPLE_FMT_S16;//AV_SAMPLE_FMT_S16;
/// 通道数
ACodecContext->channels = 2; //必须双通道,不然webrtc不支持
/// 通道类型
ACodecContext->channel_layout = AV_CH_LAYOUT_STEREO; //av_get_default_channel_layout(ACodecContext->channels);//
ACodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
/// 打开音频编码器
int result = avcodec_open2(ACodecContext, ACodec, nullptr);
if (result != 0)
{
cout << "avcodec_open2 - faild:" << result << endl;
return -3;
}
/// 打开音频输出封装上下文
AVFormatContext *AFormatContext = nullptr;
result = avformat_alloc_output_context2(&AFormatContext, nullptr, nullptr, outPath);
if (result < 0)
{
cout << "avformat_alloc_output_context2 - faild:" << result << endl;
return -4;
}
/// 创建音频输出流
//AVStream *AStream = avformat_new_stream(AFormatContext,ACodec);
AVStream *AStream = avformat_new_stream(AFormatContext, nullptr);
if (!AStream)
{
cout << "avformat_new_stream - faild!" << endl;
return -5;
}
/// 音频流媒体附加信息
AStream->codecpar->codec_tag = 0;
/// 音频流信息拷贝
result = avcodec_parameters_from_context(AStream->codecpar, ACodecContext);
if (result < 0)
{
cout << "avcodec_parameters_from_context - faild:" << GetError4(result) << endl;
return -5;
}
/// 打印信息
av_dump_format(AFormatContext, 0, outPath, 1);
// 打开io,写入头信息
result = avio_open(&AFormatContext->pb, outPath, AVIO_FLAG_WRITE);
if (result < 0)
{
cout << "avio_open - faild:" << GetError4(result) << endl;
return -6;
}
/// 写入头信息,必须编码器初始化好后调用,不然出现意想不到的错误
result = avformat_write_header(AFormatContext, nullptr);
if (result == AVSTREAM_INIT_IN_INIT_OUTPUT)
{
cout << "2 avformat_write_header - faild:" << GetError4(result) << endl;
return -7;
}
/// 创建音频重采样上下文
SwrContext *ASwrContext = nullptr;
ASwrContext = swr_alloc_set_opts(NULL,
ACodecContext->channel_layout,
ACodecContext->sample_fmt,
ACodecContext->sample_rate,
ACodecContext->channel_layout,
AV_SAMPLE_FMT_S16, //注:输入源音频的类型
//48000,//注:输入源音频的采样率
44100,//注:输入源音频的采样率
0, 0);
if (!ASwrContext)
{
cout << "swr_alloc_set_opts - faild:" << endl;
return -8;
}
/// 音频重采样初始化
result = swr_init(ASwrContext);
if (result < 0)
{
cout << "swr_init - faild:" << GetError4(result) << endl;
return -9;
}
AVAudioFifo *fifo = NULL;
fifo = av_audio_fifo_alloc(AV_SAMPLE_FMT_S16, 2, 1);
AVFormatContext* avFormatCxt = NULL;
AVDictionary* options = NULL;
char* devicename = const_cast<char*>("audio=Line 1 (Virtual Audio Cable)");
string devicename_utf8_str = GbkToUtf8(devicename);
char* devicename_utf8 = const_cast<char*>(devicename_utf8_str.c_str());
cout << devicename_utf8 << endl;
avdevice_register_all();
//get format
AVInputFormat* inFormat = av_find_input_format("dshow");
av_dict_set(&options, "audio_buffer_size", "100", 0);
int ret = avformat_open_input(&avFormatCxt, devicename_utf8, inFormat, &options);
av_dump_format(avFormatCxt, 0, "", 0); // Audio: pcm_s16le, 44100 Hz, 2 channels, s16
AVPacket av_packet;
int i = 100;
/* 是不是一直从设备 读取frame, 直到一定次数,才会 返回一个 packet?
// 是不是一直采样 22050次, 然后将数据放入到 avpacket中, 那这样一次,算几帧音频?
那怎么又算一帧呢?*/
void* opus_src_data = av_malloc(960 * 2 * 2);
const uint8_t *data2[1];
data2[0] = (uint8_t *)opus_src_data;
int k = 0;
while (av_read_frame(avFormatCxt, &av_packet) == 0) {
printf("size=%d\n", av_packet.size); // 88200 22050 * 2 * 2
if (av_audio_fifo_size(fifo) < 960) {
//ret = av_audio_fifo_realloc(fifo, 22050);
ret = av_audio_fifo_realloc(fifo, 4410);
if (ret < 0) {
cout << "av_audio_fifo_realloc err" << endl;
}
//ret = av_audio_fifo_write(fifo, (void**)dst_data, 22050);
ret = av_audio_fifo_write(fifo, (void**)(&(av_packet.data)), 4410);
cout << "av_audio_fifo_write ret = " << ret << endl;
cout << "fifo size=" << av_audio_fifo_size(fifo) << endl;
/*AVFrame* AFrame = av_frame_alloc();*/
while (1)
{
if (av_audio_fifo_size(fifo) >= 960) {
ret = av_audio_fifo_read(fifo, &opus_src_data, 960);
/*ret = av_audio_fifo_read(fifo, (void**)AFrame->data, 960);*/
//ret = av_audio_fifo_read(fifo, (void**)data2, 960);
if (ret < 0) {
cout << GetError4(ret) << endl;
}
AVFrame* AFrame = av_frame_alloc();
AFrame->format = ACodecContext->sample_fmt;//AV_SAMPLE_FMT_S16;
AFrame->channel_layout = ACodecContext->channel_layout;//av_get_default_channel_layout(ACodecContext->channels);//
AFrame->nb_samples = ACodecContext->frame_size; // 一帧音频存放的样本数量
cout << "AFrame->nb_samples" << AFrame->nb_samples << endl;
AFrame->sample_rate = ACodecContext->sample_rate;//采样率
AFrame->pts = 960 * k;//时间戳,必须写上,不然下面AFrame->extended_data不正确
k++;
result = av_frame_get_buffer(AFrame, 0); // 创建音频输出空间
if (result < 0)
{
cout << "av_frame_get_buffer - faild:" << GetError4(result) << endl;
return -9;
}
/// 转换音频
const uint8_t *data[1];
data[0] = (uint8_t *)opus_src_data;
int len = swr_convert(ASwrContext,
AFrame->extended_data,
AFrame->nb_samples,
data,
AFrame->nb_samples);
if (len <= 0)
{
break;
}
/// 音频编码
AVPacket APacket;
av_init_packet(&APacket);
result = avcodec_send_frame(ACodecContext, AFrame);
if (result != 0)
{
cout << "avcodec_send_frame - faild:" << GetError4(result) << endl;
continue;
}
result = avcodec_receive_packet(ACodecContext, &APacket);
if (result != 0)
{
cout << "avcodec_receive_packet - faild:" << GetError4(result) << endl;
continue;
}
/// 音频封装入opus
APacket.stream_index = 0;
APacket.dts = 0;
cout << "APacket.pts:" << APacket.pts << endl;
result = av_interleaved_write_frame(AFormatContext, &APacket);
if (result != 0)
{
cout << "av_interleaved_write_frame - faild:" << GetError4(result) << endl;
continue;
}
}
else {
break;
}
}
}
av_packet_unref(&av_packet); // 不是说 与 av_init_packet 对应操作吗, 这里为什么每次读取packet, 都要unref
--i;
if (i < 0) {
break;
}
}
/// 写入视频索引
av_write_trailer(AFormatContext);
/// 关闭视频索引
avio_close(AFormatContext->pb);
/// 清理 - 音频封装上下文
avformat_free_context(AFormatContext);
/// 关闭编码器
avcodec_close(ACodecContext);
/// 清理编码器上下文
avcodec_free_context(&ACodecContext);
return 0;
}