changeset 2973:910ac68ab3b5 libavformat

Add support for Matroska attachments. patch by eugeni _dot_ stepanov _at_ gmail.com and myself
author aurel
date Sun, 27 Jan 2008 15:43:17 +0000
parents bc330130bdce
children 4b6a9b61e9dd
files avformat.h matroska.c matroska.h matroskadec.c utils.c
diffstat 5 files changed, 151 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/avformat.h	Sat Jan 26 22:57:53 2008 +0000
+++ b/avformat.h	Sun Jan 27 15:43:17 2008 +0000
@@ -21,8 +21,8 @@
 #ifndef FFMPEG_AVFORMAT_H
 #define FFMPEG_AVFORMAT_H
 
-#define LIBAVFORMAT_VERSION_INT ((52<<16)+(5<<8)+0)
-#define LIBAVFORMAT_VERSION     52.5.0
+#define LIBAVFORMAT_VERSION_INT ((52<<16)+(6<<8)+0)
+#define LIBAVFORMAT_VERSION     52.6.0
 #define LIBAVFORMAT_BUILD       LIBAVFORMAT_VERSION_INT
 
 #define LIBAVFORMAT_IDENT       "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION)
@@ -347,6 +347,8 @@
 
 #define MAX_REORDER_DELAY 4
     int64_t pts_buffer[MAX_REORDER_DELAY+1];
+
+    char *filename; /**< source filename of the stream */
 } AVStream;
 
 #define AV_PROGRAM_RUNNING 1
--- a/matroska.c	Sat Jan 26 22:57:53 2008 +0000
+++ b/matroska.c	Sun Jan 27 15:43:17 2008 +0000
@@ -71,3 +71,15 @@
     {""                 , CODEC_ID_NONE}
 /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */
 };
+
+const CodecMime ff_mkv_mime_tags[] = {
+    {"text/plain"                 , CODEC_ID_TEXT},
+    {"image/gif"                  , CODEC_ID_GIF},
+    {"image/jpeg"                 , CODEC_ID_MJPEG},
+    {"image/png"                  , CODEC_ID_PNG},
+    {"image/tiff"                 , CODEC_ID_TIFF},
+    {"application/x-truetype-font", CODEC_ID_TTF},
+    {"application/x-font"         , CODEC_ID_TTF},
+
+    {""                           , CODEC_ID_NONE}
+};
--- a/matroska.h	Sat Jan 26 22:57:53 2008 +0000
+++ b/matroska.h	Sun Jan 27 15:43:17 2008 +0000
@@ -55,6 +55,7 @@
 #define MATROSKA_ID_CUES       0x1C53BB6B
 #define MATROSKA_ID_TAGS       0x1254C367
 #define MATROSKA_ID_SEEKHEAD   0x114D9B74
+#define MATROSKA_ID_ATTACHMENTS 0x1941A469
 #define MATROSKA_ID_CLUSTER    0x1F43B675
 
 /* IDs in the info master */
@@ -138,6 +139,13 @@
 #define MATROSKA_ID_BLOCKDURATION 0x9B
 #define MATROSKA_ID_BLOCKREFERENCE 0xFB
 
+/* IDs in the attachments master */
+#define MATROSKA_ID_ATTACHEDFILE        0x61A7
+#define MATROSKA_ID_FILENAME            0x466E
+#define MATROSKA_ID_FILEMIMETYPE        0x4660
+#define MATROSKA_ID_FILEDATA            0x465C
+#define MATROSKA_ID_FILEUID             0x46AE
+
 typedef enum {
   MATROSKA_TRACK_TYPE_VIDEO    = 0x1,
   MATROSKA_TRACK_TYPE_AUDIO    = 0x2,
@@ -185,6 +193,11 @@
     enum CodecID id;
 }CodecTags;
 
+typedef struct CodecMime{
+    char str[32];
+    enum CodecID id;
+}CodecMime;
+
 #define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC   "V_MS/VFW/FOURCC"
 #define MATROSKA_CODEC_ID_AUDIO_ACM          "A_MS/ACM"
 
@@ -192,5 +205,6 @@
 #define EBML_MAX_DEPTH 16
 
 extern const CodecTags ff_mkv_codec_tags[];
+extern const CodecMime ff_mkv_mime_tags[];
 
 #endif /* FFMPEG_MATROSKA_H */
--- a/matroskadec.c	Sat Jan 26 22:57:53 2008 +0000
+++ b/matroskadec.c	Sun Jan 27 15:43:17 2008 +0000
@@ -1865,6 +1865,119 @@
     return res;
 }
 
+static int
+matroska_parse_attachments(AVFormatContext *s)
+{
+    MatroskaDemuxContext *matroska = s->priv_data;
+    int res = 0;
+    uint32_t id;
+
+    av_log(matroska->ctx, AV_LOG_DEBUG, "parsing attachments...\n");
+
+    while (res == 0) {
+        if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+            res = AVERROR(EIO);
+            break;
+        } else if (matroska->level_up) {
+            matroska->level_up--;
+            break;
+        }
+
+        switch (id) {
+        case MATROSKA_ID_ATTACHEDFILE: {
+            char* name = NULL;
+            char* mime = NULL;
+            uint8_t* data = NULL;
+            int i, data_size = 0;
+            AVStream *st;
+
+            if ((res = ebml_read_master(matroska, &id)) < 0)
+                break;
+
+            while (res == 0) {
+                if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                    res = AVERROR(EIO);
+                    break;
+                } else if (matroska->level_up) {
+                    matroska->level_up--;
+                    break;
+                }
+
+                switch (id) {
+                case MATROSKA_ID_FILENAME:
+                    res = ebml_read_utf8 (matroska, &id, &name);
+                    break;
+
+                case MATROSKA_ID_FILEMIMETYPE:
+                    res = ebml_read_ascii (matroska, &id, &mime);
+                    break;
+
+                case MATROSKA_ID_FILEDATA:
+                    res = ebml_read_binary(matroska, &id, &data, &data_size);
+                    break;
+
+                default:
+                    av_log(matroska->ctx, AV_LOG_INFO,
+                           "Unknown attachedfile ID 0x%x\n", id);
+                case EBML_ID_VOID:
+                    res = ebml_read_skip(matroska);
+                    break;
+                }
+
+                if (matroska->level_up) {
+                    matroska->level_up--;
+                    break;
+                }
+            }
+
+            if (!(name && mime && data && data_size > 0)) {
+                av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n");
+                break;
+            }
+
+            st = av_new_stream(s, matroska->num_streams++);
+            if (st == NULL)
+                return AVERROR(ENOMEM);
+            st->filename = av_strdup(name);
+            st->codec->codec_id = CODEC_ID_NONE;
+            st->codec->codec_type = CODEC_TYPE_ATTACHMENT;
+            st->codec->extradata = av_malloc(data_size);
+            if(st->codec->extradata == NULL)
+                return AVERROR(ENOMEM);
+            st->codec->extradata_size = data_size;
+            memcpy(st->codec->extradata, data, data_size);
+
+            for (i=0; ff_mkv_mime_tags[i].id != CODEC_ID_NONE; i++) {
+                if (!strncmp(ff_mkv_mime_tags[i].str, mime,
+                             strlen(ff_mkv_mime_tags[i].str))) {
+                    st->codec->codec_id = ff_mkv_mime_tags[i].id;
+                    break;
+                }
+            }
+
+            av_log(matroska->ctx, AV_LOG_DEBUG, "new attachment: %s, %s, size %d \n", name, mime, data_size);
+            break;
+        }
+
+        default:
+            av_log(matroska->ctx, AV_LOG_INFO,
+                   "Unknown attachments ID 0x%x\n", id);
+            /* fall-through */
+
+        case EBML_ID_VOID:
+            res = ebml_read_skip(matroska);
+            break;
+        }
+
+        if (matroska->level_up) {
+            matroska->level_up--;
+            break;
+        }
+    }
+
+    return res;
+}
+
 #define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
 
 static int
@@ -2007,6 +2120,13 @@
                 break;
             }
 
+            case MATROSKA_ID_ATTACHMENTS: {
+                if ((res = ebml_read_master(matroska, &id)) < 0)
+                    break;
+                res = matroska_parse_attachments(s);
+                break;
+            }
+
             case MATROSKA_ID_CLUSTER: {
                 /* Do not read the master - this will be done in the next
                  * call to matroska_read_packet. */
--- a/utils.c	Sat Jan 26 22:57:53 2008 +0000
+++ b/utils.c	Sun Jan 27 15:43:17 2008 +0000
@@ -2112,6 +2112,7 @@
         av_free(st->index_entries);
         av_free(st->codec->extradata);
         av_free(st->codec);
+        av_free(st->filename);
         av_free(st);
     }
     for(i=s->nb_programs-1; i>=0; i--) {