diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c index eab574da89..702c010a40 100644 --- a/gst-libs/gst/gl/gstglfilter.c +++ b/gst-libs/gst/gl/gstglfilter.c @@ -66,6 +66,8 @@ static gboolean gst_gl_filter_query (GstBaseTransform * trans, GstPadDirection direction, GstQuery * query); static GstCaps *gst_gl_filter_transform_caps (GstBaseTransform * bt, GstPadDirection direction, GstCaps * caps, GstCaps * filter); +static GstCaps *gst_gl_filter_fixate_caps (GstBaseTransform * bt, + GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); static void gst_gl_filter_reset (GstGLFilter * filter); static gboolean gst_gl_filter_start (GstBaseTransform * bt); static gboolean gst_gl_filter_stop (GstBaseTransform * bt); @@ -98,6 +100,7 @@ gst_gl_filter_class_init (GstGLFilterClass * klass) GST_BASE_TRANSFORM_CLASS (klass)->transform_caps = gst_gl_filter_transform_caps; + GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps = gst_gl_filter_fixate_caps; GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_filter_transform; GST_BASE_TRANSFORM_CLASS (klass)->query = gst_gl_filter_query; GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_filter_start; @@ -297,6 +300,334 @@ gst_gl_filter_stop_gl (GstGLDisplay * display, gpointer data) filter_class->display_reset_cb (filter); } +static GstCaps * +gst_gl_filter_fixate_caps (GstBaseTransform * bt, + GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) +{ + GstStructure *ins, *outs; + const GValue *from_par, *to_par; + GValue fpar = { 0, }, tpar = { + 0,}; + + othercaps = gst_caps_truncate (othercaps); + othercaps = gst_caps_make_writable (othercaps); + + GST_DEBUG_OBJECT (bt, "trying to fixate othercaps %" GST_PTR_FORMAT + " based on caps %" GST_PTR_FORMAT, othercaps, caps); + + ins = gst_caps_get_structure (caps, 0); + outs = gst_caps_get_structure (othercaps, 0); + + from_par = gst_structure_get_value (ins, "pixel-aspect-ratio"); + to_par = gst_structure_get_value (outs, "pixel-aspect-ratio"); + + /* If we're fixating from the sinkpad we always set the PAR and + * assume that missing PAR on the sinkpad means 1/1 and + * missing PAR on the srcpad means undefined + */ + if (direction == GST_PAD_SINK) { + if (!from_par) { + g_value_init (&fpar, GST_TYPE_FRACTION); + gst_value_set_fraction (&fpar, 1, 1); + from_par = &fpar; + } + if (!to_par) { + g_value_init (&tpar, GST_TYPE_FRACTION); + gst_value_set_fraction (&tpar, 1, 1); + to_par = &tpar; + } + } else { + if (!to_par) { + g_value_init (&tpar, GST_TYPE_FRACTION); + gst_value_set_fraction (&tpar, 1, 1); + to_par = &tpar; + + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, + NULL); + } + if (!from_par) { + g_value_init (&fpar, GST_TYPE_FRACTION); + gst_value_set_fraction (&fpar, 1, 1); + from_par = &fpar; + } + } + + /* we have both PAR but they might not be fixated */ + { + gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d; + gint w = 0, h = 0; + gint from_dar_n, from_dar_d; + gint num, den; + + /* from_par should be fixed */ + g_return_val_if_fail (gst_value_is_fixed (from_par), othercaps); + + from_par_n = gst_value_get_fraction_numerator (from_par); + from_par_d = gst_value_get_fraction_denominator (from_par); + + gst_structure_get_int (ins, "width", &from_w); + gst_structure_get_int (ins, "height", &from_h); + + gst_structure_get_int (outs, "width", &w); + gst_structure_get_int (outs, "height", &h); + + /* if both width and height are already fixed, we can't do anything + * about it anymore */ + if (w && h) { + gint n = 1, d = 1; + + GST_DEBUG_OBJECT (bt, "dimensions already set to %dx%d, not fixating", + w, h); + if (!gst_value_is_fixed (to_par)) { + GST_DEBUG_OBJECT (bt, "fixating to_par to %dx%d", n, d); + if (gst_structure_has_field (outs, "pixel-aspect-ratio")) + gst_structure_fixate_field_nearest_fraction (outs, + "pixel-aspect-ratio", 1, 1); + else if (n != d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + 1, 1, NULL); + } + goto done; + } + + /* Calculate input DAR */ + if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d, + &from_dar_n, &from_dar_d)) { + GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } + + GST_DEBUG_OBJECT (bt, "Input DAR is %d/%d", from_dar_n, from_dar_d); + + /* If either width or height are fixed there's not much we + * can do either except choosing a height or width and PAR + * that matches the DAR as good as possible + */ + if (h) { + gint num, den; + + GST_DEBUG_OBJECT (bt, "height is fixed (%d)", h); + + if (!gst_value_is_fixed (to_par)) { + gst_value_set_fraction (&tpar, 1, 1); + } + + /* PAR is fixed, choose the height that is nearest to the + * height with the same DAR */ + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + GST_DEBUG_OBJECT (bt, "PAR is fixed %d/%d", to_par_n, to_par_d); + + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d, + to_par_n, &num, &den)) { + GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } + + w = (guint) gst_util_uint64_scale_int (h, num, den); + gst_structure_fixate_field_nearest_int (outs, "width", w); + + goto done; + } else if (w) { + gint num, den; + + GST_DEBUG_OBJECT (bt, "width is fixed (%d)", w); + + if (!gst_value_is_fixed (to_par)) { + gst_value_set_fraction (&tpar, 1, 1); + } + + /* PAR is fixed, choose the height that is nearest to the + * height with the same DAR */ + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + GST_DEBUG_OBJECT (bt, "PAR is fixed %d/%d", to_par_n, to_par_d); + + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d, + to_par_n, &num, &den)) { + GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } + + h = (guint) gst_util_uint64_scale_int (w, den, num); + gst_structure_fixate_field_nearest_int (outs, "height", h); + + goto done; + } else if (gst_value_is_fixed (to_par)) { + GstStructure *tmp; + gint set_h, set_w, f_h, f_w; + + to_par_n = gst_value_get_fraction_numerator (to_par); + to_par_d = gst_value_get_fraction_denominator (to_par); + + /* Calculate scale factor for the PAR change */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n, + to_par_d, &num, &den)) { + GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } + + /* Try to keep the input height */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", from_h); + gst_structure_get_int (tmp, "height", &set_h); + + /* This might have failed but try to scale the width + * to keep the DAR nonetheless */ + w = (guint) gst_util_uint64_scale_int (set_h, num, den); + gst_structure_fixate_field_nearest_int (tmp, "width", w); + gst_structure_get_int (tmp, "width", &set_w); + gst_structure_free (tmp); + + /* We kept the DAR and the height is nearest to the original height */ + if (set_w == w) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + goto done; + } + + f_h = set_h; + f_w = set_w; + + /* If the former failed, try to keep the input width at least */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "width", from_w); + gst_structure_get_int (tmp, "width", &set_w); + + /* This might have failed but try to scale the width + * to keep the DAR nonetheless */ + h = (guint) gst_util_uint64_scale_int (set_w, den, num); + gst_structure_fixate_field_nearest_int (tmp, "height", h); + gst_structure_get_int (tmp, "height", &set_h); + gst_structure_free (tmp); + + /* We kept the DAR and the width is nearest to the original width */ + if (set_h == h) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + goto done; + } + + /* If all this failed, keep the height that was nearest to the orignal + * height and the nearest possible width. This changes the DAR but + * there's not much else to do here. + */ + gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT, + f_h, NULL); + goto done; + } else { + GstStructure *tmp; + gint set_h, set_w, set_par_n, set_par_d, tmp2; + + /* width, height and PAR are not fixed */ + + /* First try to keep the height and width as good as possible + * and scale PAR */ + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", from_h); + gst_structure_get_int (tmp, "height", &set_h); + gst_structure_fixate_field_nearest_int (tmp, "width", from_w); + gst_structure_get_int (tmp, "width", &set_w); + + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w, + &to_par_n, &to_par_d)) { + GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } + + if (!gst_structure_has_field (tmp, "pixel-aspect-ratio")) + gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par); + gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio", + to_par_n, to_par_d); + gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n, + &set_par_d); + gst_structure_free (tmp); + + if (set_par_n == to_par_n && set_par_d == to_par_d) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + goto done; + } + + /* Otherwise try to scale width to keep the DAR with the set + * PAR and height */ + if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d, + set_par_n, &num, &den)) { + GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL), + ("Error calculating the output scaled size - integer overflow")); + goto done; + } + + w = (guint) gst_util_uint64_scale_int (set_h, num, den); + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "width", w); + gst_structure_get_int (tmp, "width", &tmp2); + gst_structure_free (tmp); + + if (tmp2 == w) { + gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height", + G_TYPE_INT, set_h, NULL); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + goto done; + } + + /* ... or try the same with the height */ + h = (guint) gst_util_uint64_scale_int (set_w, den, num); + tmp = gst_structure_copy (outs); + gst_structure_fixate_field_nearest_int (tmp, "height", h); + gst_structure_get_int (tmp, "height", &tmp2); + gst_structure_free (tmp); + + if (tmp2 == h) { + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, tmp2, NULL); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + goto done; + } + + /* If all fails we can't keep the DAR and take the nearest values + * for everything from the first try */ + gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height", + G_TYPE_INT, set_h, NULL); + if (gst_structure_has_field (outs, "pixel-aspect-ratio") || + set_par_n != set_par_d) + gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, + set_par_n, set_par_d, NULL); + } + } + + +done: + othercaps = gst_caps_fixate (othercaps); + + GST_DEBUG_OBJECT (bt, "fixated othercaps to %" GST_PTR_FORMAT, othercaps); + + if (from_par == &fpar) + g_value_unset (&fpar); + if (to_par == &tpar) + g_value_unset (&tpar); + + return othercaps; +} + static GstCaps * gst_gl_filter_transform_caps (GstBaseTransform * bt, GstPadDirection direction, GstCaps * caps, GstCaps * filter) @@ -319,9 +650,9 @@ gst_gl_filter_transform_caps (GstBaseTransform * bt, structure = gst_structure_copy (structure); -// gst_structure_set (structure, -// "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, -// "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); gst_structure_remove_field (structure, "format"); @@ -367,6 +698,7 @@ gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, { GstGLFilter *filter; GstGLFilterClass *filter_class; + guint in_width, in_height, out_width, out_height; filter = GST_GL_FILTER (bt); filter_class = GST_GL_FILTER_GET_CLASS (filter); @@ -376,42 +708,21 @@ gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, if (!gst_video_info_from_caps (&filter->out_info, outcaps)) goto wrong_caps; + in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info); + in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info); + out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); + out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); + //blocking call, generate a FBO - if (!gst_gl_display_gen_fbo (filter->display, - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), + if (!gst_gl_display_gen_fbo (filter->display, out_width, out_height, &filter->fbo, &filter->depthbuffer)) goto display_error; gst_gl_display_gen_texture (filter->display, &filter->in_tex_id, - GST_VIDEO_INFO_FORMAT (&filter->out_info), - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info)); + GST_VIDEO_FORMAT_RGBA, in_width, in_height); gst_gl_display_gen_texture (filter->display, &filter->out_tex_id, - GST_VIDEO_INFO_FORMAT (&filter->out_info), - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info)); - - filter->download = gst_gl_display_find_download (filter->display, - GST_VIDEO_INFO_FORMAT (&filter->out_info), - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info)); - - gst_gl_download_init_format (filter->download, - GST_VIDEO_INFO_FORMAT (&filter->out_info), - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info)); - - filter->upload = gst_gl_display_find_upload (filter->display, - GST_VIDEO_INFO_FORMAT (&filter->out_info), - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info)); - - gst_gl_upload_init_format (filter->upload, - GST_VIDEO_INFO_FORMAT (&filter->out_info), - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info)); + GST_VIDEO_FORMAT_RGBA, out_width, out_height); if (filter_class->display_init_cb != NULL) { gst_gl_display_thread_add (filter->display, gst_gl_filter_start_gl, filter); @@ -579,7 +890,7 @@ gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, GstVideoFrame in_frame; GstVideoFrame out_frame; guint in_tex, out_tex; - gboolean ret, out_gl_wrapped = FALSE; + gboolean ret, in_gl_wrapped, out_gl_wrapped; filter_class = GST_GL_FILTER_GET_CLASS (filter); @@ -593,29 +904,93 @@ gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, return FALSE; } - if (gst_is_gl_memory (in_frame.map[0].memory)) { + in_gl_wrapped = !gst_is_gl_memory (in_frame.map[0].memory); + out_gl_wrapped = !gst_is_gl_memory (out_frame.map[0].memory); + + if (!in_gl_wrapped && !out_gl_wrapped) { /* both GL */ in_tex = *(guint *) in_frame.data[0]; - } else { + out_tex = *(guint *) out_frame.data[0]; + } else if (in_gl_wrapped && !out_gl_wrapped) { /* input: non-GL, output: GL */ GST_INFO ("Input Buffer does not contain correct meta, " "attempting to wrap for upload"); + if (!filter->upload) { + filter->upload = gst_gl_display_find_upload (filter->display, + GST_VIDEO_FRAME_FORMAT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&in_frame), + GST_VIDEO_FRAME_HEIGHT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + + gst_gl_upload_init_format (filter->upload, + GST_VIDEO_FRAME_FORMAT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&in_frame), + GST_VIDEO_FRAME_HEIGHT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + } + + in_tex = filter->in_tex_id; + out_tex = *(guint *) out_frame.data[0]; + } else if (!in_gl_wrapped && out_gl_wrapped) { /* input: GL, output: non-GL */ + GST_INFO ("Output Buffer does not contain correct memory, " + "attempting to wrap for download"); + + if (!filter->download) { + filter->download = gst_gl_display_find_download (filter->display, + GST_VIDEO_FRAME_FORMAT (&out_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + + gst_gl_download_init_format (filter->download, + GST_VIDEO_FRAME_FORMAT (&out_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + } + + in_tex = *(guint *) in_frame.data[0]; + out_tex = filter->out_tex_id; + } else { /* both non-GL */ + if (!filter->upload) { + filter->upload = gst_gl_display_find_upload (filter->display, + GST_VIDEO_FRAME_FORMAT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&in_frame), + GST_VIDEO_FRAME_HEIGHT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + + gst_gl_upload_init_format (filter->upload, + GST_VIDEO_FRAME_FORMAT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&in_frame), + GST_VIDEO_FRAME_HEIGHT (&in_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + } + + if (!filter->download) { + filter->download = gst_gl_display_find_download (filter->display, + GST_VIDEO_FRAME_FORMAT (&out_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + + gst_gl_download_init_format (filter->download, + GST_VIDEO_FRAME_FORMAT (&out_frame), + GST_VIDEO_FRAME_WIDTH (&out_frame), + GST_VIDEO_FRAME_HEIGHT (&out_frame)); + } + gst_gl_upload_perform_with_data (filter->upload, filter->in_tex_id, in_frame.data); + out_tex = filter->out_tex_id; in_tex = filter->in_tex_id; } - if (gst_is_gl_memory (out_frame.map[0].memory)) { - out_tex = *(guint *) out_frame.data[0]; - } else { - GST_INFO ("Output Buffer does not contain correct memory, " - "attempting to wrap for download"); - - out_tex = filter->out_tex_id;; - - out_gl_wrapped = TRUE; + if (in_gl_wrapped) { + gst_gl_upload_perform_with_data (filter->upload, in_tex, in_frame.data); } + g_assert (filter_class->filter_texture); ret = filter_class->filter_texture (filter, in_tex, out_tex); if (out_gl_wrapped) { @@ -650,19 +1025,43 @@ gst_gl_filter_transform (GstBaseTransform * bt, GstBuffer * inbuf, } /* convenience functions to simplify filter development */ +/** + * gst_gl_filter_render_to_target: + * @filter: a #GstGLFilter + * @resize: whether to automatically resize the texture between the input size + * and the output size + * @input: the input texture + * @target: the output texture + * @func: the function to transform @input into @output. called with @data + * @data: the data associated with @func + * + * Transforms @input into @output using @func on through FBO. @resize should + * only ever be %TRUE whenever @input is the input texture of @filter. + */ void -gst_gl_filter_render_to_target (GstGLFilter * filter, +gst_gl_filter_render_to_target (GstGLFilter * filter, gboolean resize, GLuint input, GLuint target, GLCB func, gpointer data) { + guint in_width, in_height, out_width, out_height; + + out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); + out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); + if (resize) { + in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info); + in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info); + } else { + in_width = out_width; + in_height = out_height; + } + + GST_LOG ("rendering to target. in:%ux%u out:%ux%u", in_width, in_height, + out_width, out_height); + gst_gl_display_use_fbo (filter->display, - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), + out_width, out_height, filter->fbo, filter->depthbuffer, target, - func, GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), input, 0, - GST_VIDEO_INFO_WIDTH (&filter->out_info), 0, - GST_VIDEO_INFO_HEIGHT (&filter->out_info), - GST_GL_DISPLAY_PROJECTION_ORTHO2D, data); + func, in_width, in_height, input, 0, + in_width, 0, in_height, GST_GL_DISPLAY_PROJECTION_ORTHO2D, data); } #ifndef OPENGL_ES2 @@ -683,23 +1082,49 @@ _draw_with_shader_cb (gint width, gint height, guint texture, gpointer stuff) gst_gl_shader_set_uniform_1i (filter->default_shader, "tex", 1); - gst_gl_filter_draw_texture (filter, texture); + gst_gl_filter_draw_texture (filter, texture, width, height); } +/** + * gst_gl_filter_render_to_target_with_shader: + * @filter: a #GstGLFilter + * @resize: whether to automatically resize the texture between the input size + * and the output size + * @input: the input texture + * @target: the output texture + * @shader: the shader to use. + * + * Transforms @input into @output using @shader on through FBO. @resize should + * only ever be %TRUE whenever @input is the input texture of @filter. + * + * See also: #gst_gl_filter_render_to_target() + */ /* attach target to a FBO, use shader, pass input as "tex" uniform to * the shader, render input to a quad */ void gst_gl_filter_render_to_target_with_shader (GstGLFilter * filter, - GLuint input, GLuint target, GstGLShader * shader) + gboolean resize, GLuint input, GLuint target, GstGLShader * shader) { filter->default_shader = shader; - gst_gl_filter_render_to_target (filter, input, target, _draw_with_shader_cb, - filter); + gst_gl_filter_render_to_target (filter, resize, input, target, + _draw_with_shader_cb, filter); } +/** + * gst_gl_filter_draw_texture: + * @filter: a #GstGLFilter + * @texture: the texture to draw + * @width: width of @texture + * @height: height of texture + * + * Draws @texture into the OpenGL scene at the specified @width and @height. + */ void -gst_gl_filter_draw_texture (GstGLFilter * filter, GLuint texture) +gst_gl_filter_draw_texture (GstGLFilter * filter, GLuint texture, + guint width, guint height) { + GST_DEBUG ("drawing texture:%u dimensions:%ux%u", texture, width, height); + glActiveTexture (GL_TEXTURE0); glEnable (GL_TEXTURE_RECTANGLE_ARB); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture); @@ -708,12 +1133,11 @@ gst_gl_filter_draw_texture (GstGLFilter * filter, GLuint texture) glTexCoord2f (0.0, 0.0); glVertex2f (-1.0, -1.0); - glTexCoord2f ((gfloat) GST_VIDEO_INFO_WIDTH (&filter->out_info), 0.0); + glTexCoord2f ((gfloat) width, 0.0); glVertex2f (1.0, -1.0); - glTexCoord2f ((gfloat) GST_VIDEO_INFO_WIDTH (&filter->out_info), - (gfloat) GST_VIDEO_INFO_HEIGHT (&filter->out_info)); + glTexCoord2f ((gfloat) width, (gfloat) height); glVertex2f (1.0, 1.0); - glTexCoord2f (0.0, (gfloat) GST_VIDEO_INFO_HEIGHT (&filter->out_info)); + glTexCoord2f (0.0, (gfloat) height); glVertex2f (-1.0, 1.0); glEnd (); diff --git a/gst-libs/gst/gl/gstglfilter.h b/gst-libs/gst/gl/gstglfilter.h index c3c22e0a3b..3201b5ac3c 100644 --- a/gst-libs/gst/gl/gstglfilter.h +++ b/gst-libs/gst/gl/gstglfilter.h @@ -101,15 +101,15 @@ gboolean gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, GstBuffer * outbuf); void -gst_gl_filter_render_to_target (GstGLFilter *filter, - GLuint input, GLuint target, - GLCB func, gpointer data); +gst_gl_filter_render_to_target (GstGLFilter *filter, gboolean resize, GLuint input, + GLuint target, GLCB func, gpointer data); + #ifndef OPENGL_ES2 void -gst_gl_filter_render_to_target_with_shader (GstGLFilter * filter, +gst_gl_filter_render_to_target_with_shader (GstGLFilter * filter, gboolean resize, GLuint input, GLuint target, GstGLShader *shader); -void gst_gl_filter_draw_texture (GstGLFilter *filter, GLuint texture); +void gst_gl_filter_draw_texture (GstGLFilter *filter, GLuint texture, guint width, guint height); #endif G_END_DECLS