Camera remains busy after being released by OpenCV?

I want to implement raw saving capability for my C++ application, so turned to v4l.
I am generally using OpenCV VideoCapture with a GStreamer pipeline to stream images from my camera,
but I want to be able to dynamically disable the VideoCapture, open a v4l session where I capture raws and then restart the GStreamer pipeline when I am done saving raw.

However I am having trouble starting V4L after I have had a GStreamer session open.
Even though I call release() and destroy the OpenCV Video Capture object, V4L is complaining that the device is still busy.

I am trying to figure out what’s causing the device to be busy, but so far I can’t
Both fuser -v /dev/video0 and lsof /dev/video0 print nothing

Any ideas what I can do to get past this?

This might be caused by a race condition in libnvargus_socket.so. The workaround would be to be sure to call opencv videoCapture release, such as using a sig handler if killing opencv app, but it might not be enough in some cases with recent L4T releases.

Hi,
Please try to re-start nvargus-daemon and check if it helps:

$ sudo service nvargus-daemon restart

Probably you don’t terminate the camera capture gracefully. Restarting daemon may hep the case.

@Honey_Patouceul this is interesting. Thanks for sharing. I didn’t know about the race in libnvargus_socket.so. In my case I am definitely calling release() on the VideoCapture, so the handle to the camera should be released. Also there are no crashes. I open a GST session with cv::VideoCapture, I run the session for a while, I close it.
The report I get from GST is a bit worrying as there is a GStreamer-CRITICAL message that i’ve not managed to figure out the root cause of, but other than that the function that deals with GST return a success.

GST_ARGUS: Cleaning up
(v4l_test:15008): GStreamer-CRITICAL **: 19:38:49.610: gst_mini_object_set_qdata: assertion 'object != NULL' failed
CONSUMER: Done Success
GST_ARGUS: Done Success

After this I call my v4l function, which successfully opens the device and returns a file descriptor. I am able to query device capabilities, I am able to list available formats, but as soon as I try to set the format with VIDIOC_S_FMT I get Device or resource busy

Hi @DaneLLL,

I am doing this in the same application without exiting. After the application is closed, if I start it again either as a GST session or a V4L session, all works fine. The problem happens only if I run the application and in the same run I start a GST session, I close it and after that I try to open a V4L session.

You may try to call 10 times cap.grab() just before cap.release(), so that events are dequeued. It seems to improve for my last tests.

Also be sure when using V4L API to set bypass_mode to 0. Argus uses that bypass, so don’t interfere with it.

1 Like

Trying to grab to dequeue queued frames was a great idea! Thanks. Unfortunately it didn’t help.
Yes, I have set bypass mode to 0.
Still the problem persists. I tried to swap the calls and first record RAW with V4L and then launch GST and this scenario works fine,
The problem only occurs when I run GStreamer first.
I will try to change my GST pipeline to use V4L instead of nvarguscamrasrc just to rule that out as a point of failure.

Ok, so nothing seems to work.
I tried a hacky approach to rule out OpenCV and GST as possible holders of the resource.
After I release the OpenCV VideoCapture I sleep the application for a while. Meanwhile I restart the nvargus daemon and then when the application wakes up, V4L was able to obtain the device handle and work as intended, so it seems that after GST has edgaged with the nvargus , the nvargus is left in a state that does not allow V4L to obtain a device handle while the process is alive. Only after the process dies does the handle actually become available, unless the nvargus daemon is restarted while the application is running, in which case the device is actually released.

I can of course hack it the brutal way with something along these lines:

myCap.release();
system("sudo systemctl restart nvargus-daemon.service");

But is there a graceful way to programatically restart nvargus daemon?
Or force it to release all handles?
I wonder what GST does that even after it is closed and I get these messages in the console

CONSUMER: Done Success
GST_ARGUS: Cleaning up
GST_ARGUS: Done Success

The device handle remains taken.

PS: Interestingly enough, since NVArgus still owns the handle I can reinitialize cv::VideoCapture with GST multiple times without a problem. The issue only becomes visible when I try to obtain the handle from elsewhere, like in my case v4l.

Any suggestions how to handle this problem?

For ruling out gstreamer, you may just use a system call in your app with gst-launch using the same pipeline for a given num-buffers instead of opencv videoCapture.

If this is ok with your V4L commands, then it may be an opencv issue. Seems using appsink drop=1 helps and doesn’t need the grabs.

But your case might be different, since you are changing the video mode.
You may get further details using a separate terminal with:

sudo su
systemctl stop nvargus-daemon.service
export enableCamPclLogs=5
export enableCamScfLogs=5
export enableCamCaptureLogs=5
/usr/sbin/nvargus-daemon

and compare working case with non working case.