mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
qroverlay: Change pixel-size to percent of width or height
The size is now expressed in percent of the smallest dimention. 100 means the biggest square that fits the render area. Fixes: #3695 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7638>
This commit is contained in:
parent
809ab829d0
commit
b4ccd940d4
1 changed files with 81 additions and 41 deletions
|
@ -43,7 +43,7 @@ enum
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_X_AXIS,
|
PROP_X_AXIS,
|
||||||
PROP_Y_AXIS,
|
PROP_Y_AXIS,
|
||||||
PROP_PIXEL_SIZE,
|
PROP_SIZE,
|
||||||
PROP_QRCODE_ERROR_CORRECTION,
|
PROP_QRCODE_ERROR_CORRECTION,
|
||||||
PROP_CASE_SENSITIVE,
|
PROP_CASE_SENSITIVE,
|
||||||
};
|
};
|
||||||
|
@ -51,16 +51,18 @@ enum
|
||||||
typedef struct _GstBaseQROverlayPrivate GstBaseQROverlayPrivate;
|
typedef struct _GstBaseQROverlayPrivate GstBaseQROverlayPrivate;
|
||||||
struct _GstBaseQROverlayPrivate
|
struct _GstBaseQROverlayPrivate
|
||||||
{
|
{
|
||||||
gfloat qrcode_size;
|
|
||||||
guint qrcode_quality;
|
guint qrcode_quality;
|
||||||
guint span_frame;
|
guint span_frame;
|
||||||
QRecLevel level;
|
QRecLevel level;
|
||||||
gfloat x_percent;
|
gfloat x_percent;
|
||||||
gfloat y_percent;
|
gfloat y_percent;
|
||||||
|
gfloat size_percent;
|
||||||
GstElement *overlaycomposition;
|
GstElement *overlaycomposition;
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
gboolean valid;
|
gboolean valid;
|
||||||
gboolean case_sensitive;
|
gboolean case_sensitive;
|
||||||
|
gint window_width;
|
||||||
|
gint window_height;
|
||||||
|
|
||||||
GstPad *sinkpad, *srcpad;
|
GstPad *sinkpad, *srcpad;
|
||||||
GstVideoOverlayComposition *prev_overlay;
|
GstVideoOverlayComposition *prev_overlay;
|
||||||
|
@ -86,7 +88,9 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
);
|
);
|
||||||
|
|
||||||
#define DEFAULT_PROP_QUALITY 1
|
#define DEFAULT_PROP_QUALITY 1
|
||||||
#define DEFAULT_PROP_PIXEL_SIZE 3
|
#define DEFAULT_PROP_X 50
|
||||||
|
#define DEFAULT_PROP_Y 50
|
||||||
|
#define DEFAULT_PROP_SIZE 33
|
||||||
#define DEFAULT_PROP_CASE_SENSITIVE FALSE
|
#define DEFAULT_PROP_CASE_SENSITIVE FALSE
|
||||||
|
|
||||||
#define GST_TYPE_QRCODE_QUALITY (gst_qrcode_quality_get_type())
|
#define GST_TYPE_QRCODE_QUALITY (gst_qrcode_quality_get_type())
|
||||||
|
@ -125,6 +129,9 @@ gst_base_qr_overlay_caps_changed_cb (GstBaseQROverlay * self, GstCaps * caps,
|
||||||
{
|
{
|
||||||
GstBaseQROverlayPrivate *priv = PRIV (self);
|
GstBaseQROverlayPrivate *priv = PRIV (self);
|
||||||
|
|
||||||
|
priv->window_width = window_width;
|
||||||
|
priv->window_height = window_height;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "%" GST_PTR_FORMAT, caps);
|
GST_DEBUG_OBJECT (self, "%" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
if (gst_video_info_from_caps (&priv->info, caps))
|
if (gst_video_info_from_caps (&priv->info, caps))
|
||||||
|
@ -136,11 +143,30 @@ gst_base_qr_overlay_caps_changed_cb (GstBaseQROverlay * self, GstCaps * caps,
|
||||||
gst_mini_object_replace (((GstMiniObject **) & priv->prev_overlay), NULL);
|
gst_mini_object_replace (((GstMiniObject **) & priv->prev_overlay), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
render_size (GstBaseQROverlay * self, int *width, int *height)
|
||||||
|
{
|
||||||
|
GstBaseQROverlayPrivate *priv = PRIV (self);
|
||||||
|
gdouble video_aspect =
|
||||||
|
(gdouble) priv->info.width / (gdouble) priv->info.height;
|
||||||
|
gdouble window_aspect =
|
||||||
|
(gdouble) priv->window_width / (gdouble) priv->window_height;
|
||||||
|
|
||||||
|
/* Render size within the window */
|
||||||
|
if (video_aspect >= window_aspect) {
|
||||||
|
*width = priv->window_width;
|
||||||
|
*height = window_aspect * priv->window_height / video_aspect;
|
||||||
|
} else {
|
||||||
|
*width = video_aspect * priv->window_width / window_aspect;
|
||||||
|
*height = priv->window_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstVideoOverlayComposition *
|
static GstVideoOverlayComposition *
|
||||||
draw_overlay (GstBaseQROverlay * self, QRcode * qrcode)
|
draw_overlay (GstBaseQROverlay * self, QRcode * qrcode)
|
||||||
{
|
{
|
||||||
guint8 *qr_data, *pixels;
|
guint8 *qr_data, *pixels;
|
||||||
gint stride, pstride, y, x, yy, square_size;
|
gint stride, pstride, y, x, yy;
|
||||||
gsize offset, line_offset;
|
gsize offset, line_offset;
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
GstVideoOverlayRectangle *rect;
|
GstVideoOverlayRectangle *rect;
|
||||||
|
@ -150,7 +176,21 @@ draw_overlay (GstBaseQROverlay * self, QRcode * qrcode)
|
||||||
|
|
||||||
gst_video_info_init (&info);
|
gst_video_info_init (&info);
|
||||||
|
|
||||||
square_size = (qrcode->width + 4 * 2) * priv->qrcode_size;
|
int render_width, render_height;
|
||||||
|
render_size (self, &render_width, &render_height);
|
||||||
|
|
||||||
|
// Total size in pixels of the qrcode.
|
||||||
|
gdouble size_scale = priv->size_percent / 100;
|
||||||
|
int square_size =
|
||||||
|
render_width < render_height
|
||||||
|
? render_width * size_scale : render_height * size_scale;
|
||||||
|
// Size in pixels of 1 qrcode block (1 block margin on each side).
|
||||||
|
int qrcode_size = square_size / (qrcode->width + 2);
|
||||||
|
// Update square_size for a round number of blocks.
|
||||||
|
square_size = qrcode_size * (qrcode->width + 2);
|
||||||
|
// Margin in pixels in each side to center the qrcode.
|
||||||
|
int margin = qrcode_size;
|
||||||
|
|
||||||
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_ARGB, square_size,
|
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_ARGB, square_size,
|
||||||
square_size);
|
square_size);
|
||||||
|
|
||||||
|
@ -159,25 +199,21 @@ draw_overlay (GstBaseQROverlay * self, QRcode * qrcode)
|
||||||
pstride = info.finfo->pixel_stride[0];
|
pstride = info.finfo->pixel_stride[0];
|
||||||
|
|
||||||
/* White background */
|
/* White background */
|
||||||
for (y = 0; y < info.height; y++)
|
memset (pixels, 0xff, info.size);
|
||||||
memset (&pixels[y * stride], 0xff, stride);
|
|
||||||
|
|
||||||
/* Draw the black QR code blocks with 4px white space around it
|
/* Draw the black QR code blocks */
|
||||||
* on top */
|
line_offset = margin * stride;
|
||||||
line_offset = 4 * priv->qrcode_size * stride;
|
|
||||||
qr_data = qrcode->data;
|
qr_data = qrcode->data;
|
||||||
for (y = 0; y < qrcode->width; y++) {
|
for (y = 0; y < qrcode->width; y++) {
|
||||||
for (x = 0; x < (qrcode->width); x++) {
|
for (x = 0; x < (qrcode->width); x++) {
|
||||||
for (yy = 0; yy < priv->qrcode_size * pstride; yy += pstride) {
|
for (yy = 0; yy < qrcode_size * pstride; yy += pstride) {
|
||||||
if (!(*qr_data & 1))
|
if (!(*qr_data & 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
offset =
|
offset = line_offset + stride * (yy / pstride) +
|
||||||
(((line_offset + (stride * (yy / pstride))) +
|
x * qrcode_size * pstride + margin * pstride;
|
||||||
x * priv->qrcode_size * pstride)) +
|
|
||||||
(priv->qrcode_size * pstride) + (4 * priv->qrcode_size * pstride);
|
|
||||||
|
|
||||||
for (gint i = 0; i < priv->qrcode_size * pstride; i += pstride) {
|
for (gint i = 0; i < qrcode_size * pstride; i += pstride) {
|
||||||
pixels[offset + i] = 0x00;
|
pixels[offset + i] = 0x00;
|
||||||
pixels[offset + i + 1] = 0x00;
|
pixels[offset + i + 1] = 0x00;
|
||||||
pixels[offset + i + 2] = 0x00;
|
pixels[offset + i + 2] = 0x00;
|
||||||
|
@ -185,23 +221,28 @@ draw_overlay (GstBaseQROverlay * self, QRcode * qrcode)
|
||||||
}
|
}
|
||||||
qr_data++;
|
qr_data++;
|
||||||
}
|
}
|
||||||
line_offset += (stride * priv->qrcode_size);
|
line_offset += stride * qrcode_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = gst_buffer_new_wrapped (pixels, info.size);
|
buf = gst_buffer_new_wrapped (pixels, info.size);
|
||||||
gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
|
gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
|
||||||
GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, info.width, info.height);
|
GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB, info.width, info.height);
|
||||||
|
|
||||||
|
square_size =
|
||||||
|
priv->info.width < priv->info.height
|
||||||
|
? priv->info.width * size_scale : priv->info.height * size_scale;
|
||||||
|
|
||||||
x = (int) (priv->info.width - square_size) * (priv->x_percent / 100);
|
x = (int) (priv->info.width - square_size) * (priv->x_percent / 100);
|
||||||
x = GST_ROUND_DOWN_2 (x);
|
x = GST_ROUND_DOWN_2 (x);
|
||||||
y = (int) (priv->info.height - square_size) * (priv->y_percent / 100);
|
y = (int) (priv->info.height - square_size) * (priv->y_percent / 100);
|
||||||
y = GST_ROUND_DOWN_4 (y);
|
y = GST_ROUND_DOWN_4 (y);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "draw overlay at (%d,%d) size: %dx%d", x, y,
|
GST_DEBUG_OBJECT (self, "draw overlay at (%d,%d) size: %dx%d", x, y,
|
||||||
info.width, info.height);
|
square_size, square_size);
|
||||||
|
|
||||||
rect = gst_video_overlay_rectangle_new_raw (buf, x, y,
|
rect =
|
||||||
info.width, info.height, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
|
gst_video_overlay_rectangle_new_raw (buf, x, y, square_size, square_size,
|
||||||
|
GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
|
||||||
comp = gst_video_overlay_composition_new (rect);
|
comp = gst_video_overlay_composition_new (rect);
|
||||||
gst_video_overlay_rectangle_unref (rect);
|
gst_video_overlay_rectangle_unref (rect);
|
||||||
|
|
||||||
|
@ -283,22 +324,21 @@ gst_base_qr_overlay_class_init (GstBaseQROverlayClass * klass)
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_base_qr_overlay_debug, "qroverlay", 0,
|
GST_DEBUG_CATEGORY_INIT (gst_base_qr_overlay_debug, "qroverlay", 0,
|
||||||
"Qrcode overlay base class");
|
"Qrcode overlay base class");
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class, PROP_X_AXIS,
|
||||||
PROP_X_AXIS, g_param_spec_float ("x",
|
g_param_spec_float ("x", "X position (in percent of the width)",
|
||||||
"X position (in percent of the width)",
|
"X position (in percent of the width)", 0.0, 100.0, DEFAULT_PROP_X,
|
||||||
"X position (in percent of the width)",
|
G_PARAM_READWRITE));
|
||||||
0.0, 100.0, 50.0, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class, PROP_Y_AXIS,
|
||||||
PROP_Y_AXIS, g_param_spec_float ("y",
|
g_param_spec_float ("y", "Y position (in percent of the height)",
|
||||||
"Y position (in percent of the height)",
|
"Y position (in percent of the height)", 0.0, 100.0, DEFAULT_PROP_Y,
|
||||||
"Y position (in percent of the height)",
|
G_PARAM_READWRITE));
|
||||||
0.0, 100.0, 50.0, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class, PROP_SIZE,
|
||||||
PROP_PIXEL_SIZE, g_param_spec_float ("pixel-size",
|
g_param_spec_float ("size",
|
||||||
"pixel-size", "Pixel size of each Qrcode pixel",
|
"Size of the square (in percent of the smallest of width and height)",
|
||||||
1, 100.0, DEFAULT_PROP_PIXEL_SIZE, G_PARAM_READWRITE));
|
"Size of the square (in percent of the smallest of width and height)",
|
||||||
|
0.0, 100.0, DEFAULT_PROP_SIZE, G_PARAM_READWRITE));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_QRCODE_ERROR_CORRECTION,
|
g_object_class_install_property (gobject_class, PROP_QRCODE_ERROR_CORRECTION,
|
||||||
g_param_spec_enum ("qrcode-error-correction", "qrcode-error-correction",
|
g_param_spec_enum ("qrcode-error-correction", "qrcode-error-correction",
|
||||||
|
@ -335,12 +375,12 @@ gst_base_qr_overlay_init (GstBaseQROverlay * self)
|
||||||
{
|
{
|
||||||
GstBaseQROverlayPrivate *priv = PRIV (self);
|
GstBaseQROverlayPrivate *priv = PRIV (self);
|
||||||
|
|
||||||
priv->x_percent = 50.0;
|
priv->x_percent = DEFAULT_PROP_X;
|
||||||
priv->y_percent = 50.0;
|
priv->y_percent = DEFAULT_PROP_X;
|
||||||
|
priv->size_percent = DEFAULT_PROP_SIZE;
|
||||||
priv->qrcode_quality = DEFAULT_PROP_QUALITY;
|
priv->qrcode_quality = DEFAULT_PROP_QUALITY;
|
||||||
priv->case_sensitive = DEFAULT_PROP_CASE_SENSITIVE;
|
priv->case_sensitive = DEFAULT_PROP_CASE_SENSITIVE;
|
||||||
priv->span_frame = 0;
|
priv->span_frame = 0;
|
||||||
priv->qrcode_size = DEFAULT_PROP_PIXEL_SIZE;
|
|
||||||
priv->overlaycomposition =
|
priv->overlaycomposition =
|
||||||
gst_element_factory_make ("overlaycomposition", NULL);
|
gst_element_factory_make ("overlaycomposition", NULL);
|
||||||
gst_video_info_init (&priv->info);
|
gst_video_info_init (&priv->info);
|
||||||
|
@ -380,8 +420,8 @@ gst_base_qr_overlay_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_Y_AXIS:
|
case PROP_Y_AXIS:
|
||||||
priv->y_percent = g_value_get_float (value);
|
priv->y_percent = g_value_get_float (value);
|
||||||
break;
|
break;
|
||||||
case PROP_PIXEL_SIZE:
|
case PROP_SIZE:
|
||||||
priv->qrcode_size = g_value_get_float (value);
|
priv->size_percent = g_value_get_float (value);
|
||||||
break;
|
break;
|
||||||
case PROP_QRCODE_ERROR_CORRECTION:
|
case PROP_QRCODE_ERROR_CORRECTION:
|
||||||
priv->qrcode_quality = g_value_get_enum (value);
|
priv->qrcode_quality = g_value_get_enum (value);
|
||||||
|
@ -408,8 +448,8 @@ gst_base_qr_overlay_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_Y_AXIS:
|
case PROP_Y_AXIS:
|
||||||
g_value_set_float (value, priv->y_percent);
|
g_value_set_float (value, priv->y_percent);
|
||||||
break;
|
break;
|
||||||
case PROP_PIXEL_SIZE:
|
case PROP_SIZE:
|
||||||
g_value_set_float (value, priv->qrcode_size);
|
g_value_set_float (value, priv->size_percent);
|
||||||
break;
|
break;
|
||||||
case PROP_QRCODE_ERROR_CORRECTION:
|
case PROP_QRCODE_ERROR_CORRECTION:
|
||||||
g_value_set_enum (value, priv->qrcode_quality);
|
g_value_set_enum (value, priv->qrcode_quality);
|
||||||
|
|
Loading…
Reference in a new issue