[FFmpeg-devel,v2,0/2] avfilter: add PCM dumping between filters for audio debugging From: Yibo Fang <blueybf...@outlook.com> Subject: [FFmpeg-devel,v2,0/2] avfilter: add PCM dumping between filters for audio debugging Date: Wed, 23 Apr 2025 10:57:00 +0800 Message-Id: <cover.0.2@ffmpeg>
This series adds a debugging feature that lets developers dump raw PCM audio between filters. The data are written to files in a user- selected directory via two new commands: dump_raw_start file=/path/to/dir/ dump_raw_stop Planar audio is automatically interleaved; only audio links are affected. Patch 1/2 implements the feature, patch 2/2 documents it. Regards, Yibo Fang --- From 2df56e74273d477ae27003e0981220749a6b58cf Mon Sep 17 00:00:00 2001 From: Yibo Fang <blueybf...@outlook.com> Date: Wed, 23 Apr 2025 10:58:55 +0800 Subject: [PATCH 1/2] avfilter: add PCM dumping between filters for audio debugging This patch introduces PCM dumping support between AVFilter links, intended for audio debugging and filter-graph inspection. Two filter commands are added: dump_raw_start file=/path/to/output/dir/ dump_raw_stop When dumping is enabled, audio leaving the selected filter output is written to an automatically named file: <src_filter>-<dst_filter>.pcm Planar formats are converted to packed. File descriptors are opened on demand and closed automatically. Works only on audio links. Example (C API): avfilter_process_command(filter, "dump_raw_start", "file=/tmp/", NULL, 0, 0); Signed-off-by: Yibo Fang <blueybf...@outlook.com> --- libavfilter/avfilter.c | 144 +++++++++++++++++++++++++++++++++++++++++ libavfilter/avfilter.h | 5 ++ 2 files changed, 149 insertions(+) diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 64c1075c40..b7034569db 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" @@ return 0; } +/* ---------- PCM dump helpers ---------- */ + +static av_cold void link_uninit_dump_pcm(AVFilterLink *link) +{ + if (link->dump_pcm_fds) { + for (unsigned i = 0; i < link->nb_dump_pcm_fds; i++) + if (link->dump_pcm_fds[i] >= 0) + close(link->dump_pcm_fds[i]); + av_freep(&link->dump_pcm_fds); + link->nb_dump_pcm_fds = 0; + } + av_freep(&link->dump_pcm_path); + link->dump_pcm = 0; +} + +static av_cold int link_init_dump_pcm(AVFilterLink *link) +{ + /* build full path "<dir>/<src>-<dst>.pcm" */ + const char *dir = link->dump_pcm_path; + const char *sep = dir[strlen(dir) - 1] == '/' ? "" : "/"; + char path[4096]; + snprintf(path, sizeof(path), "%s%s%.16s-%.8s.pcm", + dir, sep, link->src->name, link->dst->name); + + link->nb_dump_pcm_fds = 1; + link->dump_pcm_fds = av_malloc(sizeof(int)); + if (!link->dump_pcm_fds) + return AVERROR(ENOMEM); + + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644); + if (fd < 0) { + link_uninit_dump_pcm(link); + return AVERROR(errno); + } + link->dump_pcm_fds[0] = fd; + av_log(link->dst, AV_LOG_INFO, "PCM dump file: %s\n", path); + return 0; +} + +static int filter_set_dump_pcm(AVFilterContext *f, const char *arg, int set) +{ + const char *prefix = "file="; + if (!arg || av_strncasecmp(arg, prefix, strlen(prefix))) { + av_log(f, AV_LOG_ERROR, + "dump_raw_* expects argument file=/dir/\n"); + return AVERROR(EINVAL); + } + const char *dir = arg + strlen(prefix); + + for (int i = 0; i < f->nb_outputs; i++) { + AVFilterLink *l = f->outputs[i]; + if (l->type != AVMEDIA_TYPE_AUDIO) + continue; + if (set) { + av_freep(&l->dump_pcm_path); + l->dump_pcm_path = av_strdup(dir); + if (!l->dump_pcm_path) + return AVERROR(ENOMEM); + l->dump_pcm = 1; + } else + link_uninit_dump_pcm(l); + } + return 0; +} + +/* write one frame */ +static int link_dump_frame(AVFilterLink *link, AVFrame *frame) +{ + int ret; + if (!link->dump_pcm_fds && + (ret = link_init_dump_pcm(link)) < 0) + return ret; + + const int ch = frame->ch_layout.nb_channels; + const int bps = av_get_bytes_per_sample(frame->format); + const int ns = frame->nb_samples; + const int totlen = ch * ns * bps; + + /* interleave planar to packed if necessary */ + if (av_sample_fmt_is_planar(frame->format)) { + uint8_t *buf = av_malloc(totlen); + if (!buf) + return AVERROR(ENOMEM); + for (int s = 0; s < ns; s++) + for (int c = 0; c < ch; c++) + memcpy(buf + (s*ch + c)*bps, + (uint8_t*)frame->extended_data[c] + s*bps, + bps); + ret = write(link->dump_pcm_fds[0], buf, totlen); + av_free(buf); + } else + ret = write(link->dump_pcm_fds[0], frame->data[0], totlen); + + if (ret < 0) { + av_log(link->dst, AV_LOG_ERROR, "PCM dump write failed: %s\n", + av_err2str(ret)); + link_uninit_dump_pcm(link); + return ret; + } + return 0; +} + static void link_free(AVFilterLink **link) { @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags) { @@ - if (res == local_res) - av_log(filter, AV_LOG_INFO, "%s", res); - return 0; + 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); @@ /* ... existing code ... */ + 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, + "PCM dump failed with %s\n", av_err2str(ret)); + } + li->frame_blocked_in = li->frame_wanted_out = 0; @@ diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index a89d3cf658..0d4c91bb6b 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ AVChannelLayout ch_layout; ///< channel layout of current buffer + int dump_pcm; ///< enable dumping on this link + int *dump_pcm_fds; ///< one FD per link (currently 1) + unsigned nb_dump_pcm_fds; ///< number of FDs + char *dump_pcm_path; ///< user-supplied directory + /** * Define the time base used by the PTS of the frames/samples * which will pass through this link. -- 2.34.1 --- From 8cf7bfa52a10be87e0f17b9783159b0e83f960f7 Mon Sep 17 00:00:00 2001 From: Yibo Fang <blueybf...@outlook.com> Date: Wed, 23 Apr 2025 12:38:00 +0800 Subject: [PATCH 2/2] doc/filters: document dump_raw_start and dump_raw_stop commands Signed-off-by: Yibo Fang <blueybf...@outlook.com> --- doc/filters.texi | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/doc/filters.texi b/doc/filters.texi index 45b3e03e5e..6a2d23df3f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ @section adumppcm Dump raw PCM audio data for debugging between filters. This filter allows writing raw audio data to disk from any audio link in the filtergraph for inspection. It supports planar and packed formats, automatically interleaving planar data for writing. @subsection Syntax @example dump_raw_start=file=/your/dump/directory/ @end example @subsection Usage To enable dumping, use the @code{dump_raw_start} command: @example ffmpeg -i input.wav -af "volume,asendcmd='0.0 dump_raw_start file=/tmp/pcm/'" -f null - @end example To stop dumping: @example asendcmd='5.0 dump_raw_stop' @end example @subsection Options @table @option @item file Specify a directory path (not a filename) where PCM data will be dumped. The dumped file is named @code{<src>-<dst>.pcm} and will be overwritten if it already exists. @end table -- 2.34.1 ________________________________ From: Fang Yibo <blueybf...@outlook.com> Sent: 26 May 2025 15:43 To: ffmpeg-devel@ffmpeg.org <ffmpeg-devel@ffmpeg.org> Subject: 回复: [FFmpeg-devel] [PATCH] avfilter: add PCM dumping between filters for audio debugging Re: [FFmpeg-devel,v2,0/2] avfilter: add PCM dumping between filters for audio debugging From: Yibo Fang <blueybf...@outlook.com> Subject: [FFmpeg-devel,v2,0/2] avfilter: add PCM dumping between filters for audio debugging Date: Wed, 23 Apr 2025 10:57:00 +0800 Message-Id: <cover.0.2@ffmpeg> This series adds a debugging feature that lets developers dump raw PCM audio between filters. The data are written to files in a user- selected directory via two new commands: dump_raw_start file=/path/to/dir/ dump_raw_stop Planar audio is automatically interleaved; only audio links are affected. Patch 1/2 implements the feature, patch 2/2 documents it. Regards, Yibo Fang --- From 2df56e74273d477ae27003e0981220749a6b58cf Mon Sep 17 00:00:00 2001 From: Yibo Fang <blueybf...@outlook.com> Date: Wed, 23 Apr 2025 10:58:55 +0800 Subject: [PATCH 1/2] avfilter: add PCM dumping between filters for audio debugging This patch introduces PCM dumping support between AVFilter links, intended for audio debugging and filter-graph inspection. Two filter commands are added: dump_raw_start file=/path/to/output/dir/ dump_raw_stop When dumping is enabled, audio leaving the selected filter output is written to an automatically named file: <src_filter>-<dst_filter>.pcm Planar formats are converted to packed. File descriptors are opened on demand and closed automatically. Works only on audio links. Example (C API): avfilter_process_command(filter, "dump_raw_start", "file=/tmp/", NULL, 0, 0); Signed-off-by: Yibo Fang <blueybf...@outlook.com> --- libavfilter/avfilter.c | 144 +++++++++++++++++++++++++++++++++++++++++ libavfilter/avfilter.h | 5 ++ 2 files changed, 149 insertions(+) diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 64c1075c40..b7034569db 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" @@ return 0; } +/* ---------- PCM dump helpers ---------- */ + +static av_cold void link_uninit_dump_pcm(AVFilterLink *link) +{ + if (link->dump_pcm_fds) { + for (unsigned i = 0; i < link->nb_dump_pcm_fds; i++) + if (link->dump_pcm_fds[i] >= 0) + close(link->dump_pcm_fds[i]); + av_freep(&link->dump_pcm_fds); + link->nb_dump_pcm_fds = 0; + } + av_freep(&link->dump_pcm_path); + link->dump_pcm = 0; +} + +static av_cold int link_init_dump_pcm(AVFilterLink *link) +{ + /* build full path "<dir>/<src>-<dst>.pcm" */ + const char *dir = link->dump_pcm_path; + const char *sep = dir[strlen(dir) - 1] == '/' ? "" : "/"; + char path[4096]; + snprintf(path, sizeof(path), "%s%s%.16s-%.8s.pcm", + dir, sep, link->src->name, link->dst->name); + + link->nb_dump_pcm_fds = 1; + link->dump_pcm_fds = av_malloc(sizeof(int)); + if (!link->dump_pcm_fds) + return AVERROR(ENOMEM); + + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644); + if (fd < 0) { + link_uninit_dump_pcm(link); + return AVERROR(errno); + } + link->dump_pcm_fds[0] = fd; + av_log(link->dst, AV_LOG_INFO, "PCM dump file: %s\n", path); + return 0; +} + +static int filter_set_dump_pcm(AVFilterContext *f, const char *arg, int set) +{ + const char *prefix = "file="; + if (!arg || av_strncasecmp(arg, prefix, strlen(prefix))) { + av_log(f, AV_LOG_ERROR, + "dump_raw_* expects argument file=/dir/\n"); + return AVERROR(EINVAL); + } + const char *dir = arg + strlen(prefix); + + for (int i = 0; i < f->nb_outputs; i++) { + AVFilterLink *l = f->outputs[i]; + if (l->type != AVMEDIA_TYPE_AUDIO) + continue; + if (set) { + av_freep(&l->dump_pcm_path); + l->dump_pcm_path = av_strdup(dir); + if (!l->dump_pcm_path) + return AVERROR(ENOMEM); + l->dump_pcm = 1; + } else + link_uninit_dump_pcm(l); + } + return 0; +} + +/* write one frame */ +static int link_dump_frame(AVFilterLink *link, AVFrame *frame) +{ + int ret; + if (!link->dump_pcm_fds && + (ret = link_init_dump_pcm(link)) < 0) + return ret; + + const int ch = frame->ch_layout.nb_channels; + const int bps = av_get_bytes_per_sample(frame->format); + const int ns = frame->nb_samples; + const int totlen = ch * ns * bps; + + /* interleave planar to packed if necessary */ + if (av_sample_fmt_is_planar(frame->format)) { + uint8_t *buf = av_malloc(totlen); + if (!buf) + return AVERROR(ENOMEM); + for (int s = 0; s < ns; s++) + for (int c = 0; c < ch; c++) + memcpy(buf + (s*ch + c)*bps, + (uint8_t*)frame->extended_data[c] + s*bps, + bps); + ret = write(link->dump_pcm_fds[0], buf, totlen); + av_free(buf); + } else + ret = write(link->dump_pcm_fds[0], frame->data[0], totlen); + + if (ret < 0) { + av_log(link->dst, AV_LOG_ERROR, "PCM dump write failed: %s\n", + av_err2str(ret)); + link_uninit_dump_pcm(link); + return ret; + } + return 0; +} + static void link_free(AVFilterLink **link) { @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags) { @@ - if (res == local_res) - av_log(filter, AV_LOG_INFO, "%s", res); - return 0; + 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); @@ /* ... existing code ... */ + 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, + "PCM dump failed with %s\n", av_err2str(ret)); + } + li->frame_blocked_in = li->frame_wanted_out = 0; @@ diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index a89d3cf658..0d4c91bb6b 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ AVChannelLayout ch_layout; ///< channel layout of current buffer + int dump_pcm; ///< enable dumping on this link + int *dump_pcm_fds; ///< one FD per link (currently 1) + unsigned nb_dump_pcm_fds; ///< number of FDs + char *dump_pcm_path; ///< user-supplied directory + /** * Define the time base used by the PTS of the frames/samples * which will pass through this link. -- 2.34.1 --- From 8cf7bfa52a10be87e0f17b9783159b0e83f960f7 Mon Sep 17 00:00:00 2001 From: Yibo Fang <blueybf...@outlook.com> Date: Wed, 23 Apr 2025 12:38:00 +0800 Subject: [PATCH 2/2] doc/filters: document dump_raw_start and dump_raw_stop commands Signed-off-by: Yibo Fang <blueybf...@outlook.com> --- doc/filters.texi | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/doc/filters.texi b/doc/filters.texi index 45b3e03e5e..6a2d23df3f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ @section adumppcm Dump raw PCM audio data for debugging between filters. This filter allows writing raw audio data to disk from any audio link in the filtergraph for inspection. It supports planar and packed formats, automatically interleaving planar data for writing. @subsection Syntax @example dump_raw_start=file=/your/dump/directory/ @end example @subsection Usage To enable dumping, use the @code{dump_raw_start} command: @example ffmpeg -i input.wav -af "volume,asendcmd='0.0 dump_raw_start file=/tmp/pcm/'" -f null - @end example To stop dumping: @example asendcmd='5.0 dump_raw_stop' @end example @subsection Options @table @option @item file Specify a directory path (not a filename) where PCM data will be dumped. The dumped file is named @code{<src>-<dst>.pcm} and will be overwritten if it already exists. @end table -- 2.34.1 ________________________________ From: ffmpeg-devel <ffmpeg-devel-boun...@ffmpeg.org> on behalf of Andreas Rheinhardt <andreas.rheinha...@outlook.com> Sent: 26 April 2025 3:00 To: ffmpeg-devel@ffmpeg.org <ffmpeg-devel@ffmpeg.org> Subject: Re: [FFmpeg-devel] [PATCH] avfilter: add PCM dumping between filters for audio debugging 一只大 肥猫: > 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". _______________________________________________ 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".