[FFmpeg-devel] [PATCH 9/9] lavf: add attachment pseudo-demuxer.

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


TODO changelog version bump

Signed-off-by: Nicolas George <george at nsup.org>
---
 doc/demuxers.texi           |   35 ++++++++++++
 libavformat/Makefile        |    1 +
 libavformat/allformats.c    |    1 +
 libavformat/attachmentdec.c |  133 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 170 insertions(+)
 create mode 100644 libavformat/attachmentdec.c

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index f0a14e0..a246bf8 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -40,6 +40,41 @@ This demuxer is used to demux ASF files and MMS network streams.
 Do not try to resynchronize by looking for a certain optional start code.
 @end table
 
+ at section attachment
+
+Attachment pseudo demuxer: this demuxer can read any file as a single
+attachment.
+
+This demuxer accepts the following option:
+
+ at table @option
+
+ at item filename
+The declared file name of the attachment (@code{filename} metadata entry).
+If not set, the base name of the actual input file name is used.
+
+ at item mime_type
+ at item mimetype
+The declared MIME type of the attachment (@code{mimetype} metadata entry).
+If not set, defaults to the MIME type associated to the codec, or
+ at code{application/octet-stream}.
+
+ at item codec
+ at item file_codec
+The detected codec of the attachment.
+If not set, defaults to the codec associated to the MIME type, or binary
+data.
+
+ at end table
+
+Example: attach a font file to a Matroska file:
+ at example
+ffmpeg -i input_raw.ts -i subtitles.ass \
+  -f attachment -file_codec ttf -i /path/to/DejaVuSans.ttf \
+  -map 0:0 -c:v ... -map 0:1 -c:a ... -map 1 -c:s copy -map 2 \
+  output.mkv
+ at end example
+
 @anchor{concat}
 @section concat
 
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 3df5c88..3c69219 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -81,6 +81,7 @@ OBJS-$(CONFIG_ASS_DEMUXER)               += assdec.o subtitles.o
 OBJS-$(CONFIG_ASS_MUXER)                 += assenc.o
 OBJS-$(CONFIG_AST_DEMUXER)               += ast.o astdec.o
 OBJS-$(CONFIG_AST_MUXER)                 += ast.o astenc.o
+OBJS-$(CONFIG_ATTACHMENT_DEMUXER)        += attachmentdec.o
 OBJS-$(CONFIG_AU_DEMUXER)                += au.o pcm.o
 OBJS-$(CONFIG_AU_MUXER)                  += au.o rawenc.o
 OBJS-$(CONFIG_AVI_DEMUXER)               += avidec.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index b5cbbef..72f2ef2 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -79,6 +79,7 @@ void av_register_all(void)
     REGISTER_MUXDEMUX(ASS,              ass);
     REGISTER_MUXDEMUX(AST,              ast);
     REGISTER_MUXER   (ASF_STREAM,       asf_stream);
+    REGISTER_DEMUXER (ATTACHMENT,       attachment);
     REGISTER_MUXDEMUX(AU,               au);
     REGISTER_MUXDEMUX(AVI,              avi);
     REGISTER_DEMUXER (AVISYNTH,         avisynth);
diff --git a/libavformat/attachmentdec.c b/libavformat/attachmentdec.c
new file mode 100644
index 0000000..fab4634
--- /dev/null
+++ b/libavformat/attachmentdec.c
@@ -0,0 +1,133 @@
+/*
+ * 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/avstring.h"
+#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct AttachmentContext {
+    const AVClass *class;
+    char *filename;
+    char *mime_type;
+    char *codec_name;
+} AttachmentContext;
+
+static const AVCodecDescriptor *find_codec_by_mime_type(const char *t)
+{
+    const AVCodecDescriptor *cd = NULL;
+    int i;
+
+    while ((cd = avcodec_descriptor_next(cd))) {
+        if (!cd->mime_types)
+            continue;
+        for (i = 0; cd->mime_types[i]; i++)
+            if (!strcmp(cd->mime_types[i], t))
+                return cd;
+    }
+    return NULL;
+}
+
+static int attachment_read_header(AVFormatContext *s)
+{
+    AttachmentContext *att = s->priv_data;
+    AVStream *st;
+    int64_t size;
+    const AVCodecDescriptor *cd = NULL;
+    const char *filename = att->filename, *mime_type = att->mime_type;
+    int ret;
+
+    size = avio_size(s->pb);
+    if (size <= 0) {
+        av_log(s, AV_LOG_ERROR, "Unknown file size\n");
+        return size < 0 ? size : AVERROR_PATCHWELCOME;
+    }
+    if (size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+        av_log(s, AV_LOG_ERROR, "File is too big (max size %d)\n",
+               INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE);
+        return AVERROR_INVALIDDATA;
+    }
+    if (!(st = avformat_new_stream(s, NULL)))
+        return AVERROR(ENOMEM);
+    if ((ret = ff_get_extradata(st->codec, s->pb, size)) < 0)
+        return ret;
+
+    if (!filename && *s->filename)
+        filename = av_basename(s->filename);
+    if (att->codec_name) {
+        if (!(cd = avcodec_descriptor_get_by_name(att->codec_name))) {
+            av_log(s, AV_LOG_ERROR, "Unknown codec: %s\n", att->codec_name);
+            return AVERROR(EINVAL);
+        }
+    }
+    if (mime_type && !cd)
+        cd = find_codec_by_mime_type(att->mime_type);
+    if (cd && !mime_type && cd->mime_types)
+        mime_type = cd->mime_types[0];
+    if (!mime_type)
+        mime_type = "application/octet-stream";
+
+    st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
+    st->codec->codec_id = cd ? cd->id : AV_CODEC_ID_BIN_DATA;
+    if (filename && *filename)
+        if ((ret = av_dict_set(&st->metadata, "filename", filename, 0)) < 0)
+            return AVERROR(ENOMEM);
+    if (*mime_type)
+        if ((ret = av_dict_set(&st->metadata, "mimetype", mime_type, 0)) < 0)
+            return AVERROR(ENOMEM);
+    return 0;
+}
+
+static int attachment_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    return AVERROR_EOF;
+}
+
+#define OFFSET(field) offsetof(AttachmentContext, field)
+#define D AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption attachment_options[] = {
+    { "filename",   "filename",   OFFSET(filename),   AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
+    { "mime_type",  "MIME type",  OFFSET(mime_type),  AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
+    { "mimetype",   "MIME type",  OFFSET(mime_type),  AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
+    { "codec",      "codec name", OFFSET(codec_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
+    { "file_codec", "codec name", OFFSET(codec_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
+    { NULL }
+};
+
+#undef OFFSET
+#undef D
+
+static const AVClass attachment_class = {
+    .class_name = "attachment",
+    .item_name  = av_default_item_name,
+    .option     = attachment_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_attachment_demuxer = {
+    .name            = "attachment",
+    .long_name       = NULL_IF_CONFIG_SMALL("single attached file"),
+    .priv_class      = &attachment_class,
+    .priv_data_size  = sizeof(AttachmentContext),
+    .read_header     = attachment_read_header,
+    .read_packet     = attachment_read_packet,
+};
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list