[FFmpeg-devel] [PATCH 1/2] lavf: add infodump muxer.

Nicolas George george at nsup.org
Thu Apr 17 14:47:21 CEST 2014


Signed-off-by: Nicolas George <george at nsup.org>
---
 doc/muxers.texi           |    8 ++
 libavformat/Makefile      |    1 +
 libavformat/allformats.c  |    1 +
 libavformat/infodumpenc.c |  182 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 192 insertions(+)
 create mode 100644 libavformat/infodumpenc.c


The existing testing muxers do not take extradata and attachments into
account. Nor do they test metadata, for that matter.


diff --git a/doc/muxers.texi b/doc/muxers.texi
index d9596eb..405609b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -360,6 +360,14 @@ each of the YUV420P components. To read or write this image file format,
 specify the name of the '.Y' file. The muxer will automatically open the
 '.U' and '.V' files as required.
 
+ at section infodump
+
+Technical information dump testing format.
+
+This muxer prints technical information about the format, streams and
+packets. The format is meant to be compact and robust, and therefore
+suitable for use in test suites.
+
 @section matroska
 
 Matroska container muxer.
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 3c69219..399255e 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -186,6 +186,7 @@ OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER)        += img2dec.o img2.o
 OBJS-$(CONFIG_IMAGE2PIPE_MUXER)          += img2enc.o img2.o
 OBJS-$(CONFIG_IMAGE2_ALIAS_PIX_DEMUXER)  += img2_alias_pix.o
 OBJS-$(CONFIG_IMAGE2_BRENDER_PIX_DEMUXER) += img2_brender_pix.o
+OBJS-$(CONFIG_INFODUMP_MUXER)            += infodumpenc.o
 OBJS-$(CONFIG_INGENIENT_DEMUXER)         += ingenientdec.o rawdec.o
 OBJS-$(CONFIG_IPMOVIE_DEMUXER)           += ipmovie.o
 OBJS-$(CONFIG_IRCAM_DEMUXER)             += ircamdec.o ircam.o pcm.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 72f2ef2..447e6fc 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -149,6 +149,7 @@ void av_register_all(void)
     REGISTER_MUXDEMUX(IMAGE2PIPE,       image2pipe);
     REGISTER_DEMUXER (IMAGE2_ALIAS_PIX, image2_alias_pix);
     REGISTER_DEMUXER (IMAGE2_BRENDER_PIX, image2_brender_pix);
+    REGISTER_MUXER   (INFODUMP,         infodump);
     REGISTER_DEMUXER (INGENIENT,        ingenient);
     REGISTER_DEMUXER (IPMOVIE,          ipmovie);
     REGISTER_MUXER   (IPOD,             ipod);
diff --git a/libavformat/infodumpenc.c b/libavformat/infodumpenc.c
new file mode 100644
index 0000000..141dd39
--- /dev/null
+++ b/libavformat/infodumpenc.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2014 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/hash.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timestamp.h"
+#include "avformat.h"
+#include "internal.h"
+
+static void print_escaped(AVIOContext *pb, const uint8_t *str, uint8_t extra)
+{
+    for (; *str; str++) {
+        if ((unsigned)(*str - ' ') < 95) {
+            if (*str == '\\' || *str == extra)
+                avio_w8(pb, '\\');
+            avio_w8(pb, *str);
+        } else {
+            avio_printf(pb, "\\x%02X", *str);
+        }
+    }
+}
+
+static void print_metadata(AVFormatContext *s, unsigned indent, const char *tag,
+                           AVDictionary *m)
+{
+    AVDictionaryEntry *e = NULL;
+
+    if (!m)
+        return;
+    if (tag) {
+        avio_printf(s->pb, "%*s%s:\n", indent, "", tag);
+        indent += 2;
+    }
+    while ((e = av_dict_get(m, "", e, AV_DICT_IGNORE_SUFFIX))) {
+        avio_printf(s->pb, "%*s", indent, "");
+        print_escaped(s->pb, e->key, '=');
+        avio_printf(s->pb, "=");
+        print_escaped(s->pb, e->value, 0);
+        avio_printf(s->pb, "\n");
+    }
+}
+
+static void print_bin_internal(AVIOContext *pb,
+                               const uint8_t *data, int size,
+                               struct AVHashContext **h)
+{
+    uint8_t buf[AV_HASH_MAX_SIZE];
+    int ret = av_hash_alloc(h, "adler32");
+    unsigned i, len;
+
+    if (ret < 0) {
+        avio_printf(pb, " (ERROR)");
+        pb->error = ret;
+        return;
+    }
+    len = av_hash_get_size(*h);
+    if (len > sizeof(buf)) {
+        avio_printf(pb, " (HASH-TOO-LONG)");
+        return;
+    }
+    av_hash_init(*h);
+    av_hash_update(*h, data, size);
+    av_hash_final(*h, buf);
+    avio_printf(pb, " (%s:", av_hash_get_name(*h));
+    for (i = 0; i < len; i++)
+        avio_printf(pb, "%02x", buf[i]);
+    avio_w8(pb, ')');
+}
+
+static void print_bin(AVIOContext *pb, const char *tag,
+                      const uint8_t *data, int size)
+{
+    struct AVHashContext *h = NULL;
+
+    avio_printf(pb, "%s:%d", tag, size);
+    if (size > 0)
+        print_bin_internal(pb, data, size, &h);
+    av_hash_freep(&h);
+    avio_w8(pb, '\n');
+}
+
+static int infodump_write_header(AVFormatContext *s)
+{
+    unsigned i;
+
+    avio_printf(s->pb, "ffmpeg infodump version 1.0\n");
+    if (s->bit_rate)
+        avio_printf(s->pb, "bitrate:%d\n", s->bit_rate);
+    print_metadata(s, 0, "global metadata", s->metadata);
+    for (i = 0; i < s->nb_chapters; i++) {
+        AVChapter *c = s->chapters[i];
+        avio_printf(s->pb,
+                    "chapter id:0x%x tb:%d/%d start:%"PRIi64" end:%"PRIi64"\n",
+                    c->id, c->time_base.num, c->time_base.den,
+                    c->start, c->end);
+        print_metadata(s, 2, NULL, c->metadata);
+    }
+    /* TODO programs */
+    for (i = 0; i < s->nb_streams; i++) {
+        AVStream *st = s->streams[i];
+        AVCodecContext *c = st->codec;
+        const AVCodecDescriptor *cd = avcodec_descriptor_get(c->codec_id);
+        avpriv_set_pts_info(st, 64,
+                            st->codec->time_base.num,
+                            st->codec->time_base.den);
+        avio_printf(s->pb,
+                    "stream id:%x tb:%d/%d sar:%d/%d afps:%d/%d rfps:%d/%d\n",
+                    st->id, st->time_base.num, st->time_base.den,
+                    st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
+                    st->avg_frame_rate.num, st->avg_frame_rate.den,
+                    st->r_frame_rate.num, st->r_frame_rate.den);
+        /* TODO disposition attached_pic side_data */
+        avio_printf(s->pb, "  codec type:%s id:%x",
+                    av_get_media_type_string(c->codec_type), c->codec_id);
+        if (cd)
+            avio_printf(s->pb, " (%s)", cd->name);
+        avio_printf(s->pb, "\n");
+        switch (c->codec_type) {
+        case AVMEDIA_TYPE_VIDEO:
+            avio_printf(s->pb, "  video %dx%d %s\n", c->width, c->height,
+                        av_x_if_null(av_get_pix_fmt_name(c->pix_fmt), "unk"));
+            break;
+        case AVMEDIA_TYPE_AUDIO:
+            avio_printf(s->pb, "  audio %dHz %s %dch", c->sample_rate,
+                        av_x_if_null(av_get_sample_fmt_name(c->sample_fmt),
+                                     "unk"),
+                        c->channels);
+            if (c->channel_layout) {
+                char buf[1024];
+                av_get_channel_layout_string(buf, sizeof(buf), -1,
+                                             c->channel_layout);
+                avio_printf(s->pb, " (%s)", buf);
+            }
+            avio_printf(s->pb, "\n");
+            break;
+        }
+        print_bin(s->pb, "  extradata", c->extradata, c->extradata_size);
+        if (c->subtitle_header)
+            print_bin(s->pb, "  subtitle_header",
+                      c->subtitle_header, c->subtitle_header_size);
+        print_metadata(s, 2, "metadata", st->metadata);
+    }
+    return 0;
+}
+
+static int infodump_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    avio_printf(s->pb, "\npacket stream:%d pts:%s dts:%s duration:%d\n",
+                pkt->stream_index,
+                av_ts2str(pkt->pts), av_ts2str(pkt->dts), pkt->duration);
+    print_bin(s->pb, "  data", pkt->data, pkt->size);
+    /* TODO side_data convergence_duration */
+    return 0;
+}
+
+AVOutputFormat ff_infodump_muxer = {
+    .name            = "infodump",
+    .long_name       = NULL_IF_CONFIG_SMALL("information dump"),
+    .video_codec     = AV_CODEC_ID_RAWVIDEO,
+    .audio_codec     = AV_CODEC_ID_PCM_S16LE,
+    .write_header    = infodump_write_header,
+    .write_packet    = infodump_write_packet,
+    .flags           = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
+                       AVFMT_TS_NEGATIVE,
+};
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list