ffmpeg4教程10:avfilter混音處理


基於vs2017 vc++  ffmpeg4.0.2下測試

ffmpeg 環境配置請百度(vs2017 ffmpeg ) 

主要是先將音頻avframe採集到隊列或鏈表裏,再通過

av_buffersrc_add_frame添加多幀取出就是混音的貼出filter初始化的

字符串[in0][in1]amix=inputs=2[out] 

其他的像寫入空聲音啥的請進羣交流(討論羣261074724)或查看前面的教程 


int InitFilter(const char* filter_desc, VideoState1 *pVideo)
{
    char args[512], pad_name[20];
    int ret = 0, anum = 2;
    /*static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16 ,AV_SAMPLE_FMT_NONE };
    static const uint8_t out_channel_layouts[] = { AV_CH_LAYOUT_STEREO, -1 };
    static const uint8_t out_sample_rates[] = { 44100 };*/

    const AVFilter** buffersrc = (const AVFilter**)av_malloc(anum * sizeof(AVFilter**));
    const AVFilter* buffersink = avfilter_get_by_name("abuffersink");
    AVFilterInOut   **outputs = (AVFilterInOut**)av_malloc(anum * sizeof(AVFilterInOut*));
    AVFilterInOut* filter_input = avfilter_inout_alloc();
    AVFilterGraph *_filter_graph = avfilter_graph_alloc();
    for (int i = 0; i < anum; i++)
    {
        buffersrc[i] = avfilter_get_by_name("abuffer");
        outputs[i] = avfilter_inout_alloc();
        pVideo[i].filter_ctx_sink = NULL;
    }
    /* buffer video source: the decoded frames from the decoder will be inserted here. */
    if (!buffersrc || !buffersink) {
        av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }
    for (int i = 0; i < anum; i++) {
        snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
            pVideo[i].pInputFormatCtx->streams[pVideo[i].audioIndex]->time_base.num,
            pVideo[i].pInputFormatCtx->streams[pVideo[i].audioIndex]->time_base.den,
            pVideo[i].pInputFormatCtx->streams[pVideo[i].audioIndex]->codecpar->sample_rate,
            av_get_sample_fmt_name((AVSampleFormat)pVideo[i].pInputFormatCtx->streams[pVideo[i].audioIndex]->codecpar->format),
            pVideo[i].pInputFormatCtx->streams[pVideo[i].audioIndex]->codecpar->channel_layout);
        snprintf(pad_name, sizeof(pad_name), "in%d", i + 1);
        ret = avfilter_graph_create_filter(&pVideo[i].buffersrc_ctx, buffersrc[i], pad_name, args, NULL, _filter_graph);
        if (ret < 0)
        {
            printf("Filter: failed to call avfilter_graph_create_filter -- src mic\n");
            return -1;
        }
    }
    ret = avfilter_graph_create_filter(&pVideo[0].filter_ctx_sink, buffersink, "out", NULL, NULL, _filter_graph);
    if (ret < 0)
    {
        printf("Filter: failed to call avfilter_graph_create_filter -- sink\n");
        return -1;
    }

    ret = av_opt_set_bin(pVideo[0].filter_ctx_sink, "sample_fmts", (uint8_t*)&pVideo[0].des_sampleFormat, sizeof(pVideo[0].des_sampleFormat), AV_OPT_SEARCH_CHILDREN);
    if (ret < 0)
    {
        printf("Filter: failed to call av_opt_set_bin -- sample_fmts\n");
        return -1;
    }

    ret = av_opt_set_bin(pVideo[0].filter_ctx_sink, "channel_layouts", (uint8_t*)&pVideo[0].des_channel_layout, sizeof(pVideo[0].des_channel_layout), AV_OPT_SEARCH_CHILDREN);
    if (ret < 0)
    {
        printf("Filter: failed to call av_opt_set_bin -- channel_layouts\n");
        return -1;
    }
    ret = av_opt_set_bin(pVideo[0].filter_ctx_sink, "sample_rates", (uint8_t*)&pVideo[0].des_samplerate, sizeof(pVideo[0].des_samplerate), AV_OPT_SEARCH_CHILDREN);
    if (ret < 0)
    {
        printf("Filter: failed to call av_opt_set_bin -- sample_rates\n");
        return -1;
    }

    for (int i = 0; i < anum; i++)
    {
        snprintf(pad_name, sizeof(pad_name), "in%d", i);
        outputs[i]->name = av_strdup(pad_name);
        outputs[i]->filter_ctx = pVideo[i ].buffersrc_ctx;
        outputs[i]->pad_idx = 0;
        if (i == anum - 1)
            outputs[i]->next = NULL;
        else
            outputs[i]->next = outputs[i + 1];
    } 

    filter_input->name = av_strdup("out");
    filter_input->filter_ctx = pVideo[0].filter_ctx_sink;
    filter_input->pad_idx = 0;
    filter_input->next = NULL;
     
    ret = avfilter_graph_parse_ptr(_filter_graph, filter_desc, &filter_input, outputs, NULL);
    if (ret < 0)
    {
        printf("Filter: failed to call avfilter_graph_parse_ptr\n");
        return -1;
    } 
    ret = avfilter_graph_config(_filter_graph, NULL);
    if (ret < 0)
    {
        printf("Filter: failed to call avfilter_graph_config\n");
        return -1;
    }

end:
    avfilter_inout_free(&filter_input);
    for (int i = 0; i < anum; i++) {
        av_free(pVideo[i].buffersrc_ctx);
    }
 
    avfilter_inout_free(outputs);
    //av_free(filter_outputs);

    char* temp = avfilter_graph_dump(_filter_graph, NULL);
    printf("%s\n", temp);
     
    //Output: srate:44100Hz fmt:s16 chlayout:stereo
    return 0;
}
採集的視頻可以保存pcm 、aac、rmtp、或者用PortAudio播放都是可以的

(討論羣261074724)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章