Maybe somebody in LibAV list interesting in adding stereoscopic flags
support / discussion?
---------- Forwarded message ----------
From: Kirill Gavrilov <[email protected]>
Date: Sat, May 7, 2011 at 9:44 PM
Subject: Re: [FFmpeg-devel] [PATCH] provide an input parameter to specify 3d
stereo format for mkv/webm 3d videos
To: FFmpeg development discussions and patches <[email protected]>
Hi,
I prepare new patch based on Alok. It read and write stereo mode flag using
metadata tags.
Also it reads combined planes virtual streams and mark them like:
stereo_mode -> left_3
stereo_mode -> right_3
2011/4/26 Reimar Döffinger <[email protected]>
> I think it would be more user-friendly to allow an actual string instead
> of just numbers, also specifying a value that is not supported should at
> least print a warning or even fail.
>
In patch integers were replaced with strings. But the problem is
that names for stereoscopic formats are not standardized
and this is unclear how user should select them (but sure - magic integers
not better)...
if ((tag = av_metadata_get(st->metadata, "stereo_mode", NULL, 0)) ||
> (tag = av_metadata_get( s->metadata, "stereo_mode", NULL, 0)))
> ...
> Will prefer stream metadata but can also use global metadata.
> Of course the proper solution is to implement a way to specify
> per-stream metadata on the command-line.
>
This is ugly but while no way to setup metadata per stream from console -
may be useful.
I'll try to implement per stream metadata setup for ffmpeg but its options
logic is much complicated
and I fear to write something stupid...
-----------------------------------------------
Kirill Gavrilov,
Software designer.
diff --git a/libavformat/matroska.h b/libavformat/matroska.h
index 0d0d0bc..4895977 100644
--- a/libavformat/matroska.h
+++ b/libavformat/matroska.h
@@ -77,8 +77,13 @@
#define MATROSKA_ID_TRACKNUMBER 0xD7
#define MATROSKA_ID_TRACKUID 0x73C5
#define MATROSKA_ID_TRACKTYPE 0x83
-#define MATROSKA_ID_TRACKAUDIO 0xE1
-#define MATROSKA_ID_TRACKVIDEO 0xE0
+#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
@@ -111,7 +116,7 @@
#define MATROSKA_ID_VIDEOPIXELCROPR 0x54DD
#define MATROSKA_ID_VIDEODISPLAYUNIT 0x54B2
#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A
-#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9
+#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B8
#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3
#define MATROSKA_ID_VIDEOCOLORSPACE 0x2EB524
@@ -218,6 +223,24 @@ 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
*/
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 55f62b8..012151a 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 {
@@ -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]))
@@ -1472,6 +1509,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 5ce2a54..d6fb553 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -588,6 +588,61 @@ 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(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
+ || stereo_fmt == MATROSKA_VIDEO_STEREOMODE_RIGHT_LEFT)
+ valid_fmt = 1;
+ 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 (st->sample_aspect_ratio.num) {
int d_width = codec->width*av_q2d(st->sample_aspect_ratio);
put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width);
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel