avviddec: Map any stereo3D info to multiview modes
authorJan Schmidt <jan@centricular.com>
Thu, 16 Mar 2017 04:23:01 +0000 (15:23 +1100)
committerJan Schmidt <jan@centricular.com>
Thu, 16 Mar 2017 04:23:01 +0000 (15:23 +1100)
Map any libav Stereo3D side data to GStreamer multiview
mode / flags for playback.

https://bugzilla.gnome.org/show_bug.cgi?id=767938

ext/libav/gstavviddec.c
ext/libav/gstavviddec.h

index 17a6430..1f6edc3 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <libavcodec/avcodec.h>
+#include <libavutil/stereo3d.h>
 
 #include <gst/gst.h>
 #include <gst/video/video.h>
@@ -442,6 +443,8 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder,
     ffmpegdec->ctx_ticks = 0;
     ffmpegdec->ctx_time_n = 0;
     ffmpegdec->ctx_time_d = 0;
+    ffmpegdec->cur_multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+    ffmpegdec->cur_multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
   }
 
   gst_caps_replace (&ffmpegdec->last_caps, state->caps);
@@ -902,7 +905,9 @@ picture_changed (GstFFMpegVidDec * ffmpegdec, AVFrame * picture)
       && ffmpegdec->pic_par_n == picture->sample_aspect_ratio.num
       && ffmpegdec->pic_par_d == picture->sample_aspect_ratio.den
       && ffmpegdec->pic_interlaced == picture->interlaced_frame
-      && ffmpegdec->pic_field_order == pic_field_order);
+      && ffmpegdec->pic_field_order == pic_field_order
+      && ffmpegdec->cur_multiview_mode == ffmpegdec->picture_multiview_mode
+      && ffmpegdec->cur_multiview_flags == ffmpegdec->picture_multiview_flags);
 }
 
 static gboolean
@@ -946,6 +951,8 @@ update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
   ffmpegdec->pic_height = picture->height;
   ffmpegdec->pic_par_n = picture->sample_aspect_ratio.num;
   ffmpegdec->pic_par_d = picture->sample_aspect_ratio.den;
+  ffmpegdec->cur_multiview_mode = ffmpegdec->picture_multiview_mode;
+  ffmpegdec->cur_multiview_flags = ffmpegdec->picture_multiview_flags;
 
   /* Remember if we have interlaced content and the field order changed
    * at least once. If that happens, we must be interlace-mode=mixed
@@ -1042,6 +1049,31 @@ no_par:
   }
 }
 
+static GstVideoMultiviewMode
+stereo_av_to_gst (enum AVStereo3DType type)
+{
+  switch (type) {
+    case AV_STEREO3D_SIDEBYSIDE:
+      return GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+    case AV_STEREO3D_TOPBOTTOM:
+      return GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+    case AV_STEREO3D_FRAMESEQUENCE:
+      return GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
+    case AV_STEREO3D_CHECKERBOARD:
+      return GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD;
+    case AV_STEREO3D_SIDEBYSIDE_QUINCUNX:
+      return GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX;
+    case AV_STEREO3D_LINES:
+      return GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
+    case AV_STEREO3D_COLUMNS:
+      return GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED;
+    default:
+      break;
+  }
+
+  return GST_VIDEO_MULTIVIEW_MODE_NONE;
+}
+
 static gboolean
 gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec,
     AVCodecContext * context, AVFrame * picture)
@@ -1240,13 +1272,8 @@ gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec,
   /* calculate and update par now */
   gst_ffmpegviddec_update_par (ffmpegdec, in_info, out_info);
 
-  /* Copy stereo/multiview info from upstream if set */
-  if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
-    GST_VIDEO_INFO_MULTIVIEW_MODE (out_info) =
-        GST_VIDEO_INFO_MULTIVIEW_MODE (in_info);
-    GST_VIDEO_INFO_MULTIVIEW_FLAGS (out_info) =
-        GST_VIDEO_INFO_MULTIVIEW_FLAGS (in_info);
-  }
+  GST_VIDEO_INFO_MULTIVIEW_MODE (out_info) = ffmpegdec->cur_multiview_mode;
+  GST_VIDEO_INFO_MULTIVIEW_FLAGS (out_info) = ffmpegdec->cur_multiview_flags;
 
   if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (ffmpegdec)))
     goto negotiate_failed;
@@ -1522,6 +1549,31 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
   gst_buffer_replace (&out_frame->output_buffer, out_dframe->buffer);
   gst_buffer_replace (&out_dframe->buffer, NULL);
 
+  /* Extract auxilliary info not stored in the main AVframe */
+  {
+    GstVideoInfo *in_info = &ffmpegdec->input_state->info;
+    /* Take multiview mode from upstream if present */
+    ffmpegdec->picture_multiview_mode = GST_VIDEO_INFO_MULTIVIEW_MODE (in_info);
+    ffmpegdec->picture_multiview_flags =
+        GST_VIDEO_INFO_MULTIVIEW_FLAGS (in_info);
+
+    /* Otherwise, see if there's info in the frame */
+    if (ffmpegdec->picture_multiview_mode == GST_VIDEO_MULTIVIEW_MODE_NONE) {
+      AVFrameSideData *side_data =
+          av_frame_get_side_data (ffmpegdec->picture, AV_FRAME_DATA_STEREO3D);
+      if (side_data) {
+        AVStereo3D *stereo = (AVStereo3D *) side_data->data;
+        ffmpegdec->picture_multiview_mode = stereo_av_to_gst (stereo->type);
+        if (stereo->flags & AV_STEREO3D_FLAG_INVERT) {
+          ffmpegdec->picture_multiview_flags =
+              GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+        } else {
+          ffmpegdec->picture_multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+        }
+      }
+    }
+  }
+
   GST_DEBUG_OBJECT (ffmpegdec,
       "pts %" G_GUINT64_FORMAT " duration %" G_GUINT64_FORMAT,
       out_frame->pts, out_frame->duration);
index 1c4375f..5fdf0dd 100644 (file)
@@ -37,6 +37,8 @@ struct _GstFFMpegVidDec
   /* decoding */
   AVCodecContext *context;
   AVFrame *picture;
+  GstVideoMultiviewMode picture_multiview_mode;
+  GstVideoMultiviewFlags picture_multiview_flags;
   gint stride[AV_NUM_DATA_POINTERS];
   gboolean opened;
 
@@ -50,6 +52,8 @@ struct _GstFFMpegVidDec
   /* GST_VIDEO_BUFFER_FLAG_RFF | GST_VIDEO_BUFFER_FLAG_TFF */
   gint pic_field_order;
   gboolean pic_field_order_changed;
+  GstVideoMultiviewMode cur_multiview_mode;
+  GstVideoMultiviewFlags cur_multiview_flags;
   /* current context */
   gint ctx_ticks;
   gint ctx_time_d;