qroverlay: Port to VideoFilter
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1730>
This commit is contained in:
parent
4a259e8f28
commit
c307f1418d
@ -116,18 +116,16 @@ gst_qrcode_quality_get_type (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define gst_qr_overlay_parent_class parent_class
|
#define gst_qr_overlay_parent_class parent_class
|
||||||
G_DEFINE_TYPE (GstQROverlay, gst_qr_overlay, GST_TYPE_BASE_TRANSFORM);
|
G_DEFINE_TYPE (GstQROverlay, gst_qr_overlay, GST_TYPE_VIDEO_FILTER);
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_qr_overlay_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out);
|
|
||||||
|
|
||||||
static void gst_qr_overlay_set_property (GObject * object, guint prop_id,
|
static void gst_qr_overlay_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_qr_overlay_get_property (GObject * object, guint prop_id,
|
static void gst_qr_overlay_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
static GstFlowReturn gst_qr_overlay_transform_ip (GstBaseTransform * base,
|
static GstFlowReturn
|
||||||
GstBuffer * outbuf);
|
gst_qr_overlay_transform_frame_ip (GstVideoFilter * base,
|
||||||
|
GstVideoFrame * frame);
|
||||||
|
|
||||||
/* GObject vmethod implementations */
|
/* GObject vmethod implementations */
|
||||||
|
|
||||||
@ -137,11 +135,9 @@ gst_qr_overlay_class_init (GstQROverlayClass * klass)
|
|||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
GstBaseTransformClass *trans_class;
|
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
trans_class = (GstBaseTransformClass *) klass;
|
|
||||||
|
|
||||||
gobject_class->set_property = gst_qr_overlay_set_property;
|
gobject_class->set_property = gst_qr_overlay_set_property;
|
||||||
gobject_class->get_property = gst_qr_overlay_get_property;
|
gobject_class->get_property = gst_qr_overlay_get_property;
|
||||||
@ -206,9 +202,8 @@ gst_qr_overlay_class_init (GstQROverlayClass * klass)
|
|||||||
|
|
||||||
gst_type_mark_as_plugin_api (GST_TYPE_QRCODE_QUALITY, 0);
|
gst_type_mark_as_plugin_api (GST_TYPE_QRCODE_QUALITY, 0);
|
||||||
|
|
||||||
GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
|
GST_VIDEO_FILTER_CLASS (klass)->transform_frame_ip =
|
||||||
GST_DEBUG_FUNCPTR (gst_qr_overlay_transform_ip);
|
GST_DEBUG_FUNCPTR (gst_qr_overlay_transform_frame_ip);
|
||||||
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_qr_overlay_set_caps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize the new element
|
/* initialize the new element
|
||||||
@ -221,7 +216,6 @@ gst_qr_overlay_init (GstQROverlay * filter)
|
|||||||
filter->x_percent = 50.0;
|
filter->x_percent = 50.0;
|
||||||
filter->y_percent = 50.0;
|
filter->y_percent = 50.0;
|
||||||
filter->qrcode_quality = DEFAULT_PROP_QUALITY;
|
filter->qrcode_quality = DEFAULT_PROP_QUALITY;
|
||||||
filter->level = QR_ECLEVEL_M;
|
|
||||||
filter->array_counter = 0;
|
filter->array_counter = 0;
|
||||||
filter->array_size = 0;
|
filter->array_size = 0;
|
||||||
filter->extra_data_interval_buffers = 60;
|
filter->extra_data_interval_buffers = 60;
|
||||||
@ -312,49 +306,12 @@ gst_qr_overlay_get_property (GObject * object, guint prop_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_qr_overlay_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
|
|
||||||
{
|
|
||||||
GstQROverlay *filter = GST_QR_OVERLAY (trans);
|
|
||||||
GstStructure *structure;
|
|
||||||
const GValue *framerate_value;
|
|
||||||
|
|
||||||
structure = gst_caps_get_structure (in, 0);
|
|
||||||
framerate_value = gst_structure_get_value (structure, "framerate");
|
|
||||||
filter->framerate_string = g_strdup_value_contents (framerate_value);
|
|
||||||
filter->width =
|
|
||||||
atoi (g_strdup_value_contents (gst_structure_get_value (structure,
|
|
||||||
"width")));
|
|
||||||
filter->height =
|
|
||||||
atoi (g_strdup_value_contents (gst_structure_get_value (structure,
|
|
||||||
"height")));
|
|
||||||
switch (filter->qrcode_quality) {
|
|
||||||
case 0:
|
|
||||||
filter->level = QR_ECLEVEL_L;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
filter->level = QR_ECLEVEL_M;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
filter->level = QR_ECLEVEL_Q;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
filter->level = QR_ECLEVEL_H;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GST_ERROR_OBJECT (filter, "Invalid level");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
build_string (GstBaseTransform * base, GstBuffer * outbuf)
|
get_qrcode_content (GstQROverlay * filter, GstBuffer * outbuf)
|
||||||
{
|
{
|
||||||
GString *res = g_string_new (NULL);
|
GString *res = g_string_new (NULL);
|
||||||
JsonGenerator *jgen;
|
JsonGenerator *jgen;
|
||||||
|
|
||||||
GstQROverlay *filter = GST_QR_OVERLAY (base);
|
|
||||||
JsonObject *jobj = json_object_new ();
|
JsonObject *jobj = json_object_new ();
|
||||||
JsonNode *root = json_node_new (JSON_NODE_OBJECT);
|
JsonNode *root = json_node_new (JSON_NODE_OBJECT);
|
||||||
|
|
||||||
@ -363,7 +320,7 @@ build_string (GstBaseTransform * base, GstBuffer * outbuf)
|
|||||||
json_object_set_int_member (jobj, "BUFFERCOUNT",
|
json_object_set_int_member (jobj, "BUFFERCOUNT",
|
||||||
(gint64) filter->frame_number);
|
(gint64) filter->frame_number);
|
||||||
json_object_set_string_member (jobj, "FRAMERATE", filter->framerate_string);
|
json_object_set_string_member (jobj, "FRAMERATE", filter->framerate_string);
|
||||||
json_object_set_string_member (jobj, "NAME", GST_ELEMENT_NAME (base));
|
json_object_set_string_member (jobj, "NAME", GST_ELEMENT_NAME (filter));
|
||||||
|
|
||||||
if (filter->extra_data_array && filter->extra_data_name &&
|
if (filter->extra_data_array && filter->extra_data_name &&
|
||||||
(filter->frame_number == 1
|
(filter->frame_number == 1
|
||||||
@ -392,88 +349,100 @@ build_string (GstBaseTransform * base, GstBuffer * outbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
overlay_qr_in_frame (GstQROverlay * filter, QRcode * qrcode, GstBuffer * outbuf)
|
overlay_qr_in_frame (GstQROverlay * filter, QRcode * qrcode,
|
||||||
|
GstVideoFrame * frame)
|
||||||
{
|
{
|
||||||
GstMapInfo current_info;
|
|
||||||
guchar *source_data;
|
guchar *source_data;
|
||||||
register int32_t k, y, x, yy, realwidth, y_position, x_position, line = 0;
|
gint32 k, y, x, yy, square_size, line = 0;
|
||||||
int img_res, quarter_img_res;
|
int x1, x2, y1, y2;
|
||||||
|
guint8 *d;
|
||||||
|
gint stride;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (filter, "Overlay QRcode in frame");
|
square_size = (qrcode->width + 4 * 2) * filter->qrcode_size;
|
||||||
gst_buffer_map (outbuf, ¤t_info, GST_MAP_WRITE);
|
|
||||||
realwidth = (qrcode->width + 4 * 2) * filter->qrcode_size;
|
|
||||||
/* White bg */
|
/* White bg */
|
||||||
x_position = (int) (filter->width - realwidth) * (filter->x_percent / 100);
|
x1 = (int) (GST_VIDEO_FRAME_WIDTH (frame) -
|
||||||
y_position = (int) (filter->height - realwidth) * (filter->y_percent / 100);
|
square_size) * (filter->x_percent / 100);
|
||||||
x_position = GST_ROUND_DOWN_2 (x_position);
|
x1 = GST_ROUND_DOWN_2 (x1);
|
||||||
y_position = GST_ROUND_DOWN_4 (y_position);
|
x2 = x1 + square_size;
|
||||||
GST_LOG_OBJECT (filter, "Add white background in frame");
|
y1 = (int) (GST_VIDEO_FRAME_HEIGHT (frame) -
|
||||||
img_res = filter->width * filter->height;
|
square_size) * (filter->y_percent / 100);
|
||||||
quarter_img_res = img_res / 4;
|
y1 = GST_ROUND_DOWN_4 (y1);
|
||||||
for (y = y_position; y < realwidth + y_position; y++) {
|
y2 = y1 + square_size;
|
||||||
memset (current_info.data + (filter->width * y + x_position), 0xff,
|
|
||||||
realwidth);
|
d = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
|
||||||
if (y % 4 == 0) {
|
stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
|
||||||
memset (current_info.data + img_res + y / 4 * filter->width +
|
|
||||||
x_position / 2, 128, realwidth / 2);
|
/* Start drawing the white luma plane */
|
||||||
memset (current_info.data + img_res + y / 4 * filter->width +
|
for (y = y1; y < y2; y++) {
|
||||||
x_position / 2 + quarter_img_res, 128, realwidth / 2);
|
for (x = x1; x < x2; x += square_size)
|
||||||
if (y < (realwidth + y_position) - 4) {
|
memset (&d[y * stride + x], 0xff, square_size);
|
||||||
memset (current_info.data + img_res + y / 4 * filter->width +
|
|
||||||
x_position / 2 + (filter->width / 2), 128, realwidth / 2);
|
|
||||||
memset (current_info.data + img_res + y / 4 * filter->width +
|
|
||||||
x_position / 2 + quarter_img_res + (filter->width / 2), 128,
|
|
||||||
realwidth / 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GST_LOG_OBJECT (filter, "Add data in frame");
|
|
||||||
/* data */
|
/* Draw the black QR code blocks with 4px white space around it
|
||||||
line += 4 * filter->qrcode_size * filter->width;
|
* on top */
|
||||||
|
line += 4 * filter->qrcode_size * stride;
|
||||||
source_data = qrcode->data;
|
source_data = qrcode->data;
|
||||||
y = (int) (filter->height - realwidth) / 2;
|
|
||||||
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 < filter->qrcode_size; yy++) {
|
for (yy = 0; yy < filter->qrcode_size; yy++) {
|
||||||
k = ((((line + (4 * filter->qrcode_size))) + filter->width * yy +
|
k = ((((line + (4 * filter->qrcode_size))) + stride * yy +
|
||||||
x * filter->qrcode_size) + x_position) +
|
x * filter->qrcode_size) + x1) + (y1 * stride);
|
||||||
(y_position * filter->width);
|
|
||||||
if (*source_data & 1) {
|
if (*source_data & 1) {
|
||||||
memset (current_info.data + k, 0, filter->qrcode_size);
|
memset (d + k, 0, filter->qrcode_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
source_data++;
|
source_data++;
|
||||||
}
|
}
|
||||||
line += (filter->width * filter->qrcode_size);
|
line += (stride * filter->qrcode_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set Chrominance planes */
|
||||||
|
x1 /= 2;
|
||||||
|
x2 /= 2;
|
||||||
|
y1 /= 2;
|
||||||
|
y2 /= 2;
|
||||||
|
stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
|
||||||
|
for (y = y1; y < y2; y++) {
|
||||||
|
for (x = x1; x < x2; x += (x2 - x1)) {
|
||||||
|
d = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
|
||||||
|
memset (&d[y * stride + x], 128, (x2 - x1));
|
||||||
|
d = GST_VIDEO_FRAME_PLANE_DATA (frame, 2);
|
||||||
|
memset (&d[y * stride + x], 128, (x2 - x1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QRcode_free (qrcode);
|
QRcode_free (qrcode);
|
||||||
gst_buffer_unmap (outbuf, ¤t_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GstBaseTransform vmethod implementations */
|
/* GstBaseTransform vmethod implementations */
|
||||||
/* this function does the actual processing
|
/* this function does the actual processing
|
||||||
*/
|
*/
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_qr_overlay_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
|
gst_qr_overlay_transform_frame_ip (GstVideoFilter * base, GstVideoFrame * frame)
|
||||||
{
|
{
|
||||||
GstQROverlay *filter = GST_QR_OVERLAY (base);
|
GstQROverlay *filter = GST_QR_OVERLAY (base);
|
||||||
QRcode *qrcode;
|
QRcode *qrcode;
|
||||||
gchar *encode_string;
|
gchar *content;
|
||||||
|
GstClockTime rtime =
|
||||||
|
gst_segment_to_running_time (&GST_BASE_TRANSFORM (base)->segment,
|
||||||
|
GST_FORMAT_TIME, GST_BUFFER_PTS (frame->buffer));
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (outbuf)))
|
if (GST_CLOCK_TIME_IS_VALID (rtime))
|
||||||
gst_object_sync_values (GST_OBJECT (filter), GST_BUFFER_TIMESTAMP (outbuf));
|
gst_object_sync_values (GST_OBJECT (filter), rtime);
|
||||||
encode_string = build_string (base, outbuf);
|
|
||||||
GST_INFO_OBJECT (filter, "String will be encoded : %s", encode_string);
|
content = get_qrcode_content (filter, frame->buffer);
|
||||||
|
GST_INFO_OBJECT (filter, "String will be encoded : %s", content);
|
||||||
qrcode =
|
qrcode =
|
||||||
QRcode_encodeString ((const char *) encode_string, 0,
|
QRcode_encodeString (content, 0, filter->qrcode_quality, QR_MODE_8, 0);
|
||||||
filter->qrcode_quality, QR_MODE_8, 0);
|
|
||||||
g_free (encode_string);
|
|
||||||
if (qrcode) {
|
if (qrcode) {
|
||||||
GST_DEBUG_OBJECT (filter, "String encoded");
|
GST_DEBUG_OBJECT (filter, "String encoded");
|
||||||
overlay_qr_in_frame (filter, qrcode, outbuf);
|
overlay_qr_in_frame (filter, qrcode, frame);
|
||||||
filter->frame_number++;
|
filter->frame_number++;
|
||||||
} else
|
} else {
|
||||||
GST_WARNING_OBJECT (filter, "Could not encode the string");
|
GST_WARNING_OBJECT (filter, "Could not encode content: %s", content);
|
||||||
|
}
|
||||||
|
g_free (content);
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,20 +23,17 @@
|
|||||||
#define __GST_QR_OVERLAY_H__
|
#define __GST_QR_OVERLAY_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstbasetransform.h>
|
#include <gst/video/gstvideofilter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
#define GST_TYPE_QR_OVERLAY (gst_qr_overlay_get_type())
|
#define GST_TYPE_QR_OVERLAY (gst_qr_overlay_get_type())
|
||||||
G_DECLARE_FINAL_TYPE (GstQROverlay, gst_qr_overlay, GST, QR_OVERLAY,
|
G_DECLARE_FINAL_TYPE (GstQROverlay, gst_qr_overlay, GST, QR_OVERLAY, GstVideoFilter);
|
||||||
GstBaseTransform);
|
|
||||||
|
|
||||||
struct _GstQROverlay
|
struct _GstQROverlay
|
||||||
{
|
{
|
||||||
GstBaseTransform element;
|
GstVideoFilter parent;
|
||||||
|
|
||||||
guint32 frame_number;
|
guint32 frame_number;
|
||||||
guint32 width;
|
|
||||||
guint32 height;
|
|
||||||
gfloat qrcode_size;
|
gfloat qrcode_size;
|
||||||
guint qrcode_quality;
|
guint qrcode_quality;
|
||||||
guint array_counter;
|
guint array_counter;
|
||||||
|
@ -4,7 +4,7 @@ if qrencode_dep.found()
|
|||||||
gstqroverlay = library('gstqroverlay', ['gstqroverlay.c'],
|
gstqroverlay = library('gstqroverlay', ['gstqroverlay.c'],
|
||||||
c_args : gst_plugins_bad_args,
|
c_args : gst_plugins_bad_args,
|
||||||
include_directories : [configinc],
|
include_directories : [configinc],
|
||||||
dependencies : [gstbase_dep, qrencode_dep, json_dep],
|
dependencies : [gstvideo_dep, qrencode_dep, json_dep],
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : plugins_install_dir,
|
install_dir : plugins_install_dir,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user