basler / gst-plugin-pylon

The official GStreamer plug-in for Basler cameras
BSD 3-Clause "New" or "Revised" License
40 stars 10 forks source link

camera reconnection #7

Open pthomasj opened 2 years ago

pthomasj commented 2 years ago

Is there a means to have the plugin periodically attempt to connect to a camera if it is not connected at startup or if it is disconnected while running?

thiesmoeller commented 2 years ago

Not yet implemented.

To poll for an unknown camera could only work with a full renegotiation of capabilities as they fully depend on the camera.

So it would require some bigger effort to get this right in any any condition. E.g depending on the camera model you might need a video converter in your already setup pipeline.

Easier is a keep alive mode, which will always try to reconnect a known camera in case of connection loss. Good idea !

pthomasj commented 2 years ago

Thank you! I was thinking in terms of a known camera in both cases.

pthomasj commented 2 years ago

What would be the best way to ask questions that may not be issues?

thiesmoeller commented 2 years ago

The issue tracker is the right place for any request to the software.

pthomasj commented 1 year ago

Would you happen to have any advice for tracking down the cause of incomplete buffer grabs? I have the packet size set to 8192, the MTU set to 9000, and jumbo frames are enabled on the switch. I'm not sure what to set the Inter-Packet Delay to, or if it will introduce a latency.

[2022-10-03 10:59:38.730][Critical] h1cam01 (40042910): Image acquisition on "h1cam01 (40042910)" failed! Error: "The buffer was incompletely grabbed. This can be caused by performance problems of the network hardware used, i.e. network adapter, switch, or ethernet cable. To fix this, try increasing the camera's Inter-Packet Delay in the Transport Layer category to reduce the required bandwidth, and adjust the camera's Packet Size setting to the highest supported frame size."

thiesmoeller commented 1 year ago

The bandwidth management of Basler cameras is in its factory settings set in a way to minimize latency on high performance hardware.

Especially increasing the inter packet delay parameter will allow to use switch hardware, that is not capable to handle the minimum interpacket delay as per IEEE spec.

We have in our full SDK a number of tools to find optimal settings for your hardware:

To configure your system to optimal values

https://docs.baslerweb.com/overview-of-the-pylon-gige-configurator

To make tests over longer time if and check the maximum reachable bandwidth

https://docs.baslerweb.com/bandwidth-manager

Question: At what framerate and resolution do you operate your camera?

-> and ... not as a fix, but as a workaround for e.g. viewing applications the next release will contain a property to control what to do in case of capture errors ( abort/skip/keep )

pthomasj commented 1 year ago

There are two cameras. One is an acA640-90gm and the other is an acA720-290gm. I have the framerate set in pylonsrc to 25/1. I am leaving the width and height unspecified. I think that means 659x494 and 728x544. Eventually this will go up to 10 cameras or so.

pthomasj commented 1 year ago

I have run the pylon-gige-configurator.

thiesmoeller commented 1 year ago

At 25/1 you have plenty of headroom to increase the inter packet delay to reduce the pressure on your system, or do you already set a non default value in userset or PFS file ?

pthomasj commented 1 year ago

No, I only just started playing around with that.

pthomasj commented 1 year ago

Thank you.

pthomasj commented 1 year ago

I see in the changelog for 0.4.0, "Add support for proper handling of a device disconnect". It does not appear to reconnect. Should this change have made it do so?

thiesmoeller commented 1 year ago

No this change only takes care of properly handling the disconnect itself ( shutting down pipeline, releasing allocated resources etc.) So at the moment we leave reconnect to the application at the moment.

Like discussed in this issue, a reconnect is tricky, as we have to record any property change during the life time of the camera and then replay the properties to recover the camera state before restarting the device and reconnecting to the pipeline....

This is technically possible but not yet implemented.

pthomasj commented 1 year ago

I didn't realize there was a way to reconnect in my application. What is the method for doing so?

michaelgruner commented 1 year ago

The recommended way would be to monitor de pipeline bus waiting for the disconnection error message. When received, you can set your pipeline to NULL and back to PLAYING again, once your camera is re-connected. Here’s a simple example on how to monitor bus messages:

https://github.com/GStreamer/gstreamer/blob/main/subprojects/gst-docs/examples/bus_example.c https://github.com/GStreamer/gstreamer/blob/main/subprojects/gst-docs/examples/bus_example.c

On 10 Oct 2022, at 12:03, pthomasj @.***> wrote:

I didn't realize there was a way to reconnect in my application. What is the method for doing so?

— Reply to this email directly, view it on GitHub https://github.com/basler/gst-plugin-pylon/issues/7#issuecomment-1273652938, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPIOFOMFYJPQI6YZURNZLWCRK55ANCNFSM562IGB3Q. You are receiving this because you are subscribed to this thread.

pthomasj commented 1 year ago

Should I set the pipeline to NULL and back to PLAYING in the bus message callback, like this?

gboolean bus_callback(GstBus* bus, GstMessage* message, gpointer user_data) {
    (void) bus;
    //GMainLoop *main_loop = (GMainLoop *) user_data;
    GstStateChangeReturn ret;

    switch (GST_MESSAGE_TYPE(message)) {
        case GST_MESSAGE_EOS: {
            g_print("End of stream\n");
            //g_main_loop_quit(main_loop);
            ret = gst_element_set_state(((gstreamer_data*) user_data)->pipeline, GST_STATE_NULL);
            if (ret == GST_STATE_CHANGE_FAILURE) {
                g_printerr("Unable to set the pipeline to the null state.\n");
            }

            sleep(1);

            ret = gst_element_set_state(((gstreamer_data*) user_data)->pipeline, GST_STATE_PLAYING);
            if (ret == GST_STATE_CHANGE_FAILURE) {
                g_printerr("Unable to set the pipeline to the playing state.\n");
            }

            break;
        }
        case GST_MESSAGE_ERROR: {
            GError *error;
            gchar *debug;
            gst_message_parse_error(message, &error, &debug);
            g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(message->src), error->message);
            g_error_free(error);
            g_printerr("Debugging information: %s\n", debug ? debug : "none");
            g_free(debug);
//            g_main_loop_quit(main_loop);
            ret = gst_element_set_state(((gstreamer_data*) user_data)->pipeline, GST_STATE_NULL);
            if (ret == GST_STATE_CHANGE_FAILURE) {
                g_printerr("Unable to set the pipeline to the null state.\n");
            }

            sleep(1);

            ret = gst_element_set_state(((gstreamer_data*) user_data)->pipeline, GST_STATE_PLAYING);
            if (ret == GST_STATE_CHANGE_FAILURE) {
                g_printerr("Unable to set the pipeline to the playing state.\n");
            }

            break;
        }
        default:
            //g_print("%s %s\n", GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message));
            break;
        }

    return TRUE;
}

If I do so then it stops with the following error when the camera is reconnected:

gige_gst_epics: /opt/pylon/include/pylon/BaslerUniversalConfigurationEventHandler.h:389: virtual Pylon::CBaslerUniversalConfigurationEventHandler::~CBaslerUniversalConfigurationEventHandler(): Assertion `(DebugGetEventHandlerRegistrationCount() == 0) && "Error: The event handler must not be destroyed while it is registered."' failed.
Aborted