diff --git a/subprojects/gst-docs/symbols/symbol_index.json b/subprojects/gst-docs/symbols/symbol_index.json index e53c438b9d5266a2faa1daebe3621405ade8e3ea..dec5e1a34155c993dd0fc96c679ae38415a2e539 100644 --- a/subprojects/gst-docs/symbols/symbol_index.json +++ b/subprojects/gst-docs/symbols/symbol_index.json @@ -17217,7 +17217,6 @@ "GstVideoOrientationInterface::set_hflip", "GstVideoOrientationInterface::set_vcenter", "GstVideoOrientationInterface::set_vflip", - "GstVideoOrientationMethod", "GstVideoOverlay", "GstVideoOverlayComposition", "GstVideoOverlayCompositionMeta", diff --git a/subprojects/gst-plugins-base/ext/gl/gstglimagesink.c b/subprojects/gst-plugins-base/ext/gl/gstglimagesink.c index aca393252e8d5e646bf4b7bf4f5c81941446fc29..26b729e67f363afeef95b8223e50a6cc1d1f36bf 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglimagesink.c +++ b/subprojects/gst-plugins-base/ext/gl/gstglimagesink.c @@ -180,23 +180,23 @@ _on_client_draw (GstGLImageSink * sink, GstGLContext * context, return ret; } -#define DEFAULT_ROTATE_METHOD GST_GL_ROTATE_METHOD_IDENTITY +#define DEFAULT_ROTATE_METHOD GST_VIDEO_ORIENTATION_IDENTITY #define GST_TYPE_GL_ROTATE_METHOD (gst_gl_rotate_method_get_type()) static const GEnumValue rotate_methods[] = { - {GST_GL_ROTATE_METHOD_IDENTITY, "Identity (no rotation)", "none"}, - {GST_GL_ROTATE_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"}, - {GST_GL_ROTATE_METHOD_180, "Rotate 180 degrees", "rotate-180"}, - {GST_GL_ROTATE_METHOD_90L, "Rotate counter-clockwise 90 degrees", + {GST_VIDEO_ORIENTATION_IDENTITY, "Identity (no rotation)", "none"}, + {GST_VIDEO_ORIENTATION_90R, "Rotate clockwise 90 degrees", "clockwise"}, + {GST_VIDEO_ORIENTATION_180, "Rotate 180 degrees", "rotate-180"}, + {GST_VIDEO_ORIENTATION_90L, "Rotate counter-clockwise 90 degrees", "counterclockwise"}, - {GST_GL_ROTATE_METHOD_FLIP_HORIZ, "Flip horizontally", "horizontal-flip"}, - {GST_GL_ROTATE_METHOD_FLIP_VERT, "Flip vertically", "vertical-flip"}, - {GST_GL_ROTATE_METHOD_FLIP_UL_LR, + {GST_VIDEO_ORIENTATION_HORIZ, "Flip horizontally", "horizontal-flip"}, + {GST_VIDEO_ORIENTATION_VERT, "Flip vertically", "vertical-flip"}, + {GST_VIDEO_ORIENTATION_UL_LR, "Flip across upper left/lower right diagonal", "upper-left-diagonal"}, - {GST_GL_ROTATE_METHOD_FLIP_UR_LL, + {GST_VIDEO_ORIENTATION_UR_LL, "Flip across upper right/lower left diagonal", "upper-right-diagonal"}, - {GST_GL_ROTATE_METHOD_AUTO, + {GST_VIDEO_ORIENTATION_AUTO, "Select rotate method based on image-orientation tag", "automatic"}, {0, NULL, NULL}, }; @@ -532,16 +532,16 @@ static const gfloat upper_right_matrix[] = { static void gst_glimage_sink_set_rotate_method (GstGLImageSink * gl_sink, - GstGLRotateMethod method, gboolean from_tag) + GstVideoOrientationMethod method, gboolean from_tag) { - GstGLRotateMethod tag_method = DEFAULT_ROTATE_METHOD; + GstVideoOrientationMethod tag_method = DEFAULT_ROTATE_METHOD; GST_GLIMAGE_SINK_LOCK (gl_sink); if (from_tag) tag_method = method; else gl_sink->rotate_method = method; - if (gl_sink->rotate_method == GST_GL_ROTATE_METHOD_AUTO) + if (gl_sink->rotate_method == GST_VIDEO_ORIENTATION_AUTO) method = tag_method; else method = gl_sink->rotate_method; @@ -552,35 +552,35 @@ gst_glimage_sink_set_rotate_method (GstGLImageSink * gl_sink, rotate_methods[method].value_nick); switch (method) { - case GST_GL_ROTATE_METHOD_IDENTITY: + case GST_VIDEO_ORIENTATION_IDENTITY: gl_sink->transform_matrix = NULL; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_90R: + case GST_VIDEO_ORIENTATION_90R: gl_sink->transform_matrix = clockwise_matrix; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_180: + case GST_VIDEO_ORIENTATION_180: gl_sink->transform_matrix = clockwise_180_matrix; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_90L: + case GST_VIDEO_ORIENTATION_90L: gl_sink->transform_matrix = counterclockwise_matrix; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_FLIP_HORIZ: + case GST_VIDEO_ORIENTATION_HORIZ: gl_sink->transform_matrix = horizontal_flip_matrix; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_FLIP_VERT: + case GST_VIDEO_ORIENTATION_VERT: gl_sink->transform_matrix = vertical_flip_matrix; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_FLIP_UL_LR: + case GST_VIDEO_ORIENTATION_UL_LR: gl_sink->transform_matrix = upper_left_matrix; gl_sink->output_mode_changed = TRUE; break; - case GST_GL_ROTATE_METHOD_FLIP_UR_LL: + case GST_VIDEO_ORIENTATION_UR_LL: gl_sink->transform_matrix = upper_right_matrix; gl_sink->output_mode_changed = TRUE; break; @@ -1114,7 +1114,7 @@ gst_glimage_sink_event (GstBaseSink * sink, GstEvent * event) { GstGLImageSink *gl_sink = GST_GLIMAGE_SINK (sink); GstTagList *taglist; - gchar *orientation; + GstVideoOrientationMethod method; gboolean ret; GST_DEBUG_OBJECT (gl_sink, "handling %s event", GST_EVENT_TYPE_NAME (event)); @@ -1123,34 +1123,9 @@ gst_glimage_sink_event (GstBaseSink * sink, GstEvent * event) case GST_EVENT_TAG: gst_event_parse_tag (event, &taglist); - if (gst_tag_list_get_string (taglist, "image-orientation", &orientation)) { - if (!g_strcmp0 ("rotate-0", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, - GST_GL_ROTATE_METHOD_IDENTITY, TRUE); - else if (!g_strcmp0 ("rotate-90", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, GST_GL_ROTATE_METHOD_90R, - TRUE); - else if (!g_strcmp0 ("rotate-180", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, GST_GL_ROTATE_METHOD_180, - TRUE); - else if (!g_strcmp0 ("rotate-270", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, GST_GL_ROTATE_METHOD_90L, - TRUE); - else if (!g_strcmp0 ("flip-rotate-0", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, - GST_GL_ROTATE_METHOD_FLIP_HORIZ, TRUE); - else if (!g_strcmp0 ("flip-rotate-90", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, - GST_GL_ROTATE_METHOD_FLIP_UR_LL, TRUE); - else if (!g_strcmp0 ("flip-rotate-180", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, - GST_GL_ROTATE_METHOD_FLIP_VERT, TRUE); - else if (!g_strcmp0 ("flip-rotate-270", orientation)) - gst_glimage_sink_set_rotate_method (gl_sink, - GST_GL_ROTATE_METHOD_FLIP_UL_LR, TRUE); - - g_free (orientation); - } + if (gst_video_orientation_from_tag (taglist, &method)) + gst_glimage_sink_set_rotate_method (gl_sink, method, TRUE); + break; default: break; @@ -2280,11 +2255,10 @@ gst_glimage_sink_on_resize (GstGLImageSink * gl_sink, gint width, gint height) src.x = 0; src.y = 0; - if (gl_sink->current_rotate_method == GST_GL_ROTATE_METHOD_90R - || gl_sink->current_rotate_method == GST_GL_ROTATE_METHOD_90L - || gl_sink->current_rotate_method == GST_GL_ROTATE_METHOD_FLIP_UL_LR - || gl_sink->current_rotate_method == - GST_GL_ROTATE_METHOD_FLIP_UR_LL) { + if (gl_sink->current_rotate_method == GST_VIDEO_ORIENTATION_90R + || gl_sink->current_rotate_method == GST_VIDEO_ORIENTATION_90L + || gl_sink->current_rotate_method == GST_VIDEO_ORIENTATION_UL_LR + || gl_sink->current_rotate_method == GST_VIDEO_ORIENTATION_UR_LL) { src.h = GST_VIDEO_SINK_WIDTH (gl_sink); src.w = GST_VIDEO_SINK_HEIGHT (gl_sink); } else { @@ -2435,10 +2409,10 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink) if (gl_sink->transform_matrix) { gfloat tmp[16]; - gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, tmp); + gst_gl_get_affine_transformation_meta_as_ndc (af_meta, tmp); gst_gl_multiply_matrix4 (tmp, gl_sink->transform_matrix, matrix); } else { - gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, matrix); + gst_gl_get_affine_transformation_meta_as_ndc (af_meta, matrix); } gst_gl_shader_set_uniform_matrix_4fv (gl_sink->redisplay_shader, diff --git a/subprojects/gst-plugins-base/ext/gl/gstglimagesink.h b/subprojects/gst-plugins-base/ext/gl/gstglimagesink.h index 78fed89dc407ab153e188f7c77c7bd6a92fa9f28..93014d2ad2c8680bf22b48207ef4d711af031d3a 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglimagesink.h +++ b/subprojects/gst-plugins-base/ext/gl/gstglimagesink.h @@ -45,19 +45,6 @@ GST_DEBUG_CATEGORY_EXTERN (gst_debug_glimage_sink); #define GST_IS_GLIMAGE_SINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GLIMAGE_SINK)) -typedef enum -{ - GST_GL_ROTATE_METHOD_IDENTITY, - GST_GL_ROTATE_METHOD_90R, - GST_GL_ROTATE_METHOD_180, - GST_GL_ROTATE_METHOD_90L, - GST_GL_ROTATE_METHOD_FLIP_HORIZ, - GST_GL_ROTATE_METHOD_FLIP_VERT, - GST_GL_ROTATE_METHOD_FLIP_UL_LR, - GST_GL_ROTATE_METHOD_FLIP_UR_LL, - GST_GL_ROTATE_METHOD_AUTO, -}GstGLRotateMethod; - typedef struct _GstGLImageSink GstGLImageSink; typedef struct _GstGLImageSinkClass GstGLImageSinkClass; @@ -139,8 +126,8 @@ struct _GstGLImageSink GstGLOverlayCompositor *overlay_compositor; /* current video flip method */ - GstGLRotateMethod current_rotate_method; - GstGLRotateMethod rotate_method; + GstVideoOrientationMethod current_rotate_method; + GstVideoOrientationMethod rotate_method; const gfloat *transform_matrix; }; diff --git a/subprojects/gst-plugins-base/ext/gl/gstgltransformation.c b/subprojects/gst-plugins-base/ext/gl/gstgltransformation.c index a5ca2005b7f7cad17a14c5a86e50a8d067e028b0..3a03b992b033817ef678da83bd3292437ef912fd 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstgltransformation.c +++ b/subprojects/gst-plugins-base/ext/gl/gstgltransformation.c @@ -807,7 +807,7 @@ gst_gl_transformation_prepare_output_buffer (GstBaseTransform * trans, GST_LOG_OBJECT (trans, "applying transformation to existing affine " "transformation meta"); - gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, upstream); + gst_gl_get_affine_transformation_meta_as_ndc (af_meta, upstream); /* apply the transformation to the existing affine meta */ graphene_matrix_init_from_float (&upstream_matrix, upstream); @@ -822,7 +822,7 @@ gst_gl_transformation_prepare_output_buffer (GstBaseTransform * trans, graphene_matrix_multiply (&tmp, &yflip, &tmp2); graphene_matrix_to_float (&tmp2, downstream); - gst_gl_set_affine_transformation_meta_from_ndc_ext (af_meta, downstream); + gst_gl_set_affine_transformation_meta_from_ndc (af_meta, downstream); return GST_FLOW_OK; } diff --git a/subprojects/gst-plugins-base/ext/gl/gstglutils.c b/subprojects/gst-plugins-base/ext/gl/gstglutils.c index 12209a6998914ed721998ab011ab4d1948b03f4a..bbbcb0fbfa41a6127b230d11abc99df4dd2d40bd 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglutils.c +++ b/subprojects/gst-plugins-base/ext/gl/gstglutils.c @@ -106,73 +106,3 @@ gst_gl_context_gen_shader (GstGLContext * context, const gchar * vert_src, return *shader != NULL; } - -static const gfloat identity_matrix[] = { - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}; - -static const gfloat from_ndc_matrix[] = { - 0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0, -}; - -static const gfloat to_ndc_matrix[] = { - 2.0, 0.0, 0.0, 0.0, - 0.0, 2.0, 0.0, 0.0, - 0.0, 0.0, 2.0, 0.0, - -1.0, -1.0, -1.0, 1.0, -}; - -void -gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result) -{ - int i, j, k; - gfloat tmp[16] = { 0.0f }; - - if (!a || !b || !result) - return; - - for (i = 0; i < 4; i++) { /* column */ - for (j = 0; j < 4; j++) { /* row */ - for (k = 0; k < 4; k++) { - tmp[j + (i * 4)] += a[k + (i * 4)] * b[j + (k * 4)]; - } - } - } - - for (i = 0; i < 16; i++) - result[i] = tmp[i]; -} - -void gst_gl_get_affine_transformation_meta_as_ndc_ext - (GstVideoAffineTransformationMeta * meta, gfloat * matrix) -{ - if (!meta) { - int i; - - for (i = 0; i < 16; i++) { - matrix[i] = identity_matrix[i]; - } - } else { - float tmp[16]; - - gst_gl_multiply_matrix4 (from_ndc_matrix, meta->matrix, tmp); - gst_gl_multiply_matrix4 (tmp, to_ndc_matrix, matrix); - } -} - -void gst_gl_set_affine_transformation_meta_from_ndc_ext - (GstVideoAffineTransformationMeta * meta, const gfloat * matrix) -{ - float tmp[16]; - - g_return_if_fail (meta != NULL); - - gst_gl_multiply_matrix4 (to_ndc_matrix, matrix, tmp); - gst_gl_multiply_matrix4 (tmp, from_ndc_matrix, meta->matrix); -} diff --git a/subprojects/gst-plugins-base/ext/gl/gstglutils.h b/subprojects/gst-plugins-base/ext/gl/gstglutils.h index bf567f603a6261f34a2b8cf069789e7b2e482792..ee7d4c6982b4e66bc3adcc4114f797887af5d513 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglutils.h +++ b/subprojects/gst-plugins-base/ext/gl/gstglutils.h @@ -28,10 +28,6 @@ G_BEGIN_DECLS gboolean gst_gl_context_gen_shader (GstGLContext * context, const gchar * shader_vertex_source, const gchar * shader_fragment_source, GstGLShader ** shader); -void gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result); -void gst_gl_get_affine_transformation_meta_as_ndc_ext (GstVideoAffineTransformationMeta * - meta, gfloat * matrix); -void gst_gl_set_affine_transformation_meta_from_ndc_ext (GstVideoAffineTransformationMeta * meta, const gfloat * matrix); G_END_DECLS diff --git a/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.c b/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.c index 5ace518d550dca07641de8139caf45e7c5188714..814f4c3f55d86b2c2c2cdd5a42508b47a33bbaf0 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.c +++ b/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.c @@ -41,7 +41,7 @@ #define GST_CAT_DEFAULT gst_gl_video_flip_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); -#define DEFAULT_METHOD GST_GL_VIDEO_FLIP_METHOD_IDENTITY +#define DEFAULT_METHOD GST_VIDEO_ORIENTATION_IDENTITY enum { @@ -72,18 +72,18 @@ static GstStaticPadTemplate _src_template = GST_STATIC_PAD_TEMPLATE ("src", #define GST_TYPE_GL_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type()) static const GEnumValue video_flip_methods[] = { - {GST_GL_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"}, - {GST_GL_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"}, - {GST_GL_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"}, - {GST_GL_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees", + {GST_VIDEO_ORIENTATION_IDENTITY, "Identity (no rotation)", "none"}, + {GST_VIDEO_ORIENTATION_90R, "Rotate clockwise 90 degrees", "clockwise"}, + {GST_VIDEO_ORIENTATION_180, "Rotate 180 degrees", "rotate-180"}, + {GST_VIDEO_ORIENTATION_90L, "Rotate counter-clockwise 90 degrees", "counterclockwise"}, - {GST_GL_VIDEO_FLIP_METHOD_FLIP_HORIZ, "Flip horizontally", "horizontal-flip"}, - {GST_GL_VIDEO_FLIP_METHOD_FLIP_VERT, "Flip vertically", "vertical-flip"}, - {GST_GL_VIDEO_FLIP_METHOD_FLIP_UL_LR, + {GST_VIDEO_ORIENTATION_HORIZ, "Flip horizontally", "horizontal-flip"}, + {GST_VIDEO_ORIENTATION_VERT, "Flip vertically", "vertical-flip"}, + {GST_VIDEO_ORIENTATION_UL_LR, "Flip across upper left/lower right diagonal", "upper-left-diagonal"}, - {GST_GL_VIDEO_FLIP_METHOD_FLIP_UR_LL, + {GST_VIDEO_ORIENTATION_UR_LL, "Flip across upper right/lower left diagonal", "upper-right-diagonal"}, - {GST_GL_VIDEO_FLIP_METHOD_AUTO, + {GST_VIDEO_ORIENTATION_AUTO, "Select flip method based on image-orientation tag", "automatic"}, {0, NULL, NULL}, }; @@ -433,35 +433,12 @@ _input_sink_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG:{ GstTagList *taglist; - gchar *orientation; + GstVideoOrientationMethod method; gst_event_parse_tag (event, &taglist); - if (gst_tag_list_get_string (taglist, "image-orientation", - &orientation)) { - if (!g_strcmp0 ("rotate-0", orientation)) - gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_IDENTITY, - TRUE); - else if (!g_strcmp0 ("rotate-90", orientation)) - gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90R, TRUE); - else if (!g_strcmp0 ("rotate-180", orientation)) - gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_180, TRUE); - else if (!g_strcmp0 ("rotate-270", orientation)) - gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90L, TRUE); - else if (!g_strcmp0 ("flip-rotate-0", orientation)) - gst_gl_video_flip_set_method (vf, - GST_VIDEO_ORIENTATION_HORIZ, TRUE); - else if (!g_strcmp0 ("flip-rotate-90", orientation)) - gst_gl_video_flip_set_method (vf, - GST_VIDEO_ORIENTATION_UR_LL, TRUE); - else if (!g_strcmp0 ("flip-rotate-180", orientation)) - gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_VERT, TRUE); - else if (!g_strcmp0 ("flip-rotate-270", orientation)) - gst_gl_video_flip_set_method (vf, - GST_VIDEO_ORIENTATION_UL_LR, TRUE); - - g_free (orientation); - } + if (gst_video_orientation_from_tag (taglist, &method)) + gst_gl_video_flip_set_method (vf, method, TRUE); break; } case GST_EVENT_CAPS:{ diff --git a/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.h b/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.h index 36f8da07da4c8253dea928ebed16869c3ccad15d..5976f8f0e7e26b98e7219319143048c2f8463d4c 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.h +++ b/subprojects/gst-plugins-base/ext/gl/gstglvideoflip.h @@ -22,6 +22,7 @@ #define _GST_GL_VIDEO_FLIP_H_ #include +#include G_BEGIN_DECLS @@ -32,31 +33,6 @@ G_BEGIN_DECLS #define GST_IS_GL_VIDEO_FLIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEO_FLIP)) #define GST_GL_VIDEO_FLIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEO_FLIP,GstGLVideoFlipClass)) -/** - * GstVideoFlipMethod: - * @GST_GL_VIDEO_FLIP_METHOD_IDENTITY: Identity (no rotation) - * @GST_GL_VIDEO_FLIP_METHOD_90R: Rotate clockwise 90 degrees - * @GST_GL_VIDEO_FLIP_METHOD_180: Rotate 180 degrees - * @GST_GL_VIDEO_FLIP_METHOD_90L: Rotate counter-clockwise 90 degrees - * @GST_GL_VIDEO_FLIP_METHOD_FLIP_HORIZ: Flip horizontally - * @GST_GL_VIDEO_FLIP_METHOD_FLIP_VERT: Flip vertically - * @GST_GL_VIDEO_FLIP_METHOD_FLIP_UL_LR: Flip across upper left/lower right diagonal - * @GST_GL_VIDEO_FLIP_METHOD_FLIP_UR_LL: Flip across upper right/lower left diagonal - * @GST_GL_VIDEO_FLIP_METHOD_AUTO: Select flip method based on image-orientation tag - * - * The different flip methods. - */ -typedef enum { - GST_GL_VIDEO_FLIP_METHOD_IDENTITY, - GST_GL_VIDEO_FLIP_METHOD_90R, - GST_GL_VIDEO_FLIP_METHOD_180, - GST_GL_VIDEO_FLIP_METHOD_90L, - GST_GL_VIDEO_FLIP_METHOD_FLIP_HORIZ, - GST_GL_VIDEO_FLIP_METHOD_FLIP_VERT, - GST_GL_VIDEO_FLIP_METHOD_FLIP_UL_LR, - GST_GL_VIDEO_FLIP_METHOD_FLIP_UR_LL, - GST_GL_VIDEO_FLIP_METHOD_AUTO, -} GstGLVideoFlipMethod; typedef struct _GstGLVideoFlip GstGLVideoFlip; typedef struct _GstGLVideoFlipClass GstGLVideoFlipClass; diff --git a/subprojects/gst-plugins-base/ext/gl/gstglvideomixer.c b/subprojects/gst-plugins-base/ext/gl/gstglvideomixer.c index a08016b54a830869a367d0ff96fc5907db0376ff..14dabcbb2b030ffd8eac36eb9053e9508d9115d7 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstglvideomixer.c +++ b/subprojects/gst-plugins-base/ext/gl/gstglvideomixer.c @@ -1616,7 +1616,7 @@ gst_gl_video_mixer_callback (gpointer stuff) gst_video_aggregator_pad_get_current_buffer (vagg_pad); af_meta = gst_buffer_get_video_affine_transformation_meta (buffer); - gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, af_matrix); + gst_gl_get_affine_transformation_meta_as_ndc (af_meta, af_matrix); gst_gl_multiply_matrix4 (af_matrix, pad->m_matrix, matrix); gst_gl_shader_set_uniform_matrix_4fv (video_mixer->shader, "u_transformation", 1, FALSE, matrix); diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.c b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.c index 52fa7d8360eeca346a39f1aa64b5292b1f4ce228..5e4f92e7dab108fed85c32423edd1fdfdbeec6fc 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.c @@ -810,17 +810,28 @@ static const gfloat to_ndc_matrix[] = { -1.0, -1.0, -1.0, 1.0, }; -/* multiplies two 4x4 matrices, @a X @b, and stores the result in @result - * https://en.wikipedia.org/wiki/Matrix_multiplication +/** + * gst_gl_multiply_matrix4: + * @a: (array fixed-size=16): a 2-dimensional 4x4 array of #gfloat + * @b: (array fixed-size=16): another 2-dimensional 4x4 array of #gfloat + * @result: (out) (array fixed-size=16): the result of the multiplication + * + * Multiplies two 4x4 matrices, @a and @b, and stores the result, a + * 2-dimensional array of #gfloat, in @result. + * + * Since: 1.20 */ -static void +/* https://en.wikipedia.org/wiki/Matrix_multiplication */ +void gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result) { int i, j, k; gfloat tmp[16] = { 0.0f }; - if (!a || !b || !result) - return; + g_return_if_fail (a != NULL); + g_return_if_fail (b != NULL); + g_return_if_fail (result != NULL); + for (i = 0; i < 4; i++) { /* column */ for (j = 0; j < 4; j++) { /* row */ for (k = 0; k < 4; k++) { @@ -833,7 +844,7 @@ gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result) result[i] = tmp[i]; } -/* +/** * gst_gl_get_affine_transformation_meta_as_ndc: * @meta: (nullable): a #GstVideoAffineTransformationMeta * @matrix: (out): result of the 4x4 matrix @@ -845,11 +856,15 @@ gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result) * - x - [-1, 1] - +ve X moves right * - y - [-1, 1] - +ve Y moves up * - z - [-1, 1] - +ve Z moves into + * + * Since: 1.20 */ void gst_gl_get_affine_transformation_meta_as_ndc (GstVideoAffineTransformationMeta * meta, gfloat * matrix) { + g_return_if_fail (matrix != NULL); + if (!meta) { int i; @@ -865,12 +880,23 @@ gst_gl_get_affine_transformation_meta_as_ndc (GstVideoAffineTransformationMeta * } } +/** + * gst_gl_set_affine_transformation_meta_from_ndc: + * @meta: a #GstVideoAffineTransformationMeta + * @matrix: a 4x4 matrix + * + * Set the 4x4 affine transformation matrix stored in @meta from the + * NDC coordinates in @matrix. + * + * Since: 1.20 + */ void gst_gl_set_affine_transformation_meta_from_ndc (GstVideoAffineTransformationMeta * meta, const gfloat * matrix) { float tmp[16]; g_return_if_fail (meta != NULL); + g_return_if_fail (matrix != NULL); /* change of basis multiplications */ gst_gl_multiply_matrix4 (to_ndc_matrix, matrix, tmp); diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.h b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.h index bbae73e6dbdd63e0a1365e32cf44f9c3a572f68c..b27145489fc511b8c1534fccf25d8576067e1dc5 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils.h @@ -59,6 +59,15 @@ gboolean gst_gl_value_set_texture_target (GValue * value, GstGLTextureTarget tar GST_GL_API GstGLTextureTarget gst_gl_value_get_texture_target_mask (const GValue * value); +GST_GL_API +void gst_gl_get_affine_transformation_meta_as_ndc (GstVideoAffineTransformationMeta * meta, gfloat * matrix); +GST_GL_API +void gst_gl_set_affine_transformation_meta_from_ndc (GstVideoAffineTransformationMeta * meta, const gfloat * matrix); + +GST_GL_API +void gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result); + + G_END_DECLS #endif /* __GST_GL_UTILS_H__ */ diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils_private.h b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils_private.h index 5a314e37b87f65c8c5a026bb443ba03beba0e441..9bc652dcb98819ee0b77861bc4ce150dc551fa38 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils_private.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglutils_private.h @@ -26,8 +26,6 @@ G_BEGIN_DECLS G_GNUC_INTERNAL gboolean gst_gl_run_query (GstElement * element, GstQuery * query, GstPadDirection direction); -G_GNUC_INTERNAL void gst_gl_get_affine_transformation_meta_as_ndc (GstVideoAffineTransformationMeta * meta, gfloat * matrix); -G_GNUC_INTERNAL void gst_gl_set_affine_transformation_meta_from_ndc (GstVideoAffineTransformationMeta * meta, const gfloat * matrix); G_END_DECLS diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/meson.build b/subprojects/gst-plugins-base/gst-libs/gst/video/meson.build index 4528b10af7deaa9e1f60cb9a93e48483e74afeb0..9c0cb6a2cce7458ffd52106889d59deba406ac88 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/meson.build +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/meson.build @@ -77,7 +77,6 @@ video_headers = [ install_headers(video_headers, subdir : 'gstreamer-1.0/gst/video/') video_mkenum_headers = [ - 'video.h', 'video-anc.h', 'video-format.h', 'video-frame.h', diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/video.c b/subprojects/gst-plugins-base/gst-libs/gst/video/video.c index 0743044576b20e7f31a5f89b0783afeca92b05fa..4e20baa6c817cfda732fec0df4d075b187316b7f 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/video.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/video.c @@ -204,3 +204,85 @@ gst_video_alignment_reset (GstVideoAlignment * align) for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) align->stride_align[i] = 0; } + +static const GEnumValue video_orientation_methods[] = { + {GST_VIDEO_ORIENTATION_IDENTITY, "Identity (no rotation)", "identity"}, + {GST_VIDEO_ORIENTATION_90R, "Rotate clockwise 90 degrees", "90r"}, + {GST_VIDEO_ORIENTATION_180, "Rotate 180 degrees", "180"}, + {GST_VIDEO_ORIENTATION_90L, "Rotate counter-clockwise 90 degrees", + "90l"}, + {GST_VIDEO_ORIENTATION_HORIZ, "Flip horizontally", "horiz"}, + {GST_VIDEO_ORIENTATION_VERT, "Flip vertically", "vert"}, + {GST_VIDEO_ORIENTATION_UL_LR, + "Flip across upper left/lower right diagonal", "ul-lr"}, + {GST_VIDEO_ORIENTATION_UR_LL, + "Flip across upper right/lower left diagonal", "ur-ll"}, + {GST_VIDEO_ORIENTATION_AUTO, + "Select rotate method based on image-orientation tag", "auto"}, + {GST_VIDEO_ORIENTATION_CUSTOM, + "Current status depends on plugin internal setup", "custom"}, + {0, NULL, NULL}, +}; + +GType +gst_video_orientation_method_get_type (void) +{ + static gsize video_orientation_method_type = 0; + + if (g_once_init_enter (&video_orientation_method_type)) { + gsize res = g_enum_register_static ("GstVideoOrientationMethod", + video_orientation_methods); + g_once_init_leave (&video_orientation_method_type, res); + } + + return (GType) video_orientation_method_type; +} + +/** + * gst_video_orientation_from_tag: + * @taglist: A #GstTagList + * @method: The location where to return the orientation. + * + * Parses the "image-orientation" tag and transforms it into the + * #GstVideoOrientationMethod enum. + * + * Returns: TRUE if there was a valid "image-orientation" tag in the taglist. + * + * Since: 1.20 + */ +gboolean +gst_video_orientation_from_tag (GstTagList * taglist, + GstVideoOrientationMethod * method) +{ + gchar *orientation; + gboolean ret = TRUE; + + g_return_val_if_fail (GST_IS_TAG_LIST (taglist), FALSE); + g_return_val_if_fail (method != NULL, FALSE); + + if (!gst_tag_list_get_string (taglist, "image-orientation", &orientation)) + return FALSE; + + if (!g_strcmp0 ("rotate-0", orientation)) + *method = GST_VIDEO_ORIENTATION_IDENTITY; + else if (!g_strcmp0 ("rotate-90", orientation)) + *method = GST_VIDEO_ORIENTATION_90R; + else if (!g_strcmp0 ("rotate-180", orientation)) + *method = GST_VIDEO_ORIENTATION_180; + else if (!g_strcmp0 ("rotate-270", orientation)) + *method = GST_VIDEO_ORIENTATION_90L; + else if (!g_strcmp0 ("flip-rotate-0", orientation)) + *method = GST_VIDEO_ORIENTATION_HORIZ; + else if (!g_strcmp0 ("flip-rotate-90", orientation)) + *method = GST_VIDEO_ORIENTATION_UR_LL; + else if (!g_strcmp0 ("flip-rotate-180", orientation)) + *method = GST_VIDEO_ORIENTATION_VERT; + else if (!g_strcmp0 ("flip-rotate-270", orientation)) + *method = GST_VIDEO_ORIENTATION_UL_LR; + else + ret = FALSE; + + g_free (orientation); + + return ret; +} diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/video.h b/subprojects/gst-plugins-base/gst-libs/gst/video/video.h index 8c1a07a4dd6b643158e2cd405b094ca1e324486b..a1a6d1a422685f65691b4b5b5dc187a7e88faf60 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/video.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/video.h @@ -89,6 +89,17 @@ typedef enum { GST_VIDEO_ORIENTATION_CUSTOM, } GstVideoOrientationMethod; +/** + * GST_TYPE_VIDEO_ORIENTATION_METHOD: + * + * Since: 1.20 + */ + +GST_VIDEO_API +GType gst_video_orientation_method_get_type (void); +#define GST_TYPE_VIDEO_ORIENTATION_METHOD \ + gst_video_orientation_method_get_type () + /* metadata macros */ /** * GST_META_TAG_VIDEO_STR: @@ -161,6 +172,11 @@ GstSample * gst_video_convert_sample (GstSample * sample, GstClockTime timeout, GError ** error); + +GST_VIDEO_API +gboolean gst_video_orientation_from_tag (GstTagList * taglist, + GstVideoOrientationMethod * method); + G_END_DECLS #include diff --git a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json index 2ac563d993320ce6ad43289230a2bd95ab6d7d6d..2e404619ba2186139f058bba54568db7fed07519 100644 --- a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json +++ b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json @@ -7114,7 +7114,20 @@ "presence": "always" } }, - "properties": {}, + "properties": { + "rotate-method": { + "blurb": "rotate method", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "identity (0)", + "mutable": "null", + "readable": true, + "type": "GstVideoOrientationMethod", + "writable": true + } + }, "rank": "none" }, "gtksink": { diff --git a/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.c b/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.c index b690c44b35b1f23d2111cc8f63abe5b2f9be8597..300502427ee068daa206ee9c5b7b6fbc418cd9e6 100644 --- a/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.c +++ b/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.c @@ -100,7 +100,9 @@ gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) g_param_spec_object ("widget", "Gtk Widget", "The GtkWidget to place in the widget hierarchy " "(must only be get from the GTK main thread)", - GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + GTK_TYPE_WIDGET, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, g_param_spec_boolean ("force-aspect-ratio", @@ -178,12 +180,12 @@ static GtkGstBaseWidget * gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink) { if (gtk_sink->widget != NULL) - return gtk_sink->widget; + return g_object_ref (gtk_sink->widget); /* Ensure GTK is initialized, this has no side effect if it was already * initialized. Also, we do that lazily, so the application can be first */ if (!gtk_init_check (NULL, NULL)) { - GST_ERROR_OBJECT (gtk_sink, "Could not ensure GTK initialization."); + GST_INFO_OBJECT (gtk_sink, "Could not ensure GTK initialization."); return NULL; } @@ -211,7 +213,25 @@ gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink) gtk_gst_base_widget_set_element (GTK_GST_BASE_WIDGET (gtk_sink->widget), GST_ELEMENT (gtk_sink)); - return gtk_sink->widget; + return g_object_ref (gtk_sink->widget); +} + +GtkWidget * +gst_gtk_base_sink_acquire_widget (GstGtkBaseSink * gtk_sink) +{ + gpointer widget = NULL; + + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->widget != NULL) + widget = g_object_ref (gtk_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); + + if (!widget) + widget = + gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget, + gtk_sink); + + return widget; } static void @@ -223,19 +243,7 @@ gst_gtk_base_sink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_WIDGET: { - GObject *widget = NULL; - - GST_OBJECT_LOCK (gtk_sink); - if (gtk_sink->widget != NULL) - widget = G_OBJECT (gtk_sink->widget); - GST_OBJECT_UNLOCK (gtk_sink); - - if (!widget) - widget = - gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget, - gtk_sink); - - g_value_set_object (value, widget); + g_value_take_object (value, gst_gtk_base_sink_acquire_widget (gtk_sink)); break; } case PROP_FORCE_ASPECT_RATIO: @@ -290,6 +298,11 @@ gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation, GtkGstBaseWidget *widget = gst_gtk_base_sink_get_widget (sink); gdouble stream_x, stream_y; + if (widget == NULL) { + GST_ERROR_OBJECT (sink, "Could not ensure GTK initialization."); + return; + } + gtk_gst_base_widget_display_size_to_stream_size (widget, x, y, &stream_x, &stream_y); gst_structure_set (structure, @@ -327,8 +340,10 @@ gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) GstGtkBaseSinkClass *klass = GST_GTK_BASE_SINK_GET_CLASS (bsink); GtkWidget *toplevel; - if (gst_gtk_base_sink_get_widget (gst_sink) == NULL) + if (gst_gtk_base_sink_get_widget (gst_sink) == NULL) { + GST_ERROR_OBJECT (bsink, "Could not ensure GTK initialization."); return FALSE; + } /* After this point, gtk_sink->widget will always be set */ diff --git a/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.h b/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.h index 6501750366a14aaf1b49739d5d8000502c55f2dc..314a0f295d85342801ece4733aada9a272a4f924 100644 --- a/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.h +++ b/subprojects/gst-plugins-good/ext/gtk/gstgtkbasesink.h @@ -91,6 +91,9 @@ struct _GstGtkBaseSinkClass G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstGtkBaseSink, gst_object_unref) +GtkWidget * +gst_gtk_base_sink_acquire_widget (GstGtkBaseSink * gtk_sink); + G_END_DECLS #endif /* __GST_GTK_BASE_SINK_H__ */ diff --git a/subprojects/gst-plugins-good/ext/gtk/gstgtkglsink.c b/subprojects/gst-plugins-good/ext/gtk/gstgtkglsink.c index 18923f54766d155370496db0d3f2ba4964949b2b..8c6605359a623e11c7cc446b057cce7146d7823d 100644 --- a/subprojects/gst-plugins-good/ext/gtk/gstgtkglsink.c +++ b/subprojects/gst-plugins-good/ext/gtk/gstgtkglsink.c @@ -28,6 +28,7 @@ #endif #include +#include #include "gstgtkglsink.h" #include "gtkgstglwidget.h" @@ -35,6 +36,11 @@ GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink); #define GST_CAT_DEFAULT gst_debug_gtk_gl_sink +static void gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + static gboolean gst_gtk_gl_sink_start (GstBaseSink * bsink); static gboolean gst_gtk_gl_sink_stop (GstBaseSink * bsink); static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query); @@ -42,6 +48,7 @@ static gboolean gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query); static GstCaps *gst_gtk_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter); +static gboolean gst_gtk_gl_sink_event (GstBaseSink * sink, GstEvent * event); static void gst_gtk_gl_sink_finalize (GObject * object); @@ -63,6 +70,12 @@ GST_ELEMENT_REGISTER_DEFINE (gtkglsink, "gtkglsink", GST_RANK_NONE, GST_TYPE_GTK_GL_SINK); +enum +{ + PROP_0, + PROP_ROTATE_METHOD, +}; + static void gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) { @@ -76,6 +89,8 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) gstbasesink_class = (GstBaseSinkClass *) klass; gstgtkbasesink_class = (GstGtkBaseSinkClass *) klass; + gobject_class->set_property = gst_gtk_gl_sink_set_property; + gobject_class->get_property = gst_gtk_gl_sink_get_property; gobject_class->finalize = gst_gtk_gl_sink_finalize; gstbasesink_class->query = gst_gtk_gl_sink_query; @@ -83,10 +98,25 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) gstbasesink_class->start = gst_gtk_gl_sink_start; gstbasesink_class->stop = gst_gtk_gl_sink_stop; gstbasesink_class->get_caps = gst_gtk_gl_sink_get_caps; + gstbasesink_class->event = gst_gtk_gl_sink_event; gstgtkbasesink_class->create_widget = gtk_gst_gl_widget_new; gstgtkbasesink_class->window_title = "Gtk+ GL renderer"; + /** + * gtkglsink:rotate-method: + * + * Rotation method #GstVideoOrientationMethod used to render the media + * + * Since: 1.20 + */ + g_object_class_install_property (gobject_class, PROP_ROTATE_METHOD, + g_param_spec_enum ("rotate-method", + "rotate method", + "rotate method", + GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_set_metadata (gstelement_class, "Gtk GL Video Sink", "Sink/Video", "A video sink that renders to a GtkWidget using OpenGL", "Matthew Waters "); @@ -100,6 +130,55 @@ gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink) { } +static void +gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_ROTATE_METHOD: + { + GtkWidget *widget = + gst_gtk_base_sink_acquire_widget (GST_GTK_BASE_SINK (object)); + if (widget != NULL) { + gtk_gst_gl_widget_set_rotate_method (GTK_GST_GL_WIDGET (widget), + g_value_get_enum (value), FALSE); + g_object_unref (widget); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_ROTATE_METHOD: + { + GtkWidget *widget = + gst_gtk_base_sink_acquire_widget (GST_GTK_BASE_SINK (object)); + + if (widget != NULL) { + g_value_set_enum (value, + gtk_gst_gl_widget_get_rotate_method (GTK_GST_GL_WIDGET (widget))); + g_object_unref (widget); + } else { + g_value_set_enum (value, GST_VIDEO_ORIENTATION_IDENTITY); + } + + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) { @@ -296,6 +375,8 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) /* we also support various metadata */ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0); + gst_query_add_allocation_meta (query, + GST_VIDEO_AFFINE_TRANSFORMATION_META_API_TYPE, 0); if (gtk_sink->context->gl_vtable->FenceSync) gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0); @@ -365,3 +446,41 @@ gst_gtk_gl_sink_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } + + +static gboolean +gst_gtk_gl_sink_event (GstBaseSink * sink, GstEvent * event) +{ + GstTagList *taglist; + GstVideoOrientationMethod orientation; + gboolean ret; + GtkGstGLWidget *widget; + + GST_DEBUG_OBJECT (sink, "handling %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + gst_event_parse_tag (event, &taglist); + + if (gst_video_orientation_from_tag (taglist, &orientation)) { + + widget = GTK_GST_GL_WIDGET + (gst_gtk_base_sink_acquire_widget (GST_GTK_BASE_SINK (sink))); + if (widget == NULL) { + GST_ERROR_OBJECT (sink, "Could not ensure GTK initialization."); + break; + } + + gtk_gst_gl_widget_set_rotate_method (widget, orientation, TRUE); + + g_object_unref (widget); + } + break; + default: + break; + } + + ret = GST_BASE_SINK_CLASS (parent_class)->event (sink, event); + + return ret; +} diff --git a/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c b/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c index 6c423ad8957f673989300acd3fa6936fefa9e774..c2d564d42dfb0822d1659c5fea942746f657ee76 100644 --- a/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c +++ b/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c @@ -66,6 +66,9 @@ struct _GtkGstGLWidgetPrivate GLint attr_texture; GLuint current_tex; GstGLOverlayCompositor *overlay_compositor; + GstVideoOrientationMethod rotate_method; + GstVideoOrientationMethod current_rotate_method; + const gfloat *transform_matrix; }; static const GLfloat vertices[] = { @@ -119,9 +122,18 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) GtkGstGLWidgetPrivate *priv = gst_widget->priv; const GstGLFuncs *gl = priv->context->gl_vtable; GError *error = NULL; + GstGLSLStage *frag_stage, *vert_stage; + + vert_stage = gst_glsl_stage_new_with_string (priv->context, + GL_VERTEX_SHADER, GST_GLSL_VERSION_NONE, + GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, + gst_gl_shader_string_vertex_mat4_vertex_transform); + frag_stage = gst_glsl_stage_new_default_fragment (priv->context); gst_gl_insert_debug_marker (priv->other_context, "initializing redisplay"); - if (!(priv->shader = gst_gl_shader_new_default (priv->context, &error))) { + if (!(priv->shader = + gst_gl_shader_new_link_with_stages (priv->context, &error, vert_stage, + frag_stage, NULL))) { GST_ERROR ("Failed to initialize shader: %s", error->message); return; } @@ -154,36 +166,107 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) priv->initted = TRUE; } +/* rotate 90 */ +static const gfloat clockwise_matrix[] = { + 0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +/* rotate 180 */ +static const gfloat clockwise_180_matrix[] = { + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +/* rotate 270 */ +static const gfloat counterclockwise_matrix[] = { + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +/* horizontal-flip */ +static const gfloat horizontal_flip_matrix[] = { + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +/* vertical-flip */ +static const gfloat vertical_flip_matrix[] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +/* upper-left-diagonal */ +static const gfloat upper_left_matrix[] = { + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +/* upper-right-diagonal */ +static const gfloat upper_right_matrix[] = { + 0.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + static void _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) { GtkGstGLWidgetPrivate *priv = gst_widget->priv; const GstGLFuncs *gl = priv->context->gl_vtable; const GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (gst_widget); + GtkWidget *widget = GTK_WIDGET (gst_widget); + if (gst_widget->base.force_aspect_ratio) { GstVideoRectangle src, dst, result; - gint widget_width, widget_height, widget_scale; + gint video_width, video_height, widget_scale; gl->ClearColor (0.0, 0.0, 0.0, 0.0); gl->Clear (GL_COLOR_BUFFER_BIT); - widget_scale = gtk_widget_get_scale_factor ((GtkWidget *) gst_widget); - widget_width = gtk_widget_get_allocated_width ((GtkWidget *) gst_widget); - widget_height = gtk_widget_get_allocated_height ((GtkWidget *) gst_widget); + widget_scale = gtk_widget_get_scale_factor (widget); + + if (priv->current_rotate_method == GST_VIDEO_ORIENTATION_90R + || priv->current_rotate_method == GST_VIDEO_ORIENTATION_90L + || priv->current_rotate_method == GST_VIDEO_ORIENTATION_UL_LR + || priv->current_rotate_method == GST_VIDEO_ORIENTATION_UR_LL) { + video_width = base_widget->display_height; + video_height = base_widget->display_width; + } else { + video_width = base_widget->display_width; + video_height = base_widget->display_height; + } src.x = 0; src.y = 0; - src.w = gst_widget->base.display_width; - src.h = gst_widget->base.display_height; + src.w = video_width; + src.h = video_height; dst.x = 0; dst.y = 0; - dst.w = widget_width * widget_scale; - dst.h = widget_height * widget_scale; + dst.w = gtk_widget_get_allocated_width (widget) * widget_scale; + dst.h = gtk_widget_get_allocated_height (widget) * widget_scale; gst_video_sink_center_rect (src, dst, &result, TRUE); + GST_LOG ("Center src %dx%d into dst %dx%d result -> %dx%d", + src.w, src.h, dst.w, dst.h, result.w, result.h); + gl->Viewport (result.x, result.y, result.w, result.h); } @@ -197,6 +280,26 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) gl->BindTexture (GL_TEXTURE_2D, tex); gst_gl_shader_set_uniform_1i (priv->shader, "tex", 0); + { + GstVideoAffineTransformationMeta *af_meta; + gfloat matrix[16]; + + af_meta = + gst_buffer_get_video_affine_transformation_meta (base_widget->buffer); + + if (priv->transform_matrix) { + gfloat tmp[16]; + + gst_gl_get_affine_transformation_meta_as_ndc (af_meta, tmp); + gst_gl_multiply_matrix4 (tmp, priv->transform_matrix, matrix); + } else { + gst_gl_get_affine_transformation_meta_as_ndc (af_meta, matrix); + } + + gst_gl_shader_set_uniform_matrix_4fv (priv->shader, + "u_transformation", 1, FALSE, matrix); + } + gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); if (gl->BindVertexArray) @@ -579,3 +682,78 @@ gtk_gst_gl_widget_get_display (GtkGstGLWidget * gst_widget) return gst_object_ref (gst_widget->priv->display); } + +void +gtk_gst_gl_widget_set_rotate_method (GtkGstGLWidget * gst_widget, + GstVideoOrientationMethod method, gboolean from_tag) +{ + GstVideoOrientationMethod tag_method = GST_VIDEO_ORIENTATION_AUTO; + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + + if (method == GST_VIDEO_ORIENTATION_CUSTOM) { + GST_WARNING_OBJECT (gst_widget, "unsupported custom orientation"); + return; + } + + GTK_GST_BASE_WIDGET_LOCK (gst_widget); + if (from_tag) + tag_method = method; + else + priv->rotate_method = method; + + if (priv->rotate_method == GST_VIDEO_ORIENTATION_AUTO) + method = tag_method; + else + method = priv->rotate_method; + + if (method != priv->current_rotate_method) { + GST_DEBUG ("Changing method from %d to %d", + priv->current_rotate_method, method); + + switch (method) { + case GST_VIDEO_ORIENTATION_IDENTITY: + priv->transform_matrix = NULL; + break; + case GST_VIDEO_ORIENTATION_90R: + priv->transform_matrix = clockwise_matrix; + break; + case GST_VIDEO_ORIENTATION_180: + priv->transform_matrix = clockwise_180_matrix; + break; + case GST_VIDEO_ORIENTATION_90L: + priv->transform_matrix = counterclockwise_matrix; + break; + case GST_VIDEO_ORIENTATION_HORIZ: + priv->transform_matrix = horizontal_flip_matrix; + break; + case GST_VIDEO_ORIENTATION_VERT: + priv->transform_matrix = vertical_flip_matrix; + break; + case GST_VIDEO_ORIENTATION_UL_LR: + priv->transform_matrix = upper_left_matrix; + break; + case GST_VIDEO_ORIENTATION_UR_LL: + priv->transform_matrix = upper_right_matrix; + break; + default: + g_assert_not_reached (); + break; + } + + priv->current_rotate_method = method; + } + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); +} + +GstVideoOrientationMethod +gtk_gst_gl_widget_get_rotate_method (GtkGstGLWidget * gst_widget) +{ + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + GstVideoOrientationMethod method; + + GTK_GST_BASE_WIDGET_LOCK (gst_widget); + method = priv->current_rotate_method; + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); + + return method; +} diff --git a/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.h b/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.h index 7f055c481822d2c713bd922bd2418b86177593de..c5ff0ac53183373833b32bfea7d0a277d1599e1d 100644 --- a/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.h +++ b/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.h @@ -72,6 +72,12 @@ GstGLDisplay * gtk_gst_gl_widget_get_display (GtkGstGLWidget * widget) GstGLContext * gtk_gst_gl_widget_get_context (GtkGstGLWidget * widget); GstGLContext * gtk_gst_gl_widget_get_gtk_context (GtkGstGLWidget * widget); +void gtk_gst_gl_widget_set_rotate_method (GtkGstGLWidget * gst_widget, + GstVideoOrientationMethod method, gboolean from_tag); +GstVideoOrientationMethod gtk_gst_gl_widget_get_rotate_method ( + GtkGstGLWidget * gst_widget); + + G_END_DECLS #endif /* __GTK_GST_GL_WIDGET_H__ */