Compare commits

...

3 Commits

Author SHA1 Message Date
Sergey Lapin
e4f5f44f85 Using device property 2021-03-31 22:44:57 +03:00
Sergey Lapin
17193163d8 Implemented some properties 2021-03-29 16:24:02 +03:00
Sergey Lapin
61c1157d81 Hue/saturation controls, qtmultimedia viewfinder works 2021-03-28 22:29:29 +03:00
4 changed files with 127 additions and 50 deletions

View File

@@ -36,6 +36,10 @@ enum
PROP_CAPS,
PROP_SYNC,
PROP_NUM_BUFFERS,
PROP_TEST_PATTERN,
PROP_HUE,
PROP_DEVICE,
PROP_MODE
};
@@ -131,7 +135,8 @@ gst_pinesrcbin_constructed (GObject * object)
G_OBJECT_CLASS (parent_class)->constructed (object);
self->type_klass = (self->flag == GST_ELEMENT_FLAG_SINK) ? "Sink" : "Source";
self->filter_caps = gst_static_caps_get (&raw_video_caps);
gst_pinesrcbin_get_gst_caps_data("rear", &width, &height, &format, &interval);
gst_pinesrcbin_get_gst_caps_data(self->device, &width, &height, &format, &interval);
self->filter_caps = gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, format,
/* we "flip" interval to get frame rate */
@@ -156,6 +161,7 @@ gst_pinesrcbin_dispose (GObject * object)
{
GstPineSrcBin *self = GST_PINESRCBIN (object);
GST_DEBUG_OBJECT (self, "gst_pinesrcbin_dispose: dispose");
gst_pinesrcbin_clear_kid (self);
if (self->filter_caps)
@@ -187,6 +193,31 @@ gst_pinesrcbin_set_property (GObject * object, guint prop_id,
if (self->kid)
g_object_set_property (G_OBJECT (self->kid), pspec->name, value);
break;
case PROP_TEST_PATTERN:
self->test_pattern = g_value_get_int (value);
g_print("setting prop test-pattern: %d\n", self->test_pattern);
set_camera_control(self->device, CONTROL_TEST_PATTERN, self->test_pattern);
break;
case PROP_HUE:
self->hue = g_value_get_int (value);
g_print("setting prop hue: %d\n", self->hue);
set_camera_control(self->device, CONTROL_HUE, self->hue);
break;
case PROP_MODE:
self->mode = g_value_get_int (value);
g_print("setting prop mode: %d\n", self->mode);
break;
case PROP_DEVICE:
{
const char * devname = g_value_get_int (value);
g_print("setting prop device: %s\n", devname);
if (devname && strlen(devname) > 0) {
if (self->device)
g_free(self->device);
self->device = g_strdup(devname);
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -209,6 +240,21 @@ gst_pinesrcbin_get_property (GObject * object, guint prop_id,
case PROP_NUM_BUFFERS:
g_value_set_int (value, self->num_buffers);
break;
case PROP_TEST_PATTERN:
g_value_set_int (value, self->test_pattern);
break;
case PROP_HUE:
g_print("getting prop hue: %d\n", self->hue);
g_value_set_int (value, self->hue);
break;
case PROP_MODE:
g_print("getting prop mode: %d\n", self->mode);
g_value_set_int (value, self->mode);
break;
case PROP_DEVICE:
g_print("getting prop device: %s\n", "");
g_value_set_string (value, "");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -221,6 +267,8 @@ gst_pinesrcbin_detect (GstPineSrcBin * self)
GstElement *kid, *filter;
GstPad *target;
GstPineSrcBinClass *klass = GST_PINESRCBIN_GET_CLASS (self);
g_print ("gst_pinesrcbin_detect\n");
GST_DEBUG_OBJECT (self, "gst_pinesrcbin_detect: setting up element");
gst_pinesrcbin_clear_kid (self);
@@ -303,6 +351,7 @@ gst_pinesrcbin_change_state (GstElement * element, GstStateChange transition)
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstPineSrcBin *sink = GST_PINESRCBIN (element);
GST_DEBUG_OBJECT (sink, "gst_pinesrcbin_change_state: state change");
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_pinesrcbin_detect (sink))
@@ -333,6 +382,7 @@ gst_pinesrcbin_class_init (GstPineSrcBinClass * klass)
GObjectClass *gobject_class;
GstElementClass *eklass;
g_print ("Class init\n");
gobject_class = G_OBJECT_CLASS (klass);
eklass = GST_ELEMENT_CLASS (klass);
@@ -349,7 +399,23 @@ gst_pinesrcbin_class_init (GstPineSrcBinClass * klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS,
g_param_spec_int ("num-buffers", "Num-buffers",
"Number of buffers until EOS, -1 = unlimited", -1, INT_MAX, 1000,
"Number of buffers until EOS, -1 = unlimited", -1, INT_MAX, -1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_TEST_PATTERN,
g_param_spec_int ("test-pattern", "Test-pattern",
"Test pattern for camera to display", 0, INT_MAX, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_HUE,
g_param_spec_int ("hue", "Hue",
"Set image hue", 0, 65535, 128,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_DEVICE,
g_param_spec_string ("device", "Device",
"Device", "",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MODE,
g_param_spec_int ("mode", "Mode",
"Set image hue", 1, 2, 1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
@@ -358,10 +424,16 @@ GST_DEBUG_CATEGORY (pinesrcbin_debug);
static void
gst_pinesrcbin_init (GstPineSrcBin * self)
{
g_print ("Plugin init\n");
self->sync = DEFAULT_SYNC;
self->num_buffers = -1;
self->test_pattern = 0;
self->hue = 128;
self->mode = 1;
self->device = g_strdup("front");
g_print("initial hue: %d\n", self->hue);
GST_DEBUG_OBJECT (self, "Starting device configuration");
gst_pinesrcbin_configure_device(self, "rear");
self->sync = DEFAULT_SYNC;
self->num_buffers = 1000;
}
static gboolean
@@ -369,8 +441,9 @@ plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (pinesrcbin_debug, "pinesrcbin", 0,
"pinephone v4lsrc camera wrapper");
return gst_element_register (plugin, "pinesrcbin",
gst_element_register (plugin, "pinesrcbin",
GST_RANK_NONE, GST_TYPE_PINESRCBIN);
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,

View File

@@ -31,6 +31,9 @@ typedef struct _GstPineSrcBin
gboolean autofocus;
/* Buffers till EOS */
int num_buffers;
int test_pattern;
int hue;
int mode;
} GstPineSrcBin;
#endif

View File

@@ -1,3 +1,7 @@
/* insert copyright here *
* THE manual: https://www.kernel.org/doc/html/v5.7/media/uapi/mediactl/media-ioc-g-topology.html
*/
#include <stdint.h>
#include <stdio.h>
@@ -82,13 +86,14 @@ struct camera_data {
int subdev_fd;
const struct media_v2_entity *entity;
const struct media_v2_interface *interface;
const struct media_v2_pad *pad;
int gain_ctrl;
int gain_max;
char devnode_path[261];
};
struct camera_config configurations[] = {
{"front", "gc2145", 320, 240, MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_SBGGR8_1X8, {1, 15}},
{"rear", "ov5640", 320, 240, MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_SBGGR8_1X8, {1, 15}},
{"front", "gc2145", 320, 240, MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_SBGGR8_1X8, {1, 15}},
{"rear", "ov5640", 1280, 720, MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_SBGGR8_1X8, {1, 30}},
};
struct camera_data cam_store[] = {
{},
@@ -216,48 +221,6 @@ static void disable_all_links(struct device_data *dev)
setup_link(dev, source_pad->id, sink_pad->id, FALSE);
}
}
#if 0
const struct media_v2_link *plink =
gst_pinesrcbin_get_link_from_entity(dev,
dev->entities[i].id);
if (plink) {
g_print("link %d %08x %08x: %08x\n", plink->id, plink->source_id, plink->sink_id, plink->flags);
if (plink->flags & MEDIA_LNK_FL_ENABLED) {
uint32_t link_type = plink->flags & MEDIA_LNK_FL_LINK_TYPE;
if (link_type == MEDIA_LNK_FL_DATA_LINK) {
g_print("data link %d\n", plink->id);
setup_link(dev, plink->source_id, plink->sink_id, FALSE);
} else if (link_type == MEDIA_LNK_FL_INTERFACE_LINK) {
struct media_v2_interface *iface = st_pinesrcbin_get_interface_by_id(dev, plink->source_id);
g_print("interface link %d entity: %d\n", plink->id, iface->);
continue;
}
const struct media_v2_pad *source_pad, *sink_pad;
g_print("link %d is active\n", plink->id);
source_pad = gst_pinesrcbin_get_pad_from_entity(dev, plink->source_id);
sink_pad = gst_pinesrcbin_get_pad_from_entity(dev, plink->sink_id);
g_assert(source_pad);
g_assert(sink_pad);
setup_link(dev, source_pad->id, sink_pad->id, FALSE);
#if 0
struct media_link_desc link = {};
link.flags = 0;
link.source.entity = plink->source_id;
link.source.index = 0;
link.sink.entity = plink->sink_id;
link.sink.index = 0;
if (xioctl(dev->fd, MEDIA_IOC_SETUP_LINK, &link) == -1)
g_printerr("MEDIA_IOC_SETUP_LINK: %d %s", errno, strerror(errno));
#endif
#if 0
/* TODO: maintain own links structure */
else
plink->flags = 0;
#endif
}
}
}
#endif
}
static struct device_data *
@@ -342,6 +305,7 @@ setup_gain(int fd, int *gain_ctrl, int *gain_max)
*gain_max = ctrl.maximum;
return;
}
camera_control(fd, *gain_ctrl, VIDIOC_S_EXT_CTRLS, gain_max);
}
static gboolean
@@ -517,6 +481,24 @@ get_camera_data(const char *conf_name)
return &cam_store[conf];
}
}
void set_camera_control(const char * conf_name, int control, int value)
{
struct camera_data *cam_data = get_camera_data(conf_name);
switch(control) {
case CONTROL_HUE:
g_print("configuring hue = %d\n", value);
camera_control (cam_data->subdev_fd, V4L2_CID_HUE, VIDIOC_S_EXT_CTRLS, &value);
break;
case CONTROL_SATURATION:
g_print("configuring saturation = %d\n", value);
camera_control (cam_data->subdev_fd, V4L2_CID_SATURATION, VIDIOC_S_EXT_CTRLS, &value);
break;
case CONTROL_TEST_PATTERN:
g_print("configuring test pattern = %d\n", value);
camera_control (cam_data->subdev_fd, V4L2_CID_TEST_PATTERN, VIDIOC_S_EXT_CTRLS, &value);
break;
}
}
void gst_pinesrcbin_configure_device(GstPineSrcBin * self, const char *conf_name)
{
struct camera_config *conf;
@@ -565,7 +547,7 @@ void gst_pinesrcbin_configure_device(GstPineSrcBin * self, const char *conf_name
if (!self->v4l2entity)
g_error ("can't find entity sun6i-csi\n");
GST_DEBUG_OBJECT (self, "sink entity: %d %s\n", self->v4l2entity->id, self->v4l2entity->name);
/* This is sink pad (for host controller) */
/* This is sink pad (for media controller) */
self->v4l2pad =
gst_pinesrcbin_get_pad_from_entity (self->media_if, self->v4l2entity->id);
GST_DEBUG_OBJECT (self, "sink pad: %d\n", self->v4l2pad->id);
@@ -591,6 +573,8 @@ void gst_pinesrcbin_configure_device(GstPineSrcBin * self, const char *conf_name
disable_all_links(self->media_if);
cam_data->entity = gst_pinesrcbin_find_media_entity(self->media_if, conf->camera_name);
GST_DEBUG_OBJECT (self, "camera: %s: source interface entity %d\n", conf->camera_name, cam_data->entity->id);
cam_data->pad =
gst_pinesrcbin_get_pad_from_entity (self->media_if, cam_data->entity->id);
cam_data->interface =
gst_pinesrcbin_get_entity_interface (self->media_if,
@@ -612,10 +596,19 @@ void gst_pinesrcbin_configure_device(GstPineSrcBin * self, const char *conf_name
camera_control (cam_data->subdev_fd, V4L2_CID_FOCUS_AUTO, VIDIOC_S_EXT_CTRLS, &enable);
}
setup_gain (cam_data->subdev_fd, &cam_data->gain_ctrl, &cam_data->gain_max);
self->test_pattern = 1;
camera_control (cam_data->subdev_fd, V4L2_CID_TEST_PATTERN, VIDIOC_S_EXT_CTRLS, &self->test_pattern);
{
int auto_gain = 1;
camera_control (cam_data->subdev_fd, V4L2_CID_AUTOGAIN, VIDIOC_S_EXT_CTRLS, &auto_gain);
}
set_camera_control(conf_name, CONTROL_HUE, self->hue);
/* now configuring camera modes */
GST_DEBUG_OBJECT (self, "configuring camera modes\n");
subdev_set_mode(cam_data->subdev_fd, conf->width,
conf->height, conf->bus_code_video,
conf->frame_interval);
GST_DEBUG_OBJECT (self, "enabling link for %s\n", conf->camera_name);
setup_link(self->media_if, cam_data->pad->id, self->v4l2pad->id, TRUE);
}

View File

@@ -18,9 +18,17 @@ struct device_data
struct media_v2_link *links;
size_t num_links;
};
enum {
CONTROL_HUE,
CONTROL_SATURATION,
CONTROL_TEST_PATTERN,
};
void gst_pinesrcbin_configure_device(GstPineSrcBin * self, const char *conf_name);
void gst_pinesrcbin_get_gst_caps_data(const char * conf_name,
int *width, int * height, const char **format,
struct v4l2_fract *interval);
void set_camera_control(const char * conf_name, int control, int value);
#endif