Blame gst-libs/gst/gl/gstglviewconvert.c

Packit 971217
/*
Packit 971217
 * GStreamer
Packit 971217
 * Copyright (C) 2009 Julien Isorce <julien.isorce@mail.com>
Packit 971217
 * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
Packit 971217
 * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:gstglviewconvert
Packit 971217
 * @title: GstGLViewConvert
Packit 971217
 * @short_description: convert between steroscopic/multiview video formats
Packit 971217
 * @see_also: #GstGLColorConvert, #GstGLContext
Packit 971217
 *
Packit 971217
 * Convert stereoscopic/multiview video using fragment shaders.
Packit 971217
 */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
#include "gstglviewconvert.h"
Packit 971217
Packit 971217
#include <gst/video/gstvideoaffinetransformationmeta.h>
Packit 971217
Packit 971217
#include "gstglcontext.h"
Packit 971217
#include "gstglframebuffer.h"
Packit 971217
#include "gstglmemory.h"
Packit 971217
#include "gstglshader.h"
Packit 971217
#include "gstglshaderstrings.h"
Packit 971217
#include "gstglsl.h"
Packit 971217
#include "gstglsl_private.h"
Packit 971217
#include "gstglslstage.h"
Packit 971217
#include "gstglutils_private.h"
Packit 971217
Packit 971217
#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
Packit 971217
#define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
Packit 971217
#define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
Packit 971217
#define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
Packit 971217
#define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
Packit 971217
Packit 971217
static GstStaticCaps caps_template =
Packit 971217
GST_STATIC_CAPS ("video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
Packit 971217
    "format = (string) RGBA, "
Packit 971217
    "width = " GST_VIDEO_SIZE_RANGE ", "
Packit 971217
    "height = " GST_VIDEO_SIZE_RANGE ", "
Packit 971217
    "framerate = " GST_VIDEO_FPS_RANGE ", "
Packit 971217
    "texture-target = (string) { 2D, rectangle, external-oes } ");
Packit 971217
Packit 971217
#define GST_CAT_DEFAULT gst_gl_view_convert_debug
Packit 971217
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
Packit 971217
Packit 971217
enum
Packit 971217
{
Packit 971217
  PROP_0,
Packit 971217
  PROP_INPUT_LAYOUT,
Packit 971217
  PROP_INPUT_FLAGS,
Packit 971217
  PROP_OUTPUT_LAYOUT,
Packit 971217
  PROP_OUTPUT_FLAGS,
Packit 971217
  PROP_OUTPUT_DOWNMIX_MODE
Packit 971217
};
Packit 971217
Packit 971217
#define DEFAULT_DOWNMIX GST_GL_STEREO_DOWNMIX_ANAGLYPH_GREEN_MAGENTA_DUBOIS
Packit 971217
Packit 971217
struct _GstGLViewConvertPrivate
Packit 971217
{
Packit 971217
  gboolean result;
Packit 971217
Packit 971217
  GstVideoMultiviewMode input_mode;
Packit 971217
  GstVideoMultiviewFlags input_flags;
Packit 971217
  GstVideoMultiviewMode output_mode;
Packit 971217
  GstVideoMultiviewFlags output_flags;
Packit 971217
Packit 971217
  GstBuffer *primary_in;
Packit 971217
  GstBuffer *auxilliary_in;
Packit 971217
Packit 971217
  GstBuffer *primary_out;
Packit 971217
  GstBuffer *auxilliary_out;
Packit 971217
Packit 971217
  GstGLMemory *in_tex[GST_VIDEO_MAX_PLANES];
Packit 971217
  GstGLMemory *out_tex[GST_VIDEO_MAX_PLANES];
Packit 971217
  guint n_out_tex;
Packit 971217
Packit 971217
  GLuint vao;
Packit 971217
  GLuint vertex_buffer;
Packit 971217
  GLuint vbo_indices;
Packit 971217
  GLuint attr_position;
Packit 971217
  GLuint attr_texture;
Packit 971217
};
Packit 971217
Packit 971217
#define GST_GL_VIEW_CONVERT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
Packit 971217
    GST_TYPE_GL_VIEW_CONVERT, GstGLViewConvertPrivate))
Packit 971217
Packit 971217
#define DEBUG_INIT \
Packit 971217
  GST_DEBUG_CATEGORY_INIT (gst_gl_view_convert_debug, "glviewconvert", 0, "glviewconvert object");
Packit 971217
Packit 971217
G_DEFINE_TYPE_WITH_CODE (GstGLViewConvert, gst_gl_view_convert,
Packit 971217
    GST_TYPE_OBJECT, DEBUG_INIT);
Packit 971217
Packit 971217
static void gst_gl_view_convert_set_property (GObject * object,
Packit 971217
    guint prop_id, const GValue * value, GParamSpec * pspec);
Packit 971217
static void gst_gl_view_convert_get_property (GObject * object,
Packit 971217
    guint prop_id, GValue * value, GParamSpec * pspec);
Packit 971217
static void gst_gl_view_convert_finalize (GObject * object);
Packit 971217
Packit 971217
static void _do_view_convert (GstGLContext * context,
Packit 971217
    GstGLViewConvert * viewconvert);
Packit 971217
Packit 971217
GType
Packit 971217
gst_gl_stereo_downmix_mode_get_type (void)
Packit 971217
{
Packit 971217
  static volatile gsize g_define_type_id__volatile = 0;
Packit 971217
  if (g_once_init_enter (&g_define_type_id__volatile)) {
Packit 971217
    static const GEnumValue values[] = {
Packit 971217
      {GST_GL_STEREO_DOWNMIX_ANAGLYPH_GREEN_MAGENTA_DUBOIS,
Packit 971217
          "Dubois optimised Green-Magenta anaglyph", "green-magenta-dubois"},
Packit 971217
      {GST_GL_STEREO_DOWNMIX_ANAGLYPH_RED_CYAN_DUBOIS,
Packit 971217
            "Dubois optimised Red-Cyan anaglyph",
Packit 971217
          "red-cyan-dubois"},
Packit 971217
      {GST_GL_STEREO_DOWNMIX_ANAGLYPH_AMBER_BLUE_DUBOIS,
Packit 971217
          "Dubois optimised Amber-Blue anaglyph", "amber-blue-dubois"},
Packit 971217
      {0, NULL, NULL}
Packit 971217
    };
Packit 971217
    GType g_define_type_id =
Packit 971217
        g_enum_register_static ("GstGLStereoDownmix", values);
Packit 971217
    g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
Packit 971217
  }
Packit 971217
  return g_define_type_id__volatile;
Packit 971217
}
Packit 971217
Packit 971217
/* *INDENT-OFF* */
Packit 971217
/* These match the order and number of DOWNMIX_ANAGLYPH_* modes */
Packit 971217
static GLfloat downmix_matrices[][2][9] = {
Packit 971217
  {                             /* Green-Magenta Dubois */
Packit 971217
        {-0.062f, 0.284f, -0.015f, -0.158f, 0.668f, -0.027f, -0.039f, 0.143f, 0.021f},
Packit 971217
        {0.529f, -0.016f, 0.009f, 0.705f, -0.015f, 0.075f, 0.024f, -0.065f, 0.937f}
Packit 971217
      },
Packit 971217
  {                             /* Red-Cyan Dubois */
Packit 971217
        /* Source of this matrix: http://www.site.uottawa.ca/~edubois/anaglyph/LeastSquaresHowToPhotoshop.pdf */
Packit 971217
        {0.437f, -0.062f, -0.048f, 0.449f, -0.062f, -0.050f, 0.164f, -0.024f, -0.017f},
Packit 971217
        {-0.011f, 0.377f, -0.026f, -0.032f, 0.761f, -0.093f, -0.007f, 0.009f, 1.234f}
Packit 971217
      },
Packit 971217
  {                             /* Amber-blue Dubois */
Packit 971217
        {1.062f, -0.026f, -0.038f, -0.205f, 0.908f, -0.173f, 0.299f, 0.068f, 0.022f},
Packit 971217
        {-0.016f, 0.006f, 0.094f, -0.123f, 0.062f, 0.185f, -0.017f, -0.017f, 0.911f}
Packit 971217
      }
Packit 971217
};
Packit 971217
Packit 971217
static gfloat identity_matrix[] = {
Packit 971217
  1.0f, 0.0f, 0.0f, 0.0f,
Packit 971217
  0.0f, 1.0f, 0.0f, 0.0f,
Packit 971217
  0.0f, 0.0f, 1.0f, 0.0f,
Packit 971217
  0.0f, 0.0f, 0.0f, 1.0f,
Packit 971217
};
Packit 971217
/* *INDENT-ON* */
Packit 971217
Packit 971217
#define glsl_OES_extension_string "#extension GL_OES_EGL_image_external : require \n"
Packit 971217
Packit 971217
/* *INDENT-OFF* */
Packit 971217
static const gchar *fragment_header =
Packit 971217
  "#ifdef GL_ES\n"
Packit 971217
  "precision mediump float;\n"
Packit 971217
  "#endif\n"
Packit 971217
  "uniform sampler2D tex_l;\n"
Packit 971217
  "uniform sampler2D tex_r;\n"
Packit 971217
  "uniform float width;\n"
Packit 971217
  "uniform float height;\n"
Packit 971217
  "uniform mat3 downmix[2];\n"
Packit 971217
  "uniform vec2 tex_scale[2];\n"
Packit 971217
  "uniform vec2 offsets[2];\n";
Packit 971217
Packit 971217
static const gchar *frag_input =
Packit 971217
  "  vec2 l_tex = v_texcoord * tex_scale[0] + offsets[0];\n"
Packit 971217
  "  vec2 r_tex = v_texcoord * tex_scale[1] + offsets[1];\n"
Packit 971217
  "  l = texture2D(tex_l, l_tex).rgba;\n"
Packit 971217
  "  r = texture2D(tex_r, r_tex).rgba;\n";
Packit 971217
Packit 971217
static const gchar *frag_output_downmix =
Packit 971217
  "  vec3 lcol = l.rgb * l.a + vec3(1.0-l.a);\n"
Packit 971217
  "  vec3 rcol = r.rgb * r.a + vec3(1.0-r.a);\n"
Packit 971217
  "  if (l.a + r.a > 0.0) {\n"
Packit 971217
  "    lcol = clamp (downmix[0] * lcol, 0.0, 1.0);\n"
Packit 971217
  "    rcol = clamp (downmix[1] * rcol, 0.0, 1.0);\n"
Packit 971217
  "    gl_FragColor = vec4 (lcol + rcol, 1.0);\n"
Packit 971217
  "  } else {\n"
Packit 971217
  "    gl_FragColor = vec4 (0.0);\n"
Packit 971217
  "  }\n";
Packit 971217
Packit 971217
static const gchar *frag_output_left =
Packit 971217
  "  gl_FragColor = l;\n";
Packit 971217
Packit 971217
static const gchar *frag_output_right =
Packit 971217
  "  gl_FragColor = r;\n";
Packit 971217
Packit 971217
static const gchar *frag_output_side_by_side =
Packit 971217
  "  if (v_texcoord.x < 0.5) {\n"
Packit 971217
  "    gl_FragColor = l;\n"
Packit 971217
  "  } else {\n"
Packit 971217
  "    gl_FragColor = r;\n"
Packit 971217
  "  };\n";
Packit 971217
Packit 971217
static const gchar *frag_output_top_bottom =
Packit 971217
  "if (v_texcoord.y < 0.5) {\n"
Packit 971217
  "  gl_FragColor = l;\n"
Packit 971217
  "} else {\n"
Packit 971217
  "  gl_FragColor = r;\n"
Packit 971217
  "};\n";
Packit 971217
Packit 971217
static const gchar *frag_output_column_interleaved =
Packit 971217
  "if (int(mod(l_tex.x * width, 2.0)) == 0) {\n"
Packit 971217
  "  gl_FragColor = l;\n"
Packit 971217
  "} else {\n"
Packit 971217
  "  gl_FragColor = r;\n"
Packit 971217
  "};\n";
Packit 971217
Packit 971217
static const gchar *frag_output_row_interleaved =
Packit 971217
  "if (int(mod(l_tex.y * height, 2.0)) == 0) {\n"
Packit 971217
  "  gl_FragColor = l;\n"
Packit 971217
  "} else {\n"
Packit 971217
  "  gl_FragColor = r;\n"
Packit 971217
  "};\n";
Packit 971217
Packit 971217
static const gchar *frag_output_checkerboard =
Packit 971217
  "if (int(mod(l_tex.x * width, 2.0)) == \n"
Packit 971217
  "    int(mod(l_tex.y * height, 2.0))) {\n"
Packit 971217
  "  gl_FragColor = l;\n"
Packit 971217
  "} else {\n"
Packit 971217
  "  gl_FragColor = r;\n"
Packit 971217
  "};\n";
Packit 971217
Packit 971217
static const gchar *frag_output_separated =
Packit 971217
  "gl_FragData[0] = l;\n"
Packit 971217
  "gl_FragData[1] = r;\n";
Packit 971217
/* *INDENT-ON* */
Packit 971217
Packit 971217
static const GLfloat vertices[] = {
Packit 971217
  1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
Packit 971217
  -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
Packit 971217
  -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
Packit 971217
  1.0f, 1.0f, 0.0f, 1.0f, 1.0f
Packit 971217
};
Packit 971217
Packit 971217
static const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
Packit 971217
Packit 971217
static void
Packit 971217
gst_gl_view_convert_class_init (GstGLViewConvertClass * klass)
Packit 971217
{
Packit 971217
  GObjectClass *gobject_class = (GObjectClass *) klass;
Packit 971217
Packit 971217
  g_type_class_add_private (klass, sizeof (GstGLViewConvertPrivate));
Packit 971217
Packit 971217
  gobject_class->set_property = gst_gl_view_convert_set_property;
Packit 971217
  gobject_class->get_property = gst_gl_view_convert_get_property;
Packit 971217
  gobject_class->finalize = gst_gl_view_convert_finalize;
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_class, PROP_INPUT_LAYOUT,
Packit 971217
      g_param_spec_enum ("input-mode-override",
Packit 971217
          "Input Multiview Mode Override",
Packit 971217
          "Override any input information about multiview layout",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_MODE,
Packit 971217
          GST_VIDEO_MULTIVIEW_MODE_NONE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_INPUT_FLAGS,
Packit 971217
      g_param_spec_flags ("input-flags-override",
Packit 971217
          "Input Multiview Flags Override",
Packit 971217
          "Override any input information about multiview layout flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGS, GST_VIDEO_MULTIVIEW_FLAGS_NONE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_OUTPUT_LAYOUT,
Packit 971217
      g_param_spec_enum ("output-mode-override",
Packit 971217
          "Output Multiview Mode Override",
Packit 971217
          "Override automatic output mode selection for multiview layout",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_MODE, GST_VIDEO_MULTIVIEW_MODE_NONE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_OUTPUT_FLAGS,
Packit 971217
      g_param_spec_flags ("output-flags-override",
Packit 971217
          "Output Multiview Flags Override",
Packit 971217
          "Override automatic negotiation for output multiview layout flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGS, GST_VIDEO_MULTIVIEW_FLAGS_NONE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_OUTPUT_DOWNMIX_MODE,
Packit 971217
      g_param_spec_enum ("downmix-mode", "Mode for mono downmixed output",
Packit 971217
          "Output anaglyph type to generate when downmixing to mono",
Packit 971217
          GST_TYPE_GL_STEREO_DOWNMIX_MODE_TYPE, DEFAULT_DOWNMIX,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_gl_view_convert_init (GstGLViewConvert * convert)
Packit 971217
{
Packit 971217
  convert->priv = GST_GL_VIEW_CONVERT_GET_PRIVATE (convert);
Packit 971217
Packit 971217
  convert->shader = NULL;
Packit 971217
  convert->downmix_mode = DEFAULT_DOWNMIX;
Packit 971217
  convert->priv->input_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
Packit 971217
  convert->priv->input_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
Packit 971217
  convert->priv->output_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
Packit 971217
  convert->priv->output_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
Packit 971217
Packit 971217
  convert->input_mode_override = GST_VIDEO_MULTIVIEW_MODE_NONE;
Packit 971217
  convert->input_flags_override = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
Packit 971217
  convert->output_mode_override = GST_VIDEO_MULTIVIEW_MODE_NONE;
Packit 971217
  convert->output_flags_override = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
Packit 971217
Packit 971217
  gst_video_info_init (&convert->in_info);
Packit 971217
  gst_video_info_init (&convert->out_info);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_gl_view_convert_finalize (GObject * object)
Packit 971217
{
Packit 971217
  GstGLViewConvert *viewconvert;
Packit 971217
Packit 971217
  viewconvert = GST_GL_VIEW_CONVERT (object);
Packit 971217
Packit 971217
  gst_gl_view_convert_reset (viewconvert);
Packit 971217
Packit 971217
  gst_buffer_replace (&viewconvert->priv->primary_in, NULL);
Packit 971217
  gst_buffer_replace (&viewconvert->priv->auxilliary_in, NULL);
Packit 971217
  gst_buffer_replace (&viewconvert->priv->primary_out, NULL);
Packit 971217
  gst_buffer_replace (&viewconvert->priv->auxilliary_out, NULL);
Packit 971217
Packit 971217
  if (viewconvert->context) {
Packit 971217
    gst_object_unref (viewconvert->context);
Packit 971217
    viewconvert->context = NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  G_OBJECT_CLASS (gst_gl_view_convert_parent_class)->finalize (object);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_new:
Packit 971217
 *
Packit 971217
 * Returns: (transfer full): a new #GstGLViewConvert
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
GstGLViewConvert *
Packit 971217
gst_gl_view_convert_new (void)
Packit 971217
{
Packit 971217
  GstGLViewConvert *convert;
Packit 971217
Packit 971217
  convert = g_object_new (GST_TYPE_GL_VIEW_CONVERT, NULL);
Packit 971217
  gst_object_ref_sink (convert);
Packit 971217
Packit 971217
  return convert;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_set_context:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @context: the #GstGLContext to set
Packit 971217
 *
Packit 971217
 * Set @context on @viewconvert
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_gl_view_convert_set_context (GstGLViewConvert * viewconvert,
Packit 971217
    GstGLContext * context)
Packit 971217
{
Packit 971217
  g_return_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert));
Packit 971217
Packit 971217
  if (gst_object_replace ((GstObject **) & viewconvert->context,
Packit 971217
          GST_OBJECT (context)))
Packit 971217
    gst_gl_view_convert_reset (viewconvert);
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_view_convert_set_format (GstGLViewConvert * viewconvert,
Packit 971217
    GstVideoInfo * in_info, GstGLTextureTarget from_target,
Packit 971217
    GstVideoInfo * out_info, GstGLTextureTarget to_target)
Packit 971217
{
Packit 971217
  gboolean passthrough;
Packit 971217
  g_return_val_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert), FALSE);
Packit 971217
Packit 971217
  if (gst_video_info_is_equal (in_info, &viewconvert->in_info) &&
Packit 971217
      gst_video_info_is_equal (out_info, &viewconvert->out_info) &&
Packit 971217
      viewconvert->from_texture_target == from_target &&
Packit 971217
      viewconvert->to_texture_target == to_target)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_RGBA ||
Packit 971217
      GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_RGBA) {
Packit 971217
    GST_ERROR_OBJECT (viewconvert,
Packit 971217
        "Multiview conversion can currently only be performed on RGBA textures");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  passthrough = gst_video_info_is_equal (in_info, out_info) &&
Packit 971217
      from_target == to_target;
Packit 971217
Packit 971217
  if (!passthrough && to_target != GST_GL_TEXTURE_TARGET_2D
Packit 971217
      && to_target != GST_GL_TEXTURE_TARGET_RECTANGLE)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  /* FIXME: Compare what changed and decide if we need a full reset or not */
Packit 971217
  GST_OBJECT_LOCK (viewconvert);
Packit 971217
  gst_gl_view_convert_reset (viewconvert);
Packit 971217
Packit 971217
  viewconvert->in_info = *in_info;
Packit 971217
  viewconvert->out_info = *out_info;
Packit 971217
  viewconvert->from_texture_target = from_target;
Packit 971217
  viewconvert->to_texture_target = to_target;
Packit 971217
  viewconvert->caps_passthrough = passthrough;
Packit 971217
Packit 971217
  gst_buffer_replace (&viewconvert->priv->primary_in, NULL);
Packit 971217
  gst_buffer_replace (&viewconvert->priv->auxilliary_in, NULL);
Packit 971217
  gst_buffer_replace (&viewconvert->priv->primary_out, NULL);
Packit 971217
  gst_buffer_replace (&viewconvert->priv->auxilliary_out, NULL);
Packit 971217
  GST_OBJECT_UNLOCK (viewconvert);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_set_caps:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @in_caps: input #GstCaps
Packit 971217
 * @out_caps: output #GstCaps
Packit 971217
 *
Packit 971217
 * Initializes @viewconvert with the information required for conversion.
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_gl_view_convert_set_caps (GstGLViewConvert * viewconvert,
Packit 971217
    GstCaps * in_caps, GstCaps * out_caps)
Packit 971217
{
Packit 971217
  GstVideoInfo in_info, out_info;
Packit 971217
  GstCapsFeatures *in_features, *out_features;
Packit 971217
  GstGLTextureTarget from_target = GST_GL_TEXTURE_TARGET_2D;
Packit 971217
  GstGLTextureTarget to_target = GST_GL_TEXTURE_TARGET_2D;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert), FALSE);
Packit 971217
  g_return_val_if_fail (GST_IS_CAPS (in_caps), FALSE);
Packit 971217
  g_return_val_if_fail (GST_IS_CAPS (out_caps), FALSE);
Packit 971217
Packit 971217
  GST_INFO_OBJECT (viewconvert,
Packit 971217
      "Configuring multiview conversion from caps %" GST_PTR_FORMAT
Packit 971217
      " to %" GST_PTR_FORMAT, in_caps, out_caps);
Packit 971217
Packit 971217
  in_features = gst_caps_get_features (in_caps, 0);
Packit 971217
  out_features = gst_caps_get_features (out_caps, 0);
Packit 971217
Packit 971217
  if (!gst_caps_features_contains (in_features,
Packit 971217
          GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
Packit 971217
    return FALSE;
Packit 971217
  if (!gst_caps_features_contains (out_features,
Packit 971217
          GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (!gst_video_info_from_caps (&in_info, in_caps))
Packit 971217
    return FALSE;
Packit 971217
  if (!gst_video_info_from_caps (&out_info, out_caps))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  {
Packit 971217
    GstStructure *in_s = gst_caps_get_structure (in_caps, 0);
Packit 971217
    GstStructure *out_s = gst_caps_get_structure (out_caps, 0);
Packit 971217
Packit 971217
    if (gst_structure_has_field_typed (in_s, "texture-target", G_TYPE_STRING)) {
Packit 971217
      from_target =
Packit 971217
          gst_gl_texture_target_from_string (gst_structure_get_string (in_s,
Packit 971217
              "texture-target"));
Packit 971217
    }
Packit 971217
Packit 971217
    if (gst_structure_has_field_typed (out_s, "texture-target", G_TYPE_STRING)) {
Packit 971217
      to_target =
Packit 971217
          gst_gl_texture_target_from_string (gst_structure_get_string (out_s,
Packit 971217
              "texture-target"));
Packit 971217
    }
Packit 971217
Packit 971217
    if (to_target == GST_GL_TEXTURE_TARGET_NONE
Packit 971217
        || from_target == GST_GL_TEXTURE_TARGET_NONE)
Packit 971217
      /* invalid caps */
Packit 971217
      return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  return _view_convert_set_format (viewconvert, &in_info, from_target,
Packit 971217
      &out_info, to_target);
Packit 971217
}
Packit 971217
Packit 971217
/* Function that can halve the value
Packit 971217
 * of ints, fractions, int/fraction ranges and lists of ints/fractions */
Packit 971217
static gboolean
Packit 971217
_halve_value (GValue * out, const GValue * in_value)
Packit 971217
{
Packit 971217
  /* Fundamental fixed types first */
Packit 971217
  if (G_VALUE_HOLDS_INT (in_value)) {
Packit 971217
    g_value_init (out, G_TYPE_INT);
Packit 971217
    g_value_set_int (out, MAX (g_value_get_int (in_value) / 2, 1));
Packit 971217
  } else if (GST_VALUE_HOLDS_FRACTION (in_value)) {
Packit 971217
    gint num, den;
Packit 971217
    num = gst_value_get_fraction_numerator (in_value);
Packit 971217
    den = gst_value_get_fraction_denominator (in_value);
Packit 971217
    g_value_init (out, GST_TYPE_FRACTION);
Packit 971217
    /* Don't adjust 'infinite' fractions */
Packit 971217
    if ((num != 1 || den != 2147483647) && (num != 2147483647 || den != 1)) {
Packit 971217
      /* FIXME - could do better approximation when den > G_MAXINT/2? */
Packit 971217
      den = den > G_MAXINT / 2 ? G_MAXINT : den * 2;
Packit 971217
    }
Packit 971217
    gst_value_set_fraction (out, num, den);
Packit 971217
  } else if (GST_VALUE_HOLDS_INT_RANGE (in_value)) {
Packit 971217
    gint range_min = gst_value_get_int_range_min (in_value);
Packit 971217
    gint range_max = gst_value_get_int_range_max (in_value);
Packit 971217
    gint range_step = gst_value_get_int_range_step (in_value);
Packit 971217
    g_value_init (out, GST_TYPE_INT_RANGE);
Packit 971217
    if (range_min != 1)
Packit 971217
      range_min = MAX (1, range_min / 2);
Packit 971217
    if (range_max != G_MAXINT)
Packit 971217
      range_max = MAX (1, range_max / 2);
Packit 971217
    gst_value_set_int_range_step (out, range_min,
Packit 971217
        range_max, MAX (1, range_step / 2));
Packit 971217
  } else if (GST_VALUE_HOLDS_FRACTION_RANGE (in_value)) {
Packit 971217
    GValue min_out = G_VALUE_INIT;
Packit 971217
    GValue max_out = G_VALUE_INIT;
Packit 971217
    const GValue *range_min = gst_value_get_fraction_range_min (in_value);
Packit 971217
    const GValue *range_max = gst_value_get_fraction_range_max (in_value);
Packit 971217
    _halve_value (&min_out, range_min);
Packit 971217
    _halve_value (&max_out, range_max);
Packit 971217
    g_value_init (out, GST_TYPE_FRACTION_RANGE);
Packit 971217
    gst_value_set_fraction_range (out, &min_out, &max_out);
Packit 971217
    g_value_unset (&min_out);
Packit 971217
    g_value_unset (&max_out);
Packit 971217
  } else if (GST_VALUE_HOLDS_LIST (in_value)) {
Packit 971217
    gint i;
Packit 971217
    g_value_init (out, GST_TYPE_LIST);
Packit 971217
    for (i = 0; i < gst_value_list_get_size (in_value); i++) {
Packit 971217
      const GValue *entry;
Packit 971217
      GValue tmp = G_VALUE_INIT;
Packit 971217
Packit 971217
      entry = gst_value_list_get_value (in_value, i);
Packit 971217
      /* Random list values might not be the right type */
Packit 971217
      if (!_halve_value (&tmp, entry))
Packit 971217
        goto fail;
Packit 971217
      gst_value_list_append_and_take_value (out, &tmp);
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
fail:
Packit 971217
  g_value_unset (out);
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static GstStructure *
Packit 971217
_halve_structure_field (const GstStructure * in, const gchar * field_name)
Packit 971217
{
Packit 971217
  GstStructure *out;
Packit 971217
  const GValue *in_value = gst_structure_get_value (in, field_name);
Packit 971217
  GValue tmp = G_VALUE_INIT;
Packit 971217
Packit 971217
  if (G_UNLIKELY (in_value == NULL))
Packit 971217
    return gst_structure_copy (in);     /* Field doesn't exist, leave it as is */
Packit 971217
Packit 971217
  if (!_halve_value (&tmp, in_value))
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  out = gst_structure_copy (in);
Packit 971217
  gst_structure_set_value (out, field_name, &tmp);
Packit 971217
  g_value_unset (&tmp);
Packit 971217
Packit 971217
  return out;
Packit 971217
}
Packit 971217
Packit 971217
/* Function that can double the value
Packit 971217
 * of ints, fractions, int/fraction ranges and lists of ints/fractions */
Packit 971217
static gboolean
Packit 971217
_double_value (GValue * out, const GValue * in_value)
Packit 971217
{
Packit 971217
  /* Fundamental fixed types first */
Packit 971217
  if (G_VALUE_HOLDS_INT (in_value)) {
Packit 971217
    gint n = g_value_get_int (in_value);
Packit 971217
    g_value_init (out, G_TYPE_INT);
Packit 971217
    if (n <= G_MAXINT / 2)
Packit 971217
      g_value_set_int (out, n * 2);
Packit 971217
    else
Packit 971217
      g_value_set_int (out, G_MAXINT);
Packit 971217
  } else if (GST_VALUE_HOLDS_FRACTION (in_value)) {
Packit 971217
    gint num, den;
Packit 971217
    num = gst_value_get_fraction_numerator (in_value);
Packit 971217
    den = gst_value_get_fraction_denominator (in_value);
Packit 971217
    g_value_init (out, GST_TYPE_FRACTION);
Packit 971217
    /* Don't adjust 'infinite' fractions */
Packit 971217
    if ((num != 1 || den != 2147483647) && (num != 2147483647 || den != 1)) {
Packit 971217
      /* FIXME - could do better approximation when num > G_MAXINT/2? */
Packit 971217
      num = num > G_MAXINT / 2 ? G_MAXINT : num * 2;
Packit 971217
    }
Packit 971217
    gst_value_set_fraction (out, num, den);
Packit 971217
  } else if (GST_VALUE_HOLDS_INT_RANGE (in_value)) {
Packit 971217
    gint range_min = gst_value_get_int_range_min (in_value);
Packit 971217
    gint range_max = gst_value_get_int_range_max (in_value);
Packit 971217
    gint range_step = gst_value_get_int_range_step (in_value);
Packit 971217
    if (range_min != 1) {
Packit 971217
      range_min = MIN (G_MAXINT / 2, range_min);
Packit 971217
      range_min *= 2;
Packit 971217
    }
Packit 971217
    if (range_max != G_MAXINT) {
Packit 971217
      range_max = MIN (G_MAXINT / 2, range_max);
Packit 971217
      range_max *= 2;
Packit 971217
    }
Packit 971217
    range_step = MIN (G_MAXINT / 2, range_step);
Packit 971217
    g_value_init (out, GST_TYPE_INT_RANGE);
Packit 971217
    gst_value_set_int_range_step (out, range_min, range_max, range_step);
Packit 971217
  } else if (GST_VALUE_HOLDS_FRACTION_RANGE (in_value)) {
Packit 971217
    GValue min_out = G_VALUE_INIT;
Packit 971217
    GValue max_out = G_VALUE_INIT;
Packit 971217
    const GValue *range_min = gst_value_get_fraction_range_min (in_value);
Packit 971217
    const GValue *range_max = gst_value_get_fraction_range_max (in_value);
Packit 971217
    _double_value (&min_out, range_min);
Packit 971217
    _double_value (&max_out, range_max);
Packit 971217
    g_value_init (out, GST_TYPE_FRACTION_RANGE);
Packit 971217
    gst_value_set_fraction_range (out, &min_out, &max_out);
Packit 971217
    g_value_unset (&min_out);
Packit 971217
    g_value_unset (&max_out);
Packit 971217
  } else if (GST_VALUE_HOLDS_LIST (in_value)) {
Packit 971217
    gint i;
Packit 971217
    g_value_init (out, GST_TYPE_LIST);
Packit 971217
    for (i = 0; i < gst_value_list_get_size (in_value); i++) {
Packit 971217
      const GValue *entry;
Packit 971217
      GValue tmp = G_VALUE_INIT;
Packit 971217
Packit 971217
      entry = gst_value_list_get_value (in_value, i);
Packit 971217
      /* Random list values might not be the right type */
Packit 971217
      if (!_double_value (&tmp, entry))
Packit 971217
        goto fail;
Packit 971217
      gst_value_list_append_and_take_value (out, &tmp);
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
fail:
Packit 971217
  g_value_unset (out);
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static GstStructure *
Packit 971217
_double_structure_field (const GstStructure * in, const gchar * field_name)
Packit 971217
{
Packit 971217
  GstStructure *out;
Packit 971217
  const GValue *in_value = gst_structure_get_value (in, field_name);
Packit 971217
  GValue tmp = G_VALUE_INIT;
Packit 971217
Packit 971217
  if (G_UNLIKELY (in_value == NULL))
Packit 971217
    return gst_structure_copy (in);     /* Field doesn't exist, leave it as is */
Packit 971217
Packit 971217
  if (!_double_value (&tmp, in_value))
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  out = gst_structure_copy (in);
Packit 971217
  gst_structure_set_value (out, field_name, &tmp);
Packit 971217
  g_value_unset (&tmp);
Packit 971217
Packit 971217
  return out;
Packit 971217
}
Packit 971217
Packit 971217
/* Return a copy of the caps with the requested field halved in value/range */
Packit 971217
#if 0
Packit 971217
static GstCaps *
Packit 971217
_halve_caps_field (const GstCaps * in, const gchar * field_name)
Packit 971217
{
Packit 971217
  gint i;
Packit 971217
  GstCaps *out = gst_caps_new_empty ();
Packit 971217
Packit 971217
  for (i = 0; i < gst_caps_get_size (in); i++) {
Packit 971217
    const GstStructure *cur = gst_caps_get_structure (in, i);
Packit 971217
    GstCapsFeatures *f = gst_caps_get_features (in, i);
Packit 971217
Packit 971217
    GstStructure *res = _halve_structure_field (cur, field_name);
Packit 971217
    out =
Packit 971217
        gst_caps_merge_structure_full (out, res,
Packit 971217
        f ? gst_caps_features_copy (f) : NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  return out;
Packit 971217
}
Packit 971217
#endif
Packit 971217
Packit 971217
/* Return a copy of the caps with the requested field doubled in value/range */
Packit 971217
static GstCaps *
Packit 971217
_double_caps_field (const GstCaps * in, const gchar * field_name)
Packit 971217
{
Packit 971217
  gint i;
Packit 971217
  GstCaps *out = gst_caps_new_empty ();
Packit 971217
Packit 971217
  for (i = 0; i < gst_caps_get_size (in); i++) {
Packit 971217
    const GstStructure *cur = gst_caps_get_structure (in, i);
Packit 971217
    GstCapsFeatures *f = gst_caps_get_features (in, i);
Packit 971217
Packit 971217
    GstStructure *res = _double_structure_field (cur, field_name);
Packit 971217
    out =
Packit 971217
        gst_caps_merge_structure_full (out, res,
Packit 971217
        f ? gst_caps_features_copy (f) : NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  return out;
Packit 971217
}
Packit 971217
Packit 971217
/* Takes ownership of the input caps  */
Packit 971217
static GstCaps *
Packit 971217
_expand_par_for_half_aspect (GstCaps * in, gboolean vertical_half_aspect)
Packit 971217
{
Packit 971217
Packit 971217
  guint mview_flags, mview_flags_mask;
Packit 971217
  GstCaps *out;
Packit 971217
  GstStructure *tmp;
Packit 971217
Packit 971217
  out = gst_caps_new_empty ();
Packit 971217
Packit 971217
  while (gst_caps_get_size (in) > 0) {
Packit 971217
    GstStructure *s;
Packit 971217
    GstCapsFeatures *features;
Packit 971217
Packit 971217
    features = gst_caps_get_features (in, 0);
Packit 971217
    if (features)
Packit 971217
      features = gst_caps_features_copy (features);
Packit 971217
Packit 971217
    s = gst_caps_steal_structure (in, 0);
Packit 971217
Packit 971217
    if (!gst_structure_get_flagset (s, "multiview-flags", &mview_flags,
Packit 971217
            &mview_flags_mask)) {
Packit 971217
      gst_caps_append_structure_full (out, s, features);
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
    /* If the input doesn't care about the half-aspect flag, allow current PAR in either variant */
Packit 971217
    if ((mview_flags_mask & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) == 0) {
Packit 971217
      gst_caps_append_structure_full (out, s, features);
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
    if (!gst_structure_has_field (s, "pixel-aspect-ratio")) {
Packit 971217
      /* No par field, dont-care the half-aspect flag */
Packit 971217
      gst_structure_set (s, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
      gst_caps_append_structure_full (out, s, features);
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
Packit 971217
    /* Halve or double PAR base on inputs input specified. */
Packit 971217
Packit 971217
    /* Append a copy with the half-aspect flag as-is */
Packit 971217
    tmp = gst_structure_copy (s);
Packit 971217
    out = gst_caps_merge_structure_full (out, tmp,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
Packit 971217
    /* and then a copy inverted */
Packit 971217
    if (mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
Packit 971217
      /* Input is half-aspect. Double/halve the PAR, clear the flag */
Packit 971217
      if (vertical_half_aspect)
Packit 971217
        tmp = _halve_structure_field (s, "pixel-aspect-ratio");
Packit 971217
      else
Packit 971217
        tmp = _double_structure_field (s, "pixel-aspect-ratio");
Packit 971217
      /* Clear the flag */
Packit 971217
      gst_structure_set (tmp, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask | GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
    } else {
Packit 971217
      if (vertical_half_aspect)
Packit 971217
        tmp = _double_structure_field (s, "pixel-aspect-ratio");
Packit 971217
      else
Packit 971217
        tmp = _halve_structure_field (s, "pixel-aspect-ratio");
Packit 971217
      /* Set the flag */
Packit 971217
      gst_structure_set (tmp, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags | GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask | GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
    }
Packit 971217
Packit 971217
    out = gst_caps_merge_structure_full (out, tmp,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
Packit 971217
    gst_structure_free (s);
Packit 971217
    if (features)
Packit 971217
      gst_caps_features_free (features);
Packit 971217
  }
Packit 971217
Packit 971217
  gst_caps_unref (in);
Packit 971217
Packit 971217
  return out;
Packit 971217
}
Packit 971217
Packit 971217
/* If input supports top-bottom or row-interleaved, we may halve height to mono frames.
Packit 971217
 * If input supports left-right, checkerboard, quincunx or column-interleaved,
Packit 971217
 * we may halve width to mono frames.
Packit 971217
 * For output of top-bottom or row-interleaved, we may double the mono height
Packit 971217
 * For output of left-right, checkerboard, quincunx or column-interleaved,
Packit 971217
 * we may double the mono width.
Packit 971217
 * In all cases, if input has half-aspect and output does not, we may double the PAR
Packit 971217
 * And if input does *not* have half-aspect flag and output does not, we may halve the PAR
Packit 971217
 */
Packit 971217
static GstCaps *
Packit 971217
_expand_structure (GstGLViewConvert * viewconvert,
Packit 971217
    GstCaps * out_caps, GstStructure * structure, GstCapsFeatures * features)
Packit 971217
{
Packit 971217
  GstCaps *expanded_caps, *tmp;
Packit 971217
  GstCaps *mono_caps;
Packit 971217
  const gchar *default_mview_mode_str = NULL;
Packit 971217
  guint mview_flags, mview_flags_mask;
Packit 971217
  const GValue *in_modes;
Packit 971217
  gint i;
Packit 971217
Packit 971217
  /* Empty caps to accumulate into */
Packit 971217
  expanded_caps = gst_caps_new_empty ();
Packit 971217
Packit 971217
  /* First, set defaults if multiview flags are missing */
Packit 971217
  default_mview_mode_str =
Packit 971217
      gst_video_multiview_mode_to_caps_string (GST_VIDEO_MULTIVIEW_MODE_MONO);
Packit 971217
Packit 971217
  mview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
Packit 971217
  mview_flags_mask = GST_FLAG_SET_MASK_EXACT;
Packit 971217
Packit 971217
  if (!gst_structure_has_field (structure, "multiview-mode")) {
Packit 971217
    gst_structure_set (structure,
Packit 971217
        "multiview-mode", G_TYPE_STRING, default_mview_mode_str, NULL);
Packit 971217
  }
Packit 971217
  if (!gst_structure_has_field (structure, "multiview-flags")) {
Packit 971217
    gst_structure_set (structure,
Packit 971217
        "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mview_flags,
Packit 971217
        mview_flags_mask, NULL);
Packit 971217
  } else {
Packit 971217
    gst_structure_get_flagset (structure, "multiview-flags",
Packit 971217
        &mview_flags, &mview_flags_mask);
Packit 971217
  }
Packit 971217
Packit 971217
  in_modes = gst_structure_get_value (structure, "multiview-mode");
Packit 971217
  mono_caps = gst_caps_new_empty ();
Packit 971217
  if (gst_value_intersect (NULL, in_modes,
Packit 971217
          gst_video_multiview_get_mono_modes ())) {
Packit 971217
    GstStructure *new_struct = gst_structure_copy (structure);
Packit 971217
    gst_structure_set_value (new_struct, "multiview-mode",
Packit 971217
        gst_video_multiview_get_mono_modes ());
Packit 971217
    /* Half-aspect makes no sense for mono or unpacked, get rid of it */
Packit 971217
    if (mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
Packit 971217
      gst_structure_set (new_struct, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
    }
Packit 971217
    gst_caps_append_structure_full (mono_caps, new_struct,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
  }
Packit 971217
  if (gst_value_intersect (NULL, in_modes,
Packit 971217
          gst_video_multiview_get_unpacked_modes ())) {
Packit 971217
    GstStructure *new_struct = gst_structure_copy (structure);
Packit 971217
Packit 971217
    gst_structure_set_value (new_struct, "multiview-mode",
Packit 971217
        gst_video_multiview_get_mono_modes ());
Packit 971217
Packit 971217
    /* Half-aspect makes no sense for mono or unpacked, get rid of it */
Packit 971217
    if (mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
Packit 971217
      gst_structure_set (new_struct, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
    }
Packit 971217
    gst_caps_append_structure_full (mono_caps, new_struct,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  if (gst_value_intersect (NULL, in_modes,
Packit 971217
          gst_video_multiview_get_doubled_height_modes ())) {
Packit 971217
    /* Append mono formats with height halved */
Packit 971217
    GstStructure *new_struct = _halve_structure_field (structure, "height");
Packit 971217
    gst_structure_set_value (new_struct, "multiview-mode",
Packit 971217
        gst_video_multiview_get_mono_modes ());
Packit 971217
    /* Normalise the half-aspect flag away */
Packit 971217
    if (mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
Packit 971217
      GstStructure *s =
Packit 971217
          _halve_structure_field (new_struct, "pixel-aspect-ratio");
Packit 971217
      gst_structure_set (structure, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask | GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
      gst_structure_free (new_struct);
Packit 971217
      new_struct = s;
Packit 971217
    }
Packit 971217
    mono_caps = gst_caps_merge_structure_full (mono_caps, new_struct,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
  }
Packit 971217
  if (gst_value_intersect (NULL, in_modes,
Packit 971217
          gst_video_multiview_get_doubled_width_modes ())) {
Packit 971217
    /* Append mono formats with width halved */
Packit 971217
    GstStructure *new_struct = _halve_structure_field (structure, "width");
Packit 971217
    gst_structure_set_value (new_struct, "multiview-mode",
Packit 971217
        gst_video_multiview_get_mono_modes ());
Packit 971217
    /* Normalise the half-aspect flag away */
Packit 971217
    if (mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
Packit 971217
      GstStructure *s =
Packit 971217
          _double_structure_field (new_struct, "pixel-aspect-ratio");
Packit 971217
      gst_structure_set (structure, "multiview-flags",
Packit 971217
          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags & ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT,
Packit 971217
          mview_flags_mask | GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT, NULL);
Packit 971217
      gst_structure_free (new_struct);
Packit 971217
      new_struct = s;
Packit 971217
    }
Packit 971217
    mono_caps = gst_caps_merge_structure_full (mono_caps, new_struct,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
  }
Packit 971217
  if (gst_value_intersect (NULL, in_modes,
Packit 971217
          gst_video_multiview_get_doubled_size_modes ())) {
Packit 971217
    /* Append checkerboard/doubled size formats with width & height halved */
Packit 971217
    GstStructure *new_struct_w = _halve_structure_field (structure, "width");
Packit 971217
    GstStructure *new_struct_wh =
Packit 971217
        _halve_structure_field (new_struct_w, "height");
Packit 971217
    gst_structure_free (new_struct_w);
Packit 971217
    gst_structure_set_value (new_struct_wh, "multiview-mode",
Packit 971217
        gst_video_multiview_get_mono_modes ());
Packit 971217
    mono_caps = gst_caps_merge_structure_full (mono_caps, new_struct_wh,
Packit 971217
        features ? gst_caps_features_copy (features) : NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  /* Everything is normalised now, unset the flags we can change */
Packit 971217
  /* Remove the views field, as these are all 'mono' modes
Packit 971217
   * Need to do this before we expand caps back out to frame packed modes */
Packit 971217
  for (i = 0; i < gst_caps_get_size (mono_caps); i++) {
Packit 971217
    GstStructure *s = gst_caps_get_structure (mono_caps, i);
Packit 971217
    gst_structure_remove_fields (s, "views", NULL);
Packit 971217
    if (gst_structure_get_flagset (s, "multiview-flags", &mview_flags,
Packit 971217
            &mview_flags_mask)) {
Packit 971217
      /* Preserve only the half-aspect and mixed-mono flags, for now.
Packit 971217
       * The rest we can change */
Packit 971217
      mview_flags_mask &=
Packit 971217
          (GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT |
Packit 971217
          GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO);
Packit 971217
      gst_structure_set (s, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags, mview_flags_mask, NULL);
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  GST_TRACE_OBJECT (viewconvert,
Packit 971217
      "Collected single-view caps %" GST_PTR_FORMAT, mono_caps);
Packit 971217
  /* Put unpacked and mono modes first. We don't care about flags. Clear them */
Packit 971217
  tmp = gst_caps_copy (mono_caps);
Packit 971217
  for (i = 0; i < gst_caps_get_size (tmp); i++) {
Packit 971217
    GstStructure *s = gst_caps_get_structure (tmp, i);
Packit 971217
    gst_structure_remove_fields (s, "views", NULL);
Packit 971217
    if (gst_structure_get_flagset (s, "multiview-flags", &mview_flags,
Packit 971217
            &mview_flags_mask)) {
Packit 971217
      /* We can change any flags for mono modes - half-aspect and mixed-mono have no meaning */
Packit 971217
      mview_flags_mask = 0;
Packit 971217
      gst_structure_set (s, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags, mview_flags_mask, NULL);
Packit 971217
    }
Packit 971217
  }
Packit 971217
  expanded_caps = gst_caps_merge (expanded_caps, tmp);
Packit 971217
Packit 971217
  /* Unpacked output modes have 2 views, for now */
Packit 971217
  tmp = gst_caps_copy (mono_caps);
Packit 971217
  gst_caps_set_value (tmp, "multiview-mode",
Packit 971217
      gst_video_multiview_get_unpacked_modes ());
Packit 971217
  for (i = 0; i < gst_caps_get_size (tmp); i++) {
Packit 971217
    GstStructure *s = gst_caps_get_structure (tmp, i);
Packit 971217
    gst_structure_set (s, "views", G_TYPE_INT, 2, NULL);
Packit 971217
    if (gst_structure_get_flagset (s, "multiview-flags", &mview_flags,
Packit 971217
            &mview_flags_mask)) {
Packit 971217
      /* We can change any flags for unpacked modes - half-aspect and mixed-mono have no meaning */
Packit 971217
      mview_flags_mask = 0;
Packit 971217
      gst_structure_set (s, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
Packit 971217
          mview_flags, mview_flags_mask, NULL);
Packit 971217
    }
Packit 971217
  }
Packit 971217
  expanded_caps = gst_caps_merge (expanded_caps, tmp);
Packit 971217
Packit 971217
  /* Double height output modes */
Packit 971217
  tmp = _double_caps_field (mono_caps, "height");
Packit 971217
  gst_caps_set_value (tmp, "multiview-mode",
Packit 971217
      gst_video_multiview_get_doubled_height_modes ());
Packit 971217
  tmp = _expand_par_for_half_aspect (tmp, TRUE);
Packit 971217
Packit 971217
  expanded_caps = gst_caps_merge (expanded_caps, tmp);
Packit 971217
Packit 971217
  /* Double width output modes */
Packit 971217
  tmp = _double_caps_field (mono_caps, "width");
Packit 971217
  gst_caps_set_value (tmp, "multiview-mode",
Packit 971217
      gst_video_multiview_get_doubled_width_modes ());
Packit 971217
  tmp = _expand_par_for_half_aspect (tmp, FALSE);
Packit 971217
Packit 971217
  expanded_caps = gst_caps_merge (expanded_caps, tmp);
Packit 971217
Packit 971217
  /* Double size output modes */
Packit 971217
  {
Packit 971217
    GstCaps *tmp_w = _double_caps_field (mono_caps, "width");
Packit 971217
    tmp = _double_caps_field (tmp_w, "height");
Packit 971217
    gst_caps_unref (tmp_w);
Packit 971217
    gst_caps_set_value (tmp, "multiview-mode",
Packit 971217
        gst_video_multiview_get_doubled_size_modes ());
Packit 971217
    expanded_caps = gst_caps_merge (expanded_caps, tmp);
Packit 971217
  }
Packit 971217
Packit 971217
  /* We're done with the mono caps now */
Packit 971217
  gst_caps_unref (mono_caps);
Packit 971217
Packit 971217
  GST_TRACE_OBJECT (viewconvert,
Packit 971217
      "expanded transform caps now %" GST_PTR_FORMAT, expanded_caps);
Packit 971217
Packit 971217
  if (gst_caps_is_empty (expanded_caps)) {
Packit 971217
    gst_caps_unref (expanded_caps);
Packit 971217
    return out_caps;
Packit 971217
  }
Packit 971217
  /* Really, we can rescale - so at this point we can append full-range
Packit 971217
   * height/width/PAR as an unpreferred final option. */
Packit 971217
  tmp = gst_caps_copy (expanded_caps);
Packit 971217
  gst_caps_set_simple (tmp, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
Packit 971217
      "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
Packit 971217
Packit 971217
  out_caps = gst_caps_merge (out_caps, expanded_caps);
Packit 971217
  out_caps = gst_caps_merge (out_caps, tmp);
Packit 971217
  return out_caps;
Packit 971217
}
Packit 971217
Packit 971217
static GstCaps *
Packit 971217
_intersect_with_mview_mode (GstCaps * caps,
Packit 971217
    GstVideoMultiviewMode mode, GstVideoMultiviewFlags flags)
Packit 971217
{
Packit 971217
  GstCaps *filter, *result;
Packit 971217
  const gchar *caps_str;
Packit 971217
Packit 971217
  caps_str = gst_video_multiview_mode_to_caps_string (mode);
Packit 971217
Packit 971217
  filter = gst_caps_new_simple ("video/x-raw",
Packit 971217
      "multiview-mode", G_TYPE_STRING,
Packit 971217
      caps_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, flags,
Packit 971217
      GST_FLAG_SET_MASK_EXACT, NULL);
Packit 971217
Packit 971217
  if (mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
Packit 971217
      mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME)
Packit 971217
    gst_caps_set_simple (filter, "views", G_TYPE_INT, 2, NULL);
Packit 971217
Packit 971217
  gst_caps_set_features (filter, 0, gst_caps_features_new_any ());
Packit 971217
Packit 971217
  GST_DEBUG ("Intersecting target caps %" GST_PTR_FORMAT
Packit 971217
      " with caps %" GST_PTR_FORMAT, caps, filter);
Packit 971217
Packit 971217
  result = gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST);
Packit 971217
  gst_caps_unref (filter);
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
static GstCaps *
Packit 971217
_intersect_with_mview_modes (GstCaps * caps, const GValue * modes)
Packit 971217
{
Packit 971217
  GstCaps *filter, *result;
Packit 971217
Packit 971217
  filter = gst_caps_new_empty_simple ("video/x-raw");
Packit 971217
Packit 971217
  gst_caps_set_value (filter, "multiview-mode", modes);
Packit 971217
  gst_caps_set_features (filter, 0, gst_caps_features_new_any ());
Packit 971217
Packit 971217
  GST_DEBUG ("Intersecting target caps %" GST_PTR_FORMAT
Packit 971217
      " with caps %" GST_PTR_FORMAT, caps, filter);
Packit 971217
Packit 971217
  result = gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST);
Packit 971217
  gst_caps_unref (filter);
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_transform_caps:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @direction: a #GstPadDirection
Packit 971217
 * @caps: (transfer none): the #GstCaps to transform
Packit 971217
 * @filter: (transfer none): a set of filter #GstCaps
Packit 971217
 *
Packit 971217
 * Provides an implementation of #GstBaseTransformClass::transform_caps()
Packit 971217
 *
Packit 971217
 * Returns: (transfer full): the converted #GstCaps
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
GstCaps *
Packit 971217
gst_gl_view_convert_transform_caps (GstGLViewConvert * viewconvert,
Packit 971217
    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
Packit 971217
{
Packit 971217
  gint i, n;
Packit 971217
  GstCaps *base_caps = gst_static_caps_get (&caps_template);
Packit 971217
  GstCaps *out_caps, *tmp_caps;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert), NULL);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (viewconvert, "Direction %s "
Packit 971217
      "input caps %" GST_PTR_FORMAT " filter %" GST_PTR_FORMAT,
Packit 971217
      direction == GST_PAD_SINK ? "sink" : "src", caps, filter);
Packit 971217
Packit 971217
  /* We can only process GLmemory RGBA caps, start from that */
Packit 971217
  caps = gst_caps_intersect (caps, base_caps);
Packit 971217
  gst_caps_unref (base_caps);
Packit 971217
Packit 971217
  /* Change input/output to the formats we can convert to/from,
Packit 971217
   * but keep the original caps at the start - we will always prefer
Packit 971217
   * passthrough */
Packit 971217
  if (direction == GST_PAD_SINK) {
Packit 971217
    out_caps = gst_caps_copy (caps);
Packit 971217
    if (viewconvert->input_mode_override != GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
      GstVideoMultiviewMode mode = viewconvert->input_mode_override;
Packit 971217
      GstVideoMultiviewFlags flags = viewconvert->input_flags_override;
Packit 971217
Packit 971217
      const gchar *caps_str = gst_video_multiview_mode_to_caps_string (mode);
Packit 971217
      /* Coerce the input caps before transforming, so the sizes come out right */
Packit 971217
      gst_caps_set_simple (out_caps, "multiview-mode", G_TYPE_STRING,
Packit 971217
          caps_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, flags,
Packit 971217
          GST_FLAG_SET_MASK_EXACT, NULL);
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    out_caps = gst_caps_new_empty ();
Packit 971217
  }
Packit 971217
Packit 971217
  for (i = 0; i < gst_caps_get_size (caps); i++) {
Packit 971217
    GstStructure *structure = gst_caps_get_structure (caps, i);
Packit 971217
    GstCapsFeatures *features = gst_caps_get_features (caps, i);
Packit 971217
    out_caps = _expand_structure (viewconvert, out_caps, structure, features);
Packit 971217
  }
Packit 971217
Packit 971217
  if (gst_caps_is_empty (out_caps))
Packit 971217
    goto out;
Packit 971217
Packit 971217
  /* If we have an output mode override, limit things to that */
Packit 971217
  if (direction == GST_PAD_SINK &&
Packit 971217
      viewconvert->output_mode_override != GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
Packit 971217
    tmp_caps = _intersect_with_mview_mode (out_caps,
Packit 971217
        viewconvert->output_mode_override, viewconvert->output_flags_override);
Packit 971217
Packit 971217
    gst_caps_unref (out_caps);
Packit 971217
    out_caps = tmp_caps;
Packit 971217
  } else if (viewconvert->input_mode_override != GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
    /* Prepend a copy of our preferred input caps in case the peer
Packit 971217
     * can handle them */
Packit 971217
    tmp_caps = _intersect_with_mview_mode (out_caps,
Packit 971217
        viewconvert->input_mode_override, viewconvert->input_flags_override);
Packit 971217
    out_caps = gst_caps_merge (out_caps, tmp_caps);
Packit 971217
  }
Packit 971217
  if (direction == GST_PAD_SRC) {
Packit 971217
    GstStructure *s;
Packit 971217
    /* When generating input caps, we also need a copy of the mono caps
Packit 971217
     * without multiview-mode or flags for backwards compat, at the end */
Packit 971217
    tmp_caps = _intersect_with_mview_mode (caps,
Packit 971217
        GST_VIDEO_MULTIVIEW_MODE_MONO, GST_VIDEO_MULTIVIEW_FLAGS_NONE);
Packit 971217
    if (!gst_caps_is_empty (tmp_caps)) {
Packit 971217
      s = gst_caps_get_structure (tmp_caps, 0);
Packit 971217
      gst_structure_remove_fields (s, "multiview-mode", "multiview-flags",
Packit 971217
          NULL);
Packit 971217
      out_caps = gst_caps_merge (out_caps, tmp_caps);
Packit 971217
    } else
Packit 971217
      gst_caps_unref (tmp_caps);
Packit 971217
  }
Packit 971217
out:
Packit 971217
  gst_caps_unref (caps);
Packit 971217
Packit 971217
  n = gst_caps_get_size (out_caps);
Packit 971217
  for (i = 0; i < n; i++) {
Packit 971217
    GstStructure *s = gst_caps_get_structure (out_caps, i);
Packit 971217
Packit 971217
    gst_structure_remove_fields (s, "texture-target", NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (viewconvert, "Returning caps %" GST_PTR_FORMAT, out_caps);
Packit 971217
  return out_caps;
Packit 971217
}
Packit 971217
Packit 971217
static guint
Packit 971217
_get_target_bitmask_from_g_value (const GValue * targets)
Packit 971217
{
Packit 971217
  guint new_targets = 0;
Packit 971217
Packit 971217
  if (targets == NULL) {
Packit 971217
    new_targets = 1 << GST_GL_TEXTURE_TARGET_2D;
Packit 971217
  } else if (G_TYPE_CHECK_VALUE_TYPE (targets, G_TYPE_STRING)) {
Packit 971217
    GstGLTextureTarget target;
Packit 971217
    const gchar *str;
Packit 971217
Packit 971217
    str = g_value_get_string (targets);
Packit 971217
    target = gst_gl_texture_target_from_string (str);
Packit 971217
Packit 971217
    if (target)
Packit 971217
      new_targets |= 1 << target;
Packit 971217
  } else if (G_TYPE_CHECK_VALUE_TYPE (targets, GST_TYPE_LIST)) {
Packit 971217
    gint j, m;
Packit 971217
Packit 971217
    m = gst_value_list_get_size (targets);
Packit 971217
    for (j = 0; j < m; j++) {
Packit 971217
      const GValue *val = gst_value_list_get_value (targets, j);
Packit 971217
      GstGLTextureTarget target;
Packit 971217
      const gchar *str;
Packit 971217
Packit 971217
      str = g_value_get_string (val);
Packit 971217
      target = gst_gl_texture_target_from_string (str);
Packit 971217
      if (target)
Packit 971217
        new_targets |= 1 << target;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return new_targets;
Packit 971217
}
Packit 971217
Packit 971217
static GstCaps *
Packit 971217
_fixate_texture_target (GstGLViewConvert * viewconvert,
Packit 971217
    GstPadDirection direction, GstCaps * caps, GstCaps * other)
Packit 971217
{
Packit 971217
  GValue item = G_VALUE_INIT;
Packit 971217
  const GValue *targets, *other_targets;
Packit 971217
  guint targets_mask = 0, other_targets_mask = 0, result_mask;
Packit 971217
  GstStructure *s, *s_other;
Packit 971217
Packit 971217
  other = gst_caps_make_writable (other);
Packit 971217
  s = gst_caps_get_structure (caps, 0);
Packit 971217
  s_other = gst_caps_get_structure (other, 0);
Packit 971217
Packit 971217
  other_targets = gst_structure_get_value (s_other, "texture-target");
Packit 971217
  targets = gst_structure_get_value (s, "texture-target");
Packit 971217
Packit 971217
  targets_mask = _get_target_bitmask_from_g_value (targets);
Packit 971217
  other_targets_mask = _get_target_bitmask_from_g_value (other_targets);
Packit 971217
Packit 971217
  result_mask = targets_mask & other_targets_mask;
Packit 971217
  if (result_mask == 0) {
Packit 971217
    /* nothing we can do here */
Packit 971217
    return gst_caps_fixate (other);
Packit 971217
  }
Packit 971217
Packit 971217
  if (direction == GST_PAD_SINK) {
Packit 971217
    result_mask &=
Packit 971217
        (1 << GST_GL_TEXTURE_TARGET_2D | 1 << GST_GL_TEXTURE_TARGET_RECTANGLE);
Packit 971217
  } else {
Packit 971217
    /* if the src caps has 2D support we can 'convert' to anything */
Packit 971217
    if (targets_mask & (1 << GST_GL_TEXTURE_TARGET_2D))
Packit 971217
      result_mask = -1;
Packit 971217
    else
Packit 971217
      result_mask = other_targets_mask;
Packit 971217
  }
Packit 971217
Packit 971217
  g_value_init (&item, G_TYPE_STRING);
Packit 971217
  if (result_mask & (1 << GST_GL_TEXTURE_TARGET_2D)) {
Packit 971217
    g_value_set_static_string (&item, GST_GL_TEXTURE_TARGET_2D_STR);
Packit 971217
  } else if (result_mask & (1 << GST_GL_TEXTURE_TARGET_RECTANGLE)) {
Packit 971217
    g_value_set_static_string (&item, GST_GL_TEXTURE_TARGET_RECTANGLE_STR);
Packit 971217
  } else if (result_mask & (1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES)) {
Packit 971217
    g_value_set_static_string (&item, GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR);
Packit 971217
  }
Packit 971217
Packit 971217
  gst_structure_set_value (s_other, "texture-target", &item);
Packit 971217
Packit 971217
  g_value_unset (&item);
Packit 971217
Packit 971217
  return gst_caps_fixate (other);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_fixate_caps:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @direction: a #GstPadDirection
Packit 971217
 * @caps: (transfer none): the #GstCaps of @direction
Packit 971217
 * @othercaps: (transfer full): the #GstCaps to fixate
Packit 971217
 *
Packit 971217
 * Provides an implementation of #GstBaseTransformClass::fixate_caps()
Packit 971217
 *
Packit 971217
 * Returns: (transfer full): the fixated #GstCaps
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
GstCaps *
Packit 971217
gst_gl_view_convert_fixate_caps (GstGLViewConvert * viewconvert,
Packit 971217
    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
Packit 971217
{
Packit 971217
  GstVideoMultiviewMode mode = viewconvert->output_mode_override;
Packit 971217
  GstVideoMultiviewFlags flags = viewconvert->output_flags_override;
Packit 971217
  GstCaps *tmp;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert), NULL);
Packit 971217
Packit 971217
  othercaps = gst_caps_make_writable (othercaps);
Packit 971217
  GST_LOG_OBJECT (viewconvert, "dir %s fixating %" GST_PTR_FORMAT
Packit 971217
      " against caps %" GST_PTR_FORMAT,
Packit 971217
      direction == GST_PAD_SINK ? "sink" : "src", othercaps, caps);
Packit 971217
Packit 971217
  if (direction == GST_PAD_SINK) {
Packit 971217
    if (mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
      /* We have a requested output mode and are fixating source caps, try and enforce it */
Packit 971217
      tmp = _intersect_with_mview_mode (othercaps, mode, flags);
Packit 971217
      gst_caps_unref (othercaps);
Packit 971217
      othercaps = tmp;
Packit 971217
    } else {
Packit 971217
      /* See if we can do passthrough */
Packit 971217
      GstVideoInfo info;
Packit 971217
Packit 971217
      if (gst_video_info_from_caps (&info, caps)) {
Packit 971217
        GstVideoMultiviewMode mode = GST_VIDEO_INFO_MULTIVIEW_MODE (&info;;
Packit 971217
        GstVideoMultiviewFlags flags = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&info;;
Packit 971217
Packit 971217
        if (viewconvert->input_mode_override != GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
          mode = viewconvert->input_mode_override;
Packit 971217
          flags = viewconvert->input_flags_override;
Packit 971217
        }
Packit 971217
Packit 971217
        tmp = _intersect_with_mview_mode (othercaps, mode, flags);
Packit 971217
        if (gst_caps_is_empty (tmp)) {
Packit 971217
          /* Nope, we can't pass our input caps downstream */
Packit 971217
          gst_caps_unref (tmp);
Packit 971217
        } else {
Packit 971217
          gst_caps_unref (othercaps);
Packit 971217
          othercaps = tmp;
Packit 971217
          goto done;
Packit 971217
        }
Packit 971217
      }
Packit 971217
Packit 971217
      /* Prefer an unpacked mode for output */
Packit 971217
      tmp =
Packit 971217
          _intersect_with_mview_modes (othercaps,
Packit 971217
          gst_video_multiview_get_unpacked_modes ());
Packit 971217
      if (!gst_caps_is_empty (tmp)) {
Packit 971217
        gst_caps_unref (othercaps);
Packit 971217
        othercaps = tmp;
Packit 971217
      } else {
Packit 971217
        gst_caps_unref (tmp);
Packit 971217
      }
Packit 971217
    }
Packit 971217
  } else if (viewconvert->input_mode_override != GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
    /* See if we can coerce the caps into matching input mode/flags,
Packit 971217
     * in case it doesn't care at all, but allow it not to too */
Packit 971217
    mode = viewconvert->input_mode_override;
Packit 971217
    flags = viewconvert->input_flags_override;
Packit 971217
    tmp = _intersect_with_mview_mode (othercaps, mode, flags);
Packit 971217
    if (gst_caps_is_empty (tmp)) {
Packit 971217
      /* Nope, we can pass our input caps downstream */
Packit 971217
      gst_caps_unref (tmp);
Packit 971217
    } else {
Packit 971217
      gst_caps_unref (othercaps);
Packit 971217
      othercaps = tmp;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  othercaps = _fixate_texture_target (viewconvert, direction, caps, othercaps);
Packit 971217
Packit 971217
done:
Packit 971217
  GST_DEBUG_OBJECT (viewconvert, "dir %s fixated to %" GST_PTR_FORMAT
Packit 971217
      " against caps %" GST_PTR_FORMAT,
Packit 971217
      direction == GST_PAD_SINK ? "sink" : "src", othercaps, caps);
Packit 971217
  return othercaps;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_reset:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 *
Packit 971217
 * Reset @viewconvert to the default state.  Further operation will require
Packit 971217
 * setting the caps with gst_gl_view_convert_set_caps().
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_gl_view_convert_reset (GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  g_return_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert));
Packit 971217
  if (viewconvert->shader)
Packit 971217
    gst_object_unref (viewconvert->shader);
Packit 971217
  viewconvert->shader = NULL;
Packit 971217
Packit 971217
  if (viewconvert->fbo)
Packit 971217
    gst_object_unref (viewconvert->fbo);
Packit 971217
  viewconvert->fbo = NULL;
Packit 971217
Packit 971217
  viewconvert->initted = FALSE;
Packit 971217
  viewconvert->reconfigure = FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_gl_view_convert_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstGLViewConvert *convert = GST_GL_VIEW_CONVERT (object);
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_INPUT_LAYOUT:
Packit 971217
      convert->input_mode_override = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_INPUT_FLAGS:
Packit 971217
      convert->input_flags_override = g_value_get_flags (value);
Packit 971217
      break;
Packit 971217
    case PROP_OUTPUT_LAYOUT:
Packit 971217
      convert->output_mode_override = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_OUTPUT_FLAGS:
Packit 971217
      convert->output_flags_override = g_value_get_flags (value);
Packit 971217
      break;
Packit 971217
    case PROP_OUTPUT_DOWNMIX_MODE:
Packit 971217
      convert->downmix_mode = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
  GST_OBJECT_LOCK (convert);
Packit 971217
  convert->reconfigure = TRUE;
Packit 971217
  GST_OBJECT_UNLOCK (convert);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_gl_view_convert_get_property (GObject * object, guint prop_id,
Packit 971217
    GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstGLViewConvert *convert = GST_GL_VIEW_CONVERT (object);
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_INPUT_LAYOUT:
Packit 971217
      g_value_set_enum (value, convert->input_mode_override);
Packit 971217
      break;
Packit 971217
    case PROP_INPUT_FLAGS:
Packit 971217
      g_value_set_flags (value, convert->input_flags_override);
Packit 971217
      break;
Packit 971217
    case PROP_OUTPUT_LAYOUT:
Packit 971217
      g_value_set_enum (value, convert->output_mode_override);
Packit 971217
      break;
Packit 971217
    case PROP_OUTPUT_FLAGS:
Packit 971217
      g_value_set_flags (value, convert->output_flags_override);
Packit 971217
      break;
Packit 971217
    case PROP_OUTPUT_DOWNMIX_MODE:
Packit 971217
      g_value_set_enum (value, convert->downmix_mode);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_perform:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @inbuf: (transfer none): the #GstGLMemory filled #GstBuffer to convert
Packit 971217
 *
Packit 971217
 * Converts the data contained by @inbuf using the formats specified by the
Packit 971217
 * #GstCaps passed to gst_gl_view_convert_set_caps()
Packit 971217
 *
Packit 971217
 * Returns: (transfer full): a converted #GstBuffer or %NULL
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_gl_view_convert_perform (GstGLViewConvert * viewconvert, GstBuffer * inbuf)
Packit 971217
{
Packit 971217
  GstBuffer *out;
Packit 971217
Packit 971217
  if (gst_gl_view_convert_submit_input_buffer (viewconvert,
Packit 971217
          GST_BUFFER_IS_DISCONT (inbuf), gst_buffer_ref (inbuf)) != GST_FLOW_OK)
Packit 971217
    return NULL;
Packit 971217
  if (gst_gl_view_convert_get_output (viewconvert, &out) != GST_FLOW_OK)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  return out;
Packit 971217
}
Packit 971217
Packit 971217
/* called by _init_convert (in the gl thread) */
Packit 971217
static gboolean
Packit 971217
_init_view_convert_fbo (GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  guint out_width, out_height;
Packit 971217
Packit 971217
  out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
Packit 971217
  out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info);
Packit 971217
Packit 971217
  viewconvert->fbo =
Packit 971217
      gst_gl_framebuffer_new_with_default_depth (viewconvert->context,
Packit 971217
      out_width, out_height);
Packit 971217
Packit 971217
  return viewconvert->fbo != NULL;
Packit 971217
}
Packit 971217
Packit 971217
/* free after use */
Packit 971217
static gchar *
Packit 971217
_get_shader_string (GstGLViewConvert * viewconvert, GstGLShader * shader,
Packit 971217
    GstVideoMultiviewMode in_mode, GstVideoMultiviewMode out_mode,
Packit 971217
    GstGLSLVersion version, GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  const gchar *input_str, *output_str;
Packit 971217
  gboolean mono_input = FALSE;
Packit 971217
  gchar *tmp, *tmp2;
Packit 971217
  GString *str = g_string_new (NULL);
Packit 971217
  guint n_outputs = 1;
Packit 971217
Packit 971217
  switch (in_mode) {
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_NONE:
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_MONO:
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_LEFT:
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_RIGHT:
Packit 971217
      mono_input = TRUE;
Packit 971217
      /* Fall through */
Packit 971217
    default:
Packit 971217
      input_str = frag_input;
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  switch (out_mode) {
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_LEFT:
Packit 971217
      output_str = frag_output_left;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_RIGHT:
Packit 971217
      output_str = frag_output_right;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
Packit 971217
      /* FIXME: implement properly with sub-sampling */
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
Packit 971217
      output_str = frag_output_side_by_side;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
Packit 971217
      output_str = frag_output_top_bottom;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
Packit 971217
      output_str = frag_output_column_interleaved;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
Packit 971217
      output_str = frag_output_row_interleaved;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_SEPARATED:
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
Packit 971217
      output_str = frag_output_separated;
Packit 971217
      n_outputs = 2;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
Packit 971217
      output_str = frag_output_checkerboard;
Packit 971217
      break;
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_NONE:
Packit 971217
    case GST_VIDEO_MULTIVIEW_MODE_MONO:
Packit 971217
    default:
Packit 971217
      if (mono_input)
Packit 971217
        output_str = frag_output_left;
Packit 971217
      else
Packit 971217
        output_str = frag_output_downmix;
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  if (viewconvert->from_texture_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
Packit 971217
    g_string_append (str, glsl_OES_extension_string);
Packit 971217
Packit 971217
  g_string_append (str, fragment_header);
Packit 971217
Packit 971217
  /* GL 3.3+ and GL ES 3.x */
Packit 971217
  if ((profile == GST_GLSL_PROFILE_CORE && version >= GST_GLSL_VERSION_330)
Packit 971217
      || (profile == GST_GLSL_PROFILE_ES && version >= GST_GLSL_VERSION_300)) {
Packit 971217
    if (n_outputs > 1) {
Packit 971217
      gint i;
Packit 971217
Packit 971217
      for (i = 0; i < n_outputs; i++) {
Packit 971217
        g_string_append_printf (str,
Packit 971217
            "layout(location = %d) out vec4 fragColor_%d;\n", i, i);
Packit 971217
      }
Packit 971217
    } else {
Packit 971217
      g_string_append (str, "layout (location = 0) out vec4 fragColor;\n");
Packit 971217
    }
Packit 971217
  } else if (profile == GST_GLSL_PROFILE_CORE
Packit 971217
      && version >= GST_GLSL_VERSION_150) {
Packit 971217
    /* no layout specifiers, use glBindFragDataLocation instead */
Packit 971217
    if (n_outputs > 1) {
Packit 971217
      gint i;
Packit 971217
Packit 971217
      for (i = 0; i < n_outputs; i++) {
Packit 971217
        gchar *var_name = g_strdup_printf ("fragColor_%d", i);
Packit 971217
        g_string_append_printf (str, "out vec4 %s;\n", var_name);
Packit 971217
        gst_gl_shader_bind_frag_data_location (shader, i, var_name);
Packit 971217
        g_free (var_name);
Packit 971217
      }
Packit 971217
    } else {
Packit 971217
      g_string_append (str, "out vec4 fragColor;\n");
Packit 971217
      gst_gl_shader_bind_frag_data_location (shader, 0, "fragColor");
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  {
Packit 971217
    const gchar *varying = NULL;
Packit 971217
Packit 971217
    if ((profile == GST_GLSL_PROFILE_ES && version >= GST_GLSL_VERSION_300)
Packit 971217
        || (profile == GST_GLSL_PROFILE_CORE
Packit 971217
            && version >= GST_GLSL_VERSION_150)) {
Packit 971217
      varying = "in";
Packit 971217
    } else {
Packit 971217
      varying = "varying";
Packit 971217
    }
Packit 971217
    g_string_append_printf (str,
Packit 971217
        "\n%s vec2 v_texcoord;\nvoid main() {\nvec4 l, r;\n", varying);
Packit 971217
  }
Packit 971217
Packit 971217
  g_string_append (str, input_str);
Packit 971217
  g_string_append (str, output_str);
Packit 971217
  g_string_append (str, "\n}");
Packit 971217
  tmp = g_string_free (str, FALSE);
Packit 971217
Packit 971217
  tmp2 =
Packit 971217
      _gst_glsl_mangle_shader (tmp, GL_FRAGMENT_SHADER,
Packit 971217
      GST_GL_TEXTURE_TARGET_2D, viewconvert->from_texture_target,
Packit 971217
      viewconvert->context, &version, &profile);
Packit 971217
Packit 971217
  return tmp2;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_bind_buffer (GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  const GstGLFuncs *gl = viewconvert->context->gl_vtable;
Packit 971217
  gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, viewconvert->priv->vbo_indices);
Packit 971217
  gl->BindBuffer (GL_ARRAY_BUFFER, viewconvert->priv->vertex_buffer);
Packit 971217
  /* Load the vertex position */
Packit 971217
  gl->VertexAttribPointer (viewconvert->priv->attr_position, 3, GL_FLOAT,
Packit 971217
      GL_FALSE, 5 * sizeof (GLfloat), (void *) 0);
Packit 971217
  /* Load the texture coordinate */
Packit 971217
  gl->VertexAttribPointer (viewconvert->priv->attr_texture, 2, GL_FLOAT,
Packit 971217
      GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
Packit 971217
  gl->EnableVertexAttribArray (viewconvert->priv->attr_position);
Packit 971217
  gl->EnableVertexAttribArray (viewconvert->priv->attr_texture);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_unbind_buffer (GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  const GstGLFuncs *gl = viewconvert->context->gl_vtable;
Packit 971217
  gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
Packit 971217
  gl->BindBuffer (GL_ARRAY_BUFFER, 0);
Packit 971217
  gl->DisableVertexAttribArray (viewconvert->priv->attr_position);
Packit 971217
  gl->DisableVertexAttribArray (viewconvert->priv->attr_texture);
Packit 971217
}
Packit 971217
Packit 971217
/* Called in the gl thread */
Packit 971217
static gboolean
Packit 971217
_init_view_convert (GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  GstGLViewConvertPrivate *priv = viewconvert->priv;
Packit 971217
  GstVideoMultiviewMode in_mode = priv->input_mode;
Packit 971217
  GstVideoMultiviewMode out_mode = priv->output_mode;
Packit 971217
  GstVideoMultiviewFlags in_flags = priv->input_flags;
Packit 971217
  GstVideoMultiviewFlags out_flags = priv->output_flags;
Packit 971217
  gfloat tex_scale[2][2] = {
Packit 971217
    {1., 1.},
Packit 971217
    {1., 1.}
Packit 971217
  };
Packit 971217
  gfloat offsets[2][2] = {
Packit 971217
    {0., 0.},
Packit 971217
    {0., 0.}
Packit 971217
  };
Packit 971217
  gchar *fragment_source_str;
Packit 971217
  GstGLFuncs *gl;
Packit 971217
  gint l_index, r_index;
Packit 971217
Packit 971217
  gl = viewconvert->context->gl_vtable;
Packit 971217
  if (viewconvert->reconfigure)
Packit 971217
    gst_gl_view_convert_reset (viewconvert);
Packit 971217
  if (viewconvert->initted)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  GST_LOG_OBJECT (viewconvert,
Packit 971217
      "Initializing multiview conversion from %s mode %d flags 0x%x w %u h %u to "
Packit 971217
      "%s mode %d flags 0x%x w %u h %u",
Packit 971217
      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
Packit 971217
          (&viewconvert->in_info)), in_mode, in_flags,
Packit 971217
      viewconvert->in_info.width, viewconvert->in_info.height,
Packit 971217
      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
Packit 971217
          (&viewconvert->out_info)), out_mode, out_flags,
Packit 971217
      viewconvert->out_info.width, viewconvert->out_info.height);
Packit 971217
Packit 971217
  if (!gl->CreateProgramObject && !gl->CreateProgram) {
Packit 971217
    GST_ERROR_OBJECT (viewconvert, "Cannot perform multiview conversion "
Packit 971217
        "without OpenGL shaders");
Packit 971217
    goto error;
Packit 971217
  }
Packit 971217
Packit 971217
  if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED
Packit 971217
      || out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    if (!gl->DrawBuffers) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert,
Packit 971217
          "Separate texture output mode requested however the current "
Packit 971217
          "OpenGL API does not support drawing to multiple buffers");
Packit 971217
      goto error;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if ((in_flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) ==
Packit 971217
      (out_flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)) {
Packit 971217
    l_index = 0;
Packit 971217
    r_index = 1;
Packit 971217
  } else {
Packit 971217
    GST_LOG_OBJECT (viewconvert, "Switching left/right views");
Packit 971217
    /* Swap the views */
Packit 971217
    l_index = 1;
Packit 971217
    r_index = 0;
Packit 971217
  }
Packit 971217
Packit 971217
  if (in_mode < GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE) {        /* unknown/mono/left/right single image */
Packit 971217
  } else if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE ||
Packit 971217
      in_mode == GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX) {
Packit 971217
    /* Side-by-side input */
Packit 971217
    offsets[r_index][0] += 0.5 * tex_scale[r_index][0];
Packit 971217
    tex_scale[0][0] *= 0.5f;    /* Half horizontal scale */
Packit 971217
    tex_scale[1][0] *= 0.5f;
Packit 971217
  } else if (in_mode == GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM) {  /* top-bottom */
Packit 971217
    offsets[r_index][1] += 0.5 * tex_scale[r_index][1];
Packit 971217
    tex_scale[0][1] *= 0.5f;    /* Half vertical scale */
Packit 971217
    tex_scale[1][1] *= 0.5f;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Flipped is vertical, flopped is horizontal.
Packit 971217
   * Adjust and offset per-view scaling. This needs to be done
Packit 971217
   * after the input scaling already splits the views, before
Packit 971217
   * adding any output scaling. */
Packit 971217
  if ((in_flags & GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED) !=
Packit 971217
      (out_flags & GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED)) {
Packit 971217
    offsets[l_index][1] += tex_scale[l_index][1];
Packit 971217
    tex_scale[l_index][1] *= -1.0;
Packit 971217
  }
Packit 971217
  if ((in_flags & GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED) !=
Packit 971217
      (out_flags & GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED)) {
Packit 971217
    offsets[l_index][0] += tex_scale[l_index][0];
Packit 971217
    tex_scale[l_index][0] *= -1.0;
Packit 971217
  }
Packit 971217
  if ((in_flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED) !=
Packit 971217
      (out_flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED)) {
Packit 971217
    offsets[r_index][1] += tex_scale[r_index][1];
Packit 971217
    tex_scale[r_index][1] *= -1.0;
Packit 971217
  }
Packit 971217
  if ((in_flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED) !=
Packit 971217
      (out_flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED)) {
Packit 971217
    offsets[r_index][0] += tex_scale[r_index][0];
Packit 971217
    tex_scale[r_index][0] *= -1.0;
Packit 971217
  }
Packit 971217
Packit 971217
  if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE ||
Packit 971217
      out_mode == GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX) {
Packit 971217
    /* Side-by-Side */
Packit 971217
    offsets[1][0] -= tex_scale[1][0];
Packit 971217
    tex_scale[0][0] *= 2.0f;
Packit 971217
    tex_scale[1][0] *= 2.0f;
Packit 971217
  } else if (out_mode == GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM) {
Packit 971217
    offsets[1][1] -= tex_scale[1][1];
Packit 971217
    tex_scale[0][1] *= 2.0f;
Packit 971217
    tex_scale[1][1] *= 2.0f;
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (viewconvert,
Packit 971217
      "Scaling matrix [ %f, %f ] [ %f %f]. Offsets [ %f, %f ] [ %f, %f ]",
Packit 971217
      tex_scale[0][0], tex_scale[0][1],
Packit 971217
      tex_scale[1][0], tex_scale[1][1],
Packit 971217
      offsets[0][0], offsets[0][1], offsets[1][0], offsets[1][1]);
Packit 971217
Packit 971217
  viewconvert->shader = gst_gl_shader_new (viewconvert->context);
Packit 971217
  {
Packit 971217
    GstGLSLVersion version;
Packit 971217
    GstGLSLProfile profile;
Packit 971217
    GstGLSLStage *vert, *frag;
Packit 971217
    gchar *tmp, *tmp1, *version_str;
Packit 971217
    const gchar *strings[2];
Packit 971217
    GError *error = NULL;
Packit 971217
Packit 971217
    tmp =
Packit 971217
        _gst_glsl_mangle_shader
Packit 971217
        (gst_gl_shader_string_vertex_mat4_vertex_transform, GL_VERTEX_SHADER,
Packit 971217
        GST_GL_TEXTURE_TARGET_2D, viewconvert->from_texture_target,
Packit 971217
        viewconvert->context, &version, &profile);
Packit 971217
Packit 971217
    tmp1 = gst_glsl_version_profile_to_string (version, profile);
Packit 971217
    version_str = g_strdup_printf ("#version %s\n", tmp1);
Packit 971217
    g_free (tmp1);
Packit 971217
    strings[0] = version_str;
Packit 971217
Packit 971217
    strings[1] = tmp;
Packit 971217
    vert =
Packit 971217
        gst_glsl_stage_new_with_strings (viewconvert->context,
Packit 971217
        GL_VERTEX_SHADER, version, profile, 2, strings);
Packit 971217
    g_free (tmp);
Packit 971217
Packit 971217
    if (!gst_gl_shader_compile_attach_stage (viewconvert->shader, vert, &error)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "Failed to compile vertex stage %s",
Packit 971217
          error->message);
Packit 971217
      gst_object_unref (viewconvert->shader);
Packit 971217
      viewconvert->shader = NULL;
Packit 971217
      g_free (version_str);
Packit 971217
      goto error;
Packit 971217
    }
Packit 971217
Packit 971217
    fragment_source_str = _get_shader_string (viewconvert, viewconvert->shader,
Packit 971217
        in_mode, out_mode, version, profile);
Packit 971217
    strings[1] = fragment_source_str;
Packit 971217
Packit 971217
    frag =
Packit 971217
        gst_glsl_stage_new_with_strings (viewconvert->context,
Packit 971217
        GL_FRAGMENT_SHADER, version, profile, 2, strings);
Packit 971217
    g_free (version_str);
Packit 971217
Packit 971217
    if (!gst_gl_shader_compile_attach_stage (viewconvert->shader, frag, &error)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "Failed to compile fragment stage %s",
Packit 971217
          error->message);
Packit 971217
      g_free (fragment_source_str);
Packit 971217
      gst_object_unref (viewconvert->shader);
Packit 971217
      viewconvert->shader = NULL;
Packit 971217
      goto error;
Packit 971217
    }
Packit 971217
    g_free (fragment_source_str);
Packit 971217
Packit 971217
    if (!gst_gl_shader_link (viewconvert->shader, &error)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "Failed to link conversion shader %s",
Packit 971217
          error->message);
Packit 971217
      gst_object_unref (viewconvert->shader);
Packit 971217
      viewconvert->shader = NULL;
Packit 971217
      goto error;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  viewconvert->priv->attr_position =
Packit 971217
      gst_gl_shader_get_attribute_location (viewconvert->shader, "a_position");
Packit 971217
  viewconvert->priv->attr_texture =
Packit 971217
      gst_gl_shader_get_attribute_location (viewconvert->shader, "a_texcoord");
Packit 971217
  gst_gl_shader_use (viewconvert->shader);
Packit 971217
  gst_gl_shader_set_uniform_2fv (viewconvert->shader, "tex_scale",
Packit 971217
      2, tex_scale[0]);
Packit 971217
  gst_gl_shader_set_uniform_2fv (viewconvert->shader, "offsets", 2, offsets[0]);
Packit 971217
  gst_gl_shader_set_uniform_1f (viewconvert->shader, "width",
Packit 971217
      GST_VIDEO_INFO_WIDTH (&viewconvert->out_info));
Packit 971217
  gst_gl_shader_set_uniform_1f (viewconvert->shader, "height",
Packit 971217
      GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info));
Packit 971217
  gst_gl_shader_set_uniform_matrix_3fv (viewconvert->shader, "downmix",
Packit 971217
      2, FALSE, &downmix_matrices[viewconvert->downmix_mode][0][0]);
Packit 971217
  gst_gl_shader_set_uniform_matrix_4fv (viewconvert->shader, "u_transformation",
Packit 971217
      1, FALSE, identity_matrix);
Packit 971217
  if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
Packit 971217
      in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    gst_gl_shader_set_uniform_1i (viewconvert->shader, "tex_l", l_index);
Packit 971217
    gst_gl_shader_set_uniform_1i (viewconvert->shader, "tex_r", r_index);
Packit 971217
  } else {
Packit 971217
    gst_gl_shader_set_uniform_1i (viewconvert->shader, "tex_l", 0);
Packit 971217
    gst_gl_shader_set_uniform_1i (viewconvert->shader, "tex_r", 0);
Packit 971217
  }
Packit 971217
  gst_gl_context_clear_shader (viewconvert->context);
Packit 971217
  if (!_init_view_convert_fbo (viewconvert)) {
Packit 971217
    goto error;
Packit 971217
  }
Packit 971217
Packit 971217
  if (!viewconvert->priv->vertex_buffer) {
Packit 971217
    if (gl->GenVertexArrays) {
Packit 971217
      gl->GenVertexArrays (1, &viewconvert->priv->vao);
Packit 971217
      gl->BindVertexArray (viewconvert->priv->vao);
Packit 971217
    }
Packit 971217
Packit 971217
    gl->GenBuffers (1, &viewconvert->priv->vertex_buffer);
Packit 971217
    gl->BindBuffer (GL_ARRAY_BUFFER, viewconvert->priv->vertex_buffer);
Packit 971217
    gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices,
Packit 971217
        GL_STATIC_DRAW);
Packit 971217
    gl->GenBuffers (1, &viewconvert->priv->vbo_indices);
Packit 971217
    gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, viewconvert->priv->vbo_indices);
Packit 971217
    gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
Packit 971217
        GL_STATIC_DRAW);
Packit 971217
    if (gl->GenVertexArrays) {
Packit 971217
      _bind_buffer (viewconvert);
Packit 971217
      gl->BindVertexArray (0);
Packit 971217
    }
Packit 971217
Packit 971217
    gl->BindBuffer (GL_ARRAY_BUFFER, 0);
Packit 971217
    gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
Packit 971217
  }
Packit 971217
Packit 971217
  viewconvert->initted = TRUE;
Packit 971217
  return TRUE;
Packit 971217
error:
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  GstGLViewConvertPrivate *priv = viewconvert->priv;
Packit 971217
  GstGLFuncs *gl;
Packit 971217
  guint out_width, out_height;
Packit 971217
  gint out_views, i;
Packit 971217
  GLint viewport_dim[4] = { 0 };
Packit 971217
  GLenum multipleRT[] = {
Packit 971217
    GL_COLOR_ATTACHMENT0,
Packit 971217
    GL_COLOR_ATTACHMENT1,
Packit 971217
    GL_COLOR_ATTACHMENT2
Packit 971217
  };
Packit 971217
  GstVideoMultiviewMode in_mode = priv->input_mode;
Packit 971217
  GstVideoMultiviewMode out_mode = priv->output_mode;
Packit 971217
  guint from_gl_target =
Packit 971217
      gst_gl_texture_target_to_gl (viewconvert->from_texture_target);
Packit 971217
Packit 971217
  gl = context->gl_vtable;
Packit 971217
Packit 971217
  gst_gl_framebuffer_bind (viewconvert->fbo);
Packit 971217
Packit 971217
  if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
Packit 971217
      out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    out_views = viewconvert->out_info.views;
Packit 971217
  } else {
Packit 971217
    out_views = 1;
Packit 971217
  }
Packit 971217
Packit 971217
  /* attach the texture to the FBO to renderer to */
Packit 971217
  for (i = 0; i < out_views; i++) {
Packit 971217
    GstGLBaseMemory *tex = (GstGLBaseMemory *) priv->out_tex[i];
Packit 971217
Packit 971217
    gst_gl_framebuffer_attach (viewconvert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
Packit 971217
  }
Packit 971217
Packit 971217
  if (gl->DrawBuffers)
Packit 971217
    gl->DrawBuffers (out_views, multipleRT);
Packit 971217
  else if (gl->DrawBuffer)
Packit 971217
    gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
Packit 971217
Packit 971217
  gst_gl_framebuffer_get_effective_dimensions (viewconvert->fbo, &out_width,
Packit 971217
      &out_height);
Packit 971217
  gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
Packit 971217
  gl->Viewport (0, 0, out_width, out_height);
Packit 971217
Packit 971217
  gst_gl_shader_use (viewconvert->shader);
Packit 971217
Packit 971217
  /* FIXME: the auxillary buffer could have a different transform matrix */
Packit 971217
  {
Packit 971217
    GstVideoAffineTransformationMeta *af_meta;
Packit 971217
    gfloat matrix[16];
Packit 971217
Packit 971217
    af_meta =
Packit 971217
        gst_buffer_get_video_affine_transformation_meta (priv->primary_in);
Packit 971217
    gst_gl_get_affine_transformation_meta_as_ndc (af_meta, matrix);
Packit 971217
    gst_gl_shader_set_uniform_matrix_4fv (viewconvert->shader,
Packit 971217
        "u_transformation", 1, FALSE, matrix);
Packit 971217
  }
Packit 971217
Packit 971217
  if (gl->BindVertexArray)
Packit 971217
    gl->BindVertexArray (priv->vao);
Packit 971217
  _bind_buffer (viewconvert);
Packit 971217
Packit 971217
  if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
Packit 971217
      in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    if (priv->in_tex[1] == NULL) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert,
Packit 971217
          "No 2nd view available during conversion!");
Packit 971217
      return FALSE;
Packit 971217
    }
Packit 971217
    gl->ActiveTexture (GL_TEXTURE1);
Packit 971217
    gl->BindTexture (from_gl_target, priv->in_tex[1]->tex_id);
Packit 971217
  }
Packit 971217
Packit 971217
  gl->ActiveTexture (GL_TEXTURE0);
Packit 971217
  gl->BindTexture (from_gl_target, priv->in_tex[0]->tex_id);
Packit 971217
Packit 971217
  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
Packit 971217
Packit 971217
  if (gl->BindVertexArray)
Packit 971217
    gl->BindVertexArray (0);
Packit 971217
  _unbind_buffer (viewconvert);
Packit 971217
  if (gl->DrawBuffer)
Packit 971217
    gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
Packit 971217
  /* we are done with the shader */
Packit 971217
  gst_gl_context_clear_shader (context);
Packit 971217
  gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
Packit 971217
      viewport_dim[3]);
Packit 971217
  gst_gl_context_clear_framebuffer (context);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_gen_buffer (GstGLViewConvert * viewconvert, GstBuffer ** target)
Packit 971217
{
Packit 971217
  GstGLVideoAllocationParams *params;
Packit 971217
  GstGLMemoryAllocator *mem_allocator;
Packit 971217
  GstAllocator *allocator;
Packit 971217
Packit 971217
  *target = gst_buffer_new ();
Packit 971217
Packit 971217
  allocator =
Packit 971217
      GST_ALLOCATOR (gst_gl_memory_allocator_get_default
Packit 971217
      (viewconvert->context));
Packit 971217
  mem_allocator = GST_GL_MEMORY_ALLOCATOR (allocator);
Packit 971217
  params = gst_gl_video_allocation_params_new (viewconvert->context, NULL,
Packit 971217
      &viewconvert->out_info, 0, NULL, viewconvert->to_texture_target, 0);
Packit 971217
Packit 971217
  if (!gst_gl_memory_setup_buffer (mem_allocator, *target, params, NULL, NULL,
Packit 971217
          0)) {
Packit 971217
    gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
Packit 971217
    gst_object_unref (allocator);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
  gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
Packit 971217
  gst_object_unref (allocator);
Packit 971217
Packit 971217
  gst_buffer_add_video_meta_full (*target, 0,
Packit 971217
      GST_VIDEO_INFO_FORMAT (&viewconvert->out_info),
Packit 971217
      GST_VIDEO_INFO_WIDTH (&viewconvert->out_info),
Packit 971217
      GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info),
Packit 971217
      GST_VIDEO_INFO_N_PLANES (&viewconvert->out_info),
Packit 971217
      viewconvert->out_info.offset, viewconvert->out_info.stride);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_do_view_convert (GstGLContext * context, GstGLViewConvert * viewconvert)
Packit 971217
{
Packit 971217
  GstGLViewConvertPrivate *priv = viewconvert->priv;
Packit 971217
  guint in_width, in_height, out_width, out_height;
Packit 971217
  GstMapInfo out_info[GST_VIDEO_MAX_PLANES], in_info[GST_VIDEO_MAX_PLANES];
Packit 971217
  GstGLMemory *dest_tex[GST_VIDEO_MAX_PLANES];
Packit 971217
  gboolean res = TRUE;
Packit 971217
  gint i = 0, j = 0;
Packit 971217
  gint in_views, out_views;
Packit 971217
  GstVideoMultiviewMode in_mode;
Packit 971217
  GstVideoMultiviewMode out_mode;
Packit 971217
Packit 971217
  out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
Packit 971217
  out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info);
Packit 971217
  in_width = GST_VIDEO_INFO_WIDTH (&viewconvert->in_info);
Packit 971217
  in_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->in_info);
Packit 971217
Packit 971217
  g_return_if_fail (priv->primary_out == NULL);
Packit 971217
  g_return_if_fail (priv->auxilliary_out == NULL);
Packit 971217
Packit 971217
  in_mode = priv->input_mode;
Packit 971217
  out_mode = priv->output_mode;
Packit 971217
Packit 971217
  if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
Packit 971217
      in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME)
Packit 971217
    in_views = viewconvert->in_info.views;
Packit 971217
  else
Packit 971217
    in_views = 1;
Packit 971217
Packit 971217
  if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
Packit 971217
      out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME)
Packit 971217
    out_views = viewconvert->out_info.views;
Packit 971217
  else
Packit 971217
    out_views = 1;
Packit 971217
Packit 971217
  if (!_init_view_convert (viewconvert)) {
Packit 971217
    priv->result = FALSE;
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  if (!_gen_buffer (viewconvert, &priv->primary_out)) {
Packit 971217
    GST_ERROR_OBJECT (viewconvert,
Packit 971217
        "Failed to setup memory for primary output buffer");
Packit 971217
    priv->result = FALSE;
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  if (out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    if (!_gen_buffer (viewconvert, &priv->auxilliary_out)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert,
Packit 971217
          "Failed to setup memory for second view output buffer");
Packit 971217
      priv->result = FALSE;
Packit 971217
      return;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  for (i = 0; i < in_views; i++) {
Packit 971217
    if (in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME && i > 0) {
Packit 971217
      priv->in_tex[i] =
Packit 971217
          (GstGLMemory *) gst_buffer_peek_memory (priv->auxilliary_in, 0);
Packit 971217
    } else {
Packit 971217
      priv->in_tex[i] =
Packit 971217
          (GstGLMemory *) gst_buffer_peek_memory (priv->primary_in, i);
Packit 971217
    }
Packit 971217
    if (!gst_is_gl_memory ((GstMemory *) priv->in_tex[i])) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "input must be GstGLMemory");
Packit 971217
      res = FALSE;
Packit 971217
      goto out;
Packit 971217
    }
Packit 971217
    if (!gst_memory_map ((GstMemory *) priv->in_tex[i],
Packit 971217
            &in_info[i], GST_MAP_READ | GST_MAP_GL)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "failed to map input memory %p",
Packit 971217
          priv->in_tex[i]);
Packit 971217
      res = FALSE;
Packit 971217
      goto out;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  for (j = 0; j < out_views; j++) {
Packit 971217
    GstGLMemory *out_tex;
Packit 971217
    guint width, height;
Packit 971217
    GstVideoInfo temp_info;
Packit 971217
Packit 971217
    if (j > 0 && out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
      dest_tex[j] = out_tex =
Packit 971217
          (GstGLMemory *) gst_buffer_peek_memory (priv->auxilliary_out, 0);
Packit 971217
    } else {
Packit 971217
      dest_tex[j] = out_tex =
Packit 971217
          (GstGLMemory *) gst_buffer_peek_memory (priv->primary_out, j);
Packit 971217
    }
Packit 971217
Packit 971217
    if (!gst_is_gl_memory ((GstMemory *) out_tex)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "output must be GstGLMemory");
Packit 971217
      res = FALSE;
Packit 971217
      goto out;
Packit 971217
    }
Packit 971217
Packit 971217
    width = gst_gl_memory_get_texture_width (out_tex);
Packit 971217
    height = gst_gl_memory_get_texture_height (out_tex);
Packit 971217
    gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA, width,
Packit 971217
        height);
Packit 971217
    if (out_tex->tex_format == GST_GL_LUMINANCE
Packit 971217
        || out_tex->tex_format == GST_GL_LUMINANCE_ALPHA
Packit 971217
        || out_width != width || out_height != height) {
Packit 971217
      /* Luminance formats are not color renderable */
Packit 971217
      /* renderering to a framebuffer only renders the intersection of all
Packit 971217
       * the attachments i.e. the smallest attachment size */
Packit 971217
      if (!priv->out_tex[j]) {
Packit 971217
        GstGLVideoAllocationParams *params;
Packit 971217
        GstGLBaseMemoryAllocator *base_mem_allocator;
Packit 971217
        GstAllocator *allocator;
Packit 971217
        GstVideoInfo temp_info;
Packit 971217
Packit 971217
        gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA, out_width,
Packit 971217
            out_height);
Packit 971217
Packit 971217
        allocator =
Packit 971217
            GST_ALLOCATOR (gst_gl_memory_allocator_get_default (context));
Packit 971217
        base_mem_allocator = GST_GL_BASE_MEMORY_ALLOCATOR (allocator);
Packit 971217
        params = gst_gl_video_allocation_params_new (context, NULL, &temp_info,
Packit 971217
            0, NULL, viewconvert->to_texture_target, GST_GL_RGBA);
Packit 971217
Packit 971217
        priv->out_tex[j] =
Packit 971217
            (GstGLMemory *) gst_gl_base_memory_alloc (base_mem_allocator,
Packit 971217
            (GstGLAllocationParams *) params);
Packit 971217
Packit 971217
        gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
Packit 971217
        gst_object_unref (allocator);
Packit 971217
      }
Packit 971217
    } else {
Packit 971217
      priv->out_tex[j] = out_tex;
Packit 971217
    }
Packit 971217
Packit 971217
    if (!gst_memory_map ((GstMemory *) priv->out_tex[j],
Packit 971217
            &out_info[j], GST_MAP_WRITE | GST_MAP_GL)) {
Packit 971217
      GST_ERROR_OBJECT (viewconvert, "failed to map output memory %p",
Packit 971217
          priv->out_tex[i]);
Packit 971217
      res = FALSE;
Packit 971217
      goto out;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  priv->n_out_tex = out_views;
Packit 971217
Packit 971217
  GST_LOG_OBJECT (viewconvert, "multiview splitting to textures:%p,%p,%p,%p "
Packit 971217
      "dimensions:%ux%u, from textures:%p,%p,%p,%p dimensions:%ux%u",
Packit 971217
      priv->out_tex[0], priv->out_tex[1],
Packit 971217
      priv->out_tex[2], priv->out_tex[3],
Packit 971217
      out_width, out_height, priv->in_tex[0],
Packit 971217
      priv->in_tex[1], priv->in_tex[2], priv->in_tex[3], in_width, in_height);
Packit 971217
Packit 971217
  if (!_do_view_convert_draw (context, viewconvert))
Packit 971217
    res = FALSE;
Packit 971217
out:
Packit 971217
  for (j--; j >= 0; j--) {
Packit 971217
    GstGLMemory *out_tex;
Packit 971217
    guint width, height;
Packit 971217
Packit 971217
    out_tex = dest_tex[j];
Packit 971217
Packit 971217
    width = gst_gl_memory_get_texture_width (out_tex);
Packit 971217
    height = gst_gl_memory_get_texture_height (out_tex);
Packit 971217
Packit 971217
    gst_memory_unmap ((GstMemory *) priv->out_tex[j], &out_info[j]);
Packit 971217
    if (out_tex != priv->out_tex[j]) {
Packit 971217
      GstMapInfo to_info, from_info;
Packit 971217
      if (!gst_memory_map ((GstMemory *) priv->out_tex[j],
Packit 971217
              &from_info, GST_MAP_READ | GST_MAP_GL)) {
Packit 971217
        GST_ERROR_OBJECT (viewconvert, "Failed to map intermediate memory");
Packit 971217
        res = FALSE;
Packit 971217
        continue;
Packit 971217
      }
Packit 971217
      if (!gst_memory_map ((GstMemory *) out_tex, &to_info,
Packit 971217
              GST_MAP_WRITE | GST_MAP_GL)) {
Packit 971217
        GST_ERROR_OBJECT (viewconvert, "Failed to map intermediate memory");
Packit 971217
        res = FALSE;
Packit 971217
        continue;
Packit 971217
      }
Packit 971217
      gst_gl_memory_copy_into (priv->out_tex[j], out_tex->tex_id,
Packit 971217
          viewconvert->to_texture_target, out_tex->tex_format, width, height);
Packit 971217
      gst_memory_unmap ((GstMemory *) out_tex, &to_info);
Packit 971217
    }
Packit 971217
Packit 971217
    priv->out_tex[j] = NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  for (i--; i >= 0; i--) {
Packit 971217
    gst_memory_unmap ((GstMemory *) priv->in_tex[i], &in_info[i]);
Packit 971217
  }
Packit 971217
Packit 971217
  if (!res) {
Packit 971217
    gst_buffer_replace (&priv->primary_out, NULL);
Packit 971217
    gst_buffer_replace (&priv->auxilliary_out, NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  priv->result = res;
Packit 971217
  return;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_submit_input_buffer:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @is_discont: true if we have a discontinuity
Packit 971217
 * @input: (transfer full): a #GstBuffer
Packit 971217
 *
Packit 971217
 * Submit @input to be processed by @viewconvert
Packit 971217
 *
Packit 971217
 * Returns: a #GstFlowReturn
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
GstFlowReturn
Packit 971217
gst_gl_view_convert_submit_input_buffer (GstGLViewConvert * viewconvert,
Packit 971217
    gboolean is_discont, GstBuffer * input)
Packit 971217
{
Packit 971217
  GstFlowReturn ret = GST_FLOW_OK;
Packit 971217
  GstVideoMultiviewMode mode;
Packit 971217
  GstBuffer **target;
Packit 971217
Packit 971217
  if (is_discont) {
Packit 971217
    gst_buffer_replace (&viewconvert->priv->primary_in, NULL);
Packit 971217
    gst_buffer_replace (&viewconvert->priv->auxilliary_in, NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  mode = viewconvert->input_mode_override;
Packit 971217
  if (mode == GST_VIDEO_MULTIVIEW_MODE_NONE)
Packit 971217
    mode = GST_VIDEO_INFO_MULTIVIEW_MODE (&viewconvert->in_info);
Packit 971217
Packit 971217
  target = &viewconvert->priv->primary_in;
Packit 971217
Packit 971217
  /* For frame-by-frame mode, we need to collect the 2nd eye into
Packit 971217
   * our auxilliary buffer */
Packit 971217
  if (mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    if (!GST_BUFFER_FLAG_IS_SET (input, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE))
Packit 971217
      target = &viewconvert->priv->auxilliary_in;
Packit 971217
  }
Packit 971217
Packit 971217
  if (*target)
Packit 971217
    gst_buffer_unref (*target);
Packit 971217
  *target = input;
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_view_convert_get_output:
Packit 971217
 * @viewconvert: a #GstGLViewConvert
Packit 971217
 * @outbuf_ptr: (out): a #GstBuffer
Packit 971217
 *
Packit 971217
 * Retrieve the processed output buffer placing the output in @outbuf_ptr.
Packit 971217
 *
Packit 971217
 * Returns: a #GstFlowReturn
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
GstFlowReturn
Packit 971217
gst_gl_view_convert_get_output (GstGLViewConvert * viewconvert,
Packit 971217
    GstBuffer ** outbuf_ptr)
Packit 971217
{
Packit 971217
  GstGLViewConvertPrivate *priv = viewconvert->priv;
Packit 971217
  GstBuffer *outbuf = NULL;
Packit 971217
  GstFlowReturn ret = GST_FLOW_OK;
Packit 971217
  GstVideoMultiviewMode in_mode, out_mode;
Packit 971217
  GstVideoMultiviewFlags in_flags, out_flags;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_GL_VIEW_CONVERT (viewconvert), GST_FLOW_ERROR);
Packit 971217
  g_return_val_if_fail (GST_IS_GL_CONTEXT (viewconvert->context),
Packit 971217
      GST_FLOW_ERROR);
Packit 971217
Packit 971217
  GST_OBJECT_LOCK (viewconvert);
Packit 971217
Packit 971217
  /* See if a buffer is available already */
Packit 971217
  if (priv->primary_out) {
Packit 971217
    outbuf = viewconvert->priv->primary_out;
Packit 971217
    priv->primary_out = NULL;
Packit 971217
    goto done;
Packit 971217
  }
Packit 971217
  if (viewconvert->priv->auxilliary_out) {
Packit 971217
    outbuf = priv->auxilliary_out;
Packit 971217
    priv->auxilliary_out = NULL;
Packit 971217
    goto done;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Check prereqs before processing a new input buffer */
Packit 971217
  if (priv->primary_in == NULL)
Packit 971217
    goto done;
Packit 971217
Packit 971217
  in_mode = viewconvert->input_mode_override;
Packit 971217
  in_flags = viewconvert->input_flags_override;
Packit 971217
  if (in_mode == GST_VIDEO_MULTIVIEW_MODE_NONE) {
Packit 971217
    in_mode = GST_VIDEO_INFO_MULTIVIEW_MODE (&viewconvert->in_info);
Packit 971217
    in_flags = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&viewconvert->in_info);
Packit 971217
  }
Packit 971217
Packit 971217
  /* Configured output mode already takes any override
Packit 971217
   * into account */
Packit 971217
  out_mode = GST_VIDEO_INFO_MULTIVIEW_MODE (&viewconvert->out_info);
Packit 971217
  out_flags = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&viewconvert->out_info);
Packit 971217
Packit 971217
  if (in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
Packit 971217
    /* For frame-by-frame, we need 2 input buffers */
Packit 971217
    if (priv->auxilliary_in == NULL) {
Packit 971217
      GST_LOG_OBJECT (viewconvert,
Packit 971217
          "Can't generate output yet - frame-by-frame mode");
Packit 971217
      goto done;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  /* Store the current conversion in the priv vars */
Packit 971217
  priv->input_mode = in_mode;
Packit 971217
  priv->input_flags = in_flags;
Packit 971217
  priv->output_mode = out_mode;
Packit 971217
  priv->output_flags = out_flags;
Packit 971217
Packit 971217
  if (priv->input_mode == priv->output_mode &&
Packit 971217
      priv->input_flags == priv->output_flags &&
Packit 971217
      viewconvert->in_info.width == viewconvert->out_info.width &&
Packit 971217
      viewconvert->in_info.height == viewconvert->out_info.height &&
Packit 971217
      viewconvert->from_texture_target == viewconvert->to_texture_target) {
Packit 971217
    /* passthrough - just pass input buffers */
Packit 971217
    outbuf = gst_buffer_ref (priv->primary_in);
Packit 971217
    if (in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME)
Packit 971217
      priv->auxilliary_out = gst_buffer_ref (priv->auxilliary_in);
Packit 971217
    goto done_clear_input;
Packit 971217
  }
Packit 971217
Packit 971217
  /* We can't output to OES textures, they're only supported for passthrough */
Packit 971217
  if (viewconvert->to_texture_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
Packit 971217
    ret = GST_FLOW_ERROR;
Packit 971217
    goto done_clear_input;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Generate new output buffer(s) */
Packit 971217
  gst_gl_context_thread_add (viewconvert->context,
Packit 971217
      (GstGLContextThreadFunc) _do_view_convert, viewconvert);
Packit 971217
Packit 971217
  if (!priv->result) {
Packit 971217
    if (priv->primary_out)
Packit 971217
      gst_object_unref (priv->primary_out);
Packit 971217
    if (priv->auxilliary_out)
Packit 971217
      gst_object_unref (priv->auxilliary_out);
Packit 971217
    priv->primary_out = NULL;
Packit 971217
    priv->auxilliary_out = NULL;
Packit 971217
    ret = GST_FLOW_ERROR;
Packit 971217
    goto done_clear_input;
Packit 971217
  }
Packit 971217
Packit 971217
  outbuf = priv->primary_out;
Packit 971217
  if (outbuf) {
Packit 971217
    gst_buffer_copy_into (outbuf, priv->primary_in,
Packit 971217
        GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
Packit 971217
    GST_BUFFER_FLAG_SET (outbuf,
Packit 971217
        GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE |
Packit 971217
        GST_VIDEO_BUFFER_FLAG_MULTIPLE_VIEW);
Packit 971217
  }
Packit 971217
Packit 971217
  if (priv->auxilliary_out) {
Packit 971217
    gst_buffer_copy_into (priv->auxilliary_out,
Packit 971217
        priv->primary_out, GST_BUFFER_COPY_FLAGS, 0, -1);
Packit 971217
    GST_BUFFER_FLAG_UNSET (priv->auxilliary_out,
Packit 971217
        GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE);
Packit 971217
  }
Packit 971217
  priv->primary_out = NULL;
Packit 971217
Packit 971217
done_clear_input:
Packit 971217
  /* Invalidate input buffers now they've been used */
Packit 971217
  gst_buffer_replace (&priv->primary_in, NULL);
Packit 971217
  gst_buffer_replace (&priv->auxilliary_in, NULL);
Packit 971217
Packit 971217
done:
Packit 971217
  GST_OBJECT_UNLOCK (viewconvert);
Packit 971217
  *outbuf_ptr = outbuf;
Packit 971217
  return ret;
Packit 971217
}