Skip to content

Commit

Permalink
gst: set_trigger & software_trigger added for aravissrc
Browse files Browse the repository at this point in the history
Co-authored-by: WhaSukGO <leeju213@gmail.com>
  • Loading branch information
EmmanuelP and WhaSukGO committed Sep 4, 2024
1 parent fcacada commit 26d0ee3
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 10 deletions.
74 changes: 64 additions & 10 deletions gst/gstaravis.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <arvgvspprivate.h>
#include <time.h>
#include <string.h>
#include <stdio.h>

/* TODO: Add l10n */
#define _(x) (x)
Expand Down Expand Up @@ -67,11 +68,21 @@ enum
PROP_NUM_ARV_BUFFERS,
PROP_USB_MODE,
PROP_STREAM,
PROP_TRIGGER,
N_PROPERTIES
};

static GParamSpec *properties[N_PROPERTIES];

enum
{
/* actions */
SIGNAL_SOFTWARE_TRIGGER,
LAST_SIGNAL
};

static guint gst_aravis_signals[LAST_SIGNAL] = { 0 };

#define GST_TYPE_ARV_AUTO (gst_arv_auto_get_type())
static GType
gst_arv_auto_get_type (void)
Expand Down Expand Up @@ -133,7 +144,7 @@ gst_aravis_get_all_camera_caps (GstAravis *gst_aravis, GError **error)
int min_frame_rate_denominator;
int max_frame_rate_numerator;
int max_frame_rate_denominator;
gboolean is_frame_rate_available;
gboolean use_frame_rate;

g_return_val_if_fail (GST_IS_ARAVIS (gst_aravis), NULL);

Expand All @@ -146,8 +157,10 @@ gst_aravis_get_all_camera_caps (GstAravis *gst_aravis, GError **error)
if (!local_error) arv_camera_get_height_bounds (gst_aravis->camera, &min_height, &max_height, &local_error);
if (!local_error) pixel_formats = arv_camera_dup_available_pixel_formats (gst_aravis->camera, &n_pixel_formats,
&local_error);
is_frame_rate_available = arv_camera_is_frame_rate_available (gst_aravis->camera, NULL);
if (is_frame_rate_available) {
use_frame_rate = arv_camera_is_frame_rate_available (gst_aravis->camera, NULL) &&
gst_aravis->trigger_source == NULL;

if (use_frame_rate) {
if (!local_error) arv_camera_get_frame_rate_bounds (gst_aravis->camera,
&min_frame_rate, &max_frame_rate, &local_error);
if (!local_error) {
Expand All @@ -174,7 +187,7 @@ gst_aravis_get_all_camera_caps (GstAravis *gst_aravis, GError **error)
"width", GST_TYPE_INT_RANGE, min_width, max_width,
"height", GST_TYPE_INT_RANGE, min_height, max_height,
NULL);
if (is_frame_rate_available)
if (use_frame_rate)
gst_structure_set (structure,
"framerate", GST_TYPE_FRACTION_RANGE,
min_frame_rate_numerator, min_frame_rate_denominator,
Expand Down Expand Up @@ -395,6 +408,13 @@ gst_aravis_set_caps (GstBaseSrc *src, GstCaps *caps)
return result;
}

static void
gst_aravis_software_trigger (GstAravis *src) {
if (ARV_IS_CAMERA (src->camera)) {
arv_camera_software_trigger(src->camera, NULL);
}
}

static gboolean
gst_aravis_init_camera (GstAravis *gst_aravis, gboolean *notify, GError **error)
{
Expand All @@ -415,6 +435,8 @@ gst_aravis_init_camera (GstAravis *gst_aravis, gboolean *notify, GError **error)
if (!local_error) gst_aravis->payload = 0;
if (!local_error && arv_camera_is_uv_device (gst_aravis->camera))
arv_camera_uv_set_usb_mode (gst_aravis->camera, gst_aravis->usb_mode);
if (!local_error && gst_aravis->trigger_source != NULL)
arv_camera_set_trigger (gst_aravis->camera, gst_aravis->trigger_source, &local_error);

if (local_error) {
g_clear_object (&gst_aravis->camera);
Expand Down Expand Up @@ -615,15 +637,19 @@ gst_aravis_fixate_caps (GstBaseSrc * bsrc, GstCaps * caps)
gint width;
gint height;
double frame_rate = 0.0;
gboolean is_frame_rate_available;
gboolean use_frame_rate;

g_return_val_if_fail (GST_IS_ARAVIS (bsrc), NULL);

GST_OBJECT_LOCK (gst_aravis);

arv_camera_get_region (gst_aravis->camera, NULL, NULL, &width, &height, &error);
is_frame_rate_available = arv_camera_is_frame_rate_available (gst_aravis->camera, NULL);
if (is_frame_rate_available)
use_frame_rate = arv_camera_is_frame_rate_available (gst_aravis->camera, NULL) &&
gst_aravis->trigger_source == NULL;

if (use_frame_rate)
if (!error) frame_rate = arv_camera_get_frame_rate (gst_aravis->camera, &error);

GST_OBJECT_UNLOCK (gst_aravis);
if (error) {
GST_ELEMENT_ERROR (gst_aravis, RESOURCE, READ,
Expand All @@ -637,7 +663,7 @@ gst_aravis_fixate_caps (GstBaseSrc * bsrc, GstCaps * caps)

gst_structure_fixate_field_nearest_int (structure, "width", width);
gst_structure_fixate_field_nearest_int (structure, "height", height);
if (is_frame_rate_available)
if (use_frame_rate)
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
(double) (0.5 + frame_rate), 1);

Expand Down Expand Up @@ -676,6 +702,8 @@ gst_aravis_init (GstAravis *gst_aravis)
gst_aravis->buffer_timeout_us = GST_ARAVIS_BUFFER_TIMEOUT_DEFAULT;
gst_aravis->frame_rate = 0.0;

gst_aravis->trigger_source = NULL;

gst_aravis->camera = NULL;
gst_aravis->stream = NULL;

Expand Down Expand Up @@ -807,6 +835,12 @@ gst_aravis_set_property (GObject * object, guint prop_id,
case PROP_USB_MODE:
gst_aravis->usb_mode = g_value_get_enum (value);
break;
case PROP_TRIGGER:
GST_OBJECT_LOCK (gst_aravis);
g_free (gst_aravis->trigger_source);
gst_aravis->trigger_source = g_strdup (g_value_get_string (value));
GST_OBJECT_UNLOCK (gst_aravis);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -909,6 +943,11 @@ gst_aravis_get_property (GObject * object, guint prop_id, GValue * value,
GST_OBJECT_LOCK (gst_aravis);
g_value_set_object (value, gst_aravis->stream);
GST_OBJECT_UNLOCK (gst_aravis);
break;
case PROP_TRIGGER:
GST_OBJECT_LOCK (gst_aravis);
g_value_set_string (value, gst_aravis->trigger_source);
GST_OBJECT_UNLOCK (gst_aravis);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Expand Down Expand Up @@ -937,7 +976,7 @@ gst_aravis_query (GstBaseSrc *bsrc, GstQuery *query)
}

/* we must have a framerate */
if (src->frame_rate <= 0.0)
if (src->frame_rate <= 0.0 || src->trigger_source != NULL)
{
GST_WARNING_OBJECT (src, "Can't give latency since framerate isn't fixated !");
goto done;
Expand Down Expand Up @@ -1092,12 +1131,25 @@ gst_aravis_class_init (GstAravisClass * klass)
"Stream instance to retrieve additional information",
ARV_TYPE_STREAM,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
properties[PROP_TRIGGER] =
g_param_spec_string("trigger",
"Configure the trigger mode",
"Enable the trigger mode using the given source",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);

g_object_class_install_properties (gobject_class,
G_N_ELEMENTS (properties),
properties);

GST_DEBUG_CATEGORY_INIT (aravis_debug, "aravissrc", 0, "Aravis interface");
gst_aravis_signals[SIGNAL_SOFTWARE_TRIGGER] =
g_signal_new ("software-trigger", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstAravisClass,
software_trigger), NULL, NULL, NULL,
G_TYPE_NONE, 0);

GST_DEBUG_CATEGORY_INIT (aravis_debug, "aravissrc", 0, "Aravis interface");

gst_element_class_set_details_simple (element_class,
"Aravis Video Source",
Expand All @@ -1117,6 +1169,8 @@ gst_aravis_class_init (GstAravisClass * klass)
gstbasesrc_class->get_times = GST_DEBUG_FUNCPTR (gst_aravis_get_times);

gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_aravis_create);

klass->software_trigger = gst_aravis_software_trigger;
}

static gboolean
Expand Down
4 changes: 4 additions & 0 deletions gst/gstaravis.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,15 @@ struct _GstAravis {
guint64 timestamp_offset;
guint64 last_timestamp;

char *trigger_source;

char *features;
};

struct _GstAravisClass {
GstPushSrcClass parent_class;

void (*software_trigger) (GstAravis *src);
};

GType gst_aravis_get_type (void);
Expand Down
1 change: 1 addition & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ if get_option('tests')
py_script_config_data = configuration_data ()
py_script_config_data.set ('GI_TYPELIB_PATH', meson.project_build_root() / 'src')
py_script_config_data.set ('LD_LIBRARY_PATH', meson.project_build_root() / 'src')
py_script_config_data.set ('GST_PLUGIN_PATH', meson.project_build_root() / 'gst')
py_script_config_data.set ('FAKE_GENICAM_PATH', meson.project_source_root() / 'src' / 'arv-fake-camera.xml')
if get_option('gentl-producer')
py_script_config_data.set ('ARV_PRODUCER_PATH', gentl_producer_library.full_path())
Expand Down
1 change: 1 addition & 0 deletions tests/pylaunch-dbg.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

export GI_TYPELIB_PATH=@GI_TYPELIB_PATH@
export LD_LIBRARY_PATH=@LD_LIBRARY_PATH@
export GST_PLUGIN_PATH=@GST_PLUGIN_PATH@
export FAKE_GENICAM_PATH=@FAKE_GENICAM_PATH@
export ARV_PRODUCER_PATH=@ARV_PRODUCER_PATH@

Expand Down
1 change: 1 addition & 0 deletions tests/pylaunch.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

export GI_TYPELIB_PATH=@GI_TYPELIB_PATH@
export LD_LIBRARY_PATH=@LD_LIBRARY_PATH@
export GST_PLUGIN_PATH=@GST_PLUGIN_PATH@
export FAKE_GENICAM_PATH=@FAKE_GENICAM_PATH@
export ARV_PRODUCER_PATH=@ARV_PRODUCER_PATH@

Expand Down
82 changes: 82 additions & 0 deletions tests/python/arv-gst-software-trigger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python

# If you have installed aravis in a non standard location, you may need
# to make GI_TYPELIB_PATH point to the correct location. For example:
#
# export GI_TYPELIB_PATH=$GI_TYPELIB_PATH:/opt/bin/lib/girepositry-1.0/
#
# You may also have to give the path to libaravis.so, using LD_PRELOAD or
# LD_LIBRARY_PATH.
#
# As this example alos uses the aravis gstreamer plugin, you may need to tell the path to the plugin using
# GST_PLUGIN_PATH.

# Example of a gstreamer pipeline using a software trigger
#
# Author: WhaSukGO <leeju213@gmail.com>

import gi
import threading
import time

gi.require_version('Gst', '1.0')
from gi.repository import Gst, GLib

# Initialize GStreamer
Gst.init(None)

def main():

# Create GStreamer elements
aravissrc = Gst.ElementFactory.make("aravissrc", "source")
aravissrc.set_property("exposure", 1700)
aravissrc.set_property("do-timestamp", True)
aravissrc.set_property("trigger", "Software")

bayer_caps = Gst.Caps.from_string("video/x-bayer,format=rggb,width=800,height=600")
bayer2rgb = Gst.ElementFactory.make("bayer2rgb", "bayer2rgb")

videoconvert = Gst.ElementFactory.make("videoconvert", "videoconvert")

videosink = Gst.ElementFactory.make("autovideosink", "videosink")

# Create a new pipeline
pipeline = Gst.Pipeline.new("mypipeline")

# Add elements to the pipeline
pipeline.add(aravissrc)
pipeline.add(bayer2rgb)
pipeline.add(videoconvert)
pipeline.add(videosink)

# Link the elements with the capsfilter in between
aravissrc.link_filtered(bayer2rgb, bayer_caps)
bayer2rgb.link(videoconvert)
videoconvert.link(videosink)

# Function to trigger the camera
def trigger_camera():
while True:
time.sleep(0.5) # Sleep for 2 milliseconds (500fps)
aravissrc.emit("software-trigger")

# Create and start the trigger thread
trigger_thread = threading.Thread(target=trigger_camera)
trigger_thread.daemon = True # Daemonize thread so it exits when the main program does
trigger_thread.start()

# Start the pipeline
pipeline.set_state(Gst.State.PLAYING)

# Run the pipeline
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
pass

# Clean up
pipeline.set_state(Gst.State.NULL)

if __name__ == "__main__":
main()

0 comments on commit 26d0ee3

Please sign in to comment.