[Cogl] [PATCH v2] cogl-gst: expose aspect ratio apis

Neil Roberts neil at linux.intel.com
Mon Apr 29 10:00:03 PDT 2013


Great, looks good to me, thanks.

It would be good to add the new functions to
doc/reference/cogl-gst/cogl-gst-sections.txt.

Reviewed-by: Neil Roberts <neil at linux.intel.com>

Regards,
- Neil

Robert Bragg <robert at sixbynine.org> writes:

> From: Robert Bragg <robert at linux.intel.com>
>
> This fixes the arithmetic precedence mistake in the last patch and also updates
> the _fit_size api to take and return a rectangle whereby the output rectangle
> can also be centered too for more convenience.
>
> This patch is now based on master instead of the cogl-gst-1.x branch
>
> -- >8 --
>
> 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     |  57 +++++++++++++++
>  cogl-gst/cogl-gst-video-sink.h     |  92 ++++++++++++++++++++++++
>  examples/cogl-basic-video-player.c | 139 +++++++++++++++++++++++++++++--------
>  3 files changed, 258 insertions(+), 30 deletions(-)
>
> diff --git a/cogl-gst/cogl-gst-video-sink.c b/cogl-gst/cogl-gst-video-sink.c
> index 50c2f91..1eaa82c 100644
> --- a/cogl-gst/cogl-gst-video-sink.c
> +++ b/cogl-gst/cogl-gst-video-sink.c
> @@ -1271,3 +1271,60 @@ 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,
> +                              const CoglGstRectangle *available,
> +                              CoglGstRectangle *output)
> +{
> +  if (available->height == 0.0f)
> +    {
> +      output->x = available->x;
> +      output->y = available->y;
> +      output->width = output->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)
> +        {
> +          output->width = available->width;
> +          output->height = available->width / video_aspect;
> +          output->x = available->x;
> +          output->y = available->y + (available->height - output->height) / 2;
> +        }
> +      else
> +        {
> +          output->width = available->height * video_aspect;
> +          output->height = available->height;
> +          output->x = available->x + (available->width - output->width) / 2;
> +          output->y = available->y;
> +        }
> +    }
> +}
> diff --git a/cogl-gst/cogl-gst-video-sink.h b/cogl-gst/cogl-gst-video-sink.h
> index a9694a6..45ed835 100644
> --- a/cogl-gst/cogl-gst-video-sink.h
> +++ b/cogl-gst/cogl-gst-video-sink.h
> @@ -330,6 +330,98 @@ void
>  cogl_gst_video_sink_setup_pipeline (CoglGstVideoSink *sink,
>                                      CoglPipeline *pipeline);
>  
> +/**
> + * 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);
> +
> +/**
> + * CoglGstRectangle:
> + * @x: The X coordinate of the top left of the rectangle
> + * @y: The Y coordinate of the top left of the rectangle
> + * @width: The width of the rectangle
> + * @height: The height of the rectangle
> + *
> + * Describes a rectangle that can be used for video output.
> + */
> +typedef struct _CoglGstRectangle
> +{
> +  float x;
> +  float y;
> +  float width;
> +  float height;
> +} CoglGstRectangle;
> +
> +/**
> + * cogl_gst_video_sink_fit_size:
> + * @sink: A #CoglGstVideoSink
> + * @available: The space available for video output
> + * @output: The return location for the calculated output position
> + *
> + * Calculates a suitable @output rectangle that can fit inside the
> + * @available space while maintaining the aspect ratio of the current
> + * video.
> + *
> + * Applications would typically use this api for "letterboxing" by
> + * using this api to position a video inside a fixed screen space and
> + * filling the remaining space with black borders.
> + *
> + * Since: 1.16
> + * Stability: unstable
> + */
> +void
> +cogl_gst_video_sink_fit_size (CoglGstVideoSink *sink,
> +                              const CoglGstRectangle *available,
> +                              CoglGstRectangle *output);
> +
>  G_END_DECLS
>  
>  #endif
> diff --git a/examples/cogl-basic-video-player.c b/examples/cogl-basic-video-player.c
> index ac6bb4b..ba1e6c6 100644
> --- a/examples/cogl-basic-video-player.c
> +++ b/examples/cogl-basic-video-player.c
> @@ -1,17 +1,23 @@
> +#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;
> +  CoglGstRectangle video_output;
> +  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 +63,55 @@ _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;
>  
> -  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);
> +  if (data->video_output.x)
> +    {
> +      int x = data->video_output.x;
> +
> +      /* Letterboxed with 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_output.width,
> +                                       data->onscreen_height);
> +    }
> +  else if (data->video_output.y)
> +    {
> +      int y = data->video_output.y;
> +
> +      /* Letterboxed with horizontal borders */
> +      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_output.height);
> +
> +    }
> +  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 +153,32 @@ _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;
> +  CoglGstRectangle available;
> +
> +  data->onscreen_width = width;
> +  data->onscreen_height = height;
> +
> +  cogl_framebuffer_orthographic (data->fb, 0, 0, width, height, -1, 100);
> +
> +  if (!data->video_pipeline)
> +    return;
> +
> +  available.x = 0;
> +  available.y = 0;
> +  available.width = width;
> +  available.height = height;
> +  cogl_gst_video_sink_fit_size (data->sink,
> +                                &available,
> +                                &data->video_output);
> +}
> +
>  /*
>    A callback like this should be attached to the cogl-pipeline-ready
>    signal. This way requesting the cogl pipeline before its creation
> @@ -129,16 +200,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 +240,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_callback (onscreen, _resize_callback, &data, NULL);
>    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
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
---------------------------------------------------------------------
Intel Corporation (UK) Limited
Registered No. 1134945 (England)
Registered Office: Pipers Way, Swindon SN3 1RJ
VAT No: 860 2173 47

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.



More information about the Cogl mailing list