一只大 肥猫: > This patch introduces PCM dumping support between AVFilter links, intended > for audio debugging. > > It adds a configure-time option `--dumpdir=PATH` to specify the output > directory for raw PCM data (default: /tmp/). > > Two commands are exposed to control dumping: > - dump_raw_start <dst_filter_name> > - dump_raw_stop <dst_filter_name> > > Dump files are written as: srcname-dstname-channel.pcm > > Supports packed and planar formats. File descriptors are managed > automatically and work only on audio links. > > Example usage: > avfilter_process_command(filter, "dump_raw_start", "volume", NULL, 0, 0); > > This feature helps developers debug filter behavior by inspecting > intermediate audio data. > --- > From 6a31c85afd2800c09076c1e2b7c734c7b719f73d Mon Sep 17 00:00:00 2001 > From: Yibo Fang <blueybf...@outlook.com> > Date: Wed, 23 Apr 2025 09:17:51 +0800 > Subject: [PATCH 1/1] avfilter: add PCM dumping between filters for audio > debugging > > This patch adds the ability to dump raw PCM audio data between AVFilter links. > It introduces a configure-time option `--dumpdir=PATH` to control the output > directory of dump files (default: /tmp/). This feature is helpful for > debugging > filter behavior and verifying audio processing. > > Two filter commands are added: > - dump_raw_start <dst_filter_name> > - dump_raw_stop <dst_filter_name> > > The PCM files are written in the format: srcname-dstname-<channel>.pcm. > > Supports both packed and planar formats. File descriptors are automatically > managed. Works only on audio links. > > Example usage: > avfilter_process_command(filter, "dump_raw_start", "volume", NULL, 0, 0); > > Signed-off-by: Yibo Fang <blueybf...@outlook.com> > --- > configure | 7 +++ > libavfilter/avfilter.c | 110 +++++++++++++++++++++++++++++++++++++++++ > libavfilter/avfilter.h | 4 ++ > 3 files changed, 121 insertions(+) > > diff --git a/configure b/configure > index c94b8eac43..381633749d 100755 > --- a/configure > +++ b/configure > @@ -524,6 +524,7 @@ Developer options (useful when working on FFmpeg itself): > --disable-large-tests disable tests that use a large amount of memory > --disable-ptx-compression don't compress CUDA PTX code even when possible > --disable-version-tracking don't include the git/release version in the > build > + --dumpdir=PATH location of pcm dump files to save. > > NOTE: Object files are built at the place where configure is launched. > EOF > @@ -2690,6 +2691,7 @@ PATHS_LIST=" > prefix > shlibdir > install_name_dir > + dumpdir > " > > CMDLINE_SET=" > @@ -4123,6 +4125,9 @@ incdir_default='${prefix}/include' > libdir_default='${prefix}/lib' > mandir_default='${prefix}/share/man' > > +# runtime path > +dumpdir_default='/tmp/' > + > # toolchain > ar_default="ar" > cc_default="gcc" > @@ -8118,6 +8123,7 @@ DOCDIR=\$(DESTDIR)$docdir > MANDIR=\$(DESTDIR)$mandir > PKGCONFIGDIR=\$(DESTDIR)$pkgconfigdir > INSTALL_NAME_DIR=$install_name_dir > +DUMPDIR=$dumpdir > SRC_PATH=$source_path > SRC_LINK=$source_link > ifndef MAIN_MAKEFILE > @@ -8267,6 +8273,7 @@ cat > $TMPH <<EOF > #define CONFIG_THIS_YEAR 2025 > #define FFMPEG_DATADIR "$(eval c_escape $datadir)" > #define AVCONV_DATADIR "$(eval c_escape $datadir)" > +#define FFMPEG_DUMPDIR "$(eval c_escape $dumpdir)" > #define CC_IDENT "$(c_escape ${cc_ident:-Unknown compiler})" > #define OS_NAME $target_os > #define EXTERN_PREFIX "${extern_prefix}" > diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c > index 64c1075c40..9fc6308544 100644 > --- a/libavfilter/avfilter.c > +++ b/libavfilter/avfilter.c > @@ -19,6 +19,9 @@ > * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > */ > > +#include <fcntl.h> > +#include <unistd.h> > + > #include "libavutil/avassert.h" > #include "libavutil/avstring.h" > #include "libavutil/bprint.h" > @@ -195,6 +198,66 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, > return 0; > } > > +static av_cold void link_uninit_dump_pcm(AVFilterLink *link, int stop) > +{ > + if (link->dump_pcm_fds) { > + int i; > + for (i = 0; i < link->nb_dump_pcm_fds; i++) { > + if (link->dump_pcm_fds[i]) > + close(link->dump_pcm_fds[i]); > + } > + av_free(link->dump_pcm_fds); > + link->dump_pcm_fds = NULL; > + link->nb_dump_pcm_fds = 0; > + } > + > + if (stop) > + link->dump_pcm = 0; > +} > + > +static av_cold int link_init_dump_pcm(AVFilterLink *link) > +{ > + char path[4096]; > + int fd, i; > + > + link->nb_dump_pcm_fds = av_sample_fmt_is_planar(link->format)? > link->ch_layout.nb_channels : 1; > + link->dump_pcm_fds = av_malloc_array(link->nb_dump_pcm_fds, sizeof(int)); > + if (!link->dump_pcm_fds) > + return AVERROR(ENOMEM); > + > + for (i = 0; i < link->nb_dump_pcm_fds; i++) { > + snprintf(path, sizeof(path), FFMPEG_DUMPDIR"%.16s-%.8s-%d.pcm", > link->src->name, link->dst->name, i); > + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); > + if (fd < 0) { > + link_uninit_dump_pcm(link, 1); > + return AVERROR(errno); > + } > + link->dump_pcm_fds[i] = fd; > + } > + > + return 0; > +} > + > +static int filter_set_dump_pcm(AVFilterContext *filter, const char *target, > int set) > +{ > + int i; > + > + for (i = 0; i < filter->nb_outputs; i++) { > + AVFilterLink *link = filter->outputs[i]; > + if (!target || !strcmp(link->dst->name, target)) { > + if (set) { > + link->dump_pcm = 1; > + } else > + link_uninit_dump_pcm(link, 1); > + > + if (target) > + return 0; > + } > + } > + > + return target ? AVERROR(EINVAL) : 0; > +} > + > static void link_free(AVFilterLink **link) > { > FilterLinkInternal *li; > @@ -208,6 +271,8 @@ static void link_free(AVFilterLink **link) > av_channel_layout_uninit(&(*link)->ch_layout); > av_frame_side_data_free(&(*link)->side_data, &(*link)->nb_side_data); > > + link_uninit_dump_pcm(*link, 1); > + > av_buffer_unref(&li->l.hw_frames_ctx); > > av_freep(link); > @@ -617,6 +682,10 @@ int avfilter_process_command(AVFilterContext *filter, > const char *cmd, const cha > if (res == local_res) > av_log(filter, AV_LOG_INFO, "%s", res); > return 0; > + }else if(!strcmp(cmd, "dump_raw_start")) { > + return filter_set_dump_pcm(filter, arg, 1); > + }else if(!strcmp(cmd, "dump_raw_stop")) { > + return filter_set_dump_pcm(filter, arg, 0); > }else if(!strcmp(cmd, "enable")) { > return set_enable_expr(fffilterctx(filter), arg); > }else if (fffilter(filter->filter)->process_command) { > @@ -1050,6 +1119,41 @@ fail: > return ret; > } > > +static int link_dump_frame(AVFilterLink *link, AVFrame *frame) > +{ > + int samples_size, ret; > + > + if (!link->dump_pcm_fds) { > + ret = link_init_dump_pcm(link); > + if (ret < 0) > + return ret; > + } > + > + samples_size = av_get_bytes_per_sample(frame->format) * > frame->nb_samples; > + if (av_sample_fmt_is_planar(frame->format)) { > + int i; > + for (i = 0; i < link->nb_dump_pcm_fds && i < > frame->ch_layout.nb_channels; i++) { > + if (i < AV_NUM_DATA_POINTERS) { > + ret = write(link->dump_pcm_fds[i], frame->data[i], > samples_size); > + } else > + ret = write(link->dump_pcm_fds[i], frame->extended_data[i - > AV_NUM_DATA_POINTERS], samples_size); > + > + if (ret < 0) > + goto err; > + } > + } else { > + ret = write(link->dump_pcm_fds[0], frame->data[0], samples_size * > frame->ch_layout.nb_channels); > + if (ret < 0) > + goto err; > + > + } > + > + return 0; > +err: > + link_uninit_dump_pcm(link, 1); > + return AVERROR(errno); > +} > + > int ff_filter_frame(AVFilterLink *link, AVFrame *frame) > { > FilterLinkInternal * const li = ff_link_internal(link); > @@ -1087,6 +1191,12 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) > link->time_base); > } > > + if (link->dump_pcm && link->type == AVMEDIA_TYPE_AUDIO) { > + ret = link_dump_frame(link, frame); > + if (ret < 0) > + av_log(link->dst, AV_LOG_ERROR, "Dump pcm files failed with > %d\n", ret); > + } > + > li->frame_blocked_in = li->frame_wanted_out = 0; > li->l.frame_count_in++; > li->l.sample_count_in += frame->nb_samples; > diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h > index a89d3cf658..6d04b9da77 100644 > --- a/libavfilter/avfilter.h > +++ b/libavfilter/avfilter.h > @@ -404,6 +404,10 @@ struct AVFilterLink { > int sample_rate; ///< samples per second > AVChannelLayout ch_layout; ///< channel layout of current buffer (see > libavutil/channel_layout.h) > > + int dump_pcm; ///< flag to dump pcm > + int *dump_pcm_fds; ///< dump files > + unsigned nb_dump_pcm_fds; ///< number of dump file > + > /** > * Define the time base used by the PTS of the frames/samples > * which will pass through this link. > -- > 2.34.1 >
Can't you use the asplit filter to duplicate the audio? - Andreas _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".