• ffmpeg filter amix混音实现


    一、实现思路

    ffmpeg的滤波filter有amix这个混音器,可以借助它来做音频的多路混音。首先我们需要编译ffmpeg并安装它,可以具备编码功能,考虑可以加mp3或者aac编码库进来,最简单的方式是编码成pcm格式直接输出到文件,用VLC也可以播放。

    二、编译ffmpeg

    1. $: git clone https://git.ffmpeg.org/ffmpeg.git
    2. $: cd ffmpeg
    3. $: git tag //打印出git提交标签,我们选择n2.9-dev 这个版本
    4. $: git checkout n2.9-dev -b n2.9-dev //新建一个分支并切换到n2.9-dev这个版本
    5. $: ./configure --disable-yasm --disable-ffplay --disable-ffprobe --disable-debug --enable-avdevice --disable-devices --disable-zlib --disable-bzlib --enable-avfilter --enable-encoders --enable-ffmpeg --enable-static --enable-gpl --enable-small --enable-nonfree --prefix=/home/xxx/ffmpegInstall_linux //编译它使用静态库编译(不编译动态库需要的自行添加即可)
    6. $: make clean
    7. $: make -j4
    8. $: make install

    三、简易框架

    如图,即将两个mp3文件通过amixfilter 混合成一个音频输出。

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

    四、编写程序audioMix.c

    1、构建输入封装器上下文input avformat

    1. cd ~/ffmpegInstall_linux
    2. mkdir src
    3. 新建audioMix.c文件并拷贝3个mp3文件进来
    4. 编译指令:
    5. $: g++ -I../include -L../lib audioMix.cpp -o audioMix -lavfilter -lavformat -lavcodec -lavutil -lmp3lame -lswresample -lswscale -lavdevice -lpostproc -lpthread -lm -ldl

    输入MP3格式的文件即可。或者其他编码的也行。

    1. int OpenNetworkInput(char* inputForamt, const char* url)
    2. {
    3. AVInputFormat* ifmt = av_find_input_format(inputForamt);
    4. AVDictionary* opt1 = NULL;
    5. av_dict_set(&opt1, "rtbufsize", "10M", 0);
    6. int ret = 0;
    7. ret = avformat_open_input(&_fmt_ctx_net, url, ifmt, &opt1);
    8. if (ret < 0)
    9. {
    10. printf("Speaker: failed to call avformat_open_input\n");
    11. return -1;
    12. }
    13. ret = avformat_find_stream_info(_fmt_ctx_net, NULL);
    14. if (ret < 0)
    15. {
    16. printf("Speaker: failed to call avformat_find_stream_info\n");
    17. return -1;
    18. }
    19. for (int i = 0; i < _fmt_ctx_net->nb_streams; i++)
    20. {
    21. if (_fmt_ctx_net->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
    22. {
    23. _index_net = i;
    24. break;
    25. }
    26. }
    27. if (_index_net < 0)
    28. {
    29. printf("Speaker: negative audio index\n");
    30. return -1;
    31. }
    32. AVCodecContext* codec_ctx = _fmt_ctx_net->streams[_index_net]->codec;
    33. AVCodec* codec = avcodec_find_decoder(codec_ctx->codec_id);
    34. if (codec == NULL)
    35. {
    36. printf("Speaker: null audio decoder\n");
    37. return -1;
    38. }
    39. ret = avcodec_open2(codec_ctx, codec, NULL);
    40. if (ret < 0)
    41. {
    42. printf("Speaker: failed to call avcodec_open2\n");
    43. return -1;
    44. }
    45. av_dump_format(_fmt_ctx_net, _index_net, url, 0);
    46. return 0;
    47. }

    2、构建输出封装器上下文

    output format这里输出的是44100 s16 pcm 小端序格式的音频。需要其他格式的音频要改AV_CODEC_ID_PCM_S16LE 。并且需要添加编码库,ffmpeg内部不集成mp3或者aac

    这里还会构建几组fifo来存储input raw data。

    1. int OpenFileOutput(char* fileName)
    2. {
    3. int ret = 0;
    4. ret = avformat_alloc_output_context2(&_fmt_ctx_out, NULL, NULL, fileName);
    5. if (ret < 0)
    6. {
    7. printf("Mixer: failed to call avformat_alloc_output_context2\n");
    8. return -1;
    9. }
    10. AVStream* stream_a = NULL;
    11. stream_a = avformat_new_stream(_fmt_ctx_out, NULL);
    12. if (stream_a == NULL)
    13. {
    14. printf("Mixer: failed to call avformat_new_stream\n");
    15. return -1;
    16. }
    17. _index_a_out = 0;
    18. stream_a->codec->codec_type = AVMEDIA_TYPE_AUDIO;
    19. AVCodec* codec_mp3 = NULL;
    20. codec_mp3 = avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE);
    21. if (codec_mp3 == NULL)
    22. {
    23. printf("Mixer: failed to call avcodec_find_encoder ++++\n");
    24. return -1;
    25. }
    26. stream_a->codec->codec = codec_mp3;
    27. stream_a->codec->sample_rate = 44100;
    28. stream_a->codec->channels = 2;
    29. stream_a->codec->channel_layout = av_get_default_channel_layout(2);
    30. stream_a->codec->sample_fmt = codec_mp3->sample_fmts[0];
    31. stream_a->codec->bit_rate = 320000;
    32. stream_a->codec->time_base.num = 1;
    33. stream_a->codec->time_base.den = stream_a->codec->sample_rate;
    34. stream_a->codec->codec_tag = 0;
    35. if (_fmt_ctx_out->oformat->flags & AVFMT_GLOBALHEADER)
    36. stream_a->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    37. if (avcodec_open2(stream_a->codec, stream_a->codec->codec, NULL) < 0)
    38. {
    39. printf("Mixer: failed to call avcodec_open2\n");
    40. return -1;
    41. }
    42. if (!(_fmt_ctx_out->oformat->flags & AVFMT_NOFILE))
    43. {
    44. if (avio_open(&_fmt_ctx_out->pb, fileName, AVIO_FLAG_WRITE) < 0)
    45. {
    46. printf("Mixer: failed to call avio_open\n");
    47. return -1;
    48. }
    49. }
    50. if (avformat_write_header(_fmt_ctx_out, NULL) < 0)
    51. {
    52. printf("Mixer: failed to call avformat_write_header\n");
    53. return -1;
    54. }
    55. bool b = (!_fmt_ctx_out->streams[0]->time_base.num && _fmt_ctx_out->streams[0]->codec->time_base.num);
    56. av_dump_format(_fmt_ctx_out, _index_a_out, fileName, 1);
    57. _fifo_net = av_audio_fifo_alloc(_fmt_ctx_net->streams[_index_net]->codec->sample_fmt, _fmt_ctx_net->streams[_index_net]->codec->channels, 30*_fmt_ctx_net->streams[_index_net]->codec->frame_size);
    58. _fifo_spk = av_audio_fifo_alloc(_fmt_ctx_spk->streams[_index_spk]->codec->sample_fmt, _fmt_ctx_spk->streams[_index_spk]->codec->channels, 30*_fmt_ctx_spk->streams[_index_spk]->codec->frame_size);
    59. _fifo_mic = av_audio_fifo_alloc(_fmt_ctx_mic->streams[_index_mic]->codec->sample_fmt, _fmt_ctx_mic->streams[_index_mic]->codec->channels, 30*_fmt_ctx_mic->streams[_index_spk]->codec->frame_size);
    60. return 0;
    61. }

    3、构建in filter ,out filter 和filter graph(滤波过程)上下文 

    1. int InitFilter(const char* filter_desc)
    2. {
    3. char args_spk[512];
    4. const char* pad_name_spk = "in0";
    5. char args_mic[512];
    6. const char* pad_name_mic = "in1";
    7. char args_net[512];
    8. const char* pad_name_net = "in2";
    9. char args_vol[512] = "-3dB";
    10. const char* pad_name_vol = "vol";
    11. AVFilter* filter_src_spk = NULL;
    12. filter_src_spk = avfilter_get_by_name("abuffer");
    13. if(filter_src_spk == NULL)
    14. {
    15. printf("fail to get avfilter ..\n");
    16. return -1;
    17. }
    18. AVFilter* filter_src_mic = NULL;
    19. filter_src_mic = avfilter_get_by_name("abuffer");
    20. if(filter_src_mic == NULL)
    21. {
    22. printf("fail to get avfilter ..\n");
    23. return -1;
    24. }
    25. AVFilter* filter_src_net = NULL;
    26. filter_src_net = avfilter_get_by_name("abuffer");
    27. if(filter_src_net == NULL)
    28. {
    29. printf("fail to get avfilter ..\n");
    30. return -1;
    31. }
    32. AVFilter* filter_src_vol = NULL;
    33. filter_src_vol = avfilter_get_by_name("volume");
    34. if(filter_src_vol == NULL)
    35. {
    36. printf("fail to get avfilter ..\n");
    37. return -1;
    38. }
    39. AVFilter* filter_sink = avfilter_get_by_name("abuffersink");
    40. AVFilterInOut* filter_output_spk = avfilter_inout_alloc();
    41. AVFilterInOut* filter_output_mic = avfilter_inout_alloc();
    42. AVFilterInOut* filter_output_net = avfilter_inout_alloc();
    43. AVFilterInOut* filter_output_vol = avfilter_inout_alloc();
    44. AVFilterInOut* filter_input = avfilter_inout_alloc();
    45. _filter_graph = avfilter_graph_alloc();
    46. //snprintf(args_spk, sizeof(args_spk), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
    47. snprintf(args_spk, sizeof(args_spk), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
    48. _fmt_ctx_spk->streams[_index_spk]->codec->time_base.num,
    49. _fmt_ctx_spk->streams[_index_spk]->codec->time_base.den,
    50. _fmt_ctx_spk->streams[_index_spk]->codec->sample_rate,
    51. av_get_sample_fmt_name(_fmt_ctx_spk->streams[_index_spk]->codec->sample_fmt),
    52. _fmt_ctx_spk->streams[_index_spk]->codec->channel_layout);
    53. printf("args spk : %s channel_layout : %d\n",args_spk,_fmt_ctx_spk->streams[_index_spk]->codec->channel_layout);
    54. //snprintf(args_mic, sizeof(args_mic), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
    55. snprintf(args_mic, sizeof(args_mic), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
    56. _fmt_ctx_mic->streams[_index_mic]->codec->time_base.num,
    57. _fmt_ctx_mic->streams[_index_mic]->codec->time_base.den,
    58. _fmt_ctx_mic->streams[_index_mic]->codec->sample_rate,
    59. av_get_sample_fmt_name(_fmt_ctx_mic->streams[_index_mic]->codec->sample_fmt),
    60. _fmt_ctx_mic->streams[_index_mic]->codec->channel_layout);
    61. printf("args mic : %s channel_layout : %d\n",args_mic,_fmt_ctx_mic->streams[_index_mic]->codec->channel_layout);
    62. //snprintf(args_mic, sizeof(args_mic), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
    63. snprintf(args_net, sizeof(args_net), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
    64. _fmt_ctx_net->streams[_index_net]->codec->time_base.num,
    65. _fmt_ctx_net->streams[_index_net]->codec->time_base.den,
    66. _fmt_ctx_net->streams[_index_net]->codec->sample_rate,
    67. av_get_sample_fmt_name(_fmt_ctx_net->streams[_index_net]->codec->sample_fmt),
    68. _fmt_ctx_net->streams[_index_net]->codec->channel_layout);
    69. printf("args net : %s channel_layout : %d\n",args_net,_fmt_ctx_net->streams[_index_net]->codec->channel_layout);
    70. //sprintf_s(args_spk, sizeof(args_spk), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x", _fmt_ctx_out->streams[_index_a_out]->codec->time_base.num, _fmt_ctx_out->streams[_index_a_out]->codec->time_base.den, _fmt_ctx_out->streams[_index_a_out]->codec->sample_rate, av_get_sample_fmt_name(_fmt_ctx_out->streams[_index_a_out]->codec->sample_fmt), _fmt_ctx_out->streams[_index_a_out]->codec->channel_layout);
    71. //sprintf_s(args_mic, sizeof(args_mic), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x", _fmt_ctx_out->streams[_index_a_out]->codec->time_base.num, _fmt_ctx_out->streams[_index_a_out]->codec->time_base.den, _fmt_ctx_out->streams[_index_a_out]->codec->sample_rate, av_get_sample_fmt_name(_fmt_ctx_out->streams[_index_a_out]->codec->sample_fmt), _fmt_ctx_out->streams[_index_a_out]->codec->channel_layout);
    72. int ret = 0;
    73. ret = avfilter_graph_create_filter(&_filter_ctx_src_spk, filter_src_spk, pad_name_spk, args_spk, NULL, _filter_graph);
    74. if (ret < 0)
    75. {
    76. printf("Filter: failed to call avfilter_graph_create_filter -- src spk\n");
    77. return -1;
    78. }
    79. ret = avfilter_graph_create_filter(&_filter_ctx_src_mic, filter_src_mic, pad_name_mic, args_mic, NULL, _filter_graph);
    80. if (ret < 0)
    81. {
    82. printf("Filter: failed to call avfilter_graph_create_filter -- src mic\n");
    83. return -1;
    84. }
    85. ret = avfilter_graph_create_filter(&_filter_ctx_src_net, filter_src_net, pad_name_net, args_net, NULL, _filter_graph);
    86. if (ret < 0)
    87. {
    88. printf("Filter: failed to call avfilter_graph_create_filter -- src net\n");
    89. return -1;
    90. }
    91. ret = avfilter_graph_create_filter(&_filter_ctx_sink, filter_sink, "out", NULL, NULL, _filter_graph);
    92. if (ret < 0)
    93. {
    94. printf("Filter: failed to call avfilter_graph_create_filter -- sink\n");
    95. return -1;
    96. }
    97. AVCodecContext* encodec_ctx = _fmt_ctx_out->streams[_index_a_out]->codec;
    98. ret = av_opt_set_bin(_filter_ctx_sink, "sample_fmts", (uint8_t*)&encodec_ctx->sample_fmt, sizeof(encodec_ctx->sample_fmt), AV_OPT_SEARCH_CHILDREN);
    99. if (ret < 0)
    100. {
    101. printf("Filter: failed to call av_opt_set_bin -- sample_fmts\n");
    102. return -1;
    103. }
    104. ret = av_opt_set_bin(_filter_ctx_sink, "channel_layouts", (uint8_t*)&encodec_ctx->channel_layout, sizeof(encodec_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);
    105. if (ret < 0)
    106. {
    107. printf("Filter: failed to call av_opt_set_bin -- channel_layouts\n");
    108. return -1;
    109. }
    110. ret = av_opt_set_bin(_filter_ctx_sink, "sample_rates", (uint8_t*)&encodec_ctx->sample_rate, sizeof(encodec_ctx->sample_rate), AV_OPT_SEARCH_CHILDREN);
    111. if (ret < 0)
    112. {
    113. printf("Filter: failed to call av_opt_set_bin -- sample_rates\n");
    114. return -1;
    115. }
    116. filter_output_spk->name = av_strdup(pad_name_spk);
    117. filter_output_spk->filter_ctx = _filter_ctx_src_spk;
    118. filter_output_spk->pad_idx = 0;
    119. filter_output_spk->next = filter_output_mic;
    120. filter_output_mic->name = av_strdup(pad_name_mic);
    121. filter_output_mic->filter_ctx = _filter_ctx_src_mic;
    122. filter_output_mic->pad_idx = 0;
    123. filter_output_mic->next = filter_output_net; //重點!!!!!
    124. filter_output_net->name = av_strdup(pad_name_net);
    125. filter_output_net->filter_ctx = _filter_ctx_src_net;
    126. filter_output_net->pad_idx = 0;
    127. filter_output_net->next = NULL;
    128. filter_output_vol->name = av_strdup(pad_name_vol);
    129. filter_output_vol->filter_ctx = _filter_ctx_src_vol;
    130. filter_output_vol->pad_idx = 0;
    131. filter_output_vol->next = filter_input;
    132. filter_input->name = av_strdup("out");
    133. filter_input->filter_ctx = _filter_ctx_sink;
    134. filter_input->pad_idx = 0;
    135. filter_input->next = NULL;
    136. AVFilterInOut* filter_outputs[3];
    137. filter_outputs[0] = filter_output_spk;
    138. filter_outputs[1] = filter_output_mic;
    139. filter_outputs[2] = filter_output_net;
    140. AVFilterInOut* filter_volinputs[2];
    141. filter_volinputs[0] = filter_output_vol;
    142. filter_volinputs[1] = filter_input;
    143. ret = avfilter_graph_parse_ptr(_filter_graph, filter_desc, &filter_input, filter_outputs, NULL);
    144. if (ret < 0)
    145. {
    146. printf("Filter: failed to call avfilter_graph_parse_ptr\n");
    147. return -1;
    148. }
    149. ret = avfilter_graph_config(_filter_graph, NULL);
    150. if (ret < 0)
    151. {
    152. printf("Filter: failed to call avfilter_graph_config\n");
    153. return -1;
    154. }
    155. avfilter_inout_free(&filter_input);
    156. //av_free(filter_src_spk);
    157. //av_free(filter_src_mic);
    158. //av_free(filter_src_net);
    159. avfilter_inout_free(filter_outputs);
    160. //av_free(filter_outputs);
    161. char* temp = avfilter_graph_dump(_filter_graph, NULL);
    162. printf("%s\n", temp);
    163. return 0;
    164. }

    这里需要注意const char* filter_desc 传进来的filter关系描述符

    const char* filter_desc = "[in0][in1][in2]amix=inputs=3[out]";
    

    解释一下,[in0] 这个对应上面的const char* pad_name_spk = “in0”;代表某一filter,[in0][in1][in2]代表的是输入节点,amix是混音滤波器=inputs=3这个是参数表示输入是3个,[out]表示输出。

    1. filter_output_spk->name = av_strdup(pad_name_spk);
    2. filter_output_spk->filter_ctx = _filter_ctx_src_spk;
    3. filter_output_spk->pad_idx = 0;
    4. filter_output_spk->next = filter_output_mic;
    5. filter_output_mic->name = av_strdup(pad_name_mic);
    6. filter_output_mic->filter_ctx = _filter_ctx_src_mic;
    7. filter_output_mic->pad_idx = 0;
    8. filter_output_mic->next = filter_output_net; //重點!!!!!
    9. filter_output_net->name = av_strdup(pad_name_net);
    10. filter_output_net->filter_ctx = _filter_ctx_src_net;
    11. filter_output_net->pad_idx = 0;
    12. filter_output_net->next = NULL;
    13. filter_output_vol->name = av_strdup(pad_name_vol);
    14. filter_output_vol->filter_ctx = _filter_ctx_src_vol;
    15. filter_output_vol->pad_idx = 0;
    16. filter_output_vol->next = filter_input;
    17. filter_input->name = av_strdup("out");
    18. filter_input->filter_ctx = _filter_ctx_sink;
    19. filter_input->pad_idx = 0;
    20. filter_input->next = NULL;
    21. AVFilterInOut* filter_outputs[3];
    22. filter_outputs[0] = filter_output_spk;
    23. filter_outputs[1] = filter_output_mic;
    24. filter_outputs[2] = filter_output_net;

    这是有填充next的即将输入串联了起来。

    4、构建输入线程

    1. void * NetworkCapThreadProc(void *lpParam)
    2. {
    3. AVFrame* pFrame = av_frame_alloc();
    4. AVPacket packet;
    5. av_init_packet(&packet);
    6. int got_sound;
    7. while (_state == RUNNING)
    8. {
    9. packet.data = NULL;
    10. packet.size = 0;
    11. if (av_read_frame(_fmt_ctx_net, &packet) < 0)
    12. {
    13. printf("there is no context spk \n");
    14. break;
    15. }
    16. if (packet.stream_index == _index_net)
    17. {
    18. if (avcodec_decode_audio4(_fmt_ctx_net->streams[_index_net]->codec, pFrame, &got_sound, &packet) < 0)
    19. {
    20. break;
    21. }
    22. av_free_packet(&packet);
    23. if (!got_sound)
    24. {
    25. continue;
    26. }
    27. int fifo_net_space = av_audio_fifo_space(_fifo_net);
    28. while(fifo_net_space < pFrame->nb_samples && _state == RUNNING)
    29. {
    30. usleep(10*1000);
    31. printf("_fifo_spk full !\n");
    32. fifo_net_space = av_audio_fifo_space(_fifo_net);
    33. }
    34. if (fifo_net_space >= pFrame->nb_samples)
    35. {
    36. //EnterCriticalSection(&_section_spk);
    37. pthread_mutex_lock(&mutex_net);
    38. int nWritten = av_audio_fifo_write(_fifo_net, (void**)pFrame->data, pFrame->nb_samples);
    39. //LeaveCriticalSection(&_section_spk);
    40. pthread_mutex_unlock(&mutex_net);
    41. }
    42. }
    43. }
    44. av_frame_free(&pFrame);
    45. }

    5、处理数据 

    1. while (_state != FINISHED)
    2. {
    3. if (kbhit())
    4. {
    5. _state = STOPPED;
    6. break;
    7. }
    8. else
    9. {
    10. int ret = 0;
    11. AVFrame* pFrame_spk = av_frame_alloc();
    12. AVFrame* pFrame_mic = av_frame_alloc();
    13. AVFrame* pFrame_net = av_frame_alloc();
    14. AVPacket packet_out;
    15. int got_packet_ptr = 0;
    16. int fifo_spk_size = av_audio_fifo_size(_fifo_spk);
    17. int fifo_mic_size = av_audio_fifo_size(_fifo_mic);
    18. int fifo_net_size = av_audio_fifo_size(_fifo_net);
    19. int frame_spk_min_size = _fmt_ctx_spk->streams[_index_spk]->codec->frame_size;
    20. int frame_mic_min_size = _fmt_ctx_mic->streams[_index_mic]->codec->frame_size;
    21. int frame_net_min_size = _fmt_ctx_net->streams[_index_net]->codec->frame_size;
    22. printf("get mini frame size : %d ###################\n",frame_spk_min_size);
    23. if (fifo_spk_size >= frame_spk_min_size && fifo_mic_size >= frame_mic_min_size && fifo_net_size >= frame_net_min_size)
    24. {
    25. tmpFifoFailed = 0;
    26. pFrame_spk->nb_samples = frame_spk_min_size;
    27. pFrame_spk->channel_layout = _fmt_ctx_spk->streams[_index_spk]->codec->channel_layout;
    28. pFrame_spk->format = _fmt_ctx_spk->streams[_index_spk]->codec->sample_fmt;
    29. pFrame_spk->sample_rate = _fmt_ctx_spk->streams[_index_spk]->codec->sample_rate;
    30. av_frame_get_buffer(pFrame_spk, 0);
    31. pFrame_mic->nb_samples = frame_mic_min_size;
    32. pFrame_mic->channel_layout = _fmt_ctx_mic->streams[_index_mic]->codec->channel_layout;
    33. pFrame_mic->format = _fmt_ctx_mic->streams[_index_mic]->codec->sample_fmt;
    34. pFrame_mic->sample_rate = _fmt_ctx_mic->streams[_index_mic]->codec->sample_rate;
    35. av_frame_get_buffer(pFrame_mic, 0);
    36. pFrame_net->nb_samples = frame_net_min_size;
    37. pFrame_net->channel_layout = _fmt_ctx_net->streams[_index_net]->codec->channel_layout;
    38. pFrame_net->format = _fmt_ctx_net->streams[_index_net]->codec->sample_fmt;
    39. pFrame_net->sample_rate = _fmt_ctx_net->streams[_index_net]->codec->sample_rate;
    40. av_frame_get_buffer(pFrame_net, 0);
    41. pthread_mutex_lock(&mutex_spk);
    42. //EnterCriticalSection(&_section_spk);
    43. ret = av_audio_fifo_read(_fifo_spk, (void**)pFrame_spk->data, frame_spk_min_size);
    44. //LeaveCriticalSection(&_section_spk);
    45. pthread_mutex_unlock(&mutex_spk);
    46. pthread_mutex_lock(&mutex_mic);
    47. //EnterCriticalSection(&_section_mic);
    48. ret = av_audio_fifo_read(_fifo_mic, (void**)pFrame_mic->data, frame_mic_min_size);
    49. //LeaveCriticalSection(&_section_mic);
    50. pthread_mutex_unlock(&mutex_mic);
    51. pthread_mutex_lock(&mutex_net);
    52. //EnterCriticalSection(&_section_net);
    53. ret = av_audio_fifo_read(_fifo_net, (void**)pFrame_net->data, frame_net_min_size);
    54. //LeaveCriticalSection(&_section_net);
    55. pthread_mutex_unlock(&mutex_net);
    56. pFrame_spk->pts = av_frame_get_best_effort_timestamp(pFrame_spk);
    57. pFrame_mic->pts = av_frame_get_best_effort_timestamp(pFrame_mic);
    58. pFrame_net->pts = av_frame_get_best_effort_timestamp(pFrame_net);
    59. BufferSourceContext* s = (BufferSourceContext*)_filter_ctx_src_spk->priv;
    60. bool b1 = (s->sample_fmt != pFrame_spk->format);
    61. bool b2 = (s->sample_rate != pFrame_spk->sample_rate);
    62. bool b3 = (s->channel_layout != pFrame_spk->channel_layout);
    63. bool b4 = (s->channels != pFrame_spk->channels);
    64. ret = av_buffersrc_add_frame(_filter_ctx_src_spk, pFrame_spk);
    65. if (ret < 0)
    66. {
    67. printf("Mixer: failed to call av_buffersrc_add_frame (speaker)\n");
    68. break;
    69. }
    70. ret = av_buffersrc_add_frame(_filter_ctx_src_mic, pFrame_mic);
    71. if (ret < 0)
    72. {
    73. printf("Mixer: failed to call av_buffersrc_add_frame (microphone)\n");
    74. break;
    75. }
    76. ret = av_buffersrc_add_frame(_filter_ctx_src_net, pFrame_net);
    77. if (ret < 0)
    78. {
    79. printf("Mixer: failed to call av_buffersrc_add_frame (network)\n");
    80. break;
    81. }
    82. while (1)
    83. {
    84. AVFrame* pFrame_out = av_frame_alloc();
    85. //AVERROR(EAGAIN) 返回这个表示还没转换完成既 不存在帧,则返回AVERROR(EAGAIN)
    86. ret = av_buffersink_get_frame_flags(_filter_ctx_sink, pFrame_out, 0 );
    87. if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
    88. {
    89. //printf("%d %d \n",AVERROR(EAGAIN),AVERROR_EOF);
    90. }
    91. if (ret < 0)
    92. {
    93. printf("Mixer: failed to call av_buffersink_get_frame_flags ret : %d \n",ret);
    94. break;
    95. }
    96. if (pFrame_out->data[0] != NULL)
    97. {
    98. av_init_packet(&packet_out);
    99. packet_out.data = NULL;
    100. packet_out.size = 0;
    101. ret = avcodec_encode_audio2(_fmt_ctx_out->streams[_index_a_out]->codec, &packet_out, pFrame_out, &got_packet_ptr);
    102. if (ret < 0)
    103. {
    104. printf("Mixer: failed to call avcodec_decode_audio4\n");
    105. break;
    106. }
    107. if (got_packet_ptr)
    108. {
    109. packet_out.stream_index = _index_a_out;
    110. packet_out.pts = frame_count * _fmt_ctx_out->streams[_index_a_out]->codec->frame_size;
    111. packet_out.dts = packet_out.pts;
    112. packet_out.duration = _fmt_ctx_out->streams[_index_a_out]->codec->frame_size;
    113. packet_out.pts = av_rescale_q_rnd(packet_out.pts,
    114. _fmt_ctx_out->streams[_index_a_out]->codec->time_base,
    115. _fmt_ctx_out->streams[_index_a_out]->time_base,
    116. (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    117. packet_out.dts = packet_out.pts;
    118. packet_out.duration = av_rescale_q_rnd(packet_out.duration,
    119. _fmt_ctx_out->streams[_index_a_out]->codec->time_base,
    120. _fmt_ctx_out->streams[_index_a_out]->time_base,
    121. (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    122. frame_count++;
    123. ret = av_interleaved_write_frame(_fmt_ctx_out, &packet_out);
    124. if (ret < 0)
    125. {
    126. printf("Mixer: failed to call av_interleaved_write_frame\n");
    127. }
    128. //printf("Mixer: write frame to file\n");
    129. }
    130. av_free_packet(&packet_out);
    131. }
    132. av_frame_free(&pFrame_out);
    133. }
    134. }
    135. else
    136. {
    137. tmpFifoFailed++;
    138. usleep(20*1000);
    139. if (tmpFifoFailed > 300)
    140. {
    141. _state = STOPPED;
    142. usleep(30*1000);
    143. break;
    144. }
    145. }
    146. av_frame_free(&pFrame_spk);
    147. av_frame_free(&pFrame_mic);
    148. }
    149. }

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

  • 相关阅读:
    MySQL学习记录(7)SQL优化
    学生信息系统(python实现)
    easyswoole 数据库相关操作集合大复盘
    阳离子卟啉化合物修饰氯甲基化交联/聚乙烯基吡啶阳离子功能化聚苯乙烯微球的研究
    java多功能手机
    【八大经典排序算法】堆排序
    如何定制.NET6.0的日志记录
    《Linux篇》超详细安装FinalShell并连接Linux教程
    互联网摸鱼日报(2023-09-04)
    2022中国眼博会,中国北京国际儿童青少年眼睛健康产业展览会
  • 原文地址:https://blog.csdn.net/m0_60259116/article/details/126587665