matroska: switch stereo mode from int to string and add support in the demuxer too
authorKirill Gavrilov <gavr.mail@gmail.com>
Sat, 21 May 2011 15:14:14 +0000 (17:14 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 21 May 2011 15:23:30 +0000 (17:23 +0200)
libavformat/matroska.h
libavformat/matroskadec.c
libavformat/matroskaenc.c

index b112351..4895977 100644 (file)
 #define MATROSKA_ID_TRACKTYPE  0x83
 #define MATROSKA_ID_TRACKVIDEO     0xE0
 #define MATROSKA_ID_TRACKAUDIO     0xE1
+#define MATROSKA_ID_TRACKOPERATION 0xE2
+#define MATROSKA_ID_TRACKCOMBINEPLANES 0xE3
+#define MATROSKA_ID_TRACKPLANE         0xE4
+#define MATROSKA_ID_TRACKPLANEUID      0xE5
+#define MATROSKA_ID_TRACKPLANETYPE     0xE6
 #define MATROSKA_ID_CODECID    0x86
 #define MATROSKA_ID_CODECPRIVATE 0x63A2
 #define MATROSKA_ID_CODECNAME  0x258688
index 8f9340d..90623bf 100644 (file)
@@ -112,6 +112,7 @@ typedef struct {
     uint64_t pixel_width;
     uint64_t pixel_height;
     uint64_t fourcc;
+    uint64_t stereoMode;
 } MatroskaTrackVideo;
 
 typedef struct {
@@ -132,6 +133,16 @@ typedef struct {
 } MatroskaTrackAudio;
 
 typedef struct {
+    uint64_t uid;
+    uint64_t type;
+} MatroskaTrackPlane;
+
+typedef struct {
+    EbmlList combine_planes;
+    /*EbmlList join_blocks;*/
+} MatroskaTrackOperation;
+
+typedef struct {
     uint64_t num;
     uint64_t uid;
     uint64_t type;
@@ -145,6 +156,7 @@ typedef struct {
     uint64_t flag_forced;
     MatroskaTrackVideo video;
     MatroskaTrackAudio audio;
+    MatroskaTrackOperation operation;
     EbmlList encodings;
 
     AVStream *stream;
@@ -291,13 +303,13 @@ static EbmlSyntax matroska_track_video[] = {
     { MATROSKA_ID_VIDEOPIXELWIDTH,    EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_width) },
     { MATROSKA_ID_VIDEOPIXELHEIGHT,   EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_height) },
     { MATROSKA_ID_VIDEOCOLORSPACE,    EBML_UINT, 0, offsetof(MatroskaTrackVideo,fourcc) },
+    { MATROSKA_ID_VIDEOSTEREOMODE,    EBML_UINT, MATROSKA_VIDEO_STEREOMODE_MONO, offsetof(MatroskaTrackVideo,stereoMode) },
     { MATROSKA_ID_VIDEOPIXELCROPB,    EBML_NONE },
     { MATROSKA_ID_VIDEOPIXELCROPT,    EBML_NONE },
     { MATROSKA_ID_VIDEOPIXELCROPL,    EBML_NONE },
     { MATROSKA_ID_VIDEOPIXELCROPR,    EBML_NONE },
     { MATROSKA_ID_VIDEODISPLAYUNIT,   EBML_NONE },
     { MATROSKA_ID_VIDEOFLAGINTERLACED,EBML_NONE },
-    { MATROSKA_ID_VIDEOSTEREOMODE,    EBML_NONE },
     { MATROSKA_ID_VIDEOASPECTRATIO,   EBML_NONE },
     { 0 }
 };
@@ -329,6 +341,22 @@ static EbmlSyntax matroska_track_encodings[] = {
     { 0 }
 };
 
+static EbmlSyntax matroska_track_plane[] = {
+    { MATROSKA_ID_TRACKPLANEUID,  EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) },
+    { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) },
+    { 0 }
+};
+
+static EbmlSyntax matroska_track_combine_planes[] = {
+    { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n=matroska_track_plane} },
+    { 0 }
+};
+
+static EbmlSyntax matroska_track_operation[] = {
+    { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n=matroska_track_combine_planes} },
+    { 0 }
+};
+
 static EbmlSyntax matroska_track[] = {
     { MATROSKA_ID_TRACKNUMBER,          EBML_UINT, 0, offsetof(MatroskaTrack,num) },
     { MATROSKA_ID_TRACKNAME,            EBML_UTF8, 0, offsetof(MatroskaTrack,name) },
@@ -343,6 +371,7 @@ static EbmlSyntax matroska_track[] = {
     { MATROSKA_ID_TRACKFLAGFORCED,      EBML_UINT, 0, offsetof(MatroskaTrack,flag_forced), {.u=0} },
     { MATROSKA_ID_TRACKVIDEO,           EBML_NEST, 0, offsetof(MatroskaTrack,video), {.n=matroska_track_video} },
     { MATROSKA_ID_TRACKAUDIO,           EBML_NEST, 0, offsetof(MatroskaTrack,audio), {.n=matroska_track_audio} },
+    { MATROSKA_ID_TRACKOPERATION,       EBML_NEST, 0, offsetof(MatroskaTrack,operation), {.n=matroska_track_operation} },
     { MATROSKA_ID_TRACKCONTENTENCODINGS,EBML_NEST, 0, 0, {.n=matroska_track_encodings} },
     { MATROSKA_ID_TRACKFLAGENABLED,     EBML_NONE },
     { MATROSKA_ID_TRACKFLAGLACING,      EBML_NONE },
@@ -1196,6 +1225,9 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap)
     EbmlList *chapters_list = &matroska->chapters;
     MatroskaChapter *chapters;
     MatroskaTrack *tracks;
+    EbmlList *combined_list;
+    MatroskaTrackPlane *planes;
+    char stereo_str[256];
     EbmlList *index_list;
     MatroskaIndex *index;
     int index_scale = 1;
@@ -1209,13 +1241,18 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap)
     /* First read the EBML header. */
     if (ebml_parse(matroska, ebml_syntax, &ebml)
         || ebml.version > EBML_VERSION       || ebml.max_size > sizeof(uint64_t)
-        || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 2) {
+        || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 3) {
         av_log(matroska->ctx, AV_LOG_ERROR,
                "EBML header using unsupported features\n"
                "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
                ebml.version, ebml.doctype, ebml.doctype_version);
         ebml_free(ebml_syntax, &ebml);
         return AVERROR_PATCHWELCOME;
+    } else if (ebml.doctype_version == 3) {
+        av_log(matroska->ctx, AV_LOG_WARNING,
+               "EBML header using unsupported features\n"
+               "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
+               ebml.version, ebml.doctype, ebml.doctype_version);
     }
     for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++)
         if (!strcmp(ebml.doctype, matroska_doctypes[i]))
@@ -1475,6 +1512,86 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap)
             st->need_parsing = AVSTREAM_PARSE_HEADERS;
             if (track->default_duration)
                 st->avg_frame_rate = av_d2q(1000000000.0/track->default_duration, INT_MAX);
+
+            /* restore stereo mode flag as metadata tag */
+            switch (track->video.stereoMode) {
+                case MATROSKA_VIDEO_STEREOMODE_LEFT_RIGHT:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "left_right", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_BOTTOM_TOP:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "bottom_top", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_TOP_BOTTOM:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "top_bottom", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_CHECKERBOARD_RL:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "checkerboard_rl", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_CHECKERBOARD_LR:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "checkerboard_lr", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_ROW_INTERLEAVED_RL:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "row_interleaved_rl", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_ROW_INTERLEAVED_LR:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "row_interleaved_lr", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_COL_INTERLEAVED_RL:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "col_interleaved_rl", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_COL_INTERLEAVED_LR:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "col_interleaved_lr", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_ANAGLYPH_CYAN_RED:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "anaglyph_cyan_red", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_RIGHT_LEFT:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "right_left", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_ANAGLYPH_GREEN_MAG:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "anaglyph_green_magenta", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_LR:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "block_lr", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_RL:
+                    av_metadata_set2(&st->metadata, "STEREO_MODE", "block_rl", 0);
+                    break;
+                case MATROSKA_VIDEO_STEREOMODE_MONO:
+                default:
+                    /**av_metadata_set2(&st->metadata, "STEREO_MODE", "mono", 0);*/
+                    break;
+            }
+
+            /* if we have virtual track - mark the real tracks */
+            combined_list = &track->operation.combine_planes;
+            planes = combined_list->elem;
+            for (int plane_id = 0; plane_id < combined_list->nb_elem; ++plane_id) {
+                switch (planes[plane_id].type) {
+                    case 0: {
+                        snprintf(stereo_str, sizeof(stereo_str), "left_%d", i);
+                        break;
+                    }
+                    case 1: {
+                        snprintf(stereo_str, sizeof(stereo_str), "right_%d", i);
+                        break;
+                    }
+                    case 2: {
+                        snprintf(stereo_str, sizeof(stereo_str), "background_%d", i);
+                        break;
+                    }
+                    default: {
+                        continue;
+                    }
+                }
+                for (int track_id = 0; track_id < matroska->tracks.nb_elem && track_id < i; ++track_id) {
+                    MatroskaTrack *check_track = &tracks[track_id];
+                    if (planes[plane_id].uid == check_track->uid) {
+                        av_metadata_set2(&s->streams[track_id]->metadata, "STEREO_MODE", stereo_str, 0);
+                        break;
+                    }
+                }
+            }
         } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
             st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
             st->codec->sample_rate = track->audio.out_samplerate;
index 564b750..0fe760b 100644 (file)
@@ -586,10 +586,45 @@ static int mkv_write_tracks(AVFormatContext *s)
                 // XXX: interlace flag?
                 put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width);
                 put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELHEIGHT, codec->height);
-                if ((tag = av_metadata_get(s->metadata, "stereo_mode", NULL, 0))) {
-                    uint8_t stereo_fmt = atoi(tag->value);
+
+                if ((tag = av_metadata_get(st->metadata, "STEREO_MODE", NULL, 0)) ||
+                    (tag = av_metadata_get( s->metadata, "STEREO_MODE", NULL, 0))) {
+                    // save stereomode flag
+                    uint64_t stereo_fmt = -1;
                     int valid_fmt = 0;
 
+                    if (!strcmp(tag->value, "mono")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_MONO;
+                    } else if (!strcmp(tag->value, "left_right")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_LEFT_RIGHT;
+                    } else if (!strcmp(tag->value, "bottom_top")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_BOTTOM_TOP;
+                    } else if (!strcmp(tag->value, "top_bottom")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_TOP_BOTTOM;
+                    } else if (!strcmp(tag->value, "checkerboard_rl")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_CHECKERBOARD_RL;
+                    } else if (!strcmp(tag->value, "checkerboard_lr")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_CHECKERBOARD_LR;
+                    } else if (!strcmp(tag->value, "row_interleaved_rl")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_ROW_INTERLEAVED_RL;
+                    } else if (!strcmp(tag->value, "row_interleaved_lr")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_ROW_INTERLEAVED_LR;
+                    } else if (!strcmp(tag->value, "col_interleaved_rl")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_COL_INTERLEAVED_RL;
+                    } else if (!strcmp(tag->value, "col_interleaved_lr")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_COL_INTERLEAVED_LR;
+                    } else if (!strcmp(tag->value, "anaglyph_cyan_red")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_ANAGLYPH_CYAN_RED;
+                    } else if (!strcmp(tag->value, "right_left")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_RIGHT_LEFT;
+                    } else if (!strcmp(tag->value, "anaglyph_green_magenta")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_ANAGLYPH_GREEN_MAG;
+                    } else if (!strcmp(tag->value, "block_lr")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_LR;
+                    } else if (!strcmp(tag->value, "block_rl")) {
+                        stereo_fmt = MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_RL;
+                    }
+
                     switch (mkv->mode) {
                         case MODE_WEBM:
                             if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_TOP_BOTTOM