Add support for Matroska attachments.
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Sun, 27 Jan 2008 15:43:17 +0000 (15:43 +0000)
committerAurelien Jacobs <aurel@gnuage.org>
Sun, 27 Jan 2008 15:43:17 +0000 (15:43 +0000)
patch by eugeni _dot_ stepanov _at_ gmail.com and myself

Originally committed as revision 11635 to svn://svn.ffmpeg.org/ffmpeg/trunk

ffmpeg.c
libavcodec/avcodec.h
libavcodec/utils.c
libavformat/avformat.h
libavformat/matroska.c
libavformat/matroska.h
libavformat/matroskadec.c
libavformat/utils.c

index 97526cb..a480068 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -2776,6 +2776,7 @@ static void opt_input_file(const char *filename)
             if(subtitle_disable)
                 ic->streams[i]->discard = AVDISCARD_ALL;
             break;
+        case CODEC_TYPE_ATTACHMENT:
         case CODEC_TYPE_UNKNOWN:
             break;
         default:
@@ -2825,6 +2826,7 @@ static void check_audio_video_sub_inputs(int *has_video_ptr, int *has_audio_ptr,
                 has_subtitle = 1;
                 break;
             case CODEC_TYPE_DATA:
+            case CODEC_TYPE_ATTACHMENT:
             case CODEC_TYPE_UNKNOWN:
                 break;
             default:
index bcf9fb6..f8c8178 100644 (file)
@@ -33,8 +33,8 @@
 #define AV_STRINGIFY(s)         AV_TOSTRING(s)
 #define AV_TOSTRING(s) #s
 
-#define LIBAVCODEC_VERSION_INT  ((51<<16)+(49<<8)+0)
-#define LIBAVCODEC_VERSION      51.49.0
+#define LIBAVCODEC_VERSION_INT  ((51<<16)+(50<<8)+0)
+#define LIBAVCODEC_VERSION      51.50.0
 #define LIBAVCODEC_BUILD        LIBAVCODEC_VERSION_INT
 
 #define LIBAVCODEC_IDENT        "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION)
@@ -284,6 +284,9 @@ enum CodecID {
     CODEC_ID_XSUB,
     CODEC_ID_SSA,
 
+    /* other specific kind of codecs (generaly used for attachments) */
+    CODEC_ID_TTF= 0x18000,
+
     CODEC_ID_MPEG2TS= 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS
                                 * stream (only used by libavformat) */
 };
@@ -300,6 +303,7 @@ enum CodecType {
     CODEC_TYPE_AUDIO,
     CODEC_TYPE_DATA,
     CODEC_TYPE_SUBTITLE,
+    CODEC_TYPE_ATTACHMENT,
     CODEC_TYPE_NB
 };
 
index 4a8cb8a..4ebc7c3 100644 (file)
@@ -1219,6 +1219,10 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
         snprintf(buf, buf_size, "Subtitle: %s", codec_name);
         bitrate = enc->bit_rate;
         break;
+    case CODEC_TYPE_ATTACHMENT:
+        snprintf(buf, buf_size, "Attachment: %s", codec_name);
+        bitrate = enc->bit_rate;
+        break;
     default:
         snprintf(buf, buf_size, "Invalid Codec type %d", enc->codec_type);
         return;
index cb60245..ddebb77 100644 (file)
@@ -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 @@ typedef struct AVStream {
 
 #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
index 382534e..b62511f 100644 (file)
@@ -71,3 +71,15 @@ const CodecTags ff_mkv_codec_tags[]={
     {""                 , 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}
+};
index 43fbb9e..370a8bf 100644 (file)
@@ -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 */
 #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 @@ typedef struct CodecTags{
     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 @@ typedef struct CodecTags{
 #define EBML_MAX_DEPTH 16
 
 extern const CodecTags ff_mkv_codec_tags[];
+extern const CodecMime ff_mkv_mime_tags[];
 
 #endif /* FFMPEG_MATROSKA_H */
index cc45e95..d96b36e 100644 (file)
@@ -1865,6 +1865,119 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
     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 @@ matroska_read_header (AVFormatContext    *s,
                 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. */
index d3e6afe..ffb2d84 100644 (file)
@@ -2112,6 +2112,7 @@ void av_close_input_stream(AVFormatContext *s)
         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--) {