matroskadec: add basic tags support (metadata)
authorAurelien Jacobs <aurel@gnuage.org>
Fri, 8 Aug 2008 23:50:38 +0000 (23:50 +0000)
committerAurelien Jacobs <aurel@gnuage.org>
Fri, 8 Aug 2008 23:50:38 +0000 (23:50 +0000)
Originally committed as revision 14672 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/matroska.h
libavformat/matroskadec.c

index 5587c01..8930e16 100644 (file)
 #define MATROSKA_ID_CUECLUSTERPOSITION 0xF1
 
 /* IDs in the tags master */
-/* TODO */
+#define MATROSKA_ID_TAG                 0x7373
+#define MATROSKA_ID_SIMPLETAG           0x67C8
+#define MATROSKA_ID_TAGNAME             0x45A3
+#define MATROSKA_ID_TAGSTRING           0x4487
+#define MATROSKA_ID_TAGLANG             0x447A
+#define MATROSKA_ID_TAGDEFAULT          0x44B4
+#define MATROSKA_ID_TAGTARGETS          0x63C0
 
 /* IDs in the seekhead master */
 #define MATROSKA_ID_SEEKENTRY  0x4DBB
index d7a1e39..89c0d67 100644 (file)
@@ -164,6 +164,12 @@ typedef struct {
 } MatroskaIndex;
 
 typedef struct {
+    char *name;
+    char *string;
+    EbmlList sub;
+} MatroskaTag;
+
+typedef struct {
     uint64_t id;
     uint64_t pos;
 } MatroskaSeekhead;
@@ -188,6 +194,7 @@ typedef struct {
     EbmlList attachments;
     EbmlList chapters;
     EbmlList index;
+    EbmlList tags;
     EbmlList seekhead;
 
     /* byte position of the segment inside the stream */
@@ -390,7 +397,25 @@ static EbmlSyntax matroska_index[] = {
     { 0 }
 };
 
+static EbmlSyntax matroska_simpletag[] = {
+    { MATROSKA_ID_TAGNAME,            EBML_UTF8, 0, offsetof(MatroskaTag,name) },
+    { MATROSKA_ID_TAGSTRING,          EBML_UTF8, 0, offsetof(MatroskaTag,string) },
+    { MATROSKA_ID_SIMPLETAG,          EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTag,sub), {.n=matroska_simpletag} },
+    { MATROSKA_ID_TAGLANG,            EBML_NONE },
+    { MATROSKA_ID_TAGDEFAULT,         EBML_NONE },
+    { EBML_ID_VOID,                   EBML_NONE },
+    { 0 }
+};
+
+static EbmlSyntax matroska_tag[] = {
+    { MATROSKA_ID_SIMPLETAG,          EBML_NEST, sizeof(MatroskaTag), 0, {.n=matroska_simpletag} },
+    { MATROSKA_ID_TAGTARGETS,         EBML_NONE },
+    { EBML_ID_VOID,                   EBML_NONE },
+    { 0 }
+};
+
 static EbmlSyntax matroska_tags[] = {
+    { MATROSKA_ID_TAG,                EBML_NEST, 0, offsetof(MatroskaDemuxContext,tags), {.n=matroska_tag} },
     { EBML_ID_VOID,                   EBML_NONE },
     { 0 }
 };
@@ -448,6 +473,25 @@ static EbmlSyntax matroska_clusters[] = {
     { 0 }
 };
 
+#define SIZE_OFF(x) sizeof(((AVFormatContext*)0)->x),offsetof(AVFormatContext,x)
+const struct {
+    const char name[16];
+    int   size;
+    int   offset;
+} metadata[] = {
+    { "TITLE",           SIZE_OFF(title)      },
+    { "ARTIST",          SIZE_OFF(author)     },
+    { "WRITTEN_BY",      SIZE_OFF(author)     },
+    { "LEAD_PERFORMER",  SIZE_OFF(author)     },
+    { "COPYRIGHT",       SIZE_OFF(copyright)  },
+    { "COMMENT",         SIZE_OFF(comment)    },
+    { "ALBUM",           SIZE_OFF(album)      },
+    { "DATE_WRITTEN",    SIZE_OFF(year)       },
+    { "DATE_RELEASED",   SIZE_OFF(year)       },
+    { "PART_NUMBER",     SIZE_OFF(track)      },
+    { "GENRE",           SIZE_OFF(genre)      },
+};
+
 /*
  * Return: Whether we reached the end of a level in the hierarchy or not.
  */
@@ -891,6 +935,27 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size,
     return -1;
 }
 
+static void matroska_convert_tags(AVFormatContext *s, EbmlList *list)
+{
+    MatroskaTag *tags = list->elem;
+    int i, j;
+
+    for (i=0; i < list->nb_elem; i++) {
+        for (j=0; j < ARRAY_SIZE(metadata); j++){
+            if (!strcmp(tags[i].name, metadata[j].name)) {
+                int *ptr = (int *)((char *)s + metadata[j].offset);
+                if (*ptr)  continue;
+                if (metadata[j].size > sizeof(int))
+                    av_strlcpy((char *)ptr, tags[i].string, metadata[j].size);
+                else
+                    *ptr = atoi(tags[i].string);
+            }
+        }
+        if (tags[i].sub.nb_elem)
+            matroska_convert_tags(s, &tags[i].sub);
+    }
+}
+
 static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
 {
     EbmlList *seekhead_list = &matroska->seekhead;
@@ -1002,6 +1067,7 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap)
     if (matroska->title)
         strncpy(matroska->ctx->title, matroska->title,
                 sizeof(matroska->ctx->title)-1);
+    matroska_convert_tags(s, &matroska->tags);
 
     tracks = matroska->tracks.elem;
     for (i=0; i < matroska->tracks.nb_elem; i++) {