diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d3ca52..ab2aa1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. -## [1.0.0] - 2024-08-09 -### Added +## [1.0.0] - 2024-08-14 +## Added - added script to generate release notes +- added python example to show use of pylonmeta from pyth + * fixes #114 ### Fixed - NVMM image width is in byte not pixels! @@ -13,6 +15,11 @@ All notable changes to this project will be documented in this file. * fixes #54 - Proper init/terminate of pylon sdk from gst-plugin-scanner * avoids output of an exception message after new install +- Removed unused pylonc library dependency + +### Changed +- Only export external header files to access PylonMeta + ## [0.7.3] - 2024-07-30 ### Added diff --git a/bindings/meson.build b/bindings/meson.build index 190af5f..7c3230d 100644 --- a/bindings/meson.build +++ b/bindings/meson.build @@ -1,7 +1,7 @@ py_mod = import('python') py3 = py_mod.find_installation('python3') py3_dep = py3.dependency() -message(py3.path()) +message(py3.full_path()) message(py3.get_install_dir()) pygstpylon_sources = [ diff --git a/ext/pylon/gstpylonsrc.cpp b/ext/pylon/gstpylonsrc.cpp index 53e3f2e..75e5f62 100644 --- a/ext/pylon/gstpylonsrc.cpp +++ b/ext/pylon/gstpylonsrc.cpp @@ -211,40 +211,8 @@ G_DEFINE_TYPE_WITH_CODE(GstPylonSrc, gst_pylon_src, GST_TYPE_PUSH_SRC, G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY, gst_pylon_src_child_proxy_init)); -static GstStateChangeReturn gst_pylon_change_state(GstElement *element, - GstStateChange transition) { - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - /* initialize the pylon SDK */ - Pylon::PylonInitialize(); - break; - - default: - break; - } - - // Call the parent class's change_state method - ret = GST_ELEMENT_CLASS(gst_pylon_src_parent_class) - ->change_state(element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - /* shutdown the pylon SDK */ - Pylon::PylonTerminate(); - break; - - default: - break; - } - - return ret; -} - static void gst_pylon_src_class_init(GstPylonSrcClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstElementClass *element_class = GST_ELEMENT_CLASS(klass); GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS(klass); GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS(klass); gchar *cam_params = NULL; @@ -418,7 +386,6 @@ static void gst_pylon_src_class_init(GstPylonSrcClass *klass) { base_src_class->stop = GST_DEBUG_FUNCPTR(gst_pylon_src_stop); base_src_class->unlock = GST_DEBUG_FUNCPTR(gst_pylon_src_unlock); base_src_class->query = GST_DEBUG_FUNCPTR(gst_pylon_src_query); - element_class->change_state = GST_DEBUG_FUNCPTR(gst_pylon_change_state); push_src_class->create = GST_DEBUG_FUNCPTR(gst_pylon_src_create); } @@ -800,6 +767,9 @@ static gboolean gst_pylon_src_start(GstBaseSrc *src) { } GST_OBJECT_LOCK(self); + + Pylon::PylonInitialize(); + GST_INFO_OBJECT( self, "Attempting to create camera device with the following configuration:" @@ -857,6 +827,9 @@ static gboolean gst_pylon_src_start(GstBaseSrc *src) { ("%s", error->message)); g_error_free(error); + /* no camera found. Stop pylon SDK */ + Pylon::PylonTerminate(); + out: return ret; } @@ -879,6 +852,8 @@ static gboolean gst_pylon_src_stop(GstBaseSrc *src) { gst_pylon_free(self->pylon); self->pylon = NULL; + Pylon::PylonTerminate(); + return ret; } diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index 0d6b410..90d513b 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -13,7 +13,7 @@ if target_machine.system() == 'linux' and (pylon_path == 'PYLON_ROOT_NOT_SET' or endif # detect pylon 7.x -pylon_dep = dependency('pylon', method : 'cmake', modules : ['pylon::pylon'], +pylon_dep = dependency('pylon', method : 'cmake', modules : ['pylon::PylonBase', 'pylon::PylonUtility'], version : '>=7.1', cmake_args : [ '-DCMAKE_PREFIX_PATH=' + pylon_path / 'share/pylon/cmake/', '-DPYLON_ROOT=' + pylon_path ] , required: false) if pylon_dep.found() @@ -43,14 +43,7 @@ gstpylon_sources = [ gstpylon_headers = [ 'gstpylon-prelude.h', - 'gstpyloncache.h', - 'gstpylondebug.h', - 'gstpylonfeaturewalker.h', - 'gstpylonintrospection.h', 'gstpylonmeta.h', - 'gstpylonmetaprivate.h', - 'gstpylonobject.h', - 'gstpylonparamspecs.h', ] install_headers(gstpylon_headers, subdir : 'gstreamer-1.0/gst/pylon/') diff --git a/packaging/debian/control b/packaging/debian/control index c734f84..05d255a 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -10,28 +10,39 @@ Build-Depends: debhelper-compat (= 11), python3-dev, libgstreamer1.0-dev, libgstreamer-plugins-base1.0-dev, - pylon (= 7.5.0.15658-deb0), + pylon (= 7.5.0.15658-deb0) | pylon (= 7.4.0.14900-deb0) | pylon (= 7.2.1.25747-deb0) , deepstream-6.3 | deepstream-6.4 | deepstream-7.0 Standards-Version: 4.5.0 Homepage: https://github.com/basler/gst-plugin-pylon Package: gst-plugin-pylon Architecture: any -Depends: libc6, pylon (= 7.5.0.15658-deb0), ${misc:Depends}, gstreamer1.0-plugins-base, deepstream-6.3 | deepstream-6.4 | deepstream-7.0 +Depends: libc6, + pylon (= 7.5.0.15658-deb0) | pylon (= 7.4.0.14900-deb0) | pylon (= 7.2.1.25747-deb0) , + ${misc:Depends}, + gstreamer1.0-plugins-base, + deepstream-6.3 | deepstream-6.4 | deepstream-7.0 Description: GStreamer plugin for Basler cameras This plugin allows the use of any Basler 2D camera (supported by Basler pylon Camera Software Suite) as a source element in a GStreamer pipeline. Package: gst-plugin-pylon-dev Architecture: any -Depends: pylon (= 7.5.0.15658-deb0), ${misc:Depends}, gst-plugin-pylon +Depends: pylon (= 7.5.0.15658-deb0) | pylon (= 7.4.0.14900-deb0) | pylon (= 7.2.1.25747-deb0) , + ${misc:Depends}, + gst-plugin-pylon Description: Development files for GStreamer plugin for Basler cameras This package contains the development files for the GStreamer plugin for Basler cameras. Package: python3-pygstpylon Architecture: any -Depends: libc6, python3, pylon (= 7.5.0.15658-deb0), ${misc:Depends}, gst-plugin-pylon, deepstream-6.3 | deepstream-6.4 | deepstream-7.0 +Depends: libc6, + python3, + pylon (= 7.5.0.15658-deb0) | pylon (= 7.4.0.14900-deb0) | pylon (= 7.2.1.25747-deb0) , + ${misc:Depends}, + gst-plugin-pylon, + deepstream-6.3 | deepstream-6.4 | deepstream-7.0 Description: Python module to access pylon specific gstreamer metadata. The python module pygstpylon allows to extract pylon specific metadata from a buffer. diff --git a/packaging/debian/gst-plugin-pylon-dev.install b/packaging/debian/gst-plugin-pylon-dev.install index 10f2686..a00f330 100644 --- a/packaging/debian/gst-plugin-pylon-dev.install +++ b/packaging/debian/gst-plugin-pylon-dev.install @@ -1,2 +1,3 @@ +usr/include/gstreamer-1.0/gst/pylon/gstpylon-prelude.h usr/include/gstreamer-1.0/gst/pylon/gstpylonmeta.h usr/lib/*/pkgconfig/gstpylon-1.0.pc diff --git a/tests/examples/pylon/gstpylonmeta.py b/tests/examples/pylon/gstpylonmeta.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/examples/pylon/howto_decode_meta.py b/tests/examples/pylon/howto_decode_meta.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/examples/python/howto_access_meta.py b/tests/examples/python/howto_access_meta.py new file mode 100755 index 0000000..5b00c59 --- /dev/null +++ b/tests/examples/python/howto_access_meta.py @@ -0,0 +1,108 @@ +#! /bin/env python3 +import gi + +gi.require_version("Gst", "1.0") +gi.require_version("GstVideo", "1.0") # Import GstVideo +from gi.repository import Gst, GObject, GstVideo + +import pygstpylon + + +# Initialize GStreamer +Gst.init(None) + + +# Define the probe function +def probe_callback(pad, info): + # Get the buffer from the probe info + buffer = info.get_buffer() + + if buffer: + # Print buffer metadata + print("Buffer Metadata:") + + # Get buffer duration + duration = buffer.duration + print(f" Duration: {duration} nanoseconds") + + # Get buffer size + size = buffer.get_size() + print(f" Size: {size} bytes") + + # Print any additional metadata (e.g., timestamps) + pts = buffer.pts + dts = buffer.dts + print(f" PTS: {pts} nanoseconds") + print(f" DTS: {dts} nanoseconds") + + # Access GstVideoMeta + video_meta = GstVideo.buffer_get_video_meta(buffer) + if video_meta: + print("GstVideoMeta:") + print(f" Width: {video_meta.width}") + print(f" Height: {video_meta.height}") + print(f" Format: {video_meta.format}") + print(f" Number of Planes: {video_meta.n_planes}") + print(f" Stride: {video_meta.stride}") + print(f" Offsets: {video_meta.offset}") + + # Extract Pylon chunk data (if available) + pylon_meta = pygstpylon.gst_buffer_get_pylon_meta(hash(buffer)) + if pylon_meta: + print("Pylon Chunk Metadata:") + print(f" BlockID: {pylon_meta.block_id}") + print(f" Image Number: {pylon_meta.image_number}") + print(f" Offset X: {pylon_meta.offset_x}") + print(f" Offset Y: {pylon_meta.offset_y}") + print(f" Skipped Images: {pylon_meta.skipped_images}") + print(f" Stride: {pylon_meta.stride}") + print(f" Timestamp: {pylon_meta.timestamp}") + print(f" Chunks: {pylon_meta.chunks}") + + return Gst.PadProbeReturn.OK + + +# Create the GStreamer elements +pylon_source = Gst.ElementFactory.make("pylonsrc", "source") +fake_sink = Gst.ElementFactory.make("fakesink", "sink") + +# Check if elements were created successfully +if not pylon_source or not fake_sink: + print("Not all elements could be created.") + exit(-1) + +# Create an empty pipeline +pipeline = Gst.Pipeline.new("test-pipeline") + +# Add elements to the pipeline +pipeline.add(pylon_source) +pipeline.add(fake_sink) + +# Link the elements +pylon_source.link(fake_sink) + +# Add a probe to the source pad of the pylonsrc element +src_pad = pylon_source.get_static_pad("src") +if src_pad: + src_pad.add_probe(Gst.PadProbeType.BUFFER, probe_callback) + + +def stop_main_loop(): + print("Stopping the main loop after 10 seconds.") + main_loop.quit() # This will stop the main loop + + +# Start the pipeline +pipeline.set_state(Gst.State.PLAYING) + +# Create the main loop +main_loop = GObject.MainLoop() + +# Schedule the stop_main_loop function to be called after 10 seconds +GObject.timeout_add(1000, stop_main_loop) # 1000 milliseconds = 1 seconds + +print("Starting the main loop.") +main_loop.run() # This will run until quit() is called + +# Stop the pipeline +pipeline.set_state(Gst.State.NULL) diff --git a/tests/examples/python/snapshot_gpio.py b/tests/examples/python/snapshot_gpio.py index fac975f..35ae2c7 100755 --- a/tests/examples/python/snapshot_gpio.py +++ b/tests/examples/python/snapshot_gpio.py @@ -1,4 +1,4 @@ -#! /usr/bin/python3 +#! /bin/env python3 """ Copyright (C) 2023 Basler AG