[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".

Reply via email to