diff --git a/doc/muxers.texi b/doc/muxers.texi index 03be693918..55b44d1018 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -232,7 +232,7 @@ Specifies the language of the track in the Matroska languages form @table @option -@item STEREO_MODE=@var{mode} +@item stereo_mode=@var{mode} Stereo 3D video layout of two views in a single video track @table @option @item mono @@ -270,7 +270,7 @@ Both eyes laced in one Block, Right-eye view is first For example a 3D WebM clip can be created using the following command line: @example -ffmpeg -i sample_left_right_clip.mpg -an -vcodec libvpx -metadata STEREO_MODE=left_right -y stereo_clip.webm +ffmpeg -i sample_left_right_clip.mpg -an -vcodec libvpx -metadata stereo_mode=left_right -y stereo_clip.webm @end example @c man end MUXERS diff --git a/libavformat/matroska.c b/libavformat/matroska.c index c7e9663316..fe9b0424a3 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -99,3 +99,27 @@ const AVMetadataConv ff_mkv_metadata_conv[] = { { "PART_NUMBER" , "track" }, { 0 } }; + +const char const *matroska_video_stereo_mode[] = { + "mono", + "left_right", + "bottom_top", + "top_bottom", + "checkerboard_rl", + "checkerboard_lr" + "row_interleaved_rl", + "row_interleaved_lr", + "col_interleaved_rl", + "col_interleaved_lr", + "anaglyph_cyan_red", + "right_left", + "anaglyph_green_magenta", + "block_lr", + "block_rl", +}; + +const char const *matroska_video_stereo_plane[] = { + "left", + "right", + "background", +}; diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 48959772f1..949195b757 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -223,24 +223,6 @@ typedef enum { MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP = 3, } MatroskaTrackEncodingCompAlgo; -typedef enum { - MATROSKA_VIDEO_STEREOMODE_MONO = 0, - MATROSKA_VIDEO_STEREOMODE_LEFT_RIGHT = 1, - MATROSKA_VIDEO_STEREOMODE_BOTTOM_TOP = 2, - MATROSKA_VIDEO_STEREOMODE_TOP_BOTTOM = 3, - MATROSKA_VIDEO_STEREOMODE_CHECKERBOARD_RL = 4, - MATROSKA_VIDEO_STEREOMODE_CHECKERBOARD_LR = 5, - MATROSKA_VIDEO_STEREOMODE_ROW_INTERLEAVED_RL = 6, - MATROSKA_VIDEO_STEREOMODE_ROW_INTERLEAVED_LR = 7, - MATROSKA_VIDEO_STEREOMODE_COL_INTERLEAVED_RL = 8, - MATROSKA_VIDEO_STEREOMODE_COL_INTERLEAVED_LR = 9, - MATROSKA_VIDEO_STEREOMODE_ANAGLYPH_CYAN_RED = 10, - MATROSKA_VIDEO_STEREOMODE_RIGHT_LEFT = 11, - MATROSKA_VIDEO_STEREOMODE_ANAGLYPH_GREEN_MAG = 12, - MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_LR = 13, - MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_RL = 14, -} MatroskaVideoStereoModeType; - /* * Matroska Codec IDs, strings */ @@ -261,5 +243,10 @@ typedef struct CodecMime{ extern const CodecTags ff_mkv_codec_tags[]; extern const CodecMime ff_mkv_mime_tags[]; extern const AVMetadataConv ff_mkv_metadata_conv[]; +extern const char const *matroska_video_stereo_mode[]; +extern const char const *matroska_video_stereo_plane[]; + +#define MATROSKA_VIDEO_STEREO_MODE_COUNT 15 +#define MATROSKA_VIDEO_STEREO_PLANE_COUNT 3 #endif /* AVFORMAT_MATROSKA_H */ diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 90623bf89f..eca32773fe 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -112,7 +112,7 @@ typedef struct { uint64_t pixel_width; uint64_t pixel_height; uint64_t fourcc; - uint64_t stereoMode; + uint64_t stereo_mode; } MatroskaTrackVideo; typedef struct { @@ -139,7 +139,6 @@ typedef struct { typedef struct { EbmlList combine_planes; - /*EbmlList join_blocks;*/ } MatroskaTrackOperation; typedef struct { @@ -303,7 +302,7 @@ 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_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,stereo_mode) }, { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE }, @@ -1225,16 +1224,13 @@ 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; uint64_t max_start = 0; Ebml ebml = { 0 }; AVStream *st; - int i, j, res; + int i, j, k, res; matroska->ctx = s; @@ -1499,6 +1495,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { + MatroskaTrackPlane *planes = track->operation.combine_planes.elem; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_tag = track->video.fourcc; st->codec->width = track->video.pixel_width; @@ -1513,84 +1511,23 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) 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; - } + /* export stereo mode flag as metadata tag */ + if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREO_MODE_COUNT) + av_metadata_set2(&st->metadata, "stereo_mode", matroska_video_stereo_mode[track->video.stereo_mode], 0); - /* 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); + /* if we have virtual track, mark the real tracks */ + for (j=0; j < track->operation.combine_planes.nb_elem; j++) { + char buf[32]; + if (planes[j].type < MATROSKA_VIDEO_STEREO_PLANE_COUNT) + continue; + snprintf(buf, sizeof(buf), "%s_%d", + matroska_video_stereo_plane[planes[j].type], i); + for (k=0; k < matroska->tracks.nb_elem; k++) + if (planes[j].uid == tracks[k].uid) { + av_metadata_set2(&s->streams[k]->metadata, + "stereo_mode", buf, 0); 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; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 0fe760b684..c3e203cb36 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -587,58 +587,24 @@ static int mkv_write_tracks(AVFormatContext *s) put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width); put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELHEIGHT, codec->height); - 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 ((tag = av_metadata_get(st->metadata, "stereo_mode", NULL, 0)) || + (tag = av_metadata_get( s->metadata, "stereo_mode", NULL, 0))) { + // save stereo mode flag + uint64_t st_mode = MATROSKA_VIDEO_STEREO_MODE_COUNT; - 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 - || stereo_fmt == MATROSKA_VIDEO_STEREOMODE_RIGHT_LEFT) - valid_fmt = 1; + for (j=0; jvalue, matroska_video_stereo_mode[j])){ + st_mode = j; break; - case MODE_MATROSKAv2: - if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_BOTH_EYES_BLOCK_RL) - valid_fmt = 1; - break; - } + } - if (valid_fmt) - put_ebml_uint (pb, MATROSKA_ID_VIDEOSTEREOMODE, stereo_fmt); + if ((mkv->mode == MODE_WEBM && st_mode > 3 && st_mode != 11) + || st_mode >= MATROSKA_VIDEO_STEREO_MODE_COUNT) { + av_log(s, AV_LOG_ERROR, + "The specified stereo mode is not valid.\n"); + return AVERROR(EINVAL); + } else + put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, st_mode); } if (st->sample_aspect_ratio.num) { @@ -786,7 +752,7 @@ static int mkv_write_tag(AVFormatContext *s, AVMetadata *m, unsigned int element end_ebml_master(s->pb, targets); while ((t = av_metadata_get(m, "", t, AV_METADATA_IGNORE_SUFFIX))) - if (strcasecmp(t->key, "title")) + if (strcasecmp(t->key, "title") && strcasecmp(t->key, "stereo_mode")) mkv_write_simpletag(s->pb, t); end_ebml_master(s->pb, tag);