#define GST_CAT_DEFAULT gst_debug_gtk_gl_sink
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
+#define DEFAULT_PAR_N 0
+#define DEFAULT_PAR_D 1
static void gst_gtk_gl_sink_finalize (GObject * object);
static void gst_gtk_gl_sink_set_property (GObject * object, guint prop_id,
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
+ PROP_PIXEL_ASPECT_RATIO,
};
enum
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
+ gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+ "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
+ G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_gtk_gl_sink_template));
gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink)
{
gtk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
+ gtk_sink->par_n = DEFAULT_PAR_N;
+ gtk_sink->par_d = DEFAULT_PAR_D;
}
static void
}
gtk_sink->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new ();
- gtk_sink->bind_aspect_ratio =
+ gtk_sink->bind_force_aspect_ratio =
g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget,
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL);
+ gtk_sink->bind_pixel_aspect_ratio =
+ g_object_bind_property (gtk_sink, "pixel-aspect-ratio", gtk_sink->widget,
+ "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL);
/* Take the floating ref, otherwise the destruction of the container will
* make this widget disapear possibly before we are done. */
case PROP_FORCE_ASPECT_RATIO:
g_value_set_boolean (value, gtk_sink->force_aspect_ratio);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gst_value_set_fraction (value, gtk_sink->par_n, gtk_sink->par_d);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_FORCE_ASPECT_RATIO:
gtk_sink->force_aspect_ratio = g_value_get_boolean (value);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gtk_sink->par_n = gst_value_get_fraction_numerator (value);
+ gtk_sink->par_d = gst_value_get_fraction_denominator (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
/* properties */
gboolean force_aspect_ratio;
- GBinding *bind_aspect_ratio;
+ GBinding *bind_force_aspect_ratio;
+
+ gint par_n;
+ gint par_d;
+ GBinding *bind_pixel_aspect_ratio;
GstGtkGLSinkPrivate *priv;
};
);
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
+#define DEFAULT_PAR_N 0
+#define DEFAULT_PAR_D 1
enum
{
PROP_0,
PROP_WIDGET,
PROP_FORCE_ASPECT_RATIO,
+ PROP_PIXEL_ASPECT_RATIO,
};
enum
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
+ gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+ "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
+ G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_gtk_sink_template));
static void
gst_gtk_sink_init (GstGtkSink * gtk_sink)
{
+ gtk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
+ gtk_sink->par_n = DEFAULT_PAR_N;
+ gtk_sink->par_d = DEFAULT_PAR_D;
}
static void
gtk_sink->bind_aspect_ratio =
g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget,
"force-aspect-ratio", G_BINDING_BIDIRECTIONAL);
+ gtk_sink->bind_pixel_aspect_ratio =
+ g_object_bind_property (gtk_sink, "pixel-aspect-ratio", gtk_sink->widget,
+ "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL);
/* Take the floating ref, other wise the destruction of the container will
* make this widget disapear possibly before we are done. */
case PROP_FORCE_ASPECT_RATIO:
g_value_set_boolean (value, gtk_sink->force_aspect_ratio);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gst_value_set_fraction (value, gtk_sink->par_n, gtk_sink->par_d);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_FORCE_ASPECT_RATIO:
gtk_sink->force_aspect_ratio = g_value_get_boolean (value);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gtk_sink->par_n = gst_value_get_fraction_numerator (value);
+ gtk_sink->par_d = gst_value_get_fraction_denominator (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
gboolean force_aspect_ratio;
GBinding *bind_aspect_ratio;
+ gint par_n;
+ gint par_d;
+ GBinding *bind_pixel_aspect_ratio;
+
GstGtkSinkPrivate *priv;
};
G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA,
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0,
- "Gtk Gst GL Widget");
- );
+ "Gtk Gst GL Widget"););
#define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate))
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
+#define DEFAULT_PAR_N 0
+#define DEFAULT_PAR_D 1
enum
{
PROP_0,
PROP_FORCE_ASPECT_RATIO,
+ PROP_PIXEL_ASPECT_RATIO,
};
struct _GtkGstGLWidgetPrivate
/* properties */
gboolean force_aspect_ratio;
+ gint par_n, par_d;
+
+ gint display_width;
+ gint display_height;
gboolean negotiated;
GstBuffer *buffer;
src.x = 0;
src.y = 0;
- src.w = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info);
- src.h = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info);
+ src.w = gst_widget->priv->display_width;
+ src.h = gst_widget->priv->display_height;
dst.x = gtk_viewport[0];
dst.y = gtk_viewport[1];
case PROP_FORCE_ASPECT_RATIO:
gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value);
+ gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_FORCE_ASPECT_RATIO:
g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gst_value_set_fraction (value, gtk_widget->priv->par_n,
+ gtk_widget->priv->par_d);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_klass, PROP_PIXEL_ASPECT_RATIO,
+ gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+ "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
+ G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gl_widget_klass->render = gtk_gst_gl_widget_render;
widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width;
widget->priv = GTK_GST_GL_WIDGET_GET_PRIVATE (widget);
widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
+ widget->priv->par_n = DEFAULT_PAR_N;
+ widget->priv->par_d = DEFAULT_PAR_D;
g_mutex_init (&widget->priv->lock);
if (!widget->priv->display)
widget->priv->display = gst_gl_display_new ();
- gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, TRUE);
+ gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, FALSE);
}
GtkWidget *
return TRUE;
}
+static gboolean
+_calculate_par (GtkGstGLWidget * widget, GstVideoInfo * info)
+{
+ gboolean ok;
+ gint width, height;
+ gint par_n, par_d;
+ gint display_par_n, display_par_d;
+ guint display_ratio_num, display_ratio_den;
+
+ width = GST_VIDEO_INFO_WIDTH (info);
+ height = GST_VIDEO_INFO_HEIGHT (info);
+
+ par_n = GST_VIDEO_INFO_PAR_N (info);
+ par_d = GST_VIDEO_INFO_PAR_D (info);
+
+ if (!par_n)
+ par_n = 1;
+
+ /* get display's PAR */
+ if (widget->priv->par_n != 0 && widget->priv->par_d != 0) {
+ display_par_n = widget->priv->par_n;
+ display_par_d = widget->priv->par_d;
+ } else {
+ display_par_n = 1;
+ display_par_d = 1;
+ }
+
+ ok = gst_video_calculate_display_ratio (&display_ratio_num,
+ &display_ratio_den, width, height, par_n, par_d, display_par_n,
+ display_par_d);
+
+ if (!ok)
+ return FALSE;
+
+ GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d);
+
+ if (height % display_ratio_den == 0) {
+ GST_DEBUG ("keeping video height");
+ widget->priv->display_width = (guint)
+ gst_util_uint64_scale_int (height, display_ratio_num,
+ display_ratio_den);
+ widget->priv->display_height = height;
+ } else if (width % display_ratio_num == 0) {
+ GST_DEBUG ("keeping video width");
+ widget->priv->display_width = width;
+ widget->priv->display_height = (guint)
+ gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
+ } else {
+ GST_DEBUG ("approximating while keeping video height");
+ widget->priv->display_width = (guint)
+ gst_util_uint64_scale_int (height, display_ratio_num,
+ display_ratio_den);
+ widget->priv->display_height = height;
+ }
+ GST_DEBUG ("scaling to %dx%d", widget->priv->display_width,
+ widget->priv->display_height);
+
+ return TRUE;
+}
+
gboolean
gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps)
{
gst_caps_set_features (widget->priv->gl_caps, 0,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
+ if (!_calculate_par (widget, &v_info)) {
+ g_mutex_unlock (&widget->priv->lock);
+ return FALSE;
+ }
+
widget->priv->v_info = v_info;
widget->priv->negotiated = TRUE;
GTK_TYPE_GST_WIDGET, GtkGstWidgetPrivate))
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
+#define DEFAULT_PAR_N 0
+#define DEFAULT_PAR_D 1
enum
{
PROP_0,
PROP_FORCE_ASPECT_RATIO,
+ PROP_PIXEL_ASPECT_RATIO,
};
struct _GtkGstWidgetPrivate
/* properties */
gboolean force_aspect_ratio;
+ gint par_n, par_d;
+
+ gint display_width;
+ gint display_height;
gboolean negotiated;
GstBuffer *buffer;
if (gst_widget->priv->negotiated && gst_widget->priv->buffer
&& gst_video_frame_map (&frame, &gst_widget->priv->v_info,
gst_widget->priv->buffer, GST_MAP_READ)) {
- gdouble scale_x =
- (gdouble) widget_width / GST_VIDEO_INFO_WIDTH (&frame.info);
+ gdouble scale_x = (gdouble) widget_width / gst_widget->priv->display_width;
gdouble scale_y =
- (gdouble) widget_height / GST_VIDEO_INFO_HEIGHT (&frame.info);
+ (gdouble) widget_height / gst_widget->priv->display_height;
GstVideoRectangle result;
gst_widget->priv->v_info = frame.info;
src.x = 0;
src.y = 0;
- src.w = GST_VIDEO_INFO_WIDTH (&frame.info);
- src.h = GST_VIDEO_INFO_HEIGHT (&frame.info);
+ src.w = gst_widget->priv->display_width;
+ src.h = gst_widget->priv->display_height;
dst.x = 0;
dst.y = 0;
result.h = widget_height;
}
+ scale_x *=
+ (gdouble) gst_widget->priv->display_width / (gdouble) frame.info.width;
+ scale_y *=
+ (gdouble) gst_widget->priv->display_height /
+ (gdouble) frame.info.height;
+
cairo_translate (cr, result.x, result.y);
cairo_scale (cr, scale_x, scale_y);
cairo_rectangle (cr, 0, 0, result.w, result.h);
case PROP_FORCE_ASPECT_RATIO:
gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value);
+ gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_FORCE_ASPECT_RATIO:
g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio);
break;
+ case PROP_PIXEL_ASPECT_RATIO:
+ gst_value_set_fraction (value, gtk_widget->priv->par_n,
+ gtk_widget->priv->par_d);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
DEFAULT_FORCE_ASPECT_RATIO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_klass, PROP_PIXEL_ASPECT_RATIO,
+ gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+ "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
+ G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
widget_klass->draw = gtk_gst_widget_draw;
widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width;
widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height;
widget->priv = GTK_GST_WIDGET_GET_PRIVATE (widget);
widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
+ widget->priv->par_n = DEFAULT_PAR_N;
+ widget->priv->par_d = DEFAULT_PAR_D;
g_mutex_init (&widget->priv->lock);
}
return G_SOURCE_REMOVE;
}
+static gboolean
+_calculate_par (GtkGstWidget * widget, GstVideoInfo * info)
+{
+ gboolean ok;
+ gint width, height;
+ gint par_n, par_d;
+ gint display_par_n, display_par_d;
+ guint display_ratio_num, display_ratio_den;
+
+ width = GST_VIDEO_INFO_WIDTH (info);
+ height = GST_VIDEO_INFO_HEIGHT (info);
+
+ par_n = GST_VIDEO_INFO_PAR_N (info);
+ par_d = GST_VIDEO_INFO_PAR_D (info);
+
+ if (!par_n)
+ par_n = 1;
+
+ /* get display's PAR */
+ if (widget->priv->par_n != 0 && widget->priv->par_d != 0) {
+ display_par_n = widget->priv->par_n;
+ display_par_d = widget->priv->par_d;
+ } else {
+ display_par_n = 1;
+ display_par_d = 1;
+ }
+
+ ok = gst_video_calculate_display_ratio (&display_ratio_num,
+ &display_ratio_den, width, height, par_n, par_d, display_par_n,
+ display_par_d);
+
+ if (!ok)
+ return FALSE;
+
+ GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d);
+
+ if (height % display_ratio_den == 0) {
+ GST_DEBUG ("keeping video height");
+ widget->priv->display_width = (guint)
+ gst_util_uint64_scale_int (height, display_ratio_num,
+ display_ratio_den);
+ widget->priv->display_height = height;
+ } else if (width % display_ratio_num == 0) {
+ GST_DEBUG ("keeping video width");
+ widget->priv->display_width = width;
+ widget->priv->display_height = (guint)
+ gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
+ } else {
+ GST_DEBUG ("approximating while keeping video height");
+ widget->priv->display_width = (guint)
+ gst_util_uint64_scale_int (height, display_ratio_num,
+ display_ratio_den);
+ widget->priv->display_height = height;
+ }
+ GST_DEBUG ("scaling to %dx%d", widget->priv->display_width,
+ widget->priv->display_height);
+
+ return TRUE;
+}
+
gboolean
gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps)
{
g_mutex_lock (&widget->priv->lock);
+ if (!_calculate_par (widget, &v_info)) {
+ g_mutex_unlock (&widget->priv->lock);
+ return FALSE;
+ }
+
gst_caps_replace (&widget->priv->caps, caps);
widget->priv->v_info = v_info;
widget->priv->negotiated = TRUE;