ffmpeg4教程2:採集桌面聲音儲存為pcm
基於vs2017 vc++ ffmpeg4.0.2下測試
ffmpeg 環境配置請百度(vs2017 ffmpeg )影象和聲音請安裝dshow便於查詢
部分方法在https://blog.csdn.net/Java_lilin/article/details/85118365中查詢
標頭檔案參考上篇教程
static int test2() {
AVFormatContext *formatCtx = avformat_alloc_context();
AVInputFormat *ifmt = av_find_input_format("dshow");//裝置型別
AVDictionary* options = NULL;
//av_dict_set(&options, "video_size","1920*1080",0);//大小 預設全部
av_dict_set(&options, "framerate", "15", 0);//幀lu
if (avformat_open_input(&formatCtx, "audio=virtual-audio-capturer", ifmt, &options) != 0) {
/*不通過dshow的裝置查詢
wchar_t wt[] = L"audio=內建麥克風 (Conexant SmartAudio HD)";
char * psDevName = dup_wchar_to_utf8(wt);
if (avformat_open_input(&formatCtx, psDevName, ifmt, &options) != 0) {
*/
printf("open input device fail\n");
return -1;
}
av_dict_free(&options);
if (avformat_find_stream_info(formatCtx, NULL) < 0) {
printf("avformat_find_stream_info faill\n");
return -1;
}
if (formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
printf("no find stream info\n");
return -1;
}
//查詢解密器
AVCodec *codec = avcodec_find_decoder(formatCtx->streams[0]->codecpar->codec_id);
if (codec == NULL) {
printf("codec not found\n");
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("codec not open\n");
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);
//目標
ctx->channel_layout = av_get_default_channel_layout(ctx->channels);
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 desc_channel_layout = 3;
int desc_channel_count = 2;
int desc_sample_rate = 44100;
AVSampleFormat desc_fmt = AV_SAMPLE_FMT_S16;
av_opt_set_int(swr, "out_channel_count", desc_channel_count, 0);
av_opt_set_int(swr, "out_channel_layout", desc_channel_layout, 0);
av_opt_set_int(swr, "out_sample_rate", desc_sample_rate, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", desc_fmt, 0);
printf("\n聲道%d,取樣率%d格式%d----》聲道%d,取樣率%d格式%d\n", ctx->channels,ctx->sample_rate,
ctx->sample_fmt, desc_channel_count, desc_sample_rate, desc_fmt);
int DES_NB_SAMPLES = 1024;
AVFrame *outframe = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, DES_NB_SAMPLES);
AVFrame *newframe = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, 0);
AVFrame *newframe2= alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, 0);
AVAudioFifo *fifo = av_audio_fifo_alloc(desc_fmt, desc_channel_count,10240);
FILE *file = NULL;
fopen_s(&file, "C:\\Users\\lilin\\Desktop\\1.pcm","wb");//ffplay -ar 44100 -channels 2 -f s16le -i 1.pcm或用Audacity 播放
int fnum = 500;
while (fnum--) {
int size = av_audio_fifo_size(fifo);
if (size >= DES_NB_SAMPLES) {//超過
printf("\n第一次超過\n");
size = DES_NB_SAMPLES;
av_audio_fifo_read(fifo, (void**)outframe->data, size);
//完整
//寫檔案
fwrite(outframe->data[0],size,desc_channel_count*av_get_bytes_per_sample(desc_fmt),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("audio decode error\n");
}
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, desc_sample_rate);
if(dealy>0){
swr_convert_frame(swr, newframe2,NULL);
av_audio_fifo_write(fifo, (void**)newframe2->data, newframe2->nb_samples);
}
//這裡可以判斷下fifo裡的數量是否夠1024
int size = av_audio_fifo_size(fifo);
if (size < DES_NB_SAMPLES) {
//資料不夠
av_packet_unref(&packet);
continue;
}
size = DES_NB_SAMPLES;//夠了
av_audio_fifo_read(fifo, (void**)outframe->data,size);//固定大小的
//寫檔案
fwrite(outframe->data[0], size, desc_channel_count*av_get_bytes_per_sample(desc_fmt), file);
}
}
av_packet_unref(&packet);
}
av_frame_free(&frame);
av_frame_free(&newframe);
av_frame_free(&newframe2);
av_frame_free(&outframe);
av_audio_fifo_free(fifo);
avcodec_free_context(&ctx);
avformat_close_input(&formatCtx);
fclose(file);
return 0;
}
int main(){
printf("ok:%d\n", avcodec_version());
avdevice_register_all();
test2();
}
討論群261074724