QSocketNotifier--is errno still valid in slot connected to activate(int)
I have an application that's streaming frames from a webcam. After a few minutes of streaming, the QSocketNotifier associated with camera fd stops generating activated events.
This might be a camera hardware, firmware, or RPI kernel issue, but I want to make sure my use of a QSocketNotifier instead of the exact code in the Vl42 example isn't part of the problem
In examples mainLoop() function there is a blocking select:
Code:
r = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == r) {
if (EINTR == errno)
continue;
I have these lines of code instead:
Code:
fd = open(dev_name.toAscii().data(), O_RDWR /* required */ | O_NONBLOCK, 0);
connect(notify_fd, SIGNAL(activated(int)), this, SLOT(read_frame(int)), Qt::QueuedConnection );
So, what happens when the fd associated the QSocketNotifier breaks out of the select with EINTR==errno? I've been assuming that's a QSocketNotifier::Exception event, so creating the QSocketNotifier using a QSocketNotifier::Read type would result in exceptions like the EINTR==errno being ignored. That's the equivalent of the example code.
Is this true? Can I check errno in the read_frame slot, or will it likely be reset before the slot code executes?
Next step will be to redo the code without the QtSocketNotifier, but that will take a few hours to get working, I think.
Thanks!
Re: QSocketNotifier--is errno still valid in slot connected to activate(int)
Your approach looks valid to me.
Have you tried a second notifier for the Exception type?
Cheers,
_
Re: QSocketNotifier--is errno still valid in slot connected to activate(int)
Thanks for the reply.
We think alike--yes, I added this since my post:
exception_fd = new QSocketNotifier(fd, QSocketNotifier::Exception);
connect(exception_fd, SIGNAL(activated(int)), this, SLOT(printException(int)));
void printException(int _fd){qDebug() << "errno: " << errno;}
I reproduce the hang, but printException never gets called.
Re: QSocketNotifier--is errno still valid in slot connected to activate(int)
Strange, the Qt event loop, or rather the unix event dispatcher works quite similar to the select() call.
Cheers,
_
Re: QSocketNotifier--is errno still valid in slot connected to activate(int)
What do you do in the read_frame(int) slot? Are you certain that you read all the bytes available for reading? The name of the slot suggests that it reads exactly one frame. Perhaps, at some point, two frames (or one frame and a fraction of another, etc.) are available for reading by the time the slot has a chance to run, then the slot only reads one frame, and activated(int) is never emitted again since there are some bytes still waiting to be read.
Re: QSocketNotifier--is errno still valid in slot connected to activate(int)
While that's not the cause of this issue (camera quits streaming), your note got me looking at the read_frame code.
I'd had a code fragment that just ignored the frame (by re-queuing without processing it) when it didn't match the expected frame size. However, that code was for a specific camera resolution and needed changing for the camera I'm testing with now.
But, the hang occurs immediately after receiving frames of the expected size. I fixedthe code that ignores frames with unexpected buffer sizes, but it never executes even when I see the hangs. So, that's not what's causing this issue.
But thanks for the good suggestion! It lead me to fix what would have been a nasty bug.
Code for read_frame:
Code:
int CameraInterface::read_frame(int)
{
struct v4l2_buffer buf;
unsigned int i;
//qDebug() << frames_read++;
if (testing_only) return 0;
if (!stream_forever && frames_read >= frame_count)
{
qDebug() << "frame count exceeded";
emit frames_done();
return 0;
}
switch (io)
{
.....
case IO_METHOD_MMAP:
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
{
switch (errno)
{
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("VIDIOC_DQBUF");
}
}
#if 0
qDebug() << "frames read: " << frames_read++;
if (frames_read % 2)
{
qDebug() << "skipping frame";
xioctl(fd, VIDIOC_QBUF, &buf);
return 1;
}
#endif
frameQueued = false;
assert(buf.index < n_buffers);
qDebug() << "\t\t\tframe DQ'ed, bytes " << buf.bytesused << "buffers = " << n_buffers;
if (buf.bytesused != 921600)
{
qDebug() << "partial frame";
xioctl(fd, VIDIOC_QBUF, &buf);
frameQueued = true;
qDebug() << "Unexpected framesize" << buf.bytesused;
//exit(-1);
}
/*
if (!colorCamera && buf.bytesused < 1843200)
{
xioctl(fd, VIDIOC_QBUF, &buf);
frameQueued = true;
qDebug() << "Partial frame" << buf.bytesused;
}
*/
else
{
emit frameReady(buffers[buf.index].start,buf.bytesused);
// when streaming expect client to send message to queue next frame
// otherwise, we know there's been seconds for client to process frame
// setup = false;
if (!setup)
{
xioctl(fd, VIDIOC_QBUF, &buf);
frameQueued=true;
}
}
break;
...
Re: QSocketNotifier--is errno still valid in slot connected to activate(int)
The problem probably isn't related to QSocketNotifier.
I hacked my code to immediately enqueue after each dequeue. With this change, it streamed for several hours without hanging. This is using the same code that binds the activated (type = read) signal from a QTSocketNotifier to a slot to do the xioctl to dequeue the frame.
So, I conclude that the issue isn't related to my use of QSocketNotifier.
I also tried sleeping two seconds after each dequeue, then enqueing. So far,no hang, but it will have to run much longer to get a lot of frames through.