|
|
|
@ -76,13 +76,22 @@ gpointer _VideoDevThread (gpointer data) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VideoDev::VideoDev() {
|
|
|
|
|
inbuffer.size = 0;
|
|
|
|
|
inbuffer.data = NULL;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < VDEV_INBUFFERS; i++) {
|
|
|
|
|
inbuffer[i].size = 0;
|
|
|
|
|
inbuffer[i].data = NULL;
|
|
|
|
|
}
|
|
|
|
|
vf.data = NULL;
|
|
|
|
|
vf.h = 0;
|
|
|
|
|
vf.w = 0;
|
|
|
|
|
vf.size = 0;
|
|
|
|
|
running = 0;
|
|
|
|
|
callback = NULL;
|
|
|
|
|
thread = NULL;
|
|
|
|
|
fd = -1;
|
|
|
|
|
io = IOMODE_MMAP;
|
|
|
|
|
inbuffer_idx = 0;
|
|
|
|
|
CLEAR(cropcap);
|
|
|
|
|
CLEAR(crop);
|
|
|
|
|
CLEAR(fmt);
|
|
|
|
@ -150,7 +159,7 @@ int VideoDev::Start(std::string dev, gboolean (*callback_func)(gpointer data)) {
|
|
|
|
|
|
|
|
|
|
int VideoDev::Stop() {
|
|
|
|
|
if (running == 1) {
|
|
|
|
|
running = 0;
|
|
|
|
|
running = 0; // we can jump directly to 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (thread) {
|
|
|
|
@ -164,26 +173,24 @@ int VideoDev::Stop() {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// try to read a video every 0.05ms (25hz)
|
|
|
|
|
// running = 2 ... thread is running normaly
|
|
|
|
|
// running = 1 ... thread need to close wait for GTK to set running to 0
|
|
|
|
|
// running = 0 ... thread stopped and all handlers can be freed
|
|
|
|
|
//
|
|
|
|
|
#define CYCLETIME 0.050
|
|
|
|
|
void VideoDev::Thread() {
|
|
|
|
|
struct timeval cycle_timestamp;
|
|
|
|
|
int lastsec = 0;
|
|
|
|
|
float cycle_time, cycle_wait;
|
|
|
|
|
float cycle_time = 0.0;
|
|
|
|
|
float cycle_wait = 0.0;
|
|
|
|
|
int i;
|
|
|
|
|
fd_set fds;
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
VideoFrame vf;
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s Enter\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
cycle_time = get_cycletime(&cycle_timestamp); // just start counting
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// open and init device buffers device
|
|
|
|
|
if (OpenInit() != VDEV_STATUS_OK) {
|
|
|
|
|
printf ("%s:%d %s something went wrong on Open()\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
running = 0;
|
|
|
|
|
}
|
|
|
|
|
if (OpenInit() != VDEV_STATUS_OK) running = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// start capturing
|
|
|
|
@ -191,7 +198,7 @@ void VideoDev::Thread() {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// read untill something bad happens..
|
|
|
|
|
while (running > 0) {
|
|
|
|
|
while (running) {
|
|
|
|
|
i = Grab(&vf);
|
|
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
@ -215,12 +222,13 @@ void VideoDev::Thread() {
|
|
|
|
|
}
|
|
|
|
|
if (cycle_wait > 0.0 && cycle_wait < 1.0 ) usleep ((int)(cycle_wait * 1000000.0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// stop capturing
|
|
|
|
|
if (callback) gdk_threads_add_idle(callback, NULL);
|
|
|
|
|
|
|
|
|
|
CaptureStop();
|
|
|
|
|
UnInit();
|
|
|
|
|
|
|
|
|
|
if (callback) gdk_threads_add_idle(callback, NULL);
|
|
|
|
|
Close();
|
|
|
|
|
|
|
|
|
|
printf ("%s:%d %s Exit\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
@ -266,7 +274,7 @@ int VideoDev::Grab(VideoFrame *vf) {
|
|
|
|
|
|
|
|
|
|
switch (io) {
|
|
|
|
|
case IOMODE_READ:
|
|
|
|
|
if ((len = read (fd, inbuffer.data, fmt.fmt.pix.sizeimage)) == -1) {
|
|
|
|
|
if ((len = read (fd, inbuffer[0].data, fmt.fmt.pix.sizeimage)) == -1) {
|
|
|
|
|
switch (errno) {
|
|
|
|
|
case EAGAIN:
|
|
|
|
|
return VDEV_STATUS_AGAIN;
|
|
|
|
@ -276,8 +284,11 @@ int VideoDev::Grab(VideoFrame *vf) {
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Convert(vf, inbuffer.data, len, fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
|
|
|
else {
|
|
|
|
|
LockMutex();
|
|
|
|
|
Convert(vf, inbuffer[0].data, len, fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
|
|
|
UnLockMutex();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IOMODE_MMAP:
|
|
|
|
@ -285,7 +296,6 @@ int VideoDev::Grab(VideoFrame *vf) {
|
|
|
|
|
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
|
buf.index = 0;
|
|
|
|
|
|
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
|
|
|
|
|
switch (errno) {
|
|
|
|
@ -294,19 +304,16 @@ int VideoDev::Grab(VideoFrame *vf) {
|
|
|
|
|
|
|
|
|
|
case EIO:
|
|
|
|
|
printf ( "%s:%d error on VIDIOC_DQBUF EIO %s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
/* Could ignore EIO, see spec. */
|
|
|
|
|
/* fall through */
|
|
|
|
|
default:
|
|
|
|
|
printf ( "%s:%d error on VIDIOC_DQBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printf ("%s:%d DQBUF used:%d field:%d flags:%d index:%d len:%d seq:%d mem:%d\n", __FILE__, __LINE__, buf.bytesused, buf.field,
|
|
|
|
|
// buf.flags, buf.index, buf.length, buf.sequence, buf.memory);
|
|
|
|
|
|
|
|
|
|
if (buf.index == 0) {
|
|
|
|
|
Convert(vf, inbuffer.data, buf.bytesused, fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
|
|
|
if (buf.index >= 0 && buf.index < VDEV_INBUFFERS) {
|
|
|
|
|
LockMutex();
|
|
|
|
|
Convert(vf, inbuffer[buf.index].data, buf.bytesused, fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
|
|
|
UnLockMutex();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
|
|
|
@ -314,8 +321,7 @@ int VideoDev::Grab(VideoFrame *vf) {
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printf ("%s:%d QBUF used:%d field:%d flags:%d index:%d len:%d seq:%d mem:%d\n", __FILE__, __LINE__, buf.bytesused, buf.field,
|
|
|
|
|
// buf.flags, buf.index, buf.length, buf.sequence, buf.memory);
|
|
|
|
|
if (++inbuffer_idx >= VDEV_INBUFFERS) inbuffer_idx = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -404,12 +410,10 @@ int VideoDev::OpenInit() {
|
|
|
|
|
|
|
|
|
|
CLEAR (fmt);
|
|
|
|
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
// fmt.fmt.pix.width = cropcap.defrect.width;
|
|
|
|
|
// fmt.fmt.pix.height = cropcap.defrect.height;
|
|
|
|
|
fmt.fmt.pix.width = 1920;
|
|
|
|
|
fmt.fmt.pix.height = 1080;
|
|
|
|
|
// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
|
|
|
|
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
|
|
|
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
|
|
|
|
|
// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
|
|
|
|
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
|
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) {
|
|
|
|
@ -449,10 +453,12 @@ int VideoDev::InitMMap() {
|
|
|
|
|
struct v4l2_buffer bufinfo;
|
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
CLEAR(bufreq);
|
|
|
|
|
CLEAR(bufinfo);
|
|
|
|
|
|
|
|
|
|
bufreq.count = 1;
|
|
|
|
|
bufreq.count = VDEV_INBUFFERS;
|
|
|
|
|
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
bufreq.memory = V4L2_MEMORY_MMAP;
|
|
|
|
|
|
|
|
|
@ -472,24 +478,25 @@ int VideoDev::InitMMap() {
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < VDEV_INBUFFERS; i++) {
|
|
|
|
|
CLEAR(bufinfo);
|
|
|
|
|
|
|
|
|
|
bufinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
bufinfo.memory = V4L2_MEMORY_MMAP;
|
|
|
|
|
bufinfo.index = 0;
|
|
|
|
|
bufinfo.index = i;
|
|
|
|
|
|
|
|
|
|
if(ioctl(fd, VIDIOC_QUERYBUF, &bufinfo) < 0){
|
|
|
|
|
perror("VIDIOC_QUERYBUF");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inbuffer.size = bufinfo.length;
|
|
|
|
|
inbuffer.data = (unsigned char*)mmap(NULL, bufinfo.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bufinfo.m.offset);
|
|
|
|
|
if (inbuffer.data == MAP_FAILED) {
|
|
|
|
|
inbuffer[i].size = bufinfo.length;
|
|
|
|
|
inbuffer[i].data = (unsigned char*)mmap(NULL, bufinfo.length, PROT_READ | PROT_WRITE,
|
|
|
|
|
MAP_SHARED, fd, bufinfo.m.offset);
|
|
|
|
|
if (inbuffer[i].data == MAP_FAILED) {
|
|
|
|
|
printf ( "%s:%d error on mmap %s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -508,17 +515,20 @@ int VideoDev::CaptureStart() {
|
|
|
|
|
|
|
|
|
|
case IOMODE_MMAP:
|
|
|
|
|
struct v4l2_buffer buf;
|
|
|
|
|
CLEAR(buf);
|
|
|
|
|
|
|
|
|
|
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) {
|
|
|
|
|
CLEAR(buf);
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
|
buf.index = 0;
|
|
|
|
|
buf.index = inbuffer_idx;
|
|
|
|
|
|
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
|
|
|
|
printf ( "%s:%d error on VIDIOC_QBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
exit (1);
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inbuffer_idx = 0;
|
|
|
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) {
|
|
|
|
|
printf ( "%s:%d VIDIOC_STREAMON %s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
@ -532,16 +542,6 @@ int VideoDev::CaptureStart() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
|
|
|
|
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|
|
|
|
jerr.pub.error_exit = jpg_error_exit;
|
|
|
|
|
if (setjmp(jerr.setjmp_buffer)) {
|
|
|
|
|
/* If we get here, the JPEG code has signaled an error.
|
|
|
|
|
* We need to clean up the JPEG object, close the input file, and return.
|
|
|
|
|
*/
|
|
|
|
|
printf ("%s:%d %s JPEG Error\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
jpeg_create_decompress(&cinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -584,10 +584,15 @@ int VideoDev::UnInit() {
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IOMODE_MMAP:
|
|
|
|
|
if (-1 == munmap(inbuffer.data, inbuffer.size)){
|
|
|
|
|
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++)
|
|
|
|
|
if (inbuffer[inbuffer_idx].data) {
|
|
|
|
|
if (-1 == munmap(inbuffer[inbuffer_idx].data, inbuffer[inbuffer_idx].size)){
|
|
|
|
|
fprintf(stderr, "Fatal Error @ %s:%d munmap Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
inbuffer[inbuffer_idx].data = NULL;
|
|
|
|
|
inbuffer[inbuffer_idx].size = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -661,7 +666,7 @@ int VideoDev::Convert (VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uin
|
|
|
|
|
|
|
|
|
|
if (dest->data != NULL && dest->w != srcw && dest->h != srch) {
|
|
|
|
|
free (dest->data);
|
|
|
|
|
dest->data == NULL;
|
|
|
|
|
dest->data = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dest->data == NULL) {
|
|
|
|
@ -799,6 +804,14 @@ int VideoDev::Convert (VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uin
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case (V4L2_PIX_FMT_MJPEG):
|
|
|
|
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|
|
|
|
jerr.pub.error_exit = jpg_error_exit;
|
|
|
|
|
if (setjmp(jerr.setjmp_buffer)) {
|
|
|
|
|
// jpeg data and allocations will be destroyed via StopCapture.
|
|
|
|
|
printf ("%s:%d %s JPEG Error\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
|
return VDEV_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jpeg_mem_src(&cinfo, ptrsrc, srcsize);
|
|
|
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
@ -818,3 +831,15 @@ int VideoDev::Convert (VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uin
|
|
|
|
|
return VDEV_STATUS_OK;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VideoDev::LockMutex() {
|
|
|
|
|
g_mutex_lock(&mutex);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VideoDev::UnLockMutex() {
|
|
|
|
|
g_mutex_unlock(&mutex);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|