From e6ec9212c543c77ab3ddab90ac52021cfbbdac17 Mon Sep 17 00:00:00 2001 From: Kirill Gavrilov Date: Sat, 21 May 2011 17:14:14 +0200 Subject: [PATCH] matroska: switch stereo mode from int to string and add support in the demuxer too --- libavformat/matroska.h | 5 ++ libavformat/matroskadec.c | 121 +++++++++++++++++++++++++++++++++++++- libavformat/matroskaenc.c | 39 +++++++++++- 3 files changed, 161 insertions(+), 4 deletions(-) diff --git a/libavformat/matroska.h b/libavformat/matroska.h index b1123515298..48959772f1a 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -79,6 +79,11 @@ #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 diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 8f9340dbdc1..90623bf89f5 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -112,6 +112,7 @@ typedef struct { uint64_t pixel_width; uint64_t pixel_height; uint64_t fourcc; + uint64_t stereoMode; } MatroskaTrackVideo; typedef struct { @@ -131,6 +132,16 @@ typedef struct { uint8_t *buf; } 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; @@ -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; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 564b7509c16..0fe760b6846 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -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 -- 2.39.2