opencv / opencv

Open Source Computer Vision Library
https://opencv.org
Apache License 2.0
75.95k stars 55.62k forks source link

Now there is no way to control GStreamer drop timeout when ip-camera drops #22868

Closed qwertyfive closed 1 year ago

qwertyfive commented 1 year ago

Descripe the feature and motivation

I'm using OpenCV with GStreamer, and sometimes my camera can disconnect. And when its happened, i just have program freezing for 20 s. And (maybe i didn't find) there is no way to change that timeout. Similar thing - is CAP_PROP_READ_TIMEOUT_MSEC for ffmpeg, but it didnt work for GStreamer.

Additional context

No response

kallaballa commented 1 year ago

Hi! I am a contributor. The obvious thing to do would be to set a timeout on the v4l2src element, but it simply doesn't provide that option (unlike e.g. udpsrc). Maybe you could workaround it using the watchdog element

for example:

cv::VideoCapture capture("v4l2src device=/dev/video1 ! watchdog timeout=1000 ! appsink", cv::CAP_GSTREAMER, {});
qwertyfive commented 1 year ago

Actually, im using rtspsrc and there is some timeouts, but they do not change anything(like tcp-timeout which is 20s just reduce open timeout, but not read)

kallaballa commented 1 year ago

And did you try watchdog as an alternative?

qwertyfive commented 1 year ago

Hey, it actually worked! Thank you so much, i`ve been looking for solution for 2 days! Thank you so much!

qwertyfive commented 1 year ago

Hmm, it worked with cmd directly to gstreamer, but still have issue with opencv. That strange!

qwertyfive commented 1 year ago

My pipeline:

string ns = " rtspsrc protocols=tcp location=" + s + " retry=1 latency=0 tcp-timeout=1 buffer-mode=1 ! watchdog timeout=1000 ! decodebin ! videoconvert ! videorate ! video/x-raw,framerate=25/1 ! appsink";

qwertyfive commented 1 year ago

Interesting thing - what happened when we write incorrect pipeline? Why and how opencv ignore wrong parts? Maybe this is the key? Like when i try watchdog timeout=1000 ! rtspsrc location=rtsp://my-link:8554 latency=0 ! decodebin ! autovideosink (console), it drops me with error (Could not link watchdog to rtspsrc), but when i try this with opencv, it just timeout after watchdog timeout(after begining of program)

kallaballa commented 1 year ago

Could you please:

qwertyfive commented 1 year ago

Im suppose to do this on CMake list, am I? Cause im using Windows OpenCV build, then add libs and include to my project with VS 19, and dont understand, how am i suppose to do second part of your ask)

kallaballa commented 1 year ago

Oh, I didn't catch that you are on Windows. Instead of export you can use the cmd command set or the GUI

I can't test it on my side, but the following should work:

set OPENCV_LOG_LEVEL=VERBOSE
set OPENCV_VIDEOIO_DEBUG=1
set OPENCV_VIDEOCAPTURE_DEBUG=1
your_command.exe
qwertyfive commented 1 year ago

Log.txt My code:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    string s = "rtsp://192.168.144.25:8554";
    string ns = " rtspsrc protocols=tcp location=" + s + " retry=1 latency=0 tcp-timeout=100000 buffer-mode=1 ! watchdog timeout=2000 ! decodebin ! videoconvert ! videorate ! video/x-raw,framerate=25/1 ! appsink";

    VideoCapture cap(ns, CAP_GSTREAMER);
    Mat frame;

    if (!cap.isOpened())
    {
        cout << "NO CONNECTION" << endl;
        return -1;
    }

    while (cap.isOpened())
    {
        cap >> frame;
        if (frame.empty())
        {
            cout << "EMPTY FRAME" << endl;
            return -1;
        }

        imshow("GG", frame);
        waitKey(1);
    }
    return 0;
}
kallaballa commented 1 year ago

The pipeline doesn't seem to be the problem, because the following works for me (on Linux):

cv::VideoCapture capture("rtspsrc protocols=tcp location=rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4 retry=1 latency=0 tcp-timeout=100000 buffer-mode=1 ! watchdog timeout=2000 ! decodebin ! videoconvert ! videorate ! video/x-raw,framerate=25/1 ! appsink", cv::CAP_GSTREAMER, {});

Could you try again and use the rtsp-url i used? rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4

qwertyfive commented 1 year ago

Same problem. Did u disconnect your network when testing this? I have this issue when i disconnect my camera(or when i trying test rtsp stream and then just drop my internet connection)

kallaballa commented 1 year ago

Yes I did, and watchdog worked.

qwertyfive commented 1 year ago

I`ve tried that on my friend linux pc, and he still have same issue

kallaballa commented 1 year ago

I don't fully understand what your problem at the moment is. The log file you supplied looks good. Stream is running until watchdog triggers and ends it.

qwertyfive commented 1 year ago

u can see, that there is no logs between 6 and 26 sec - this is when programm freeze

qwertyfive commented 1 year ago

What happened, if you play this test stream and then enable airplane mode?

kallaballa commented 1 year ago

You are right. I have the same problem now. Investigating

kallaballa commented 1 year ago

There seems to be a problem with error propagation because this works (it terminates ~2 seconds after i shut down my network interface):

gst-launch-1.0 -v rtspsrc protocols=tcp location=rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4 udp-reconnect=false udp-buffer-size=1024 timeout=0 retry=0 latency=1000 do-retransmission=false buffer-mode=0 ! watchdog timeout=2000 ! decodebin ! videoconvert ! videorate ! video/x-raw,framerate=25/1 ! autovideosink

While this doesn't (watchdog triggers but no immediate reaction to the error on the gstreamer-bus):

cv::VideoCapture capture("rtspsrc protocols=tcp location=rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4 udp-reconnect=false udp-buffer-size=1024 timeout=0 retry=0 latency=1000 do-retransmission=false buffer-mode=0 ! watchdog timeout=2000 ! decodebin ! videoconvert ! videorate ! video/x-raw,framerate=25/1 ! appsink", cv::CAP_GSTREAMER, {});
qwertyfive commented 1 year ago

Yeah, this is why i`ve been so happy yesterday, when u told me about watchdog. It works directly with gstreamer(from cmd or terminal), but have some troubles with opencv(

kallaballa commented 1 year ago

I am familiar with Gstreamer but not with the OpenCV/Gstreamer backend. I need time... wanted to read that code anyway. Maybe in the meantime someone more enlightened can help :)

qwertyfive commented 1 year ago

I hope so) Maybe someone else notice that issue)

asmorkalov commented 1 year ago

Some findings on the issue: According to GStreamer documentation, watchdog sends message to the pipeline bus, but does not change pipeline state. Proof: https://gstreamer.freedesktop.org/documentation/debugutilsbad/watchdog.html?gi-language=c. OpenCV does not have permanent bus event handler, but check messages time-to-time in open/close to check operation status. See https://github.com/opencv/opencv/blob/4.x/modules/videoio/src/cap_gstreamer.cpp#L2376 and how it's used. OpenCV grabFrame waits for the next frame with gst_app_sink_pull_sample which does not have timeout and fails only if the pipeline changes its state. See https://github.com/opencv/opencv/blob/4.x/modules/videoio/src/cap_gstreamer.cpp#L494.

Options I see:

qwertyfive commented 1 year ago

Hmm, why they dont use gst_app_sink_try_pull_sample with some kind of timeout that can be set? I think that could help, i'll try this myself, and if this will help, it's gonna be good update for OpenCV?)

qwertyfive commented 1 year ago

Yeah, it works. Maybe we need request for that like - Change gst_app_sink_pull_sample for gstreamer backend to gst_app_sink_try_pull_sample with new addition Parameter like CAP_PROP_GST_READ_TIMEOUT?

kallaballa commented 1 year ago

I'm just a contributor and not familiar yet with the Gstreamer backend, but from what I've seen by now that sounds like a good idea.

asmorkalov commented 1 year ago

Sounds like good solution. I'll take a look on technical details and return back with patch. Fill free to contribute, if you are ready.

qwertyfive commented 1 year ago

No, thank you, i'm not sure i can do that properly)

asmorkalov commented 1 year ago

@qwertyfive I added timeouts in https://github.com/opencv/opencv/pull/22919. Could you try my branch with timeouts and report status to the PR.

asmorkalov commented 1 year ago

Merged

asmorkalov commented 1 year ago

BTW, You need GStreamer 1.10 or newer to use the feature.

linglongxian commented 11 months ago

@qwertyfive hello, did you solve the problem? if yes, could you share your solution?

qwertyfive commented 11 months ago

@qwertyfive hello, did you solve the problem? if yes, could you share your solution?

Already added in #22919, so you can use it

qwertyfive commented 11 months ago

@qwertyfive hello, did you solve the problem? if yes, could you share your solution?

use CAP_PROP_OPEN_TIMEOUT_MSEC and CAP_PROP_READ_TIMEOUT_MSEC

linglongxian commented 11 months ago

@qwertyfive ok, thanks for your reply. i will rebuild my opencv and test it