From fbc5a4102f750fd6ce88d66fdb75be503c3adc6b Mon Sep 17 00:00:00 2001 From: "yu.dongliang" <18588496441@163.com> Date: Sat, 15 Apr 2023 12:20:07 +0800 Subject: [PATCH] ffmpeg_alsa: add output filter --- simp.h | 5 ++ simp_ffmpeg_alsa.c | 125 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/simp.h b/simp.h index cf706c6..372d95f 100644 --- a/simp.h +++ b/simp.h @@ -55,11 +55,16 @@ typedef struct { AVAudioFifo* afifo; + AVFilterContext* obuffersrc_ctx; + AVFilterContext* obuffersink_ctx; + AVFilterGraph* ograph; + int idx_in; int idx_out; AVFrame* iframe; AVFrame* oframe; + AVFrame* fframe; AVPacket* ipkt; AVPacket* opkt; diff --git a/simp_ffmpeg_alsa.c b/simp_ffmpeg_alsa.c index 214c379..794bf58 100644 --- a/simp_ffmpeg_alsa.c +++ b/simp_ffmpeg_alsa.c @@ -1,6 +1,95 @@ #include"simp_ffmpeg.h" #include"scf_def.h" +static int _output_filter_init(simp_audio_t* priv) +{ + char args[512]; + int ret = 0; + + const AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); + const AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); + + AVFilterInOut *outputs = NULL; + AVFilterInOut *inputs = NULL; + + const char *afilters_descr = "[in]aresample=44100[out]"; + + priv->ograph = avfilter_graph_alloc(); + if (!priv->ograph) { + ret = -ENOMEM; + goto end; + } + + snprintf(args, sizeof(args), + "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=%#x", + 1, 44100, 44100, + av_get_sample_fmt_name(AV_SAMPLE_FMT_FLTP), + AV_CH_LAYOUT_STEREO); + + printf("%s\n", args); + + ret = avfilter_graph_create_filter(&priv->obuffersrc_ctx, abuffersrc, "in", args, NULL, priv->ograph); + if (ret < 0) + goto end; + + outputs = avfilter_inout_alloc(); + if (!outputs) { + ret = -ENOMEM; + goto end; + } + + outputs->name = av_strdup("in"); + outputs->filter_ctx = priv->obuffersrc_ctx; + outputs->pad_idx = 0; + outputs->next = NULL; + + const enum AVSampleFormat sample_fmts[] = {priv->codec_out->sample_fmt, -1}; + const int sample_rates[] = {priv->codec_out->sample_rate, -1}; + const int64_t layouts[] = {priv->codec_out->channel_layout, -1}; + + ret = avfilter_graph_create_filter(&priv->obuffersink_ctx, abuffersink, "out", NULL, NULL, priv->ograph); + if (ret < 0) + goto end; + + inputs = avfilter_inout_alloc(); + if (!inputs) { + ret = -ENOMEM; + goto end; + } + + inputs->name = av_strdup("out"); + inputs->filter_ctx = priv->obuffersink_ctx; + inputs->pad_idx = 0; + inputs->next = NULL; + + ret = av_opt_set_int_list(priv->obuffersink_ctx, "sample_fmts", sample_fmts, -1, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto end; + + ret = av_opt_set_int_list(priv->obuffersink_ctx, "channel_layouts", layouts, -1, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto end; + + ret = av_opt_set_int_list(priv->obuffersink_ctx, "sample_rates", sample_rates, -1, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto end; + + if ((ret = avfilter_graph_parse_ptr(priv->ograph, afilters_descr, &inputs, &outputs, NULL)) < 0) { + scf_loge("\n"); + goto end; + } + + if ((ret = avfilter_graph_config(priv->ograph, NULL)) < 0) { + scf_loge("\n"); + goto end; + } + +end: + avfilter_inout_free(&inputs); + avfilter_inout_free(&outputs); + return ret; +} + static int _audio_input_init(simp_audio_t* priv, const char* path) { AVInputFormat* in = av_find_input_format("alsa"); @@ -117,10 +206,20 @@ static int _audio_output_init(simp_audio_t* priv, const char* path) return ret; } + ret = _output_filter_init(priv); + if (ret < 0) { + scf_loge("output filter init error, ret: %d, %s\n", ret, av_err2str(ret)); + return ret; + } + priv->afifo = av_audio_fifo_alloc(priv->codec_out->sample_fmt, 2, 1024); if (!priv->afifo) return -ENOMEM; + priv->fframe = av_frame_alloc(); + if (!priv->fframe) + return -ENOMEM; + priv->opkt = av_packet_alloc(); if (!priv->opkt) return -ENOMEM; @@ -154,6 +253,9 @@ void simp_audio_free(simp_audio_t* priv) if (priv->codec_out) avcodec_close(priv->codec_out); + if (priv->ograph) + avfilter_graph_free(&priv->ograph); + if (priv->afifo) av_audio_fifo_free(priv->afifo); @@ -163,6 +265,9 @@ void simp_audio_free(simp_audio_t* priv) if (priv->oframe) av_frame_free(&priv->oframe); + if (priv->fframe) + av_frame_free(&priv->fframe); + if (priv->ipkt) av_packet_free(&priv->ipkt); @@ -251,17 +356,31 @@ static int __output_audio(simp_avio_t* io, AVCodecContext* c, AVPacket* pkt, AVF scf_list_del(&f->list); pthread_mutex_unlock(&io->mutex); - ret = av_audio_fifo_write(priv->afifo, (void**)f->frame->data, f->frame->nb_samples); - scf_logd("priv->aidx: %d, frame->pts: %ld, frame->nb_samples: %d, afifo->size: %d\n", priv->aidx, f->frame->pts, f->frame->nb_samples, av_audio_fifo_size(priv->afifo)); + ret = av_buffersrc_add_frame_flags(priv->obuffersrc_ctx, f->frame, AV_BUFFERSRC_FLAG_KEEP_REF); simp_frame_free(f); f = NULL; - if (ret < 0) return ret; + while (1) { + ret = av_buffersink_get_frame(priv->obuffersink_ctx, priv->fframe); + + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + scf_loge("av_buffersink_get_frame error, ret: %s\n", av_err2str(ret)); + return ret; + } + + ret = av_audio_fifo_write(priv->afifo, (void**)priv->fframe->data, priv->fframe->nb_samples); + av_frame_unref(priv->fframe); + if (ret < 0) + return ret; + } + } else { pthread_mutex_unlock(&io->mutex); } -- 2.25.1