FFMpeg音訊混合,背景音(七):fileter音訊混合存入快取佇列
阿新 • • 發佈:2020-10-26
#include<iostream> #include<windows.h> using namespace std; //用到的C的標頭檔案 extern "C" { #include<libavcodec/avcodec.h> #include<libavfilter/avfilter.h> #include<libavfilter/buffersink.h> #include<libavfilter/buffersrc.h> #include<libavfilter/avfiltergraph.h> #include<libavformat/avformat.h> #include<libavutil/avutil.h> #include<libavutil/fifo.h> #include<libavutil/audio_fifo.h> #include<libavdevice/avdevice.h> } //對用到的預編譯 #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avfilter.lib") #pragma comment(lib, "avutil.lib") #pragmacomment(lib, "avformat.lib") #pragma comment(lib, "swscale.lib") //第一個音訊檔案 AVFormatContext* ctx3 = NULL; int ctx3index = -1; AVCodecContext* codec_ctx_three = NULL; AVAudioFifo* ctx3buff = NULL; //第二個音訊檔案 AVFormatContext* ctx4 = NULL; int ctx4index = -1; AVCodecContext* codec_ctx_four = NULL; AVAudioFifo* ctx4buff = NULL; AVFilterGraph* filter_graph = NULL; AVFilterContext* filter_three_ctx = NULL; AVFilterContext* filter_four_ctx = NULL; AVFilterContext* filter_out_ctx = NULL; //開啟輸出的檔案流IO //輸出檔案初始化 AVCodecContext* acode = NULL; AVFormatContext* out = NULL; bool status = false; //開啟第一個音訊檔案 int openMp3Codec3(char* filename) { int ret = 0; ret = avformat_open_input(&ctx3, filename, NULL, NULL); if (ret < 0) { cout << "avformat_open_input ctx3 faaild" << endl; return -1; } ret = avformat_find_stream_info(ctx3, NULL); if (ret < 0) { cout << "avformat_find_stream_info ctx3 faaild" << endl; return -1; } for (int i = 0; i < ctx3->nb_streams; i++) { if (ctx3->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { ctx3index = i; break; } } if (ctx3index < 0) { cout << "stream not find ctx3 failed" << endl; return -1; } AVCodec* codec = avcodec_find_decoder(ctx3->streams[ctx3index]->codecpar ->codec_id); if (!codec) { cout << "avcodec_find_decoder ctx3 failed" << endl; return -1; } //根據找到的解碼器創造上下文 codec_ctx_three = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx_three, ctx3->streams[ctx3index]->codecpar); avcodec_open2(codec_ctx_three, codec, NULL); if (ret < 0) { cout << "avcodec_open2 ctx3 failed" << endl; return -1; } //第四個引數設定為0,表示輸入的音訊資料,如果為1的話,就是輸出的音訊資料 av_dump_format(ctx3, ctx3index, filename,0); return ret; } //開啟第二個音訊檔案 int openMp3Codec4(char* filename) { int ret = 0; ret = avformat_open_input(&ctx4, filename, NULL, NULL); ret = avformat_find_stream_info(ctx4, NULL); for (int i = 0; i < ctx4->nb_streams; i++) { if (ctx4->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { ctx4index = i; break; } } AVCodec* codec = avcodec_find_decoder(ctx4->streams[ctx4index]->codecpar->codec_id); //根據找到的解碼器創造上下文 codec_ctx_four = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx_four, ctx4->streams[ctx4index]->codecpar); avcodec_open2(codec_ctx_four, codec, NULL); //第四個引數設定為0,表示輸入的音訊資料,如果為1的話,就是輸出的音訊資料 av_dump_format(ctx4, ctx4index, filename, 0); return ret; } int openFileIO(char* filename) { int ret = 0; AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_MP3); if (!codec) { cout << "avcodec_find_encoder faild" << endl; return -1; } acode = avcodec_alloc_context3(codec); if (!acode) { cout << "avcodec_alloc_context3 out faild" << endl; return -1; } acode->sample_rate = 44100; acode->bit_rate = 320000; acode->time_base.num = 1; acode->time_base.den = 44100; acode->channels = 2; acode->channel_layout = AV_CH_LAYOUT_STEREO; acode->sample_fmt = AV_SAMPLE_FMT_S32P; acode->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; ret = avcodec_open2(acode, codec, NULL); if (ret < 0) { cout << "avcodec_open2 out faild" << endl; return -1; } ret = avformat_alloc_output_context2(&out, NULL, NULL, filename); if (ret < 0) { cout << "avformat_alloc_output_context2 out faild" << endl; return -1; } AVStream* audio_stream = avformat_new_stream(out, NULL); audio_stream->codecpar->codec_tag = 0; avcodec_parameters_from_context(audio_stream->codecpar, acode); ret = avio_open(&out->pb, filename, AVIO_FLAG_WRITE); if (ret < 0) { cout << "avio_open out faild" << endl; return -1; } avformat_write_header(out, NULL); ctx3buff = av_audio_fifo_alloc(codec_ctx_three->sample_fmt, ctx3->streams[ctx3index]->codecpar->channels, 30 * codec_ctx_three->frame_size ); ctx4buff = av_audio_fifo_alloc(codec_ctx_four->sample_fmt, ctx4->streams[ctx4index]->codecpar->channels, 30 * codec_ctx_four->frame_size ); return ret; } int InitFilter(const char* filter_desc) { int ret = 0; const char* mp3_three = "in0"; const char* mp3_four = "in1"; //用於裝載音訊引數 char args_three[512]; char args_four[512]; //尋找輸入輸出的過濾器 AVFilter * filter_three = avfilter_get_by_name("abuffer"); AVFilter* filter_four = avfilter_get_by_name("abuffer"); AVFilter* filter_out = avfilter_get_by_name("abuffersink"); if (!filter_three || !filter_four || !filter_out) { cout << " avfilter_get_by_name faild" << endl; return -1; } //AVFilterGraph,分配輸入輸出流 AVFilterInOut* filter_three_inout = avfilter_inout_alloc(); AVFilterInOut* filter_four_inout = avfilter_inout_alloc(); AVFilterInOut* filter_out_inout = avfilter_inout_alloc(); //分配一個過濾圖 filter_graph = avfilter_graph_alloc(); if (!filter_graph) { cout << " avfilter_inout_alloc faild" << endl; return -1; } sprintf_s(args_three, sizeof(args_three), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x", codec_ctx_three->time_base.num, codec_ctx_three->time_base.den, ctx3->streams[ctx3index]->codecpar->sample_rate, av_get_sample_fmt_name(codec_ctx_three->sample_fmt), ctx3->streams[ctx3index]->codecpar->channel_layout ); sprintf_s(args_four, sizeof(args_four), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x", codec_ctx_four->time_base.num, codec_ctx_four->time_base.den, ctx4->streams[ctx4index]->codecpar->sample_rate, av_get_sample_fmt_name(codec_ctx_four->sample_fmt), ctx4->streams[ctx4index]->codecpar->channel_layout ); //AVFilterContext* filter_three_ctx = NULL; //AVFilterContext* filter_four_ctx = NULL; //AVFilterContext* filter_out_ctx = NULL; ret = avfilter_graph_create_filter(&filter_three_ctx, filter_three, mp3_three, args_three, NULL, filter_graph); if (ret < 0) { cout << "avfilter_graph_create_filter faild" << endl; return -1; } ret = avfilter_graph_create_filter(&filter_four_ctx, filter_four, mp3_four, args_four, NULL, filter_graph); if (ret < 0) { cout << "avfilter_graph_create_filter faild" << endl; return -1; } //初始化AVFilterContext,並將其新增到過濾圖,輸出的過濾圖初始化 ret = avfilter_graph_create_filter(&filter_out_ctx, filter_out, "out", NULL, NULL, filter_graph); if (ret < 0) { cout << "avfilter_graph_create_filter faild" << endl; return -1; } //輸出的取樣率,樣本格式,通道樣本佈局 ret = av_opt_set_bin(filter_out_ctx, "sample_rates", (uint8_t *)&acode->sample_rate, sizeof(acode->sample_rate), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { cout << "av_opt_set_bin faild" << endl; return -1; } ret = av_opt_set_bin(filter_out_ctx, "channel_layouts", (uint8_t*)&acode->channel_layout, sizeof(acode->channel_layout), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { cout << "av_opt_set_bin faild" << endl; return -1; } ret = av_opt_set_bin(filter_out_ctx, "sample_fmts", (uint8_t*)&acode->sample_fmt, sizeof(acode->sample_fmt), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { cout << "av_opt_set_bin faild" << endl; return -1; } //AVFilterGraph分配輸入輸出流 filter_three_inout->name = av_strdup(mp3_three); filter_three_inout->filter_ctx = filter_three_ctx; filter_three_inout->pad_idx = 0; filter_three_inout->next = filter_four_inout; filter_four_inout->name = av_strdup(mp3_four); filter_four_inout->filter_ctx = filter_four_ctx; filter_four_inout->pad_idx = 0; filter_four_inout->next = NULL; filter_out_inout->name = av_strdup("out"); filter_out_inout->filter_ctx = filter_out_ctx; filter_out_inout->pad_idx = 0; filter_out_inout->next = NULL; AVFilterInOut* filter_outputs[2]; filter_outputs[0] = filter_three_inout; filter_outputs[1] = filter_four_inout; //將描述的過濾圖新增到物件中 ret = avfilter_graph_parse_ptr(filter_graph, filter_desc, &filter_out_inout, filter_outputs, NULL); if (ret < 0) { cout << "avfilter_graph_parse_ptr faild" << endl; return -1; } //檢查過濾圖所有連結格式 ret = avfilter_graph_config(filter_graph, NULL); if (ret < 0) { cout << " avfilter_graph_config faild" << endl; return -1; } char *infos = avfilter_graph_dump(filter_graph, NULL); printf("%s\n", infos); return ret; } DWORD WINAPI three_demux(LPVOID IpParam) { int ret = 0; AVPacket packet; av_init_packet(&packet); AVFrame* pFrame = av_frame_alloc(); while (status) { packet.data = NULL; packet.size = 0; //讀取資料 ret = av_read_frame(ctx3, &packet); if (ret < 0) { av_packet_unref(&packet); break; } cout << packet.size << endl; //將資料傳送到解碼執行緒 ret = avcodec_send_packet(codec_ctx_three, &packet); if (ret < 0) { cout << "avcodec_send_packet faild" << endl; break; } //接受解碼後的資料 ret = avcodec_receive_frame(codec_ctx_three, pFrame); int three_size = av_audio_fifo_space(ctx3buff); while (three_size < pFrame->nb_samples && !status) { Sleep(10); three_size = av_audio_fifo_space(ctx3buff); cout<< "ctx3buff full wait" << endl; } //判斷快取佇列中可供寫入大小 if (three_size >= pFrame->nb_samples) { av_audio_fifo_write(ctx3buff, (void**)pFrame->data, pFrame->nb_samples); } av_packet_unref(&packet); } av_frame_free(&pFrame); return ret; } DWORD WINAPI four_demux(LPVOID IpParam) { int ret = 0; AVPacket packet; AVFrame* pFrame = av_frame_alloc(); av_init_packet(&packet); while (status) { packet.data = NULL; packet.size = 0; ret = av_read_frame(ctx4, &packet); if (ret < 0) { av_packet_unref(&packet); break; } cout << packet.size << endl; ret = avcodec_send_packet(codec_ctx_four, &packet); if (ret < 0) { cout << "avcodec_send_packet faild" << endl; break; } ret = avcodec_receive_frame(codec_ctx_four, pFrame); int four_size = av_audio_fifo_space(ctx4buff); while (four_size < pFrame->nb_samples && !status) { Sleep(10); four_size = av_audio_fifo_space(ctx4buff); cout << "ctx3buff full wait" << endl; } if (four_size >= pFrame->nb_samples) { av_audio_fifo_write(ctx4buff, (void**)pFrame->data, pFrame->nb_samples); } av_packet_unref(&packet); } av_frame_free(&pFrame); return ret; } int main() { //註冊 av_register_all(); avcodec_register_all(); avfilter_register_all(); int ret = 0; char input3[] = "3.mp3"; char input4[] = "4.mp3"; ret = openMp3Codec3(input3); if (ret < 0) { cout << "openMp3Codec3 faild" << endl; return -1; } ret = openMp3Codec4(input4); if (ret < 0) { cout << "openMp3Codec4 faild" << endl; return -1; } char outfile[] = "out.mp3"; ret = openFileIO(outfile); if (ret < 0) { cout << "openFileIO faild" << endl; return -1; } //過濾器配置 const char* filter_desc = "[in0][in1]amix=inputs=2[out]"; ret = InitFilter(filter_desc); if (ret < 0) { cout << "InitFilter faild" << endl; return -1; } status = true; CreateThread(NULL, 0, three_demux, 0, 0, NULL); CreateThread(NULL, 0, four_demux, 0, 0, NULL); while (status) { } return 0; }