QCamera::stop hangs or causes a crash. How to deinit the camera properly?
-
My program connects to the camera (
QCamera::start()), receives one viewfinder frame (via a customQAbstractVideoSurfacesublcass with overriddenpresentmethod), and then disconnects from the camera (by callingstopand then deleting the camera object).One of two things happen: either the
stopcall freezes indefinitely, or access violation occurs deep inside Qt multimedia after callingQCamera::~QCamera()(but not directly through the destructor; something goes wrong afterward in some event handler). This is on Windows. Here's the link to the project's repository for testing.What's the problem?
I suspect
stop()may be a non-blocking call and deleting theQCameraimmediately is a mistake. I've tried callingunloadafterstop, but it didn't fix the problem. So how to deleteQCameraproperly and safely? -
My program connects to the camera (
QCamera::start()), receives one viewfinder frame (via a customQAbstractVideoSurfacesublcass with overriddenpresentmethod), and then disconnects from the camera (by callingstopand then deleting the camera object).One of two things happen: either the
stopcall freezes indefinitely, or access violation occurs deep inside Qt multimedia after callingQCamera::~QCamera()(but not directly through the destructor; something goes wrong afterward in some event handler). This is on Windows. Here's the link to the project's repository for testing.What's the problem?
I suspect
stop()may be a non-blocking call and deleting theQCameraimmediately is a mistake. I've tried callingunloadafterstop, but it didn't fix the problem. So how to deleteQCameraproperly and safely?@Violet-Giraffe said:
One of two things happen: either the stop call freezes indefinitely, or access violation occurs deep inside Qt multimedia after calling QCamera::~QCamera() (but not directly through the destructor; something goes wrong afterward in some event handler).
I don't have a windows to test, but the stack trace of the crash may be useful.
I suspect stop() may be a non-blocking call and deleting the QCamera immediately is a mistake. I've tried calling unload after stop, but it didn't fix the problem. So how to delete QCamera properly and safely?
If you're correct in your suspicion, you can delete the camera through an event, try:
camera->deleteLater(). -
That doesn't explain
stophanging, though. Probably a lock of some kind. -
That doesn't explain
stophanging, though. Probably a lock of some kind.@Violet-Giraffe said:
That doesn't explain stop hanging, though. Probably a lock of some kind.
It may be, it also might be a bug, or some idiosyncrasy of the Windows' backend. I have no reference for comparison, so I can't know.
PS:
Btw, you're intercepting the_displayWidget's paint event, but you're not stopping its propagation, is this intended? -
No, that's a mistake. Good catch, thank you.
-
No, that's a mistake. Good catch, thank you.
Good catch, thank you.
No problem. Do consider interrupting the runtime when you get
stop()to hang and extracting the stack. It may attract some better answers.Kind regards.
-
Here's the crash stack:
Of course, the moment I decided I'm going to capture the stack of the freeze I lost the ability to reproduce it.
-
My program connects to the camera (
QCamera::start()), receives one viewfinder frame (via a customQAbstractVideoSurfacesublcass with overriddenpresentmethod), and then disconnects from the camera (by callingstopand then deleting the camera object).One of two things happen: either the
stopcall freezes indefinitely, or access violation occurs deep inside Qt multimedia after callingQCamera::~QCamera()(but not directly through the destructor; something goes wrong afterward in some event handler). This is on Windows. Here's the link to the project's repository for testing.What's the problem?
I suspect
stop()may be a non-blocking call and deleting theQCameraimmediately is a mistake. I've tried callingunloadafterstop, but it didn't fix the problem. So how to deleteQCameraproperly and safely?Hello,
Are you deleting the QCamera object in slot connected to signal that was thrown by the camera?
-
Here's the crash stack:
Of course, the moment I decided I'm going to capture the stack of the freeze I lost the ability to reproduce it.
It appears the event loop is crashing, I can't see any reference to your code in that trace (except the trivial
QApplication::exec). However:_camera = std::make_shared<QCamera>(cameraInfo);Looks suspicious. Qt has its own ownership system for
QObjectsubclasses, so this shared pointer could be deleting the camera based on you "not using" the camera anymore, while there's a scheduled event somewhere in the event loop still referencing the object. I suggest dropping that line and using a raw pointer (or better yetQPointer) to track the object's lifetime.Kind regards.
-
Hello,
Are you deleting the QCamera object in slot connected to signal that was thrown by the camera?
@t3685
I'm deleting it in a slot connected to QAbstractVideoSurface::present(). Now that I think about it, it may well be, in turn, called from QCamera. I will investigate. -
It appears the event loop is crashing, I can't see any reference to your code in that trace (except the trivial
QApplication::exec). However:_camera = std::make_shared<QCamera>(cameraInfo);Looks suspicious. Qt has its own ownership system for
QObjectsubclasses, so this shared pointer could be deleting the camera based on you "not using" the camera anymore, while there's a scheduled event somewhere in the event loop still referencing the object. I suggest dropping that line and using a raw pointer (or better yetQPointer) to track the object's lifetime.Kind regards.
@kshegunov said:
Qt has its own ownership system for
QObjectsubclasses,It does have an ownership system, but not reference counting. Raw pointers are raw pointers. I might have to use
deleteLater, though, but it's not documented in any QCamera samples I've seen. -
@kshegunov said:
Qt has its own ownership system for
QObjectsubclasses,It does have an ownership system, but not reference counting. Raw pointers are raw pointers. I might have to use
deleteLater, though, but it's not documented in any QCamera samples I've seen.@Violet-Giraffe said:
It does have an ownership system, but not reference counting.
It has parent-child system instead; no need for reference counting, as there can't be
QObjectcopying anyway. Additionally, Qt provides (as already mentioned) guarded pointers toQObjects, so reference counting becomes unnecessary. By giving a parent to aQObjectyou ensure the memory will be freed. And while it's generally possible to justdeleteaQObject@t3685's question is relevant - you can't do it from inside a slot. My advice is to post a deferred delete throughQObject::deleteLater(and keep your camera pointer in aQPointernot STL shared one).Kind regards.
-
Hi,
a slot connected to present? Can you tell more about that ?In any case, deleting a camera from a QAbstractVideoSurface doesn't sound like a good idea. What happens usually is that your camera backend receives a QAbstractVideoSurface to paint images on.
-
Hi,
a slot connected to present? Can you tell more about that ?In any case, deleting a camera from a QAbstractVideoSurface doesn't sound like a good idea. What happens usually is that your camera backend receives a QAbstractVideoSurface to paint images on.
@SGaist
Yes, I don't know the specific chain of events that lead to a crash, but I'm certain that deleting theQCameraobject from a slot connected topresentwas the cause of the problem.
I didn't exactly fix it, instead I decided to keep the QCamera object andstop+unloadit instead ofstop+delete. Makes more sense since I know I always need to connect to the same camera, might as well avoid constructing it from scratch every time.What I have is a custom
QAbstractVideoSurfacesubclass withpresent(const QVideoFrame& frame)method overridden. It takes the frame, converts it toQImageand emits it in a signal. The image is then displayed and analyzed to take different actions. I hate having to reject the the nativeQCameraViewfinderwidget entirely (which probably uses OpenGL for fast rendering) and use the slowQPainter::drawImage, but I didn't find any other way to intercept the viewfinder frames other thangrab()from theQCameraViewfinderwidget, which is also an odd method that I don't like. -
What about QVideoProbe ?
-
Isn't implemented for QCamera on Windows.