[Cogl] [PATCH] cogl-gst: expose aspect ratio apis
Robert Bragg
robert at sixbynine.org
Thu Apr 25 17:06:01 PDT 2013
From: Robert Bragg <robert at linux.intel.com>
This adds several utility apis that aim to make it as easy as possible
for an application to determine what size a video should be drawn at.
The important detail here is that these apis take into account the
pixel-aspect-ratio in addition to the video's own aspect ratio.
This patch updates the cogl-basic-video-player example to use the
cogl_gst_video_sink_fit_size() api to perform letterboxing.
---
cogl-gst/cogl-gst-video-sink.c | 51 +++++++++++++
cogl-gst/cogl-gst-video-sink.h | 81 ++++++++++++++++++++
examples/cogl-basic-video-player.c | 149 +++++++++++++++++++++++++++++--------
3 files changed, 251 insertions(+), 30 deletions(-)
diff --git a/cogl-gst/cogl-gst-video-sink.c b/cogl-gst/cogl-gst-video-sink.c
index a121b11..fec7cb1 100644
--- a/cogl-gst/cogl-gst-video-sink.c
+++ b/cogl-gst/cogl-gst-video-sink.c
@@ -1232,3 +1232,54 @@ cogl_gst_video_sink_new (CoglContext *ctx)
return sink;
}
+
+float
+cogl_gst_video_sink_get_aspect (CoglGstVideoSink *vt)
+{
+ GstVideoInfo *info = &vt->priv->info;
+ return (float)info->width * (float)info->par_n /
+ (float)info->height * (float)info->par_d;
+}
+
+float
+cogl_gst_video_sink_get_width_for_height (CoglGstVideoSink *vt,
+ float height)
+{
+ float aspect = cogl_gst_video_sink_get_aspect (vt);
+ return height * aspect;
+}
+
+float
+cogl_gst_video_sink_get_height_for_width (CoglGstVideoSink *vt,
+ float width)
+{
+ float aspect = cogl_gst_video_sink_get_aspect (vt);
+ return width / aspect;
+}
+
+void
+cogl_gst_video_sink_fit_size (CoglGstVideoSink *vt,
+ float available_width,
+ float available_height,
+ float *width,
+ float *height)
+{
+ if (available_height == 0.0f)
+ *width = *height = 0;
+ else
+ {
+ float available_aspect = available_width / available_height;
+ float video_aspect = cogl_gst_video_sink_get_aspect (vt);
+
+ if (video_aspect > available_aspect)
+ {
+ *width = available_width;
+ *height = available_width / video_aspect;
+ }
+ else
+ {
+ *width = available_height * video_aspect;
+ *height = available_height;
+ }
+ }
+}
diff --git a/cogl-gst/cogl-gst-video-sink.h b/cogl-gst/cogl-gst-video-sink.h
index e210475..5b656a6 100644
--- a/cogl-gst/cogl-gst-video-sink.h
+++ b/cogl-gst/cogl-gst-video-sink.h
@@ -150,6 +150,87 @@ cogl_gst_video_sink_attach_custom_conversion (CoglGstVideoSink *sink,
int previous_layer,
CoglBool modulate,
char *convertion_name);
+
+/**
+ * cogl_gst_video_sink_get_aspect:
+ * @sink: A #CoglGstVideoSink
+ *
+ * Returns a width-for-height aspect ratio that lets you calculate a
+ * suitable width for displaying your video based on a given height by
+ * multiplying your chosen height by the returned aspect ratio.
+ *
+ * This aspect ratio is calculated based on the underlying size of the
+ * video buffers and the current pixel-aspect-ratio.
+ *
+ * Return value: a width-for-height aspect ratio
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+float
+cogl_gst_video_sink_get_aspect (CoglGstVideoSink *sink);
+
+/**
+ * cogl_gst_video_sink_get_width_for_height:
+ * @sink: A #CoglGstVideoSink
+ * @height: A specific output @height
+ *
+ * Calculates a suitable output width for a specific output @height
+ * that will maintain the video's aspect ratio.
+ *
+ * Return value: An output width for the given output @height.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+float
+cogl_gst_video_sink_get_width_for_height (CoglGstVideoSink *sink,
+ float height);
+
+/**
+ * cogl_gst_video_sink_get_height_for_width:
+ * @sink: A #CoglGstVideoSink
+ * @width: A specific output @width
+ *
+ * Calculates a suitable output height for a specific output @width
+ * that will maintain the video's aspect ratio.
+ *
+ * Return value: An output height for the given output @width.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+float
+cogl_gst_video_sink_get_height_for_width (CoglGstVideoSink *sink,
+ float width);
+
+/**
+ * cogl_gst_video_sink_fit_size:
+ * @sink: A #CoglGstVideoSink
+ * @available_width: The width of space available for video output
+ * @available_height: The height of space available for video output
+ * @width: (out): A return location for the calculated output width
+ * @height: (out): A return location for the calculated output height
+ *
+ * Calculates a suitable output @width and @height that can fit inside
+ * the @available_width and @available_height space while maintaining
+ * the aspect ratio of the current video.
+ *
+ * Applications would typically use this api for "letterboxing" by
+ * using this api to calculate a suitable output size and then the
+ * application can position the video in their available output space
+ * and fill the remaining space with black borders.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_gst_video_sink_fit_size (CoglGstVideoSink *sink,
+ float available_width,
+ float available_height,
+ float *width,
+ float *height);
+
G_END_DECLS
#endif
diff --git a/examples/cogl-basic-video-player.c b/examples/cogl-basic-video-player.c
index ac6bb4b..61b2f03 100644
--- a/examples/cogl-basic-video-player.c
+++ b/examples/cogl-basic-video-player.c
@@ -1,17 +1,25 @@
+#include <stdbool.h>
+
#include <cogl/cogl.h>
#include <cogl-gst/cogl-gst.h>
typedef struct _Data
{
CoglFramebuffer *fb;
- CoglPipeline *pln;
+ CoglPipeline *border_pipeline;
+ CoglPipeline *video_pipeline;
CoglGstVideoSink *sink;
- CoglBool draw_ready;
- CoglBool frame_ready;
+ int onscreen_width;
+ int onscreen_height;
+ int video_width;
+ int video_height;
+ bool letterbox;
+ bool draw_ready;
+ bool frame_ready;
GMainLoop *main_loop;
}Data;
-static CoglBool
+static gboolean
_bus_watch (GstBus *bus,
GstMessage *msg,
void *user_data)
@@ -57,16 +65,58 @@ _draw (Data *data)
*/
CoglPipeline* current = cogl_gst_video_sink_get_pipeline (data->sink);
- cogl_framebuffer_clear4f (data->fb,
- COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_DEPTH, 0,
- 0, 0, 1);
- data->pln = current;
+ data->video_pipeline = current;
+
+ if (data->letterbox)
+ {
+ int x = (data->onscreen_width - data->video_width) / 2;
+
+ if (x)
+ {
+ /* Vertical borders */
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->border_pipeline,
+ 0, 0, x, data->onscreen_height);
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->border_pipeline,
+ data->onscreen_width - x,
+ 0,
+ data->onscreen_width,
+ data->onscreen_height);
+ cogl_framebuffer_draw_rectangle (data->fb, data->video_pipeline,
+ x, 0,
+ x + data->video_width,
+ data->onscreen_height);
+ }
+ else
+ {
+ /* Horizontal borders */
+ int y = (data->onscreen_height - data->video_height) / 2;
+
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->border_pipeline,
+ 0, 0, data->onscreen_width, y);
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->border_pipeline,
+ 0,
+ data->onscreen_height - y,
+ data->onscreen_width,
+ data->onscreen_height);
+ cogl_framebuffer_draw_rectangle (data->fb, data->video_pipeline,
+ 0, y,
+ data->onscreen_width,
+ y + data->video_height);
- cogl_framebuffer_push_matrix (data->fb);
- cogl_framebuffer_translate (data->fb, 640 / 2, 480 / 2, 0);
- cogl_framebuffer_draw_textured_rectangle (data->fb, data->pln, -320, -240,
- 320, 240, 0, 0, 1, 1);
- cogl_framebuffer_pop_matrix (data->fb);
+ }
+ }
+ else
+ {
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->video_pipeline,
+ 0, 0,
+ data->onscreen_width,
+ data->onscreen_height);
+ }
cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
}
@@ -108,6 +158,37 @@ _new_frame_cb (CoglGstVideoSink *sink,
_check_draw (data);
}
+static void
+_resize_callback (CoglOnscreen *onscreen,
+ int width,
+ int height,
+ void *user_data)
+{
+ Data *data = user_data;
+ float video_width, video_height;
+
+ data->onscreen_width = width;
+ data->onscreen_height = height;
+
+ cogl_framebuffer_orthographic (data->fb, 0, 0, width, height, -1, 100);
+
+ if (!data->video_pipeline)
+ return;
+
+ cogl_gst_video_sink_fit_size (data->sink,
+ width, height,
+ &video_width, &video_height);
+
+ /* pixel align... */
+ data->video_width = video_width + 0.5;
+ data->video_height = video_height + 0.5;
+
+ if (data->video_width != width || data->video_height != height)
+ data->letterbox = TRUE;
+ else
+ data->letterbox = FALSE;
+}
+
/*
A callback like this should be attached to the cogl-pipeline-ready
signal. This way requesting the cogl pipeline before its creation
@@ -129,16 +210,26 @@ _set_up_pipeline (gpointer instance,
*/
int free_layer = cogl_gst_video_sink_get_free_layer (data->sink);
- data->pln = cogl_gst_video_sink_get_pipeline (data->sink);
+ data->video_pipeline = cogl_gst_video_sink_get_pipeline (data->sink);
while (free_layer > 0)
{
free_layer--;
- cogl_pipeline_set_layer_filters (data->pln, free_layer,
+ cogl_pipeline_set_layer_filters (data->video_pipeline, free_layer,
COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR,
COGL_PIPELINE_FILTER_LINEAR);
}
+ /* disable blending... */
+ cogl_pipeline_set_blend (data->video_pipeline,
+ "RGBA = ADD (SRC_COLOR, 0)", NULL);
+
+ /* Now that we know the video size we can perform letterboxing */
+ _resize_callback (COGL_ONSCREEN (data->fb),
+ data->onscreen_width,
+ data->onscreen_height,
+ data);
+
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data->fb), _frame_callback,
data, NULL);
@@ -159,33 +250,31 @@ main (int argc,
Data data;
CoglContext *ctx;
CoglOnscreen *onscreen;
- CoglMatrix view;
- float fovy, aspect, z_near, z_2d, z_far;
GstElement *pipeline;
GstElement *bin;
GSource *cogl_source;
GstBus *bus;
char *uri;
+ memset (&data, 0, sizeof (Data));
+
/* Set the necessary cogl elements */
ctx = cogl_context_new (NULL, NULL);
+
onscreen = cogl_onscreen_new (ctx, 640, 480);
- data.fb = COGL_FRAMEBUFFER (onscreen);
+ cogl_onscreen_set_resizable (onscreen, TRUE);
+ cogl_onscreen_add_resize_handler (onscreen, _resize_callback, &data);
cogl_onscreen_show (onscreen);
- cogl_framebuffer_set_viewport (data.fb, 0, 0, 640, 480);
- fovy = 60;
- aspect = 640 / 480;
- z_near = 0.1;
- z_2d = 1000;
- z_far = 2000;
-
- cogl_framebuffer_perspective (data.fb, fovy, aspect, z_near, z_far);
- cogl_matrix_init_identity (&view);
- cogl_matrix_view_2d_in_perspective (&view, fovy, aspect, z_near, z_2d,
- 640, 480);
- cogl_framebuffer_set_modelview_matrix (data.fb, &view);
+ data.fb = COGL_FRAMEBUFFER (onscreen);
+ cogl_framebuffer_orthographic (data.fb, 0, 0, 640, 480, -1, 100);
+
+ data.border_pipeline = cogl_pipeline_new (ctx);
+ cogl_pipeline_set_color4f (data.border_pipeline, 0, 0, 0, 1);
+ /* disable blending */
+ cogl_pipeline_set_blend (data.border_pipeline,
+ "RGBA = ADD (SRC_COLOR, 0)", NULL);
/* Intialize GStreamer */
--
1.8.2.1
More information about the Cogl
mailing list