static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query) { gboolean res = FALSE; GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { res = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display, &mix->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); break; } case GST_QUERY_CAPS: res = gst_gl_mixer_query_caps (agg->srcpad, agg, query); break; default: res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query); break; } return res; }
static void gst_gl_mixer_set_context (GstElement * element, GstContext * context) { GstGLMixer *mix = GST_GL_MIXER (element); gst_gl_handle_set_context (element, context, &mix->display); }
static void gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (object); GstGLMixer *mix = GST_GL_MIXER (gst_pad_get_parent (GST_PAD (pad))); switch (prop_id) { case PROP_PAD_XPOS: pad->xpos = g_value_get_int (value); pad->geometry_change = TRUE; break; case PROP_PAD_YPOS: pad->ypos = g_value_get_int (value); pad->geometry_change = TRUE; break; case PROP_PAD_WIDTH: pad->width = g_value_get_int (value); pad->geometry_change = TRUE; break; case PROP_PAD_HEIGHT: pad->height = g_value_get_int (value); pad->geometry_change = TRUE; break; case PROP_PAD_ALPHA: pad->alpha = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } gst_object_unref (mix); }
static gboolean gst_gl_mixer_start (GstAggregator * agg) { guint i; GstGLMixer *mix = GST_GL_MIXER (agg); GstElement *element = GST_ELEMENT (agg); if (!GST_AGGREGATOR_CLASS (parent_class)->start (agg)) return FALSE; GST_OBJECT_LOCK (mix); mix->array_buffers = g_ptr_array_new_full (element->numsinkpads, (GDestroyNotify) _free_glmixer_frame_data); mix->frames = g_ptr_array_new_full (element->numsinkpads, NULL); g_ptr_array_set_size (mix->array_buffers, element->numsinkpads); g_ptr_array_set_size (mix->frames, element->numsinkpads); for (i = 0; i < element->numsinkpads; i++) mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData); GST_OBJECT_UNLOCK (mix); return TRUE; }
static gboolean _draw_background (GstGLVideoMixer * video_mixer) { GstGLMixer *mixer = GST_GL_MIXER (video_mixer); const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable; switch (video_mixer->background) { case GST_GL_VIDEO_MIXER_BACKGROUND_BLACK: gl->ClearColor (0.0, 0.0, 0.0, 1.0); gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); break; case GST_GL_VIDEO_MIXER_BACKGROUND_WHITE: gl->ClearColor (1.0, 1.0, 1.0, 1.0); gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); break; case GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT: gl->ClearColor (0.0, 0.0, 0.0, 0.0); gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); break; case GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER: return _draw_checker_background (video_mixer); break; default: break; } return TRUE; }
static void _mosaic_render (GstGLContext * context, GstGLMosaic * mosaic) { GstGLMixer *mixer = GST_GL_MIXER (mosaic); gst_gl_framebuffer_draw_to_texture (mixer->fbo, mosaic->out_tex, gst_gl_mosaic_callback, mosaic); }
static void gst_gl_mixer_finalize (GObject * object) { GstGLMixerPrivate *priv = GST_GL_MIXER (object)->priv; g_mutex_clear (&priv->gl_resource_lock); g_cond_clear (&priv->gl_resource_cond); G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean _negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps) { GstGLMixer *mix = GST_GL_MIXER (vagg); gboolean ret = gst_gl_mixer_do_bufferpool (mix, caps); mix->priv->negotiated = ret; return ret; }
static void gst_gl_mixer_set_context (GstElement * element, GstContext * context) { GstGLMixer *mix = GST_GL_MIXER (element); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); gst_gl_handle_set_context (element, context, &mix->display, &mix->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); }
static gboolean gst_gl_mixer_stop (GstAggregator * agg) { GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg)) return FALSE; GST_OBJECT_LOCK (agg); g_ptr_array_free (mix->frames, TRUE); mix->frames = NULL; g_ptr_array_free (mix->array_buffers, TRUE); mix->array_buffers = NULL; GST_OBJECT_UNLOCK (agg); if (mixer_class->reset) mixer_class->reset (mix); if (mix->fbo) { gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer); mix->fbo = 0; mix->depthbuffer = 0; } if (mix->download) { gst_object_unref (mix->download); mix->download = NULL; } gst_aggregator_iterate_sinkpads (GST_AGGREGATOR (mix), _clean_upload, NULL); if (mix->priv->query) { gst_query_unref (mix->priv->query); mix->priv->query = NULL; } if (mix->priv->pool) { gst_object_unref (mix->priv->pool); mix->priv->pool = NULL; } if (mix->display) { gst_object_unref (mix->display); mix->display = NULL; } if (mix->context) { gst_object_unref (mix->context); mix->context = NULL; } gst_gl_mixer_reset (mix); return TRUE; }
static gboolean gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, GstQuery * query) { gboolean ret = FALSE; GstGLMixer *mix = GST_GL_MIXER (agg); GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_ALLOCATION: { GstQuery *decide_query = NULL; gboolean negotiated; GST_OBJECT_LOCK (mix); if (G_UNLIKELY (!(negotiated = mix->priv->negotiated))) { GST_DEBUG_OBJECT (mix, "not negotiated yet, can't answer ALLOCATION query"); GST_OBJECT_UNLOCK (mix); return FALSE; } if ((decide_query = mix->priv->query)) gst_query_ref (decide_query); GST_OBJECT_UNLOCK (mix); GST_DEBUG_OBJECT (mix, "calling propose allocation with query %" GST_PTR_FORMAT, decide_query); /* pass the query to the propose_allocation vmethod if any */ ret = gst_gl_mixer_propose_allocation (mix, decide_query, query); if (decide_query) gst_query_unref (decide_query); GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query); break; } case GST_QUERY_CONTEXT: { ret = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display); break; } default: ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query); break; } return ret; }
static gboolean _draw_checker_background (GstGLVideoMixer * video_mixer) { GstGLMixer *mixer = GST_GL_MIXER (video_mixer); const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable; gint attr_position_loc = 0; /* *INDENT-OFF* */ gfloat v_vertices[] = { -1.0,-1.0,-1.0f, 1.0,-1.0,-1.0f, 1.0, 1.0,-1.0f, -1.0, 1.0,-1.0f, }; /* *INDENT-ON* */ if (!video_mixer->checker) { if (!gst_gl_context_gen_shader (GST_GL_BASE_MIXER (mixer)->context, checker_v_src, checker_f_src, &video_mixer->checker)) return FALSE; } gst_gl_shader_use (video_mixer->checker); attr_position_loc = gst_gl_shader_get_attribute_location (video_mixer->checker, "a_position"); _init_vbo_indices (video_mixer); if (!video_mixer->checker_vbo) { gl->GenBuffers (1, &video_mixer->checker_vbo); gl->BindBuffer (GL_ARRAY_BUFFER, video_mixer->checker_vbo); gl->BufferData (GL_ARRAY_BUFFER, 4 * 3 * sizeof (GLfloat), v_vertices, GL_STATIC_DRAW); } else { gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices); gl->BindBuffer (GL_ARRAY_BUFFER, video_mixer->checker_vbo); } gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof (GLfloat), (void *) 0); gl->EnableVertexAttribArray (attr_position_loc); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); gl->DisableVertexAttribArray (attr_position_loc); gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); gl->BindBuffer (GL_ARRAY_BUFFER, 0); return TRUE; }
static GstFlowReturn gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) { gboolean res = FALSE; GstGLMixer *mix = GST_GL_MIXER (vagg); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg); if (mix_class->process_buffers) res = gst_gl_mixer_process_buffers (mix, outbuf); else if (mix_class->process_textures) res = gst_gl_mixer_process_textures (mix, outbuf); return res ? GST_FLOW_OK : GST_FLOW_ERROR; }
static void gst_gl_mixer_finalize (GObject * object) { GstGLMixer *mix = GST_GL_MIXER (object); GstGLMixerPrivate *priv = mix->priv; if (mix->other_context) { gst_object_unref (mix->other_context); mix->other_context = NULL; } g_mutex_clear (&priv->gl_resource_lock); g_cond_clear (&priv->gl_resource_cond); G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gst_gl_mixer_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstGLMixer *mixer = GST_GL_MIXER (object); switch (prop_id) { case PROP_CONTEXT: g_value_set_object (value, mixer->context); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static GstFlowReturn gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator, GstBuffer ** outbuf) { GstGLMixer *mix = GST_GL_MIXER (videoaggregator); if (!mix->priv->pool_active) { if (!gst_buffer_pool_set_active (mix->priv->pool, TRUE)) { GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS, ("failed to activate bufferpool"), ("failed to activate bufferpool")); return GST_FLOW_ERROR; } mix->priv->pool_active = TRUE; } return gst_buffer_pool_acquire_buffer (mix->priv->pool, outbuf, NULL); }
static GstFlowReturn gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) { gboolean res = FALSE; GstGLMixer *mix = GST_GL_MIXER (vagg); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg); GstGLSyncMeta *sync_meta; if (mix_class->process_buffers) res = gst_gl_mixer_process_buffers (mix, outbuf); else if (mix_class->process_textures) res = gst_gl_mixer_process_textures (mix, outbuf); sync_meta = gst_buffer_get_gl_sync_meta (outbuf); if (sync_meta) gst_gl_sync_meta_set_sync_point (sync_meta, mix->context); return res ? GST_FLOW_OK : GST_FLOW_ERROR; }
static gboolean gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode, gboolean active) { GstGLMixer *mix; gboolean result = FALSE; mix = GST_GL_MIXER (aggregator); switch (mode) { case GST_PAD_MODE_PUSH: case GST_PAD_MODE_PULL: result = gst_gl_mixer_activate (mix, active); break; default: result = TRUE; break; } return result; }
static gboolean gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, GstQuery * query) { gboolean ret = FALSE; GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS: { GstCaps *filter, *caps; gst_query_parse_caps (query, &filter); caps = gst_gl_mixer_pad_sink_getcaps (GST_PAD (bpad), mix, filter); gst_query_set_caps_result (query, caps); gst_caps_unref (caps); ret = TRUE; break; } case GST_QUERY_ACCEPT_CAPS: { GstCaps *caps; gst_query_parse_accept_caps (query, &caps); ret = gst_gl_mixer_pad_sink_acceptcaps (GST_PAD (bpad), mix, caps); gst_query_set_accept_caps_result (query, ret); ret = TRUE; break; } case GST_QUERY_ALLOCATION: { GstQuery *decide_query = NULL; GST_OBJECT_LOCK (mix); if (G_UNLIKELY (!mix->priv->negotiated)) { GST_DEBUG_OBJECT (mix, "not negotiated yet, can't answer ALLOCATION query"); GST_OBJECT_UNLOCK (mix); return FALSE; } if ((decide_query = mix->priv->query)) gst_query_ref (decide_query); GST_OBJECT_UNLOCK (mix); GST_DEBUG_OBJECT (mix, "calling propose allocation with query %" GST_PTR_FORMAT, decide_query); /* pass the query to the propose_allocation vmethod if any */ ret = gst_gl_mixer_propose_allocation (mix, decide_query, query); if (decide_query) gst_query_unref (decide_query); GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query); break; } case GST_QUERY_CONTEXT: { ret = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display, &mix->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); break; } default: ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query); break; } return ret; }
/* opengl scene, params: input texture (not the output mixer->texture) */ static void gst_gl_video_mixer_callback (gpointer stuff) { GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (stuff); GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (stuff); GstGLMixer *mixer = GST_GL_MIXER (video_mixer); GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable; GLint attr_position_loc = 0; GLint attr_texture_loc = 0; guint out_width, out_height; guint count = 0; out_width = GST_VIDEO_INFO_WIDTH (&vagg->info); out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info); gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context); gl->BindTexture (GL_TEXTURE_2D, 0); gl->Disable (GL_DEPTH_TEST); gl->Disable (GL_CULL_FACE); if (gl->GenVertexArrays) { if (!video_mixer->vao) gl->GenVertexArrays (1, &video_mixer->vao); gl->BindVertexArray (video_mixer->vao); } if (!_draw_background (video_mixer)) return; gst_gl_shader_use (video_mixer->shader); attr_position_loc = gst_gl_shader_get_attribute_location (video_mixer->shader, "a_position"); attr_texture_loc = gst_gl_shader_get_attribute_location (video_mixer->shader, "a_texCoord"); gl->Enable (GL_BLEND); while (count < video_mixer->input_frames->len) { GstGLMixerFrameData *frame; GstGLVideoMixerPad *pad; GstVideoInfo *v_info; guint in_tex; guint in_width, in_height; /* *INDENT-OFF* */ gfloat v_vertices[] = { -1.0,-1.0,-1.0f, 0.0f, 0.0f, 1.0,-1.0,-1.0f, 1.0f, 0.0f, 1.0, 1.0,-1.0f, 1.0f, 1.0f, -1.0, 1.0,-1.0f, 0.0f, 1.0f, }; /* *INDENT-ON* */ frame = g_ptr_array_index (video_mixer->input_frames, count); if (!frame) { GST_DEBUG ("skipping texture, null frame"); count++; continue; } pad = (GstGLVideoMixerPad *) frame->pad; v_info = &GST_VIDEO_AGGREGATOR_PAD (pad)->info; in_width = GST_VIDEO_INFO_WIDTH (v_info); in_height = GST_VIDEO_INFO_HEIGHT (v_info); if (!frame->texture || in_width <= 0 || in_height <= 0 || pad->alpha == 0.0f) { GST_DEBUG ("skipping texture:%u frame:%p width:%u height:%u alpha:%f", frame->texture, frame, in_width, in_height, pad->alpha); count++; continue; } in_tex = frame->texture; _init_vbo_indices (video_mixer); if (pad->geometry_change || !pad->vertex_buffer) { gint pad_width, pad_height; gfloat w, h; _mixer_pad_get_output_size (video_mixer, pad, &pad_width, &pad_height); w = ((gfloat) pad_width / (gfloat) out_width); h = ((gfloat) pad_height / (gfloat) out_height); /* top-left */ v_vertices[0] = v_vertices[15] = 2.0f * (gfloat) pad->xpos / (gfloat) out_width - 1.0f; /* bottom-left */ v_vertices[1] = v_vertices[6] = 2.0f * (gfloat) pad->ypos / (gfloat) out_height - 1.0f; /* top-right */ v_vertices[5] = v_vertices[10] = v_vertices[0] + 2.0f * w; /* bottom-right */ v_vertices[11] = v_vertices[16] = v_vertices[1] + 2.0f * h; GST_TRACE ("processing texture:%u dimensions:%ux%u, at %f,%f %fx%f with " "alpha:%f", in_tex, in_width, in_height, v_vertices[0], v_vertices[1], v_vertices[5], v_vertices[11], pad->alpha); if (!pad->vertex_buffer) gl->GenBuffers (1, &pad->vertex_buffer); gl->BindBuffer (GL_ARRAY_BUFFER, pad->vertex_buffer); gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), v_vertices, GL_STATIC_DRAW); pad->geometry_change = FALSE; } else { gl->BindBuffer (GL_ARRAY_BUFFER, pad->vertex_buffer); } gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices); gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl->BlendEquation (GL_FUNC_ADD); gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (GL_TEXTURE_2D, in_tex); gst_gl_shader_set_uniform_1i (video_mixer->shader, "texture", 0); gst_gl_shader_set_uniform_1f (video_mixer->shader, "alpha", pad->alpha); gl->EnableVertexAttribArray (attr_position_loc); gl->EnableVertexAttribArray (attr_texture_loc); gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), (void *) 0); gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat))); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); ++count; } gl->DisableVertexAttribArray (attr_position_loc); gl->DisableVertexAttribArray (attr_texture_loc); if (gl->GenVertexArrays) gl->BindVertexArray (0); gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); gl->BindBuffer (GL_ARRAY_BUFFER, 0); gl->BindTexture (GL_TEXTURE_2D, 0); gl->Disable (GL_BLEND); gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context); }
/* opengl scene, params: input texture (not the output mixer->texture) */ static gboolean gst_gl_mosaic_callback (gpointer stuff) { GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff); GstGLMixer *mixer = GST_GL_MIXER (mosaic); GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable; GList *walk; static GLfloat xrot = 0; static GLfloat yrot = 0; static GLfloat zrot = 0; GLint attr_position_loc = 0; GLint attr_texture_loc = 0; const GLfloat matrix[] = { 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; const GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; guint count = 0; gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context); gl->BindTexture (GL_TEXTURE_2D, 0); gl->Enable (GL_DEPTH_TEST); gl->ClearColor (0.0, 0.0, 0.0, 0.0); gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gst_gl_shader_use (mosaic->shader); attr_position_loc = gst_gl_shader_get_attribute_location (mosaic->shader, "a_position"); attr_texture_loc = gst_gl_shader_get_attribute_location (mosaic->shader, "a_texCoord"); GST_OBJECT_LOCK (mosaic); walk = GST_ELEMENT (mosaic)->sinkpads; while (walk) { GstGLMixerPad *pad = walk->data; /* *INDENT-OFF* */ gfloat v_vertices[] = { /* front face */ 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, -1.0f, 1.0f,-1.0f, 0.0f, 0.0f, /* right face */ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-1.0f,-1.0f, 0.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, /* left face */ -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f,-1.0f, 1.0f, 1.0f, -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, -1.0f,-1.0f, 1.0f, 0.0f, 0.0f, /* top face */ 1.0f,-1.0f, 1.0f, 1.0f, 0.0f, -1.0f,-1.0f, 1.0f, 0.0f, 0.0f, -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, /* bottom face */ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, /* back face */ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f }; /* *INDENT-ON* */ guint in_tex; guint width, height; in_tex = pad->current_texture; width = GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR_PAD (pad)->info); height = GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR_PAD (pad)->info); if (!in_tex || width <= 0 || height <= 0) { GST_DEBUG ("skipping texture:%u pad:%p width:%u height %u", in_tex, pad, width, height); count++; walk = g_list_next (walk); continue; } GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, width, height); gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count]); gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count + 3]); gl->EnableVertexAttribArray (attr_position_loc); gl->EnableVertexAttribArray (attr_texture_loc); gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (GL_TEXTURE_2D, in_tex); gst_gl_shader_set_uniform_1i (mosaic->shader, "s_texture", 0); gst_gl_shader_set_uniform_1f (mosaic->shader, "xrot_degree", xrot); gst_gl_shader_set_uniform_1f (mosaic->shader, "yrot_degree", yrot); gst_gl_shader_set_uniform_1f (mosaic->shader, "zrot_degree", zrot); gst_gl_shader_set_uniform_matrix_4fv (mosaic->shader, "u_matrix", 1, GL_FALSE, matrix); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); ++count; walk = g_list_next (walk); } GST_OBJECT_UNLOCK (mosaic); gl->DisableVertexAttribArray (attr_position_loc); gl->DisableVertexAttribArray (attr_texture_loc); gl->BindTexture (GL_TEXTURE_2D, 0); gl->Disable (GL_DEPTH_TEST); gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context); xrot += 0.6f; yrot += 0.4f; zrot += 0.8f; return TRUE; }