matroskaenc: write correct Display{Width, Height} in stereo encoding

Message ID 20141027191226.789EE5DDCC@aruru.libav.org
State New
Headers show

Commit Message

Janne Grunau Oct. 27, 2014, 7:12 p.m.
Module: libav
Branch: master
Commit: 090c67d586e3916f9acc49e010b6389d07f97153

Author:    Vittorio Giovara <vittorio.giovara@gmail.com>
Committer: Vittorio Giovara <vittorio.giovara@gmail.com>
Date:      Wed Oct 22 14:36:32 2014 +0100

matroskaenc: write correct Display{Width, Height} in stereo encoding

should be the raw amount of pixels (for example 3840x1080 for full HD side by
side) and the DisplayWidth/Height in pixels should be the amount of pixels for
one plane (1920x1080 for that full HD stream)."

So, move the aspect ratio check in the mkv_write_stereo_mode() function
and always write the embl when stereo format and/or aspect ration is set.
Also add a few comments to that function.

CC: libav-stable@libav.org
Found-by: Asan Usipov <asan.usipov@gmail.com>

---

 libavformat/matroskaenc.c |   30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

Patch

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index ed68170..4ec474d 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -629,6 +629,9 @@  static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
                                  AVStream *st, int mode)
 {
     int i;
+    int display_width, display_height;
+    int h_width = 1, h_height = 1;
+    AVCodecContext *codec = st->codec;
     AVDictionaryEntry *tag;
     MatroskaVideoStereoModeType format = MATROSKA_VIDEO_STEREOMODE_TYPE_NB;
 
@@ -643,6 +646,7 @@  static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
         }
     }
 
+    // iterate to find the stereo3d side data
     for (i = 0; i < st->nb_side_data; i++) {
         AVPacketSideData sd = st->side_data[i];
         if (sd.type == AV_PKT_DATA_STEREO3D) {
@@ -656,11 +660,13 @@  static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
                 format = (stereo->flags & AV_STEREO3D_FLAG_INVERT)
                     ? MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT
                     : MATROSKA_VIDEO_STEREOMODE_TYPE_LEFT_RIGHT;
+                h_width = 2;
                 break;
             case AV_STEREO3D_TOPBOTTOM:
                 format = MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM;
                 if (stereo->flags & AV_STEREO3D_FLAG_INVERT)
                     format--;
+                h_height = 2;
                 break;
             case AV_STEREO3D_CHECKERBOARD:
                 format = MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_LR;
@@ -671,11 +677,13 @@  static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
                 format = MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_LR;
                 if (stereo->flags & AV_STEREO3D_FLAG_INVERT)
                     format--;
+                h_height = 2;
                 break;
             case AV_STEREO3D_COLUMNS:
                 format = MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_LR;
                 if (stereo->flags & AV_STEREO3D_FLAG_INVERT)
                     format--;
+                h_width = 2;
                 break;
             case AV_STEREO3D_FRAMESEQUENCE:
                 format = MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_LR;
@@ -688,14 +696,30 @@  static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
         }
     }
 
+    // if webm, do not write unsupported modes
     if (mode == MODE_WEBM &&
         (format > MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM &&
          format != MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT))
         format = MATROSKA_VIDEO_STEREOMODE_TYPE_NB;
 
+    // write StereoMode if format is valid
     if (format < MATROSKA_VIDEO_STEREOMODE_TYPE_NB)
         put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, format);
 
+    // write DisplayWidth and DisplayHeight, they contain the size of
+    // a single source view and/or the display aspect ratio
+    display_width  = codec->width  / h_width;
+    display_height = codec->height / h_height;
+    if (st->sample_aspect_ratio.num) {
+        display_width *= av_q2d(st->sample_aspect_ratio);
+        put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, 3); // DAR
+    }
+    if (st->sample_aspect_ratio.num ||
+        format < MATROSKA_VIDEO_STEREOMODE_TYPE_NB) {
+        put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH,  display_width);
+        put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, display_height);
+    }
+
     return 0;
 }
 
@@ -805,12 +829,6 @@  static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
         if (ret < 0)
             return ret;
 
-        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);
-            put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height);
-            put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, 3);
-        }
         end_ebml_master(pb, subinfo);
         break;