Compare commits
No commits in common. 'master' and '0.0.1' have entirely different histories.
@ -1,32 +0,0 @@
|
|||||||
|
|
||||||
include Makefile.config
|
|
||||||
USE_VFW = 1
|
|
||||||
|
|
||||||
TARGET = $(APP).exe
|
|
||||||
CROSSENV = /opt/W64-cross-compile/
|
|
||||||
CPP = /usr/bin/x86_64-w64-mingw32-g++
|
|
||||||
CPPFLAGS = -ggdb -Wall -O0 `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated -D_POSIX_C_SOURCE=200112L
|
|
||||||
INCLUDES =
|
|
||||||
LDFLAGS = -lws2_32 -ljpeg
|
|
||||||
LIBS = `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -mwindows
|
|
||||||
|
|
||||||
OBJECTS := $(OBJECTS) windows.oo
|
|
||||||
|
|
||||||
#
|
|
||||||
# add makefile configuration for svbony cams
|
|
||||||
#
|
|
||||||
ifeq ($(USE_SVBONY),1)
|
|
||||||
CPPFLAGS := $(CPPFLAGS)
|
|
||||||
LDFLAGS := $(LDFLAGS) -lSVBCameraSDK
|
|
||||||
OBJECTS := $(OBJECTS) videodev-svbcam.oo
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# add makefile configuration for vfw cams
|
|
||||||
#
|
|
||||||
ifeq ($(USE_VFW),1)
|
|
||||||
OBJECTS := $(OBJECTS) videodev-vfw.oo
|
|
||||||
LDFLAGS := $(LDFLAGS) -lvfw32
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
@ -1,34 +1,9 @@
|
|||||||
|
|
||||||
include Makefile.config
|
|
||||||
|
|
||||||
USE_V4L2 = 1
|
|
||||||
TARGET = $(APP)
|
TARGET = $(APP)
|
||||||
|
|
||||||
CPP = c++
|
CPP = c++
|
||||||
CPPFLAGS = -std=c++11 -pg -ggdb -Wall -Werror -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
|
CPPFLAGS = -std=c++11 -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
|
||||||
INCLUDES =
|
INCLUDES =
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -ljpeg -pg
|
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -ljpeg
|
||||||
OBJECTS =
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# add makefile configuration for svbony cams
|
|
||||||
#
|
|
||||||
ifeq ($(USE_SVBONY),1)
|
|
||||||
CPPFLAGS := $(CPPFLAGS) -I/usr/local/include
|
|
||||||
LDFLAGS := $(LDFLAGS) -lSVBCameraSDK -L/usr/local/lib `pkg-config --libs libusb-1.0`
|
|
||||||
OBJECTS := $(OBJECTS) videodev-svbcam.oo
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# add makefile configuration for svbony cams
|
|
||||||
#
|
|
||||||
ifeq ($(USE_V4L2),1)
|
|
||||||
OBJECTS := $(OBJECTS) videodev-v4l2.oo
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
|
|
||||||
include Makefile.config
|
|
||||||
|
|
||||||
USE_VFW = 1
|
|
||||||
TARGET = $(APP).exe
|
|
||||||
CPP = g++
|
|
||||||
CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated -D_POSIX_C_SOURCE=200112L
|
|
||||||
#CPPFLAGS = -Wall -O3 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated -D_POSIX_C_SOURCE=200112L
|
|
||||||
INCLUDES =
|
|
||||||
LDFLAGS = -lws2_32 -ljpeg
|
|
||||||
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -mwindows
|
|
||||||
|
|
||||||
OBJECTS := $(OBJECTS) windows.oo
|
|
||||||
|
|
||||||
#
|
|
||||||
# add makefile configuration for svbony cams
|
|
||||||
#
|
|
||||||
ifeq ($(USE_SVBONY),1)
|
|
||||||
CPPFLAGS := $(CPPFLAGS) -I/usr/local/include
|
|
||||||
LDFLAGS := $(LDFLAGS) -lSVBCameraSDK -L/usr/local/lib
|
|
||||||
OBJECTS := $(OBJECTS) videodev-svbcam.oo
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# add makefile configuration for vfw cams
|
|
||||||
#
|
|
||||||
ifeq ($(USE_VFW),1)
|
|
||||||
OBJECTS := $(OBJECTS) videodev-vfw.oo
|
|
||||||
LDFLAGS := $(LDFLAGS) -lvfw32
|
|
||||||
endif
|
|
||||||
#
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 734 KiB |
@ -1,249 +0,0 @@
|
|||||||
/*
|
|
||||||
* tool to check and gain some basic information about videodum-files
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* enable files > 2GB on 32 bit systems */
|
|
||||||
#define _LARGEFILE64_SOURCE 1
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
std::string convert_from_pixelformat (uint32_t fmt) {
|
|
||||||
char txt[5];
|
|
||||||
|
|
||||||
snprintf (txt, 5, "%c%c%c%c", ((char*)&fmt)[0], ((char*)&fmt)[1], ((char*)&fmt)[2], ((char*)&fmt)[3]);
|
|
||||||
return txt;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int fixfile(char *src, char *dest) {
|
|
||||||
int fd, fd2;
|
|
||||||
int cnt = 0;
|
|
||||||
char *inbuf = NULL;
|
|
||||||
int inbufsize = 0;
|
|
||||||
int frmcnt = 0;
|
|
||||||
|
|
||||||
uint32_t i;
|
|
||||||
uint32_t size, size2;
|
|
||||||
|
|
||||||
printf ("fix file:'%s' output file:'%s'\n", src, dest);
|
|
||||||
|
|
||||||
if ((fd = open (src, O_RDONLY)) < 0) {
|
|
||||||
printf ("could not open input file: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((fd2 = open (dest, O_WRONLY | O_CREAT | O_TRUNC), S_IRUSR | S_IWUSR) < 0) {
|
|
||||||
printf ("could not open output file: %s\n", strerror(errno));
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// read header w, h, pixfmt
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (write (fd2, &i, 4) != 4) {
|
|
||||||
printf ("could not write all bytes.\n");
|
|
||||||
close (fd2);
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf (" Width: %d\n", ntohl(i));
|
|
||||||
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (write (fd2, &i, 4) != 4) {
|
|
||||||
printf ("could not write all bytes.\n");
|
|
||||||
close (fd2);
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf (" Height: %d\n", ntohl(i));
|
|
||||||
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (write (fd2, &i, 4) != 4) {
|
|
||||||
printf ("could not write all bytes.\n");
|
|
||||||
close (fd2);
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf(" Pixfmt: %s\n", convert_from_pixelformat(ntohl(i)).c_str());
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// read frame
|
|
||||||
while (read (fd, &size, 4) == 4) {
|
|
||||||
size = ntohl(size);
|
|
||||||
size2 = htonl(size / 2);
|
|
||||||
if (write (fd2, &size2, 4) != 4) {
|
|
||||||
printf ("could not write framesize of frame %d.\n", frmcnt);
|
|
||||||
close (fd2);
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (write (fd2, &i, 4) != 4) {
|
|
||||||
printf ("could not write timestamp of frame %d.\n", frmcnt);
|
|
||||||
close (fd2);
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
i = ntohl(i);
|
|
||||||
|
|
||||||
if (inbuf == NULL){
|
|
||||||
inbuf = (char*) malloc (size);
|
|
||||||
inbufsize = size;
|
|
||||||
}
|
|
||||||
else if (inbufsize < size) {
|
|
||||||
inbuf = (char*)realloc(inbuf, size);
|
|
||||||
inbufsize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inbuf == NULL) {
|
|
||||||
printf ("Error could not allocate enough memory\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (read (fd, inbuf, size) != size) {
|
|
||||||
printf ("could not read to next frame.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (write (fd2, inbuf, size/2) != size/2) {
|
|
||||||
printf ("could not write frame %d.\n", frmcnt);
|
|
||||||
close (fd2);
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf ("Frame: %-9d Timestamp:%-9d Size:%d\n", cnt++, i, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
close (fd);
|
|
||||||
close (fd2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int checkfile(char *src) {
|
|
||||||
uint32_t i;
|
|
||||||
uint32_t size;
|
|
||||||
int fd;
|
|
||||||
int cnt = 0;
|
|
||||||
char *inbuf = NULL;
|
|
||||||
int inbufsize = 0;
|
|
||||||
|
|
||||||
printf ("reading file :'%s'\n", src);
|
|
||||||
|
|
||||||
if ((fd = open (src, O_RDONLY)) < 0) {
|
|
||||||
printf ("could not open file: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// read header w, h, pixfmt
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf (" Width: %d\n", ntohl(i));
|
|
||||||
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf (" Height: %d\n", ntohl(i));
|
|
||||||
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf(" Pixfmt: %s\n", convert_from_pixelformat(ntohl(i)).c_str());
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// read frame
|
|
||||||
while (read (fd, &size, 4) == 4) {
|
|
||||||
size = ntohl(size);
|
|
||||||
if (read (fd, &i, 4) != 4) {
|
|
||||||
printf ("could not read all bytes.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
i = ntohl(i);
|
|
||||||
|
|
||||||
if (inbuf == NULL){
|
|
||||||
inbuf = (char*) malloc (size);
|
|
||||||
inbufsize = size;
|
|
||||||
}
|
|
||||||
else if (inbufsize < size) {
|
|
||||||
inbuf = (char*)realloc(inbuf, size);
|
|
||||||
inbufsize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inbuf == NULL) {
|
|
||||||
printf ("Error could not allocate enough memory\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (read (fd, inbuf, size) != size) {
|
|
||||||
printf ("could not read to next frame.\n");
|
|
||||||
close (fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf ("Frame: %-9d Timestamp:%-9d Size:%d\n", cnt++, i, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf ("\nFile seems to be fine.\n");
|
|
||||||
|
|
||||||
close (fd);
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
|
|
||||||
if (argc == 2) {
|
|
||||||
checkfile(argv[1]);
|
|
||||||
}
|
|
||||||
else if (argc == 3) {
|
|
||||||
fixfile(argv[1], argv[2]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf ("please give a file name as parameter.\n");
|
|
||||||
printf ("checkdumpfile FILE to check file\n");
|
|
||||||
printf ("checkdumpfile SRCFILE DESTFILE to fix file\n");
|
|
||||||
printf ("\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,558 +0,0 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
#include "windows.h"
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "video.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "debayer.h"
|
|
||||||
|
|
||||||
uint32_t convert_pixelformats [] = {
|
|
||||||
V4L2_PIX_FMT_MJPEG,
|
|
||||||
V4L2_PIX_FMT_YUYV,
|
|
||||||
V4L2_PIX_FMT_RGB32,
|
|
||||||
V4L2_PIX_FMT_BGR32,
|
|
||||||
V4L2_PIX_FMT_RGB24,
|
|
||||||
V4L2_PIX_FMT_BGR24,
|
|
||||||
V4L2_PIX_FMT_UYVY,
|
|
||||||
V4L2_PIX_FMT_SGRBG16,
|
|
||||||
V4L2_PIX_FMT_SGRBG8,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dump data into debug file
|
|
||||||
*
|
|
||||||
* file description:
|
|
||||||
* <HEDER>
|
|
||||||
* uint32_t width;
|
|
||||||
* uint32_t height;
|
|
||||||
* uint32_t pixelformat;
|
|
||||||
* <FRAMEHEADER>
|
|
||||||
* uint32_t size;
|
|
||||||
* uint32_t timestamp_ms;
|
|
||||||
* <FRAME>
|
|
||||||
* uint8_t data[size];
|
|
||||||
* <FRAMEHEADER>
|
|
||||||
* <FRAME>
|
|
||||||
* ....
|
|
||||||
*/
|
|
||||||
int convert_debug_fd = -1;
|
|
||||||
struct timeval convert_debug_tv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* will be called on first frame
|
|
||||||
*/
|
|
||||||
int convert_debug_open(uint32_t pixelformat, int srcw, int srch) {
|
|
||||||
time_t t = time(NULL);
|
|
||||||
struct tm *tmptr;
|
|
||||||
char fname[LEN_FILENAME];
|
|
||||||
char fullfname[LEN_FULLFILENAME];
|
|
||||||
|
|
||||||
if (config.debugpath == NULL) return -1;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
//
|
|
||||||
// check to create file, if not possible try creating the directory and create the file again
|
|
||||||
tmptr = localtime(&t);
|
|
||||||
strftime(fname, LEN_FILENAME, "%Y%m%d-%H%M%S", tmptr);
|
|
||||||
snprintf (fullfname, LEN_FULLFILENAME, "%s/%s.videodump", config.debugpath, fname);
|
|
||||||
|
|
||||||
if ((convert_debug_fd = creat (fullfname, 0666)) == -1) {
|
|
||||||
printf ("%s:%d could not create file '%s'. Error:%s\n", __FILE__, __LINE__, fullfname, strerror(errno));
|
|
||||||
printf ("%s:%d try to create folder\n", __FILE__, __LINE__);
|
|
||||||
|
|
||||||
// create folder
|
|
||||||
// FIXME: how to do thin on windows
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
if ((mkdir (config.debugpath)) == -1) {
|
|
||||||
#else
|
|
||||||
if ((mkdir (config.debugpath, 0777)) == -1) {
|
|
||||||
#endif
|
|
||||||
printf ("%s:%d could not create debug folder.\n", __FILE__, __LINE__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if ((convert_debug_fd = creat (fullfname, 0666)) == -1) {
|
|
||||||
printf ("%s:%d could again not create file '%s'. Error:%s\n", __FILE__, __LINE__, fullfname, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// file is open for writing, write header information
|
|
||||||
uint32_t wwidth = htonl(srcw);
|
|
||||||
uint32_t wheight = htonl(srch);
|
|
||||||
uint32_t wpixfmt = htonl(pixelformat);
|
|
||||||
write (convert_debug_fd, &wwidth, 4);
|
|
||||||
write (convert_debug_fd, &wheight, 4);
|
|
||||||
write (convert_debug_fd, &wpixfmt, 4);
|
|
||||||
|
|
||||||
//
|
|
||||||
// save start time, this is needed to calculate the time between the frames
|
|
||||||
gettimeofday (&convert_debug_tv, NULL);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if fd is not open open file and set up header
|
|
||||||
*/
|
|
||||||
void convert_debug_dumpframe(unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch) {
|
|
||||||
struct timeval tv;
|
|
||||||
uint32_t wts, ts;
|
|
||||||
uint32_t wsize;
|
|
||||||
|
|
||||||
if (ptrsrc == NULL) return;
|
|
||||||
if (config.debugpath == NULL) return;
|
|
||||||
if (convert_debug_fd == -1)
|
|
||||||
if (convert_debug_open(pixelformat, srcw, srch) == -1) return;
|
|
||||||
|
|
||||||
//
|
|
||||||
// construct and write header
|
|
||||||
wsize = htonl(srcsize);
|
|
||||||
gettimeofday (&tv, NULL);
|
|
||||||
ts = 1000 * (tv.tv_sec - convert_debug_tv.tv_sec) +
|
|
||||||
(tv.tv_usec - convert_debug_tv.tv_usec) / 1000;
|
|
||||||
wts = htonl(ts);
|
|
||||||
|
|
||||||
write (convert_debug_fd, &wsize, 4);
|
|
||||||
write (convert_debug_fd, &wts, 4);
|
|
||||||
|
|
||||||
//
|
|
||||||
// write frame
|
|
||||||
write (convert_debug_fd, ptrsrc, srcsize);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* close file and reset all data
|
|
||||||
*/
|
|
||||||
void convert_debug_close() {
|
|
||||||
if (convert_debug_fd != -1) {
|
|
||||||
close (convert_debug_fd);
|
|
||||||
convert_debug_fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* helper part for converting different video types
|
|
||||||
*/
|
|
||||||
|
|
||||||
//
|
|
||||||
// jpeg: replacement for error_exit
|
|
||||||
//
|
|
||||||
METHODDEF(void) jpg_error_exit (j_common_ptr cinfo) {
|
|
||||||
jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err;
|
|
||||||
(*cinfo->err->output_message) (cinfo);
|
|
||||||
longjmp(myerr->setjmp_buffer, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// clamp and convert2rgb is build on the sample of the v4l2 api documentation
|
|
||||||
//
|
|
||||||
inline unsigned char clamp (double x) {
|
|
||||||
int r = (int)x;
|
|
||||||
|
|
||||||
if (r < 0) return 0;
|
|
||||||
else if (r > 255) return 255;
|
|
||||||
else return r;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
inline void convert2rgb (unsigned char Y1, unsigned char Cb, unsigned char Cr,
|
|
||||||
unsigned char *ER, unsigned char *EB, unsigned char *EG) {
|
|
||||||
int y1, pb, pr;
|
|
||||||
|
|
||||||
y1 = Y1 - 16;
|
|
||||||
pb = Cb - 128;
|
|
||||||
pr = Cr - 128;
|
|
||||||
|
|
||||||
*ER = clamp (y1 + 1.402 * pr);
|
|
||||||
*EB = clamp (y1 - 0.344 * pb - 0.714 * pr);
|
|
||||||
*EG = clamp (y1 + 1.772 * pb);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int ConvertStart(ConvertData *cdata, uint32_t pixelformat) {
|
|
||||||
if (cdata == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
if (pixelformat == V4L2_PIX_FMT_MJPEG) {
|
|
||||||
jpeg_create_decompress(&cdata->cinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ConvertStop(ConvertData *cdata, uint32_t pixelformat) {
|
|
||||||
convert_debug_close();
|
|
||||||
|
|
||||||
if (cdata == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
if (pixelformat == V4L2_PIX_FMT_MJPEG) jpeg_destroy_decompress(&cdata->cinfo);
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* converts the video from input type to RGB24 type - 24Bit
|
|
||||||
*/
|
|
||||||
int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch) {
|
|
||||||
int xs, ys;
|
|
||||||
int xd, yd;
|
|
||||||
unsigned char r,g,b;
|
|
||||||
unsigned char cb, cr, y1;
|
|
||||||
unsigned char *ptrdst = NULL;
|
|
||||||
|
|
||||||
if (config.debugpath != NULL) convert_debug_dumpframe(ptrsrc, srcsize, pixelformat, srcw, srch);
|
|
||||||
|
|
||||||
struct jpg_error_mgr jerr;
|
|
||||||
if (cdata == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
// check if there is a destination and that the destination is large to keep
|
|
||||||
// the full image
|
|
||||||
if (dest == NULL || ptrsrc == NULL)
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
if (dest->data != NULL && dest->w != srcw && dest->h != srch) {
|
|
||||||
free (dest->data);
|
|
||||||
dest->data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest->data == NULL) {
|
|
||||||
dest->w = srcw;
|
|
||||||
dest->h = srch;
|
|
||||||
dest->size = srcw * srch * 3;
|
|
||||||
dest->data = (unsigned char*) malloc (dest->size);
|
|
||||||
}
|
|
||||||
ptrdst = dest->data;
|
|
||||||
|
|
||||||
switch (pixelformat) {
|
|
||||||
case (V4L2_PIX_FMT_RGB32):
|
|
||||||
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
|
|
||||||
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
|
|
||||||
/* read the pixel */
|
|
||||||
|
|
||||||
r = *(ptrsrc++);
|
|
||||||
g = *(ptrsrc++);
|
|
||||||
b = *(ptrsrc++);
|
|
||||||
ptrsrc++;
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dest->w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(ptrdst++) = r;
|
|
||||||
*(ptrdst++) = g;
|
|
||||||
*(ptrdst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places.. */
|
|
||||||
if (xd < dest->w)
|
|
||||||
ptrdst += 3 * (dest->w - xd);
|
|
||||||
yd++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_BGR32):
|
|
||||||
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
|
|
||||||
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
|
|
||||||
/* read the pixel */
|
|
||||||
|
|
||||||
ptrsrc++;
|
|
||||||
b = *(ptrsrc++);
|
|
||||||
g = *(ptrsrc++);
|
|
||||||
r = *(ptrsrc++);
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dest->w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(ptrdst++) = r;
|
|
||||||
*(ptrdst++) = g;
|
|
||||||
*(ptrdst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places.. */
|
|
||||||
if (xd < dest->w)
|
|
||||||
ptrdst += 3 * (dest->w - xd);
|
|
||||||
yd++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_RGB24):
|
|
||||||
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
|
|
||||||
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
|
|
||||||
/* read the pixel */
|
|
||||||
|
|
||||||
r = *(ptrsrc++);
|
|
||||||
g = *(ptrsrc++);
|
|
||||||
b = *(ptrsrc++);
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dest->w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(ptrdst++) = r;
|
|
||||||
*(ptrdst++) = g;
|
|
||||||
*(ptrdst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places.. */
|
|
||||||
if (xd < dest->w)
|
|
||||||
ptrdst += 3 * (dest->w - xd);
|
|
||||||
yd++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_BGR24):
|
|
||||||
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
|
|
||||||
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
|
|
||||||
/* read the pixel */
|
|
||||||
|
|
||||||
b = *(ptrsrc++);
|
|
||||||
g = *(ptrsrc++);
|
|
||||||
r = *(ptrsrc++);
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dest->w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(ptrdst++) = r;
|
|
||||||
*(ptrdst++) = g;
|
|
||||||
*(ptrdst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places.. */
|
|
||||||
if (xd < dest->w)
|
|
||||||
ptrdst += 3 * (dest->w - xd);
|
|
||||||
yd++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_SGRBG16):
|
|
||||||
if (config.debayer_mode == 0)
|
|
||||||
debayer_grbg16_simple ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
|
|
||||||
else
|
|
||||||
debayer_grbg16_bilinear ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_SGRBG8):
|
|
||||||
if (config.debayer_mode == 0)
|
|
||||||
debayer_grbg8_simple ((uint8_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
|
|
||||||
else
|
|
||||||
debayer_grbg8_bilinear ((uint8_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_UYVY):
|
|
||||||
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
|
|
||||||
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
|
|
||||||
/* read the pixel */
|
|
||||||
if (xs & 1) {
|
|
||||||
y1 = (unsigned char)*(ptrsrc + 1);
|
|
||||||
cr = (unsigned char)*(ptrsrc);
|
|
||||||
cb = (unsigned char)*(ptrsrc - 2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
y1 = (unsigned char)*(ptrsrc + 1);
|
|
||||||
cr = (unsigned char)*(ptrsrc + 2);
|
|
||||||
cb = (unsigned char)*(ptrsrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
convert2rgb (y1, cr, cb, &r, &g, &b);
|
|
||||||
ptrsrc += 2;
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dest->w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(ptrdst++) = r;
|
|
||||||
*(ptrdst++) = g;
|
|
||||||
*(ptrdst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places.. */
|
|
||||||
if (xd < dest->w)
|
|
||||||
ptrdst += 3 * (dest->w - xd);
|
|
||||||
yd++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_YUYV):
|
|
||||||
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
|
|
||||||
if (yd < dest->h) {
|
|
||||||
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
|
|
||||||
/* read the pixel */
|
|
||||||
if (xs & 1) {
|
|
||||||
y1 = *(ptrsrc);
|
|
||||||
cb = *(ptrsrc + 1);
|
|
||||||
cr = *(ptrsrc - 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
y1 = *(ptrsrc);
|
|
||||||
cb = *(ptrsrc + 3);
|
|
||||||
cr = *(ptrsrc + 1);
|
|
||||||
}
|
|
||||||
convert2rgb (y1, cr, cb, &r, &g, &b);
|
|
||||||
ptrsrc += 2;
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dest->w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(ptrdst++) = r;
|
|
||||||
*(ptrdst++) = g;
|
|
||||||
*(ptrdst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places.. */
|
|
||||||
if (xd < dest->w)
|
|
||||||
ptrdst += 3 * (dest->w - xd);
|
|
||||||
yd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (V4L2_PIX_FMT_MJPEG):
|
|
||||||
cdata->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(&cdata->cinfo, ptrsrc, srcsize);
|
|
||||||
jpeg_read_header(&cdata->cinfo, TRUE);
|
|
||||||
jpeg_start_decompress(&cdata->cinfo);
|
|
||||||
|
|
||||||
while (cdata->cinfo.output_scanline < cdata->cinfo.output_height) {
|
|
||||||
unsigned char *temp_array[] = {ptrdst + (cdata->cinfo.output_scanline) * srcw * 3};
|
|
||||||
jpeg_read_scanlines(&cdata->cinfo, temp_array, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
jpeg_finish_decompress(&cdata->cinfo);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf ("%s:%d Error no default possible, need to finish\n", __FILE__, __LINE__);
|
|
||||||
exit (-1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string convert_from_pixelformat (uint32_t fmt) {
|
|
||||||
char txt[5];
|
|
||||||
|
|
||||||
snprintf (txt, 5, "%c%c%c%c", ((char*)&fmt)[0], ((char*)&fmt)[1], ((char*)&fmt)[2], ((char*)&fmt)[3]);
|
|
||||||
return txt;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t convert_to_pixelformat(std::string s) {
|
|
||||||
uint32_t u = 0;
|
|
||||||
|
|
||||||
u = ((unsigned char) s[0]) + ((unsigned char) s[1] << 8) +
|
|
||||||
((unsigned char) s[2] << 16) + ((unsigned char) s[3] << 24);
|
|
||||||
|
|
||||||
return u;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* copy part of an raw image
|
|
||||||
* destination must be pointer in case we need to align the size of the destination image.
|
|
||||||
* this function will also realloc needed memory if needed. (only if: givin size < needed size)
|
|
||||||
*
|
|
||||||
* crop image to event set of dimensions
|
|
||||||
*/
|
|
||||||
int PixCopy(unsigned char *srcdata, uint32_t srcpixfmt, int srcw, int srch,
|
|
||||||
unsigned char **dstdataptr, int *dstsize, int *dstw, int *dsth,
|
|
||||||
int regionx, int regiony, int regionw, int regionh) {
|
|
||||||
|
|
||||||
if (srcpixfmt == 0 || srcpixfmt == V4L2_PIX_FMT_MJPEG) return 0;
|
|
||||||
if (srcdata == NULL || dstdataptr == NULL) return 0;
|
|
||||||
|
|
||||||
// crop size to an even number
|
|
||||||
(*dsth) = regionw & ~1;
|
|
||||||
(*dstw) = regionh & ~1;
|
|
||||||
|
|
||||||
int bytesperpixel = 3;
|
|
||||||
int dsize = 0;
|
|
||||||
|
|
||||||
switch (srcpixfmt) {
|
|
||||||
case (V4L2_PIX_FMT_SGRBG8):
|
|
||||||
bytesperpixel = 1;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_SGRBG16):
|
|
||||||
bytesperpixel = 2;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR32):
|
|
||||||
case (V4L2_PIX_FMT_RGB32):
|
|
||||||
bytesperpixel = 4;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR24):
|
|
||||||
case (V4L2_PIX_FMT_RGB24):
|
|
||||||
bytesperpixel = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// calculate image size and allocate memory if needed
|
|
||||||
dsize = (*dsth) * (*dstw) * bytesperpixel;
|
|
||||||
if ((*dstsize) < dsize || (*dstdataptr) == NULL) {
|
|
||||||
*dstdataptr = (unsigned char*) realloc (*dstdataptr, dsize);
|
|
||||||
if (*dstdataptr == NULL) {
|
|
||||||
errorexit((char*)"%s:%d could not realloc memory. dsize:%d error:%s\n", __FILE__, __LINE__, dsize, strerror(errno));
|
|
||||||
}
|
|
||||||
*dstsize = dsize;
|
|
||||||
printf ("%s:%d reallocate memory for destination raw image\n", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char *dptr, *sptr;
|
|
||||||
int y, dy, x;
|
|
||||||
|
|
||||||
// debug_drawraw(srcdata, srcpixfmt, srcw, srch);
|
|
||||||
for (y = regiony & (~1), dy = 0; dy < *dsth && y < srch; y++, dy++) {
|
|
||||||
x = regionx & (~1);
|
|
||||||
dptr = (*dstdataptr) + bytesperpixel * (dy * *dstw);
|
|
||||||
sptr = (srcdata) + bytesperpixel * ( y * srcw + x);
|
|
||||||
memcpy (dptr, sptr, *dstw * bytesperpixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.show_debugwin) debug_drawraw(*dstdataptr, srcpixfmt, *dstw, *dsth);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _CONVERT_H_
|
|
||||||
#define _CONVERT_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
#include "video.h"
|
|
||||||
#include "videoframe.h"
|
|
||||||
|
|
||||||
#ifndef CLEAR
|
|
||||||
#define CLEAR(x) memset (&(x), 0, sizeof (x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct {
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
|
||||||
} typedef ConvertData;
|
|
||||||
|
|
||||||
int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch);
|
|
||||||
int ConvertStart(ConvertData *cdata, uint32_t pixelformat);
|
|
||||||
int ConvertStop(ConvertData *cdata, uint32_t pixelformat);
|
|
||||||
|
|
||||||
int PixCopy(unsigned char *srcdata, uint32_t srcpixfmt, int srcw, int srch,
|
|
||||||
unsigned char **dstdataptr, int *dstsize, int *dstw, int *dsth,
|
|
||||||
int regionx, int regiony, int regionw, int regionh);
|
|
||||||
|
|
||||||
extern uint32_t convert_pixelformats[];
|
|
||||||
std::string convert_from_pixelformat (uint32_t fmt);
|
|
||||||
uint32_t convert_to_pixelformat(std::string s);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
CROSS_DEST_DIR=/opt/W64-cross-compile/lib
|
|
||||||
CROSS_COMPILER_DIR=/usr/x86_64-w64-mingw32/lib
|
|
||||||
CROSS_GCC_DIR=/usr/lib/gcc/x86_64-w64-mingw32/10-win32
|
|
||||||
|
|
||||||
cp -v $CROSS_COMPILER_DIR/zlib1.dll ./
|
|
||||||
|
|
||||||
# copy dll dependencys
|
|
||||||
copy_dependency() {
|
|
||||||
local I
|
|
||||||
for I in `strings $1 | grep -i '\.dll$' | grep -e "^lib"`
|
|
||||||
do
|
|
||||||
if [ -e ./$I ]
|
|
||||||
then
|
|
||||||
echo "File Exist"
|
|
||||||
|
|
||||||
elif [ -e $CROSS_COMPILER_DIR/$I ]
|
|
||||||
then
|
|
||||||
cp -v $CROSS_COMPILER_DIR/$I ./
|
|
||||||
copy_dependency $CROSS_COMPILER_DIR/$I
|
|
||||||
|
|
||||||
elif [ -e $CROSS_GCC_DIR/$I ]
|
|
||||||
then
|
|
||||||
cp -v $CROSS_GCC_DIR/$I ./
|
|
||||||
copy_dependency $CROSS_GCC_DIR/$I
|
|
||||||
|
|
||||||
elif [ -e $CROSS_DEST_DIR/$I ]
|
|
||||||
then
|
|
||||||
cp -v $CROSS_DEST_DIR/$I ./
|
|
||||||
copy_dependency $CROSS_DEST_DIR/$I
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_dependency simpleskycam.exe
|
|
||||||
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
CROSS_PREFIX=/opt/W64-cross-compile
|
|
||||||
|
|
||||||
mkdir share
|
|
||||||
cp -rf $CROSS_PREFIX/share/glib-2.0 share/glib-2.0
|
|
||||||
cp -rf $CROSS_PREFIX/share/gtk-2.0 share/gtk-4.0
|
|
||||||
cp -rf $CROSS_PREFIX/share/gtk-3.0 share/gtk-3.0
|
|
||||||
cp -rf $CROSS_PREFIX/share/icons share/icons
|
|
||||||
|
|
||||||
@ -1,366 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function converts a 16bit GRBG 2x2 CFA coded image into an 8bit
|
|
||||||
RGB image by setting the missing RGB values to zero.
|
|
||||||
*/
|
|
||||||
void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h) {
|
|
||||||
|
|
||||||
// GG RR
|
|
||||||
// BB GG
|
|
||||||
uint16_t t;
|
|
||||||
uint8_t r, g, b;
|
|
||||||
int ys, yd, xs, xd;
|
|
||||||
|
|
||||||
for (ys = 0, yd = 0; ys < src_h && yd < dst_h; ys++, yd++) {
|
|
||||||
for (xs = 0, xd = 0; xs < src_w; xs++) {
|
|
||||||
|
|
||||||
/* read the pixel but only the higher 8bit, assuming data is little endian */
|
|
||||||
t = (*(src++) >> 8) & 0xff;
|
|
||||||
|
|
||||||
if (xs & 1) {
|
|
||||||
if (ys & 1) {
|
|
||||||
// lower right green pixel
|
|
||||||
b = 0; g = t; r = 0;
|
|
||||||
} else {
|
|
||||||
// upper right red pixel
|
|
||||||
b = 0; g = 0; r = t;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ys & 1) {
|
|
||||||
// lower left blue pixel
|
|
||||||
b = t; g = 0; r = 0;
|
|
||||||
} else {
|
|
||||||
// upper left green pixel
|
|
||||||
b = 0; g = t; r = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dst_w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(dst++) = r;
|
|
||||||
*(dst++) = g;
|
|
||||||
*(dst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places */
|
|
||||||
if (xd < dst_w)
|
|
||||||
dst += 3 * (dst_w - xd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// macros to make code better readable
|
|
||||||
#define CE (*(src))
|
|
||||||
#define UP (*(src-src_w))
|
|
||||||
#define DN (*(src+src_w))
|
|
||||||
#define LE (*(src-1))
|
|
||||||
#define RI (*(src+1))
|
|
||||||
#define UPLE (*(src-src_w-1))
|
|
||||||
#define UPRI (*(src-src_w+1))
|
|
||||||
#define DNLE (*(src+src_w-1))
|
|
||||||
#define DNRI (*(src+src_w+1))
|
|
||||||
|
|
||||||
#define BITCONV(d) ((d>>8) & 0xff)
|
|
||||||
#define STORE *(dst++) = BITCONV(r); *(dst++) = BITCONV(g); *(dst++) = BITCONV(b); src++;
|
|
||||||
#define STORE8 *(dst++) = (r & 0xff); *(dst++) = (g & 0xff); *(dst++) = (b & 0xff); src++;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function converts a 16bit GRBG 2x2 CFA coded image into an 8bit
|
|
||||||
RGB image by bilinear interpolation.
|
|
||||||
*/
|
|
||||||
void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h) {
|
|
||||||
|
|
||||||
// GG RR GG RR
|
|
||||||
// BB GG BB GG
|
|
||||||
// GG RR GG RR
|
|
||||||
// BB GG BB GG
|
|
||||||
uint32_t r, g, b;
|
|
||||||
int xs, ys;
|
|
||||||
|
|
||||||
// start with upper left pixel (green)
|
|
||||||
r = RI;
|
|
||||||
g = CE;
|
|
||||||
b = DN;
|
|
||||||
STORE;
|
|
||||||
|
|
||||||
// upper first line, starts with RR GG RR ...
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// red pixel
|
|
||||||
r = CE;
|
|
||||||
g = (LE + RI + DN) / 3;
|
|
||||||
b = (DNLE + DNRI) / 2;
|
|
||||||
STORE;
|
|
||||||
// green pixel
|
|
||||||
r = (LE + RI) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = DN;
|
|
||||||
STORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// upper right pixel (red)
|
|
||||||
r = CE;
|
|
||||||
g = (DN + LE) / 2;
|
|
||||||
b = DNLE;
|
|
||||||
STORE;
|
|
||||||
|
|
||||||
// go through the "body" of the image
|
|
||||||
for (ys = 1; ys < src_h - 1; ys+=2) {
|
|
||||||
|
|
||||||
// every second line with BB GG BB GG (start at 2nd line)
|
|
||||||
|
|
||||||
// left hand pixel (blue)
|
|
||||||
r = (UPRI + DNRI) / 2;
|
|
||||||
g = (UP + DN + RI) / 3;
|
|
||||||
b = CE;
|
|
||||||
STORE;
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// green pixel
|
|
||||||
r = (UP + DN) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = (LE + RI) / 2;
|
|
||||||
STORE;
|
|
||||||
// blue pixel
|
|
||||||
r = (UPLE + UPRI + DNLE + DNRI) / 4;
|
|
||||||
g = (LE + RI + UP + DN) / 4;
|
|
||||||
b = CE;
|
|
||||||
STORE;
|
|
||||||
}
|
|
||||||
// last pixel in line (green)
|
|
||||||
r = (UP + DN) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = LE;
|
|
||||||
STORE;
|
|
||||||
|
|
||||||
// every second line with GG RR GG RR ... (start at 3rd line)
|
|
||||||
|
|
||||||
// left hand pixel (green)
|
|
||||||
r = RI;
|
|
||||||
g = CE;
|
|
||||||
b = (UP + DN) / 2;
|
|
||||||
STORE;
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// red pixel
|
|
||||||
r = CE;
|
|
||||||
g = (LE + RI + UP + DN) / 4;
|
|
||||||
b = (UPLE + UPRI + DNLE + DNRI) / 4;
|
|
||||||
STORE;
|
|
||||||
// green pixel
|
|
||||||
r = (LE + RI) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = (UP + DN) / 2;
|
|
||||||
STORE;
|
|
||||||
}
|
|
||||||
// last pixel in line (red)
|
|
||||||
r = CE;
|
|
||||||
g = (UP + DN + LE) / 3;
|
|
||||||
b = (UPLE + DNLE) / 2;
|
|
||||||
STORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bottom left pixel
|
|
||||||
r = UPRI;
|
|
||||||
g = (UP + RI) / 2;
|
|
||||||
b = CE;
|
|
||||||
STORE;
|
|
||||||
|
|
||||||
// last line starting with GG BB GG ...
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// green pixel
|
|
||||||
r = UP;
|
|
||||||
g = CE;
|
|
||||||
b = (LE + RI) / 2;
|
|
||||||
STORE;
|
|
||||||
// blue pixel
|
|
||||||
r = (UPLE + UPRI) / 2;
|
|
||||||
g = (LE + UP + RI) / 2;
|
|
||||||
b = CE;
|
|
||||||
STORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bottom right pixel (green)
|
|
||||||
r = UP;
|
|
||||||
g = CE;
|
|
||||||
b = LE;
|
|
||||||
STORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function converts a 8bit GRBG 2x2 CFA coded image into an 8bit
|
|
||||||
RGB image by setting the missing RGB values to zero.
|
|
||||||
*/
|
|
||||||
void debayer_grbg8_simple (uint8_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h) {
|
|
||||||
|
|
||||||
// GG RR
|
|
||||||
// BB GG
|
|
||||||
uint8_t t;
|
|
||||||
uint8_t r, g, b;
|
|
||||||
int ys, yd, xs, xd;
|
|
||||||
|
|
||||||
for (ys = 0, yd = 0; ys < src_h && yd < dst_h; ys++, yd++) {
|
|
||||||
for (xs = 0, xd = 0; xs < src_w; xs++) {
|
|
||||||
|
|
||||||
/* read the pixel but only the higher 8bit, assuming data is little endian */
|
|
||||||
t = *(src++);
|
|
||||||
|
|
||||||
if (xs & 1) {
|
|
||||||
if (ys & 1) {
|
|
||||||
// lower right green pixel
|
|
||||||
b = 0; g = t; r = 0;
|
|
||||||
} else {
|
|
||||||
// upper right red pixel
|
|
||||||
b = 0; g = 0; r = t;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ys & 1) {
|
|
||||||
// lower left blue pixel
|
|
||||||
b = t; g = 0; r = 0;
|
|
||||||
} else {
|
|
||||||
// upper left green pixel
|
|
||||||
b = 0; g = t; r = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* only paint the image if the source is within the destination */
|
|
||||||
if (xd < dst_w) {
|
|
||||||
/* set the pixel */
|
|
||||||
*(dst++) = r;
|
|
||||||
*(dst++) = g;
|
|
||||||
*(dst++) = b;
|
|
||||||
xd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the source image is too small ignore the other places */
|
|
||||||
if (xd < dst_w)
|
|
||||||
dst += 3 * (dst_w - xd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function converts a 8bit GRBG 2x2 CFA coded image into an 8bit
|
|
||||||
RGB image by bilinear interpolation.
|
|
||||||
*/
|
|
||||||
void debayer_grbg8_bilinear (uint8_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h) {
|
|
||||||
|
|
||||||
// GG RR GG RR
|
|
||||||
// BB GG BB GG
|
|
||||||
// GG RR GG RR
|
|
||||||
// BB GG BB GG
|
|
||||||
uint16_t r, g, b;
|
|
||||||
int xs, ys;
|
|
||||||
|
|
||||||
// start with upper left pixel (green)
|
|
||||||
r = RI;
|
|
||||||
g = CE;
|
|
||||||
b = DN;
|
|
||||||
STORE8;
|
|
||||||
|
|
||||||
// upper first line, starts with RR GG RR ...
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// red pixel
|
|
||||||
r = CE;
|
|
||||||
g = (LE + RI + DN) / 3;
|
|
||||||
b = (DNLE + DNRI) / 2;
|
|
||||||
STORE8;
|
|
||||||
// green pixel
|
|
||||||
r = (LE + RI) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = DN;
|
|
||||||
STORE8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// upper right pixel (red)
|
|
||||||
r = CE;
|
|
||||||
g = (DN + LE) / 2;
|
|
||||||
b = DNLE;
|
|
||||||
STORE8;
|
|
||||||
|
|
||||||
// go through the "body" of the image
|
|
||||||
for (ys = 1; ys < src_h - 1; ys+=2) {
|
|
||||||
|
|
||||||
// every second line with BB GG BB GG (start at 2nd line)
|
|
||||||
|
|
||||||
// left hand pixel (blue)
|
|
||||||
r = (UPRI + DNRI) / 2;
|
|
||||||
g = (UP + DN + RI) / 3;
|
|
||||||
b = CE;
|
|
||||||
STORE8;
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// green pixel
|
|
||||||
r = (UP + DN) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = (LE + RI) / 2;
|
|
||||||
STORE8;
|
|
||||||
// blue pixel
|
|
||||||
r = (UPLE + UPRI + DNLE + DNRI) / 4;
|
|
||||||
g = (LE + RI + UP + DN) / 4;
|
|
||||||
b = CE;
|
|
||||||
STORE8;
|
|
||||||
}
|
|
||||||
// last pixel in line (green)
|
|
||||||
r = (UP + DN) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = LE;
|
|
||||||
STORE8;
|
|
||||||
|
|
||||||
// every second line with GG RR GG RR ... (start at 3rd line)
|
|
||||||
|
|
||||||
// left hand pixel (green)
|
|
||||||
r = RI;
|
|
||||||
g = CE;
|
|
||||||
b = (UP + DN) / 2;
|
|
||||||
STORE8;
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// red pixel
|
|
||||||
r = CE;
|
|
||||||
g = (LE + RI + UP + DN) / 4;
|
|
||||||
b = (UPLE + UPRI + DNLE + DNRI) / 4;
|
|
||||||
STORE8;
|
|
||||||
// green pixel
|
|
||||||
r = (LE + RI) / 2;
|
|
||||||
g = CE;
|
|
||||||
b = (UP + DN) / 2;
|
|
||||||
STORE8;
|
|
||||||
}
|
|
||||||
// last pixel in line (red)
|
|
||||||
r = CE;
|
|
||||||
g = (UP + DN + LE) / 3;
|
|
||||||
b = (UPLE + DNLE) / 2;
|
|
||||||
STORE8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bottom left pixel
|
|
||||||
r = UPRI;
|
|
||||||
g = (UP + RI) / 2;
|
|
||||||
b = CE;
|
|
||||||
STORE8;
|
|
||||||
|
|
||||||
// last line starting with GG BB GG ...
|
|
||||||
for (xs = 1; xs < src_w - 1; xs+=2) {
|
|
||||||
// green pixel
|
|
||||||
r = UP;
|
|
||||||
g = CE;
|
|
||||||
b = (LE + RI) / 2;
|
|
||||||
STORE8;
|
|
||||||
// blue pixel
|
|
||||||
r = (UPLE + UPRI) / 2;
|
|
||||||
g = (LE + UP + RI) / 2;
|
|
||||||
b = CE;
|
|
||||||
STORE8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bottom right pixel (green)
|
|
||||||
r = UP;
|
|
||||||
g = CE;
|
|
||||||
b = LE;
|
|
||||||
STORE8;
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
#ifndef _DEBAYER_H_
|
|
||||||
#define _DEBAYER_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h);
|
|
||||||
void debayer_grbg8_simple (uint8_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h);
|
|
||||||
|
|
||||||
void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h);
|
|
||||||
void debayer_grbg8_bilinear (uint8_t * src, int src_w, int src_h,
|
|
||||||
uint8_t * dst, int dst_w, int dst_h);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,119 +0,0 @@
|
|||||||
/***************************************************************************************
|
|
||||||
*
|
|
||||||
* debug-angles.cc is part of SimpleSkyCam.
|
|
||||||
*
|
|
||||||
*****************************************************************************************/
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "gui.h"
|
|
||||||
|
|
||||||
position_f_2d dbga_axis;
|
|
||||||
position_f_2d dbga_pos;
|
|
||||||
double dbga_angle = NAN;
|
|
||||||
double dbga_len = NAN;
|
|
||||||
|
|
||||||
#define DBGA_W 200
|
|
||||||
#define DBGA_H 200
|
|
||||||
|
|
||||||
void debug_angles_calculate() {
|
|
||||||
position_f_2d center;
|
|
||||||
|
|
||||||
center.x = DBGA_W >> 1;
|
|
||||||
center.y = DBGA_H >> 1;
|
|
||||||
|
|
||||||
dbga_len = dbga_axis.perpendicular(dbga_pos, center);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void debug_angles_draw(cairo_t *cr) {
|
|
||||||
int centerX = DBGA_W >> 1;
|
|
||||||
int centerY = DBGA_H >> 1;
|
|
||||||
position_f_2d v;
|
|
||||||
double d, a;
|
|
||||||
|
|
||||||
debug_angles_calculate();
|
|
||||||
|
|
||||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
||||||
cairo_set_line_width(cr, 1.0);
|
|
||||||
cairo_move_to(cr, 0, 0);
|
|
||||||
cairo_line_to(cr, DBGA_W, 0);
|
|
||||||
cairo_line_to(cr, DBGA_W, DBGA_H);
|
|
||||||
cairo_line_to(cr, 0, DBGA_H);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
if (isnan(dbga_axis.x)) return;
|
|
||||||
|
|
||||||
// len
|
|
||||||
cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
|
|
||||||
draw_printf(cr, 100, 10, 0.0, (char*)"Len: %5.2f", dbga_len);
|
|
||||||
|
|
||||||
// draw pos
|
|
||||||
cairo_set_source_rgb(cr, 0.3, 0.3, 1.0);
|
|
||||||
draw_printf(cr, 0, 10, 0.0, (char*)"Pos: %5.1f,%5.1f", dbga_pos.x, dbga_pos.y);
|
|
||||||
cairo_set_line_width(cr, 3.0);
|
|
||||||
cairo_move_to(cr, centerX, centerY);
|
|
||||||
cairo_line_to(cr, dbga_pos.x, dbga_pos.y);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
cairo_set_line_width(cr, 1.0);
|
|
||||||
if (dbga_len >= 0.0) cairo_set_source_rgb(cr, 1.0, 0.5, 0.5);
|
|
||||||
else cairo_set_source_rgb(cr, 0.5, 1.0, 0.5);
|
|
||||||
d = hypot(dbga_axis.x, dbga_axis.y);
|
|
||||||
v.x = dbga_len * dbga_axis.y / d;
|
|
||||||
v.y = dbga_len * (-dbga_axis.x) / d;
|
|
||||||
cairo_move_to(cr, dbga_pos.x, dbga_pos.y);
|
|
||||||
cairo_line_to(cr, dbga_pos.x + v.x, dbga_pos.y + v.y);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
// draw axis
|
|
||||||
a = 180.0 * atan2(dbga_axis.x, dbga_axis.y) / M_PI;
|
|
||||||
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
|
|
||||||
draw_printf(cr, 0, 25, 0.0, (char*)"Axis: %5.1f,%5.1f", dbga_axis.x, dbga_axis.y);
|
|
||||||
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
|
|
||||||
draw_printf(cr, 0, 40, 0.0, (char*)"Axis: %5.1f", a);
|
|
||||||
cairo_set_line_width(cr, 3.0);
|
|
||||||
cairo_move_to(cr, centerX, centerY);
|
|
||||||
cairo_line_to(cr, centerX + dbga_axis.x, centerY + dbga_axis.y);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
||||||
cairo_set_line_width(cr, 1.0);
|
|
||||||
cairo_move_to(cr, centerX, centerY);
|
|
||||||
cairo_line_to(cr, centerX + sindeg(a) * (double)centerX * 0.8, centerY + cosdeg(a) * (double)centerX * 0.8);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
|
|
||||||
cairo_set_line_width(cr, 1.0);
|
|
||||||
d = hypot(dbga_axis.x, dbga_axis.y);
|
|
||||||
v.x = centerX * dbga_axis.x / d;
|
|
||||||
v.y = centerY * dbga_axis.y / d;
|
|
||||||
cairo_move_to(cr, centerX - v.x, centerY - v.y);
|
|
||||||
cairo_line_to(cr, centerX + v.x, centerY + v.y);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void debug_angles_motionevent(GdkEvent *event) {
|
|
||||||
if (event->motion.x < 0 || event->motion.x >= DBGA_W
|
|
||||||
|| event->motion.y < 0 || event->motion.y >= DBGA_H) return;
|
|
||||||
|
|
||||||
dbga_pos.x = event->motion.x;
|
|
||||||
dbga_pos.y = event->motion.y;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void debug_angles_btnpress(GdkEvent *event) {
|
|
||||||
if (event->motion.x < 0 || event->motion.x >= DBGA_W
|
|
||||||
|| event->motion.y < 0 || event->motion.y >= DBGA_H) return;
|
|
||||||
|
|
||||||
dbga_axis.x = event->motion.x - (DBGA_W >> 1);
|
|
||||||
dbga_axis.y = event->motion.y - (DBGA_H >> 1);
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <string>
|
|
||||||
#include <time.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
# include <backtrace.h>
|
|
||||||
#else
|
|
||||||
# include <execinfo.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "convert.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "video.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "debayer.h"
|
|
||||||
|
|
||||||
|
|
||||||
extern GtkBuilder *_builder_; // work around for threads
|
|
||||||
GtkWidget *debug_da = NULL;
|
|
||||||
GdkPixbuf *debug_pixbuf = NULL;
|
|
||||||
VideoFrame debug_frame;
|
|
||||||
int debug_uninit = 1;
|
|
||||||
GMutex debug_mutex;
|
|
||||||
time_t debug_time;
|
|
||||||
#define LEN 2048
|
|
||||||
|
|
||||||
void debug_init() {
|
|
||||||
debug_uninit = 0;
|
|
||||||
g_mutex_init (&debug_mutex);
|
|
||||||
debug_time = time(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_tofile(char *fname, int isheader, char *fmt, ...) {
|
|
||||||
struct timeval tv;
|
|
||||||
va_list args;
|
|
||||||
char buffer[LEN];
|
|
||||||
int fd, len;
|
|
||||||
std::string fn;
|
|
||||||
|
|
||||||
if (debug_uninit) debug_init();
|
|
||||||
debug_lock_mutex();
|
|
||||||
|
|
||||||
// locale set to C, floating points decimals are .
|
|
||||||
std::string s = setlocale(LC_ALL, NULL);
|
|
||||||
setlocale (LC_ALL, "C");
|
|
||||||
|
|
||||||
// append time to filename to the start of the filename
|
|
||||||
struct tm *timetm = localtime(&debug_time);
|
|
||||||
char timestr[64] = "";
|
|
||||||
strftime(timestr, 63, "%Y%m%d-%H%M%S", timetm);
|
|
||||||
fn = "debug-" + (std::string)timestr + "-" + (std::string)fname;
|
|
||||||
|
|
||||||
gettimeofday(&tv,NULL);
|
|
||||||
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
fd = open(fn.c_str(), O_WRONLY | O_APPEND | O_CREAT);
|
|
||||||
#else
|
|
||||||
fd = open(fn.c_str(), O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
||||||
#endif
|
|
||||||
if (fd < 0) errorexit((char*)"%s:%d could not open debug '%s' file. Error:%s\n", __FILE__, __LINE__, fname, strerror(errno));
|
|
||||||
|
|
||||||
if (isheader) snprintf (buffer, 32, "time,");
|
|
||||||
else snprintf (buffer, 32, "%lld,", (long long int) (tv.tv_sec)*1000 + (long long int) tv.tv_usec/1000);
|
|
||||||
len = strlen (buffer);
|
|
||||||
va_start (args, fmt);
|
|
||||||
vsnprintf (buffer+len, LEN-1-len, fmt, args);
|
|
||||||
va_end (args);
|
|
||||||
buffer[LEN-1] = 0;
|
|
||||||
write (fd, buffer, strlen(buffer));
|
|
||||||
close (fd);
|
|
||||||
|
|
||||||
// reset locale to user setting
|
|
||||||
setlocale (LC_ALL, s.c_str());
|
|
||||||
|
|
||||||
debug_unlock_mutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gboolean debug_thread_cb (gpointer data) {
|
|
||||||
debug_lock_mutex();
|
|
||||||
|
|
||||||
//
|
|
||||||
// create video drawarea if needed
|
|
||||||
if (debug_da == NULL)
|
|
||||||
debug_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "debug-da"));
|
|
||||||
|
|
||||||
if (debug_pixbuf == NULL) {
|
|
||||||
debug_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, 100, 100);
|
|
||||||
memset (gdk_pixbuf_get_pixels(debug_pixbuf), 0, 3 * gdk_pixbuf_get_height(debug_pixbuf) * gdk_pixbuf_get_width(debug_pixbuf));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_frame.ToPixbuf(&debug_pixbuf); // convert Frame to pixeldata
|
|
||||||
|
|
||||||
// redraw drawarea on screen.
|
|
||||||
gdk_window_invalidate_rect(gtk_widget_get_window(debug_da), NULL, true);
|
|
||||||
|
|
||||||
debug_unlock_mutex();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void debug_lock_mutex() {
|
|
||||||
g_mutex_lock(&debug_mutex);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
inline void debug_unlock_mutex() {
|
|
||||||
g_mutex_unlock(&debug_mutex);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void debug_drawraw(unsigned char *data, int pixfmt, int w, int h) {
|
|
||||||
ConvertData cd;
|
|
||||||
int size, bytesperpixel = 0;
|
|
||||||
|
|
||||||
switch (pixfmt) {
|
|
||||||
case (V4L2_PIX_FMT_SGRBG8):
|
|
||||||
bytesperpixel = 1;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_SGRBG16):
|
|
||||||
bytesperpixel = 2;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR32):
|
|
||||||
case (V4L2_PIX_FMT_RGB32):
|
|
||||||
bytesperpixel = 4;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR24):
|
|
||||||
case (V4L2_PIX_FMT_RGB24):
|
|
||||||
bytesperpixel = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = bytesperpixel * w * h;
|
|
||||||
debug_lock_mutex();
|
|
||||||
|
|
||||||
ConvertStart(&cd, pixfmt);
|
|
||||||
Convert(&cd, &debug_frame, data, size, pixfmt, w, h);
|
|
||||||
ConvertStop(&cd, pixfmt);
|
|
||||||
|
|
||||||
gdk_threads_add_idle(debug_thread_cb, NULL);
|
|
||||||
|
|
||||||
debug_unlock_mutex();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define BT_BUF_SIZE 100
|
|
||||||
void debug_backtrace () {
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
unsigned int nptrs;
|
|
||||||
void *buffer[BT_BUF_SIZE];
|
|
||||||
char **strings;
|
|
||||||
|
|
||||||
nptrs = backtrace(buffer, BT_BUF_SIZE);
|
|
||||||
printf("backtrace() returned %d addresses\n", nptrs);
|
|
||||||
|
|
||||||
/* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
|
|
||||||
* would produce similar output to the following: */
|
|
||||||
|
|
||||||
strings = backtrace_symbols(buffer, nptrs);
|
|
||||||
if (strings == NULL) {
|
|
||||||
perror("backtrace_symbols");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t j = 0; j < nptrs; j++)
|
|
||||||
printf("%s\n", strings[j]);
|
|
||||||
free(strings);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
/***************************************************************************************
|
|
||||||
*
|
|
||||||
* debug.h is part of SimpleSkyCam.
|
|
||||||
*
|
|
||||||
*****************************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _DEBUG_H_
|
|
||||||
#define _DEBUG_H_
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "simpleskycam.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "videoframe.h"
|
|
||||||
|
|
||||||
struct Debug_ThreadData {
|
|
||||||
VideoFrameRaw raw;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_ANGLES
|
|
||||||
extern void debug_angles_draw(cairo_t *cr);
|
|
||||||
extern void debug_angles_motionevent(GdkEvent *event);
|
|
||||||
extern void debug_angles_btnpress(GdkEvent *event);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void debug_init();
|
|
||||||
extern void debug_tofile(char *fname, int isheader, char *fmt, ...);
|
|
||||||
extern inline void debug_lock_mutex();
|
|
||||||
extern inline void debug_unlock_mutex();
|
|
||||||
void debug_drawraw(unsigned char *data, int pixfmt, int w, int h);
|
|
||||||
void debug_backtrace ();
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
/*
|
|
||||||
DNG file format class based on LibTIFF.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <tiffio.h>
|
|
||||||
#include "dng.h"
|
|
||||||
|
|
||||||
DNG::DNG() {
|
|
||||||
/* initialize public data */
|
|
||||||
ImageWidth = 0;
|
|
||||||
ImageHeight = 0;
|
|
||||||
BitsPerSample = 0;
|
|
||||||
SamplesPerPixel = 0;
|
|
||||||
ColorID = 0;
|
|
||||||
|
|
||||||
/* initialize internal data */
|
|
||||||
tif = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DNG::~DNG() {
|
|
||||||
/* close file if necessary */
|
|
||||||
if(tif) {
|
|
||||||
TIFFClose(tif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Run-time detection if we are little- or big-endian.
|
|
||||||
*/
|
|
||||||
int DNG::IsBigEndian(void) {
|
|
||||||
int i = 1;
|
|
||||||
return ! *((char *)&i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the file name of the DNG file to be written. Returns -1 on
|
|
||||||
failure, 0 on success.
|
|
||||||
*/
|
|
||||||
int DNG::setFile(char * file) {
|
|
||||||
/*
|
|
||||||
w = write
|
|
||||||
l = little endian
|
|
||||||
b = big endian
|
|
||||||
-> if neither l or b is given, data is written in native CPU format
|
|
||||||
*/
|
|
||||||
if (!(tif = TIFFOpen(file, "w"))) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the color ID. Only few formats are supported right now.
|
|
||||||
*/
|
|
||||||
void DNG::setColorID(int id) {
|
|
||||||
|
|
||||||
switch(id) {
|
|
||||||
|
|
||||||
case DNG_COLORID_RGB:
|
|
||||||
BitsPerSample = 8;
|
|
||||||
SamplesPerPixel = 3;
|
|
||||||
ColorID = id;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DNG_COLORID_RAW16:
|
|
||||||
BitsPerSample = 16;
|
|
||||||
SamplesPerPixel = 1;
|
|
||||||
ColorID = id;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DNG_COLORID_RAW8:
|
|
||||||
BitsPerSample = 8;
|
|
||||||
SamplesPerPixel = 1;
|
|
||||||
ColorID = id;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Error: DNG color ID #%d not supported\n", id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the image width.
|
|
||||||
*/
|
|
||||||
int DNG::setWidth(int width) {
|
|
||||||
ImageWidth = width;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets the image width.
|
|
||||||
*/
|
|
||||||
int DNG::getWidth(void) {
|
|
||||||
return ImageWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the image height.
|
|
||||||
*/
|
|
||||||
int DNG::setHeight(int height) {
|
|
||||||
ImageHeight = height;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets the image height.
|
|
||||||
*/
|
|
||||||
int DNG::getHeight(void) {
|
|
||||||
return ImageHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Saves given sample data into the DNG file according to the color ID
|
|
||||||
and image size specifications.
|
|
||||||
*/
|
|
||||||
int DNG::writeFile(void * data) {
|
|
||||||
|
|
||||||
/* create timestamp */
|
|
||||||
time_t abs_ts;
|
|
||||||
struct tm tm;
|
|
||||||
char timestamp[64];
|
|
||||||
|
|
||||||
/* get time stamp */
|
|
||||||
time (&abs_ts);
|
|
||||||
gmtime_r (&abs_ts, &tm);
|
|
||||||
sprintf(timestamp, "%04d:%02d:%02d %02d:%02d:%02d",
|
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
|
||||||
|
|
||||||
/* set general meta data */
|
|
||||||
TIFFSetField(tif, TIFFTAG_MAKE, "Svbony");
|
|
||||||
TIFFSetField(tif, TIFFTAG_MODEL, "Svbony SV305");
|
|
||||||
TIFFSetField(tif, TIFFTAG_SOFTWARE, "SimpleSkyCam v0.0.1");
|
|
||||||
TIFFSetField(tif, TIFFTAG_ARTIST, "Steffen Pohle");
|
|
||||||
TIFFSetField(tif, TIFFTAG_DATETIME, timestamp);
|
|
||||||
TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0");
|
|
||||||
TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0");
|
|
||||||
|
|
||||||
/* set image meta data */
|
|
||||||
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0); // image
|
|
||||||
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, ImageWidth); // in pixels
|
|
||||||
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, ImageHeight); // in pixels
|
|
||||||
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, BitsPerSample); // int
|
|
||||||
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
|
||||||
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
|
||||||
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
|
|
||||||
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, SamplesPerPixel);
|
|
||||||
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
|
||||||
|
|
||||||
if(ColorID == DNG_COLORID_RAW8 || ColorID == DNG_COLORID_RAW16) {
|
|
||||||
static const short CFARepeatPattern[] = { 2,2 }; // 2x2 CFA
|
|
||||||
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
|
|
||||||
TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, CFARepeatPattern);
|
|
||||||
TIFFSetField(tif, TIFFTAG_CFALAYOUT, 1);
|
|
||||||
TIFFSetField(tif, TIFFTAG_CFAPLANECOLOR, 3, "\000\001\002"); // RGB
|
|
||||||
// 0 = Red, 1 = Green, 2 = Blue
|
|
||||||
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\001\000\002\001"); // GRBG
|
|
||||||
}
|
|
||||||
else if(ColorID == DNG_COLORID_RGB) {
|
|
||||||
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
// go through all lines
|
|
||||||
for(int y = 0; y < ImageHeight; y++) {
|
|
||||||
|
|
||||||
// calculate offset into source image based on color ID settings
|
|
||||||
int offset = y * (ImageWidth * BitsPerSample/8 * SamplesPerPixel);
|
|
||||||
|
|
||||||
// write complete scanline
|
|
||||||
TIFFWriteScanline(tif, &((uint8_t *)data)[offset], y, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,68 +0,0 @@
|
|||||||
#ifndef _DNG_H_
|
|
||||||
#define _DNG_H_
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Example usage of the class:
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
DNG * dng = new DNG();
|
|
||||||
dng->setFile((char *)"test.dng");
|
|
||||||
dng->setWidth(640);
|
|
||||||
dng->setHeight(480);
|
|
||||||
dng->setColorID(DNG_COLORID_RGB);
|
|
||||||
uint8_t * data = (uint8_t *)malloc(dng->getWidth() * dng->getHeight() * 3);
|
|
||||||
memset(data, 0, dng->getWidth() * dng->getHeight() * 3);
|
|
||||||
for(int y = 0; y < dng->getHeight()/3; y++) {
|
|
||||||
for(int x = 0; x < dng->getWidth(); x++) {
|
|
||||||
data[y*dng->getWidth()*3 + x*3 + 0] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int y = dng->getHeight()/3; y < 2*dng->getHeight()/3; y++) {
|
|
||||||
for(int x = 0; x < dng->getWidth(); x++) {
|
|
||||||
data[y*dng->getWidth()*3 + x*3 + 1] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int y = 2*dng->getHeight()/3; y < 3*dng->getHeight()/3; y++) {
|
|
||||||
for(int x = 0; x < dng->getWidth(); x++) {
|
|
||||||
data[y*dng->getWidth()*3 + x*3 + 2] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dng->writeFile(data);
|
|
||||||
delete dng;
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <tiffio.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DNG_COLORID_RGB = 100,
|
|
||||||
DNG_COLORID_RAW16 = 101,
|
|
||||||
DNG_COLORID_RAW8 = 102
|
|
||||||
};
|
|
||||||
|
|
||||||
class DNG {
|
|
||||||
|
|
||||||
private:
|
|
||||||
TIFF * tif;
|
|
||||||
int ImageWidth;
|
|
||||||
int ImageHeight;
|
|
||||||
int BitsPerSample;
|
|
||||||
int SamplesPerPixel;
|
|
||||||
int ColorID;
|
|
||||||
int IsBigEndian(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
DNG();
|
|
||||||
~DNG();
|
|
||||||
|
|
||||||
int setWidth(int);
|
|
||||||
int setHeight(int);
|
|
||||||
int getWidth(void);
|
|
||||||
int getHeight(void);
|
|
||||||
void setColorID(int);
|
|
||||||
int setFile(char *);
|
|
||||||
int writeFile(void *);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,102 +0,0 @@
|
|||||||
/***************************************************************************************
|
|
||||||
*
|
|
||||||
* error.h is part of SimpleSkyCam.
|
|
||||||
*
|
|
||||||
*****************************************************************************************/
|
|
||||||
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
#include <execinfo.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include "gui.h"
|
|
||||||
#include "error.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
extern GtkBuilder *_builder_; // work around for threads
|
|
||||||
|
|
||||||
gboolean errormessage_thread (gpointer data) {
|
|
||||||
struct ErrorMessage *em = (struct ErrorMessage*) data;
|
|
||||||
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_),
|
|
||||||
em->window));
|
|
||||||
|
|
||||||
if (window == NULL) window = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_),
|
|
||||||
"window-main"));
|
|
||||||
|
|
||||||
GtkWidget *dialog;
|
|
||||||
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
|
|
||||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
GTK_MESSAGE_ERROR,
|
|
||||||
GTK_BUTTONS_OK,
|
|
||||||
"%s", em->message);
|
|
||||||
gtk_window_set_title(GTK_WINDOW(dialog), em->title);
|
|
||||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
||||||
gtk_widget_destroy(dialog);
|
|
||||||
|
|
||||||
free (em);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void errormessage_display (char *window, char *title, char *fmt,...) {
|
|
||||||
struct ErrorMessage *em = (struct ErrorMessage *) malloc (sizeof (struct ErrorMessage));
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
char buffer[ERRORMSG_LEN];
|
|
||||||
|
|
||||||
va_start (args, fmt);
|
|
||||||
vsnprintf (buffer, (ERRORMSG_LEN-1), fmt, args);
|
|
||||||
va_end (args);
|
|
||||||
buffer[ERRORMSG_LEN-1] = 0;
|
|
||||||
strncpy(em->title, title, ERRORMSG_LEN); em->title[ERRORMSG_LEN-1] = 0;
|
|
||||||
strncpy(em->message, buffer, ERRORMSG_LEN); em->message[ERRORMSG_LEN-1] = 0;
|
|
||||||
strncpy(em->window, window, ERRORMSG_LEN); em->window[ERRORMSG_LEN-1] = 0;
|
|
||||||
|
|
||||||
gdk_threads_add_idle(errormessage_thread, em);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* print error message and the backtrace
|
|
||||||
*/
|
|
||||||
#define SIZE 100
|
|
||||||
void errorexit (char *fmt,...) {
|
|
||||||
//
|
|
||||||
// error message
|
|
||||||
va_list args;
|
|
||||||
char text[4096];
|
|
||||||
|
|
||||||
va_start (args, fmt);
|
|
||||||
vsnprintf (text, 4096, fmt, args);
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
printf ("***************************\n");
|
|
||||||
printf (" ERROR\n");
|
|
||||||
printf ("***************************\n");
|
|
||||||
printf ("%s", text);
|
|
||||||
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
//
|
|
||||||
// backtrace
|
|
||||||
int j, nptrs;
|
|
||||||
void *buffer[SIZE];
|
|
||||||
char **s;
|
|
||||||
|
|
||||||
nptrs = backtrace(buffer, SIZE);
|
|
||||||
if ((s = (char**) backtrace_symbols(buffer, nptrs)) == NULL) {
|
|
||||||
for (j = 0; j < nptrs; j++) printf ("%-5d %p\n", j, buffer[j]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (j = 0; j < nptrs; j++) printf ("%-5d %s\n", j, s[j]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
/***************************************************************************************
|
|
||||||
*
|
|
||||||
* error.h is part of SimpleSkyCam.
|
|
||||||
*
|
|
||||||
*****************************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _ERROR_H_
|
|
||||||
#define _ERROR_H_
|
|
||||||
|
|
||||||
#define ERRORMSG_LEN 2048
|
|
||||||
struct ErrorMessage {
|
|
||||||
char window[ERRORMSG_LEN];
|
|
||||||
char title[ERRORMSG_LEN];
|
|
||||||
char message[ERRORMSG_LEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
void errorexit (char *fmt,...);
|
|
||||||
void errormessage_display (char *windowname, char *title, char *fmt,...);
|
|
||||||
|
|
||||||
#endif // _ERROR_H_
|
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "gui.h"
|
||||||
|
#include "filter.h"
|
||||||
|
|
||||||
|
extern Filter filter;
|
||||||
|
//gboolean cb_filtertemp_thread (gpointer data);
|
||||||
|
//gboolean cb_filterout_thread (gpointer data);
|
||||||
|
|
||||||
|
//
|
||||||
|
// C / C++ Wrapper for the thread function
|
||||||
|
//
|
||||||
|
gpointer _FilterThread (gpointer data) {
|
||||||
|
filter.Thread ();
|
||||||
|
return NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Filter::Filter() { // @suppress("Class members should be properly initialized")
|
||||||
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
g_mutex_init (&mutexin);
|
||||||
|
g_mutex_init (&muteximage);
|
||||||
|
g_mutex_init (&mutextmp);
|
||||||
|
g_mutex_init (&mutex);
|
||||||
|
running = 1;
|
||||||
|
inFrame.SetSize(64, 64);
|
||||||
|
image.SetSize(64, 64);
|
||||||
|
imagegtk.SetSize(64, 64);
|
||||||
|
thread = NULL;
|
||||||
|
thread = g_thread_new("Filter", _FilterThread, NULL);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Filter::~Filter() {
|
||||||
|
running = 0;
|
||||||
|
if (thread) {
|
||||||
|
g_thread_join (thread);
|
||||||
|
thread = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int Filter::NewFrame(VideoFrame *newframe, int posx, int posy) {
|
||||||
|
if (newframe == NULL) return -1;
|
||||||
|
LockInMutex();
|
||||||
|
inFrame.CopyFrom(newframe);
|
||||||
|
inFrameNew = 1;
|
||||||
|
UnLockInMutex();
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void Filter::NewImage() {
|
||||||
|
newimage = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// NewFrame: will set new frame
|
||||||
|
// Thread: newFrame |------> Find Object --- not found ---> send gui information
|
||||||
|
void Filter::Thread() {
|
||||||
|
while (running) {
|
||||||
|
// check for new frame
|
||||||
|
LockInMutex();
|
||||||
|
if (inFrameNew == 1) {
|
||||||
|
inFrameNew = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// do some other stuff use if possible only the oldFrame data
|
||||||
|
ComposeOutput();
|
||||||
|
UnLockInMutex();
|
||||||
|
|
||||||
|
// copy output image for gtk
|
||||||
|
LockImageMutex();
|
||||||
|
imagegtk.CopyFrom(&image);
|
||||||
|
UnLockImageMutex();
|
||||||
|
gdk_threads_add_idle(cb_thread_filter , &imagegtk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UnLockInMutex();
|
||||||
|
|
||||||
|
usleep (10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define FACTOR 25.0
|
||||||
|
void Filter::ComposeOutput() {
|
||||||
|
int x, y, idx, i;
|
||||||
|
float *pixd = NULL; // destination
|
||||||
|
unsigned char *pixs = NULL; // source
|
||||||
|
|
||||||
|
image.SetSize(inFrame.w, inFrame.h);
|
||||||
|
pixd = image.data;
|
||||||
|
pixs = inFrame.data;
|
||||||
|
|
||||||
|
if (pixd == NULL || pixs == NULL) return;
|
||||||
|
if (newimage) {
|
||||||
|
inFrame.CopyTo(&image);
|
||||||
|
newimage = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (x = 0; x < inFrame.w; x++)
|
||||||
|
for (y = 0; y < inFrame.h; y++) {
|
||||||
|
idx = 3 * (inFrame.w * y + x);
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
pixd[idx+i] = ((FACTOR-1.0) * (float)pixd[idx+i]/FACTOR) + (float)(pixs[idx+i] / FACTOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1,252 +0,0 @@
|
|||||||
/***************************************************************************************
|
|
||||||
*
|
|
||||||
* histogram.cc is part of SimpleSkyCam.
|
|
||||||
*
|
|
||||||
*****************************************************************************************/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "simpleskycam.h"
|
|
||||||
#include "histogram.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "video.h"
|
|
||||||
|
|
||||||
#define HISTOGRAM_WIDTH 256
|
|
||||||
#define HISTOGRAM_MARGIN 16
|
|
||||||
|
|
||||||
GtkWidget *histogram_da = NULL;
|
|
||||||
int histogram[3][HISTOGRAM_WIDTH]; // 6* hist_width min, max, min , max.....
|
|
||||||
int histogram_max; // max vlaue
|
|
||||||
int histogram_zoom_start = 0; // first zoom value
|
|
||||||
int histogram_zoom_stop = HISTOGRAM_WIDTH-1; // second zoom value
|
|
||||||
int histogram_x; // current mouse x-coordinate
|
|
||||||
int histogram_pressed_x; // window x-coordinate when pressing a button
|
|
||||||
int histogram_released_x; // window x-coordinate when releasing a button
|
|
||||||
int histogram_pressed = 0; // indicates button pressed or not
|
|
||||||
int histogram_zoomed = 0; // indicates zoom
|
|
||||||
|
|
||||||
extern GtkBuilder *_builder_; // work around for threads
|
|
||||||
|
|
||||||
void cb_histogramda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) {
|
|
||||||
int clientw, clienth, px, px2, py2;
|
|
||||||
GdkRGBA color;
|
|
||||||
char txt[255];
|
|
||||||
|
|
||||||
if (histogram_da == NULL) // should only be called once
|
|
||||||
histogram_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "histogram-da"));
|
|
||||||
clienth = gtk_widget_get_allocated_height(histogram_da);
|
|
||||||
clientw = gtk_widget_get_allocated_width(histogram_da);
|
|
||||||
|
|
||||||
//
|
|
||||||
// put the drawing area on the screen
|
|
||||||
cairo_paint(cr);
|
|
||||||
cairo_fill (cr);
|
|
||||||
|
|
||||||
if (histogram_max == 0) return;
|
|
||||||
|
|
||||||
for (int chan = 0; chan < 3; chan++) {
|
|
||||||
switch (chan) {
|
|
||||||
case 0:
|
|
||||||
color.blue = 0.0;
|
|
||||||
color.red = 1.0;
|
|
||||||
color.green = 0.0;
|
|
||||||
color.alpha = 0.5;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
color.blue = 0.0;
|
|
||||||
color.red = 0.0;
|
|
||||||
color.green = 1.0;
|
|
||||||
color.alpha = 0.5;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
color.blue = 1.0;
|
|
||||||
color.red = 0.0;
|
|
||||||
color.green = 0.0;
|
|
||||||
color.alpha = 0.5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gdk_cairo_set_source_rgba(cr, &color);
|
|
||||||
|
|
||||||
int histogram_width = histogram_zoom_stop - histogram_zoom_start + 1;
|
|
||||||
int histogram_scale = histogram_width - 1 > 0 ? histogram_width - 1 : 1;
|
|
||||||
for (int i = 0; i < histogram_width; i++) {
|
|
||||||
px = HISTOGRAM_MARGIN + ((clientw-HISTOGRAM_MARGIN*2) * i) / histogram_scale;
|
|
||||||
if (config.GetHistogramLog())
|
|
||||||
py2 = (clienth-HISTOGRAM_MARGIN) - ((clienth-HISTOGRAM_MARGIN*2) * log10(histogram[chan][histogram_zoom_start+i]+1) / log10(histogram_max));
|
|
||||||
else
|
|
||||||
py2 = (clienth-HISTOGRAM_MARGIN) - ((clienth-HISTOGRAM_MARGIN*2) * histogram[chan][histogram_zoom_start+i] / histogram_max);
|
|
||||||
|
|
||||||
if (i == 0) cairo_move_to(cr, px, py2);
|
|
||||||
else cairo_line_to(cr, px, py2);
|
|
||||||
|
|
||||||
}
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
if (histogram_pressed) {
|
|
||||||
if (histogram_pressed_x < histogram_x) {
|
|
||||||
px = histogram_pressed_x;
|
|
||||||
px2 = histogram_x;
|
|
||||||
} else {
|
|
||||||
px2 = histogram_pressed_x;
|
|
||||||
px = histogram_x;
|
|
||||||
}
|
|
||||||
cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 0.5);
|
|
||||||
cairo_rectangle (cr, px, 0, px2-px, clienth);
|
|
||||||
cairo_fill (cr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw some text
|
|
||||||
if (config.GetHistogramLog()) snprintf (txt, 255, "%d - Log", histogram_max);
|
|
||||||
else snprintf (txt, 255, "%d - Lin", histogram_max);
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
int dx, dy;
|
|
||||||
|
|
||||||
switch (i) {
|
|
||||||
case 0:
|
|
||||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
||||||
dx = -1;
|
|
||||||
dy = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
dx = +1;
|
|
||||||
dy = 0;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
dx = 0;
|
|
||||||
dy = -1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
dx = 0;
|
|
||||||
dy = +1;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
|
|
||||||
dx = 0;
|
|
||||||
dy = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
|
||||||
cairo_set_font_size (cr, 12);
|
|
||||||
cairo_move_to (cr, 10+dx, 15+dy);
|
|
||||||
cairo_show_text(cr, txt);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* test function
|
|
||||||
*/
|
|
||||||
void histogram_update(VideoFrame *vf) {
|
|
||||||
|
|
||||||
// save some time
|
|
||||||
static int to = 0;
|
|
||||||
if ((++to) % 8 == 0) return;
|
|
||||||
|
|
||||||
int chan, i, x, y;
|
|
||||||
|
|
||||||
if (vf == NULL) return;
|
|
||||||
if (vf->w <= 0 ) return;
|
|
||||||
|
|
||||||
// initialize histogram
|
|
||||||
memset (histogram, 0, sizeof(histogram));
|
|
||||||
|
|
||||||
for (i = 0, x = 0; x < vf->w; x++) {
|
|
||||||
for (y = 0; y < vf->h; y++) {
|
|
||||||
for (chan = 0; chan < 3; chan++) {
|
|
||||||
histogram[chan][vf->data[i++]]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (histogram_da)
|
|
||||||
gdk_window_invalidate_rect(gtk_widget_get_window(histogram_da), NULL, true);
|
|
||||||
|
|
||||||
for (histogram_max = 0, chan = 0; chan < 3; chan++) for (i = 0; i < HISTOGRAM_WIDTH; i++)
|
|
||||||
if (histogram_max < histogram[chan][i]) histogram_max = histogram[chan][i];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cb_histogramda_motion (GtkWidget *widget, GdkEvent *event, gpointer data) {
|
|
||||||
if(!histogram_zoomed) {
|
|
||||||
histogram_x = (int)round(event->button.x);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void cb_histogramda_btnpress (GtkWidget *widget, gpointer data) {
|
|
||||||
if (!histogram_zoomed) {
|
|
||||||
if (!histogram_pressed) {
|
|
||||||
histogram_pressed = 1;
|
|
||||||
histogram_pressed_x = histogram_x;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
histogram_zoomed = 0;
|
|
||||||
histogram_zoom_start = 0;
|
|
||||||
histogram_zoom_stop = HISTOGRAM_WIDTH-1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void cb_histogramda_btnrelease (GtkWidget *widget, gpointer data) {
|
|
||||||
if (!histogram_zoomed) {
|
|
||||||
if (histogram_pressed) {
|
|
||||||
histogram_pressed = 0;
|
|
||||||
histogram_released_x = histogram_x;
|
|
||||||
histogram_zoomed = 1;
|
|
||||||
|
|
||||||
// here we need to compute start/stop coordinates inside histogram
|
|
||||||
int clientw;
|
|
||||||
clientw = gtk_widget_get_allocated_width(histogram_da);
|
|
||||||
|
|
||||||
// translate first coordinate
|
|
||||||
histogram_zoom_start = (histogram_pressed_x - HISTOGRAM_MARGIN) * HISTOGRAM_WIDTH / (clientw - HISTOGRAM_MARGIN*2);
|
|
||||||
if (histogram_zoom_start < 0) histogram_zoom_start = 0;
|
|
||||||
if (histogram_zoom_start >= HISTOGRAM_WIDTH) histogram_zoom_start = HISTOGRAM_WIDTH-1;
|
|
||||||
|
|
||||||
// translate second coordinate
|
|
||||||
histogram_zoom_stop = (histogram_released_x - HISTOGRAM_MARGIN) * HISTOGRAM_WIDTH / (clientw - HISTOGRAM_MARGIN*2) + 1;
|
|
||||||
// limit the values
|
|
||||||
if (histogram_zoom_stop < 0) histogram_zoom_stop = 0;
|
|
||||||
if (histogram_zoom_stop >= HISTOGRAM_WIDTH) histogram_zoom_stop = HISTOGRAM_WIDTH-1;
|
|
||||||
|
|
||||||
// exchange the values if necessary
|
|
||||||
if (histogram_zoom_start > histogram_zoom_stop) {
|
|
||||||
int t = histogram_zoom_start;
|
|
||||||
histogram_zoom_start = histogram_zoom_stop;
|
|
||||||
histogram_zoom_stop = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void cb_histogramda_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data) {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (event == NULL) return;
|
|
||||||
|
|
||||||
else if (event->keyval == 'l') config.SetHistogramLog(config.GetHistogramLog() == 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void cb_histogram_show_window (GtkWidget *widget, gpointer data) {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-histogram"));
|
|
||||||
gtk_widget_show(wnd);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void cb_menu_set_histlog (GtkCheckMenuItem *checkmenuitem, gpointer user_data) {
|
|
||||||
config.SetHistogramLog(gtk_check_menu_item_get_active(checkmenuitem) == TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
/***************************************************************************************
|
|
||||||
*
|
|
||||||
* histogram.h is part of SimpleSkyCam.
|
|
||||||
*
|
|
||||||
***************************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _HISTOGRAM_H_
|
|
||||||
#define _HISTOGRAM_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "gui.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "videoframe.h"
|
|
||||||
|
|
||||||
void histogram_update(VideoFrame *vf);
|
|
||||||
|
|
||||||
#endif // _HISTOGRAM_H_
|
|
||||||
|
|
||||||
@ -1,239 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "output.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
extern GtkBuilder *_builder_; // work around for threads
|
|
||||||
extern Output output;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* callback from output thread
|
|
||||||
*/
|
|
||||||
gboolean cb_thread_output (gpointer data) {
|
|
||||||
int mode = output.GetStatus();
|
|
||||||
GtkWidget *btncapture = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputcapture"));
|
|
||||||
GtkWidget *btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputstop"));
|
|
||||||
GtkWidget *btnsnapshot = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputsnapshot"));
|
|
||||||
GtkWidget *btninputdest = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_btn_destpath"));
|
|
||||||
GtkWidget *inputdest = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath"));
|
|
||||||
|
|
||||||
if (mode & OUTPUT_MODE_SER_STARTED) {
|
|
||||||
gtk_widget_set_sensitive(btnstop, true);
|
|
||||||
gtk_widget_set_sensitive(btncapture, false);
|
|
||||||
gtk_widget_set_sensitive(btnsnapshot, false);
|
|
||||||
gtk_widget_set_sensitive(btninputdest, false);
|
|
||||||
gtk_widget_set_sensitive(inputdest, false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gtk_widget_set_sensitive(btnstop, false);
|
|
||||||
gtk_widget_set_sensitive(btncapture, true);
|
|
||||||
gtk_widget_set_sensitive(btnsnapshot, true);
|
|
||||||
gtk_widget_set_sensitive(btninputdest, true);
|
|
||||||
gtk_widget_set_sensitive(inputdest, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void input_getdestandsufix (std::string *sdir, std::string *ssufix) {
|
|
||||||
GtkWidget *inputdest = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath"));
|
|
||||||
GtkWidget *inputsufix = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_input_filesufix"));
|
|
||||||
if (sdir != NULL) *sdir = gtk_entry_get_text(GTK_ENTRY(inputdest));
|
|
||||||
if (ssufix != NULL) *ssufix = gtk_entry_get_text(GTK_ENTRY(inputsufix));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void cb_input_btncapture (GtkWidget *widget, gpointer data) {
|
|
||||||
std::string sdir, ssufix;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
input_getdestandsufix(&sdir, &ssufix);
|
|
||||||
output.SERStart(sdir, ssufix);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void cb_input_btnsnapshot (GtkWidget *widget, gpointer data) {
|
|
||||||
std::string sdir, ssufix;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
input_getdestandsufix(&sdir, &ssufix);
|
|
||||||
// output.Capture(sdir, ssufix);
|
|
||||||
};
|
|
||||||
|
|
||||||
void cb_input_btnstop (GtkWidget *widget, gpointer data) {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
output.SERStop();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// C / C++ Wrapper for the thread function
|
|
||||||
//
|
|
||||||
gpointer _OutputThread (gpointer data) {
|
|
||||||
output.Thread ();
|
|
||||||
return NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Output::Output() { // @suppress("Class members should be properly initialized")
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
outputser = NULL;
|
|
||||||
g_mutex_init (&mutexin);
|
|
||||||
g_mutex_init (&muteximage);
|
|
||||||
g_mutex_init (&mutextmp);
|
|
||||||
g_mutex_init (&mutex);
|
|
||||||
running = 1;
|
|
||||||
inFrame.Delete();
|
|
||||||
mode = 0;
|
|
||||||
|
|
||||||
thread = NULL;
|
|
||||||
thread = g_thread_new("Output", _OutputThread, NULL);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void Output::NotifyGTK () {
|
|
||||||
gdk_threads_add_idle(cb_thread_output, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* open output file and set mode flag
|
|
||||||
* all the other SER stuff will be set with the first frame
|
|
||||||
*/
|
|
||||||
void Output::SERStart (std::string destpath, std::string sufix) {
|
|
||||||
time_t t = time(NULL);
|
|
||||||
struct tm *tmptr;
|
|
||||||
char fname[LEN_FILENAME];
|
|
||||||
char fullfname[LEN_FULLFILENAME];
|
|
||||||
|
|
||||||
//
|
|
||||||
// check to create file, if not possible try creating the directory and create the file again
|
|
||||||
tmptr = localtime(&t);
|
|
||||||
strftime(fname, LEN_FILENAME, "%Y%m%d-%H%M%S", tmptr);
|
|
||||||
snprintf (fullfname, LEN_FULLFILENAME, "%s/%s-%s.ser", destpath.c_str(), fname, sufix.c_str());
|
|
||||||
outputfilename = fullfname;
|
|
||||||
printf ("%s:%d SERStart Destination File: %s\n", __FILE__, __LINE__, outputfilename.c_str());
|
|
||||||
|
|
||||||
mode |= OUTPUT_MODE_SER_STARTED;
|
|
||||||
NotifyGTK();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clode output file
|
|
||||||
*/
|
|
||||||
void Output::SERStop () {
|
|
||||||
mode &= ~(OUTPUT_MODE_SER_STARTED);
|
|
||||||
if (outputser) {
|
|
||||||
// close SER and delete object --> deleting the object should also rewrite the write the header
|
|
||||||
delete outputser;
|
|
||||||
outputser = NULL;
|
|
||||||
}
|
|
||||||
NotifyGTK();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Output::~Output() {
|
|
||||||
running = 0;
|
|
||||||
if (thread) {
|
|
||||||
g_thread_join (thread);
|
|
||||||
thread = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Output::NewFrame(VideoFrameRaw *rawframe) {
|
|
||||||
if (rawframe == NULL) return -1;
|
|
||||||
|
|
||||||
// printf ("%s:%d Output::NewFrame Frame Raw: %d x %d Type: %s\n", __FILE__, __LINE__, rawframe->w, rawframe->h, convert_from_pixelformat(rawframe->pixfmt).c_str());
|
|
||||||
if (inFrameNew) {
|
|
||||||
printf ("%s:%d Output::NewFrame truncating one frame.\n", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
LockInMutex();
|
|
||||||
inFrame.CopyFrom(rawframe);
|
|
||||||
inFrameNew = 1;
|
|
||||||
UnLockInMutex();
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// NewFrame: will set new frame
|
|
||||||
// Thread: newFrame |------> Find Object --- not found ---> send gui information
|
|
||||||
void Output::Thread() {
|
|
||||||
while (running) {
|
|
||||||
// check for new frame
|
|
||||||
LockInMutex();
|
|
||||||
|
|
||||||
if (inFrameNew == 1) {
|
|
||||||
if (mode & OUTPUT_MODE_SER_STARTED) {
|
|
||||||
if (outputser == NULL) { // first frame of ser output
|
|
||||||
int pixsize;
|
|
||||||
int serformat;
|
|
||||||
outputserw = inFrame.w;
|
|
||||||
outputserh = inFrame.h;
|
|
||||||
outputserfmt = inFrame.pixfmt;
|
|
||||||
|
|
||||||
if (!ser_convert_type_to_ser(outputserfmt, &pixsize, &serformat)) {
|
|
||||||
errormessage_display((char*)"windows-main", (char*)"Error", (char*)"Pixelformat [%s] not supported.", convert_from_pixelformat(outputserfmt).c_str());
|
|
||||||
SERStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
outputser = new SER();
|
|
||||||
if (outputser) outputser->setWidth(outputserw);
|
|
||||||
if (outputser) outputser->setHeight(outputserh);
|
|
||||||
if (outputser) outputser->setColorID(serformat);
|
|
||||||
if (outputser) outputser->setPixelDepth(pixsize);
|
|
||||||
if (outputser->setFile((char *)outputfilename.c_str()) == -1) {
|
|
||||||
errormessage_display((char*)"windows-main", (char*)"Error", (char*)"Could not set output file [%s]. Error: %s", outputfilename.c_str(), strerror(errno));
|
|
||||||
SERStop();
|
|
||||||
}
|
|
||||||
if (outputser) outputser->setObserver((char *)"FIXME:read username from OS");
|
|
||||||
if (outputser) outputser->setTelescope((char *)"FIXME:not implemented yet");
|
|
||||||
if (outputser) outputser->setInstrument((char *)"FIXME:just read device from driver");
|
|
||||||
if (outputser) outputser->setNumberOfFrames(0);
|
|
||||||
if (outputser) outputser->writeHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
//
|
|
||||||
// check if the frame type or size changed
|
|
||||||
if (outputserw != inFrame.w || outputserh != inFrame.h || outputserfmt != inFrame.pixfmt) {
|
|
||||||
errormessage_display((char*)"windows-main", (char*)"Error", (char*)"Frame format or dimensions changed.\n(%s @ %d x %d) != (%s @ %d x %d)\n",
|
|
||||||
convert_from_pixelformat(outputserfmt).c_str(), outputserw, outputserh,
|
|
||||||
convert_from_pixelformat(inFrame.pixfmt).c_str(), inFrame.w, inFrame.h);
|
|
||||||
SERStop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputser) { // we need to check in case outputser got deleted.
|
|
||||||
//
|
|
||||||
// write frame
|
|
||||||
outputser->appendFrame(inFrame.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inFrameNew = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnLockInMutex();
|
|
||||||
|
|
||||||
usleep (1000); // sleep 10ms
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
The file implements a simple PID regulator. The time resolution is
|
|
||||||
1usec. The update function should be called regularily as often as
|
|
||||||
possible.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include "pid.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
This this the class constructor. The min/max values are the minimum
|
|
||||||
and maximum values output by the regulator. The three regulator
|
|
||||||
parameters must be adjusted by experiments.
|
|
||||||
*/
|
|
||||||
PID::PID(double min, double max, double kp, double kd, double ki) {
|
|
||||||
Min = min;
|
|
||||||
Max = max;
|
|
||||||
Kp = kp;
|
|
||||||
Kd = kd;
|
|
||||||
Ki = ki;
|
|
||||||
Integral = 0;
|
|
||||||
PreviousError = 0;
|
|
||||||
PreviousTime = GetTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* default parameter
|
|
||||||
*/
|
|
||||||
PID::PID() {
|
|
||||||
Min = 0.0;
|
|
||||||
Max = 1.0;
|
|
||||||
Kp = 1.0;
|
|
||||||
Kd = 0.0;
|
|
||||||
Ki = 0.0;
|
|
||||||
Integral = 0;
|
|
||||||
PreviousError = 0;
|
|
||||||
PreviousTime = GetTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Class destructor.
|
|
||||||
*/
|
|
||||||
PID::~PID() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
A static function to obtain a timestamp for the integrative/derivative
|
|
||||||
parts of the regulator.
|
|
||||||
*/
|
|
||||||
int64_t PID::GetTime(void) {
|
|
||||||
|
|
||||||
struct timeval current_time;
|
|
||||||
int64_t t;
|
|
||||||
|
|
||||||
gettimeofday (¤t_time, NULL);
|
|
||||||
t = current_time.tv_sec * 1000000L + current_time.tv_usec;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function can be used to re-start the PID regulator. Re-setting
|
|
||||||
the integral and setting the current time as starting point.
|
|
||||||
*/
|
|
||||||
void PID::Start(void) {
|
|
||||||
Integral = 0;
|
|
||||||
PreviousError = 0;
|
|
||||||
PreviousTime = GetTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is the update function of the PID regulator. Passing the
|
|
||||||
target value of the regulator, the current process value and the
|
|
||||||
timestamp when the value was obtained.
|
|
||||||
*/
|
|
||||||
double PID::Update(double target, double value, int64_t time) {
|
|
||||||
double error, out;
|
|
||||||
int64_t dt;
|
|
||||||
double P, I, D;
|
|
||||||
double Derivative;
|
|
||||||
|
|
||||||
error = target - value;
|
|
||||||
|
|
||||||
// proportional part
|
|
||||||
P = Kp * error;
|
|
||||||
|
|
||||||
// integral part
|
|
||||||
dt = time - PreviousTime;
|
|
||||||
Integral += error * dt;
|
|
||||||
I = Ki * Integral;
|
|
||||||
|
|
||||||
if (dt > 0) {
|
|
||||||
// derivative part
|
|
||||||
Derivative = (error - PreviousError) / dt;
|
|
||||||
D = Kd * Derivative;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
D = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate output of regulator
|
|
||||||
out = P + I + D;
|
|
||||||
|
|
||||||
// Min/Max limitations of the regulator output
|
|
||||||
if (out > Max) out = Max;
|
|
||||||
if (out < Min) out = Min;
|
|
||||||
|
|
||||||
// save previous error value and time
|
|
||||||
PreviousError = error;
|
|
||||||
PreviousTime = time;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is a shortcut function of the update function without passing
|
|
||||||
the timestamp. The timestamp will be the time when the fuction is
|
|
||||||
called.
|
|
||||||
*/
|
|
||||||
double PID::Update(double target, double value) {
|
|
||||||
return Update(target, value, GetTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PID::SetParam (double mi, double ma, double p, double i, double d) {
|
|
||||||
Kp = p;
|
|
||||||
Ki = i/1000000.0;
|
|
||||||
Kd = d/1000000.0;
|
|
||||||
Min = mi;
|
|
||||||
Max = ma;
|
|
||||||
Start();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void PID::GetParam (double *mi, double *ma, double *p, double *i, double *d) {
|
|
||||||
if (p != NULL) *p = Kp;
|
|
||||||
if (i != NULL) *i = Ki*1000000.0;
|
|
||||||
if (d != NULL) *d = Kd*1000000.0;
|
|
||||||
if (mi != NULL) *mi = Min;
|
|
||||||
if (ma != NULL) *ma = Max;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1 +0,0 @@
|
|||||||
<mxfile host="Electron" modified="2023-02-05T21:56:36.730Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="qnZzmQGoDEGPjH1afGyG" version="20.3.0" type="device"><diagram id="1p0Bprw3xxz6Ckpdy3R8" name="Seite-1">3VnLdpswEP0aL9MDiOcytpM06enjNIsk3fQoIBs1MnKF/MrXVxhhg2Rsx6XEZQUaDSMx92oe0AODyfKGwWn8mUaI9CwjWvbAsGdZpuE54pJJVrnEte1cMGY4kkpbwT1+RcWTUjrDEUoripxSwvG0KgxpkqCQV2SQMbqoqo0oqa46hWOkCe5DSHTpA454nEt9y9vKPyI8jouVTTfIZyawUJZvksYwoouSCFz1wIBRyvO7yXKASOa8wi/5c9c1s5uNMZTwYx749Sn6encXvHp9b3jp3a5eaZBcWLmVOSQz+cJys3xVeAAl0WXmSDEKCUxTHPZAP+YTIgSmuGV0lkQoW8QQI31XcqMoqjha7vEG0QnibCUUFlv3OtJlccmzhYwhAjmeV+GBEuXxxtxmhW8Ui51YhmQkKOCQfLR9o2oipTMWIvlU2Z2KIc89YIhDNkZcMyRuSq+9Fa3RegNyoDXk8hfZsxW7mwirhkyjXYRtDeEnDWKOlrwKasoZfUEDSigTkoQmQrM/woQoIkjwOMmYIeBGQt6fI8axCHyXcmKCoyhbpr+IMUf3Uxhmay5EmD+eOplNtNxLCjlrBVVn+zJvlDjj7uAMMOrpUcHjrc53NOc/dtf5nl1zZN7L+27Twa2MQc8CkYP8yNYAEzO+9Qxc9z9IZI6Sf4B7aiJTwtxmgy2FOa+1RNY15Fw1QQXtIhdoyIUz9nNK0+5GStdQXO6+c6Qs+qQSCHCJU7PDECiVgvXuEJgaBPsimPRqBNN47RZzFypFr2lrHhSOY6vHbPDBcorxk3x4PRguy6rDVU0KhMgfhbtSoBv66Hn0Vx1BcFYB1/UVxpzaEVhqz9dywDXf1vRJptUmShGt5xsK1vLKOMCr01lSxK5zoYl7oBA6uqIyFUNHNo4CN7gqqU0zhXTPhtVICCpfgMRNbrFZDuptaWMcTIVjuF7prcXXmBQWahl3JkRylHgDVPxPLfA2XySaJpJK2KANIulNHuxu1aJxwtSrFqvVqqXxvqvBAuNcDnJTnZoNlANmtlw4+PpZE12CjnhnzhtQc6Oln7d2uwS9W/6Bs59lXUXAsWsOTwkB+x8h8BsOvjwi+5lcvZDvw9v5zOk/XLTapp36wVGJfDsweLfy+NDXpqODoXo0G/tzJobb/6m5+vavNLj6Aw==</diagram></mxfile>
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
#ifndef _PID_H_
|
|
||||||
#define _PID_H_
|
|
||||||
|
|
||||||
class PID {
|
|
||||||
|
|
||||||
private:
|
|
||||||
double Min, Max;
|
|
||||||
double Kp; // proportional factor
|
|
||||||
double Ki; // integral factor
|
|
||||||
double Kd; // derivative factor
|
|
||||||
double Integral;
|
|
||||||
double PreviousError;
|
|
||||||
int64_t PreviousTime;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PID(double min, double max, double kp, double kd, double ki);
|
|
||||||
PID();
|
|
||||||
~PID();
|
|
||||||
|
|
||||||
void Start(void);
|
|
||||||
void SetParam(double mi, double ma, double p, double i, double d);
|
|
||||||
void GetParam(double *mi, double *ma, double *p, double *i, double *d);
|
|
||||||
double GetMax() { return Max; };
|
|
||||||
double GetMin() { return Min; };
|
|
||||||
double Update(double target, double value, int64_t time);
|
|
||||||
double Update(double target, double value);
|
|
||||||
static int64_t GetTime(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1 +0,0 @@
|
|||||||
<mxfile host="Electron" modified="2024-04-04T17:50:32.413Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="RaccqhXgUPgrDxD3-wkT" version="20.3.0" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7VzZdps6FP0ar3Xvg7NAeMCPsZ2hbdqkTpuhL10yCEyDkYtxbPfrrwQCoyEED8GObx+aIkVISPvsfY6m1IzeeHERwsnoM7aRXwOavagZ/RoAZkMnP2nGkmWYWpLhhp6dZOmrjFvvD2KZabGZZ6MpVzDC2I+8CZ9p4SBAVsTlwTDEc76Yg32+1Ql0kZRxa0Ffzr337GjEegHaq/xL5LmjtGW91Ul+M4ZpYdaT6QjaeJ7LMs5qRi/EOEqexose8unYpeNy/2F57189tS4+fp3+ht+7n759uasnlZ2v80rWhRAF0cZVP/R+Xz88zj74N+cw+Pop+gEQqLNReIb+jI0X62u0TAcwxLPARrQSvWZ0R9HYZ4+/UBQtGeBwFmGShcNohF0cQP8K4wkr5+AgYsV0mkaBfUqBJemhj62nJOvc82nFWpJi5U2SmkYhfsqwM2hOCgQt7MMh8rvQenLjD+1hH4fkVwEOEK3KJsbA+rL6uLNVbhctvOiB1nXSZKlH9t30ub9Iv4kmlizhkG9NG6oBw24i025kn5r7jQmGRqsVdykKl7lmaPIx6y5JrBqKU8t86gaF3hhFKGSZJc2Bmc0Uz0ILFZRjNhDB0EWsvttPfvdq0Pt9e+NcGbBev+jdzOqNpBwd0hy1mLFdIEw+MVySAiHyYeQ98/yDjMZuVi579QZ7pB9AY4oDDEDGKH6JSY5uaHwlSZfYe3mTF6pqpFrFKgINoaKkz1JF5CHXo1VWzCg1u8DA6s+vJ9bDwp/YT8PB2fXV5xSBHLus4c9oFCJo/3wmsoj/OTn5VyIcHeAratU83aDvuQF5tgjq1BS6zyiMPCJ0p+wXY8+2Y5MO0dT7A4dxfdReJrR/cY+b3Vqzn1KStWjI5lQoFaRVtFBJN2uRU0fOMNhb2gkAnRYHTDpSW5pOXe/wr2DHmaJtoVWOhi4r54DASnLuKLDk/z6MoITtdO6NfRhL0wiH3h+CA0xlT1QViEzHUqlKyzLR0FlbCCTkXkRI52nTYsn5yn9mTBrlfWdbexWxATWUwCXjkbXW4Vtryq0pG2sKjUGf0CKAEepSPzDdEnSlAmaRAE/WYgfD+89fs/EkLc98lNJpKpxrTgvyLrWhNIRCo33VJRiySyhyHbtzCRxiBfAUfXWOkj04roGWT7rQHYbkyaVPjKeD0/uXWMpDNh95EbqdwHjE5iRIfhkL0veu68PplFGaj110MXZZE7byBG7yDtSQKaWnRfKcEt3jzpCRxbKHA9qdeDZAfpjkX9ejycFF9+jx0LUKAVF3wZQQ6ZMI06II0JqBdo59nwxMmrzBUy/ycEAeCXRkGP3j8G2gLUPR7ij8jSH6m3LOTWxO4UsPxbvpugTput5tA1e20fxLcH9vPLsqZFDelyoLdmRfqh5+bV/OtOizFQJx4OKcKlt5cQYcRTtA1uaWgqJvp83ytFHwluc+hkcIBBCn6+2mDAV4Iyju+9/6D/jSvPyozz886YNx/8cPtqKWR0LlB8UA8/iQaRoCMqoA5q1IolbL5tbOajdTsdR/pc+PnC9T+y+aEN3Opj5s06mgwn0Vrfq96r72NhVUz9RlDX08u1WaTBVLbYX4FNr39sttde1Eaxj8BIS5uE2X23a6vFZkdTn47ggodn4iYpxLcPLyCHhQiVJOaLnxwqUbXScOmd5YIxhGJzayvGlcpVKbt2TYGlMT0f8pRNZQiGzrzUQWbC2ymyjqLqN5ETyF6O9aMcvup+wv4C/67Bzl0iWAY4tmxDizyohfbQnGoQQzGfU44q14uKcgJKUKtyBdELAfCKWy9fa943rkQarKPgrn1gdiIEDesnhnYerOdoXrdFs4DVMPNzDV5SWB/2Fkqnf2Hpo2DkxatSOVVsX8v2i9+FCEFUg0/XL9nnQ1nQDv4LSN3m6bHHu3PW1TwekaefdBAu/IzyXmj2htvE9W2TlF2azLHkksDNNeVZ3KziQKJ6J0wa+VPZEoLqS3Kz6RKMeb2fbFavciyfDSjPjMIj2yaMcbgMmZxaQM+QZPfI/kDV/cCalAccs6wFRidqKwZoeD9ZDWV5W9B3IYS4SOjj1pPaDR7PUsmszkTcZ3cshDPMGoiFezg4aF5y52t6srL2mnQ6x5DvkRIETd2YGvtmWGUxqLNuCgSJlSxZ6uOrQypTHe92JbJRF/dnj1NedbNuLXd+58tyKYzK9U0Y6cUaptordilDKokEf+b7BeRbC+66C7omDaaPHOudlpbhZMgwZPhA6oNphuKuy+dDDtxOL0/oLpQgU4wFg6uxrU5l/ZSWytvvUlnz2RoVvJl0U9imfxGK70UsvLyRprjJuLg7pToKQ45LyQKsBO87bVEPFA2qZXBLMP2tcVQXmh0o2e6KCRaZjvBa5kOoRhEW8skocYms1GU+FTHNNClrWWRKjCI9441zO08lGOofHIZHsQ+ThHU5iY6AV2FufoqtWTd0/ssl6/GmI3BD62xAl5WWKLCiFV9NbElqPiv8ROkGkLyCjuxFRMbFUk9+6J3TooYhsCsU3xsnBpjy2YT/YHSaoidusvsV8gtiC5puIqt5LYYvC2CbHbd99njvfp1P36ZYo+G5ozub1U3N8I0WxKr+cNZ45D14bEuxsWniyTaUvcb7vGbqSyVfGCS8MlUM5m7i/N9VOUfeREu8BYMSErB3vpqEx1EwSoVp82wJgkV39dJ6Hv6k8UGWf/AQ==</diagram></mxfile>
|
|
||||||
@ -1,523 +0,0 @@
|
|||||||
/*
|
|
||||||
Video file format class according the specification of the
|
|
||||||
"SER format description version 3" found at
|
|
||||||
https://free-astro.org/images/5/51/SER_Doc_V3b.pdf
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include "ser.h"
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert v4l2 pixelformat to the corresponding ser format.
|
|
||||||
* Also return depth per channel.
|
|
||||||
*/
|
|
||||||
int ser_convert_type_to_ser (int v4l2_fmt, int *pixeldepth, int *serformat) {
|
|
||||||
if (pixeldepth == NULL || serformat == NULL) return 0;
|
|
||||||
|
|
||||||
switch (v4l2_fmt) {
|
|
||||||
case (V4L2_PIX_FMT_RGB24):
|
|
||||||
*serformat = SER_COLORID_RGB;
|
|
||||||
*pixeldepth = 8;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR24):
|
|
||||||
*serformat = SER_COLORID_BGR;
|
|
||||||
*pixeldepth = 8;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_SGRBG8):
|
|
||||||
*serformat = SER_COLORID_BAYER_GRBG;
|
|
||||||
*pixeldepth = 8;
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_SGRBG16):
|
|
||||||
*serformat = SER_COLORID_BAYER_GRBG;
|
|
||||||
*pixeldepth = 16;
|
|
||||||
break;
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SER::SER() {
|
|
||||||
/* clear header */
|
|
||||||
memset(&header, 0, sizeof(header));
|
|
||||||
|
|
||||||
/* fill some initial data */
|
|
||||||
memcpy(header.FileID, "LUCAM-RECORDER", strlen("LUCAM-RECORDER"));
|
|
||||||
header.LuID = 0;
|
|
||||||
header.ColorID = SER_COLORID_RGB;
|
|
||||||
header.LittleEndian = 0; // opposite meaning of the specification
|
|
||||||
header.ImageWidth = 0;
|
|
||||||
header.ImageHeight = 0;
|
|
||||||
header.PixelDepthPerPlane = 8;
|
|
||||||
header.FrameCount = 0;
|
|
||||||
header.DateTime = 0;
|
|
||||||
header.DateTimeUTC = 0;
|
|
||||||
|
|
||||||
FileDesc = NULL;
|
|
||||||
Frame = NULL;
|
|
||||||
FramePointer = 0;
|
|
||||||
FrameSize = 0;
|
|
||||||
NumberOfPlanes = 0;
|
|
||||||
BytesPerPixel = 0;
|
|
||||||
Reading = 1;
|
|
||||||
NumberOfTimeStamps = 0;
|
|
||||||
TimeStamps = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Class destructor. Free resources.
|
|
||||||
*/
|
|
||||||
SER::~SER() {
|
|
||||||
|
|
||||||
if(FileDesc) {
|
|
||||||
|
|
||||||
/* Update header if necessary */
|
|
||||||
if(!Reading) {
|
|
||||||
|
|
||||||
int err;
|
|
||||||
int64_t offset = (int64_t)&header.FrameCount - (int64_t)&header;
|
|
||||||
header.FrameCount = FramePointer;
|
|
||||||
|
|
||||||
/* goto file beginning */
|
|
||||||
if((err = fseek(FileDesc, offset, SEEK_SET)) == -1) {
|
|
||||||
fprintf(stderr, "Error: failed seek SER file FrameCount (%d, %s)\n", err, strerror(errno));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* write framecount in header data */
|
|
||||||
if((err = fwrite(&header.FrameCount, sizeof(header.FrameCount), 1, FileDesc)) != 1) {
|
|
||||||
fprintf(stderr, "Error: failed writing SER file FrameCount (%d, %s)\n",
|
|
||||||
err, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* goto file end */
|
|
||||||
if((err = fseek(FileDesc, 0, SEEK_END)) == -1) {
|
|
||||||
fprintf(stderr, "Error: failed seek SER file end (%d, %s)\n", err, strerror(errno));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* write timestamp data */
|
|
||||||
if((err = fwrite(TimeStamps, sizeof(header.DateTime), FramePointer, FileDesc)) != FramePointer) {
|
|
||||||
fprintf(stderr, "Error: failed writing SER file TimeStamps (%d, %s)\n",
|
|
||||||
err, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close file if necessary */
|
|
||||||
fclose(FileDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free timestamps */
|
|
||||||
if(TimeStamps) {
|
|
||||||
free(TimeStamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free frame memory if necessary */
|
|
||||||
if(Frame) {
|
|
||||||
free(Frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the name of the observer. E.g. "Steffen Pohle"
|
|
||||||
40 ASCII characters {32...126 dec.}, fill unused characters with 0 dec.
|
|
||||||
*/
|
|
||||||
int SER::setObserver(char *name) {
|
|
||||||
strncpy(header.Observer, name, sizeof(header.Observer));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the name of the used camera. E.g. "Svbony SV305"
|
|
||||||
40 ASCII characters {32...126 dec.}, fill unused characters with 0 dec.
|
|
||||||
*/
|
|
||||||
int SER::setInstrument(char *name) {
|
|
||||||
strncpy(header.Instrument, name, sizeof(header.Instrument));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the name of the used telescope. E.g. "Sky-Watcher EVOSTAR 102"
|
|
||||||
40 ASCII characters {32...126 dec.}, fill unused characters with 0 dec.
|
|
||||||
*/
|
|
||||||
int SER::setTelescope(char *name) {
|
|
||||||
strncpy(header.Telescope, name, sizeof(header.Telescope));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set the file name for input/output operations. If file exists, we open it
|
|
||||||
for reading, otherwise we try to create the file.
|
|
||||||
*/
|
|
||||||
int SER::setFile(char *name) {
|
|
||||||
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
/* try opening file for reading */
|
|
||||||
if((file = fopen(name, "rb")) == NULL) {
|
|
||||||
|
|
||||||
/* file does probably not exist */
|
|
||||||
if((file = fopen(name, "wb")) == NULL) {
|
|
||||||
|
|
||||||
/* failed to create file */
|
|
||||||
fprintf(stderr, "Error: failed to create file '%s' (%s)\n", name, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stdout, "Debug: created file '%s' for writing SER file\n", name);
|
|
||||||
FileDesc = file;
|
|
||||||
Reading = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "Debug: opened file '%s' for reading SER file\n", name);
|
|
||||||
FileDesc = file;
|
|
||||||
Reading = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function writes the file header of the SER file.
|
|
||||||
*/
|
|
||||||
int SER::writeHeader(void) {
|
|
||||||
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* adjust time stamps for header */
|
|
||||||
setDateTime();
|
|
||||||
|
|
||||||
if(FileDesc == NULL) {
|
|
||||||
fprintf(stderr, "Error: writing header, SER file not yet specified\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* goto file beginning */
|
|
||||||
if((err = fseek(FileDesc, 0, SEEK_SET)) == -1) {
|
|
||||||
fprintf(stderr, "Error: failed seek SER file beginning (%d, %s)\n", err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write header data */
|
|
||||||
if((err = fwrite(&header, sizeof(header), 1, FileDesc)) != 1) {
|
|
||||||
fprintf(stderr, "Error: failed writing SER header (%d, %s)\n", err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset space for timestamps */
|
|
||||||
NumberOfTimeStamps = 16;
|
|
||||||
if(TimeStamps) {
|
|
||||||
free(TimeStamps);
|
|
||||||
}
|
|
||||||
/* allocate some memory for the upcoming timestamps */
|
|
||||||
if((TimeStamps = (int64_t *)malloc(sizeof(header.DateTime) * NumberOfTimeStamps)) == NULL) {
|
|
||||||
fprintf(stderr, "Error: failed to allocate %llu bytes for timestamps\n",
|
|
||||||
(long long unsigned int) sizeof(header.DateTime) * (long)NumberOfTimeStamps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FramePointer = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function reads the file header of the SER file.
|
|
||||||
*/
|
|
||||||
int SER::readHeader(void) {
|
|
||||||
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if(FileDesc == NULL) {
|
|
||||||
fprintf(stderr, "Error: reading header, SER file not yet specified\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* goto file beginning */
|
|
||||||
if((err = fseek(FileDesc, 0, SEEK_SET)) == -1) {
|
|
||||||
fprintf(stderr, "Error: failed seek SER file beginning (%d, %s)\n", err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read header data */
|
|
||||||
if((err = fread(&header, sizeof(header), 1, FileDesc)) != 1) {
|
|
||||||
fprintf(stderr, "Error: failed reading SER header (%d, %s)\n", err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FramePointer = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function apppends a single frame at the current file position.
|
|
||||||
Frame size is determined by internal header data.
|
|
||||||
*/
|
|
||||||
int SER::appendFrame(void *data) {
|
|
||||||
|
|
||||||
if(FileDesc == NULL) {
|
|
||||||
fprintf(stderr, "Error: appending frame, SER file not yet specified\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write frame data */
|
|
||||||
if(fwrite(data, FrameSize, 1, FileDesc) != 1) {
|
|
||||||
fprintf(stderr, "Error: failed write SER frame (%s)\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ensure we have enough memory allocated for timestamps */
|
|
||||||
if(FramePointer >= NumberOfTimeStamps) {
|
|
||||||
while(FramePointer >= NumberOfTimeStamps)
|
|
||||||
NumberOfTimeStamps *= 2;
|
|
||||||
if((TimeStamps = (int64_t *)realloc(TimeStamps, sizeof(header.DateTime) * NumberOfTimeStamps)) == NULL) {
|
|
||||||
fprintf(stderr, "Error: failed to re-allocate %llu bytes for timestamps\n",
|
|
||||||
(long long unsigned int) sizeof(header.DateTime) * (long)NumberOfTimeStamps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* save timestamp for this frame */
|
|
||||||
TimeStamps[FramePointer++] = currentDateTimeUTC();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Updates the internal data according changes in the header.
|
|
||||||
*/
|
|
||||||
void SER::updateHeaderData(void) {
|
|
||||||
NumberOfPlanes = header.ColorID < SER_COLORID_RGB ? 1 : 3;
|
|
||||||
BytesPerPixel = NumberOfPlanes * (header.PixelDepthPerPlane <= 8 ? 1 : 2);
|
|
||||||
FrameSize = header.ImageWidth * header.ImageHeight * BytesPerPixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the pixel depth in bits.
|
|
||||||
*/
|
|
||||||
int SER::setPixelDepth(int pixeldepth) {
|
|
||||||
header.PixelDepthPerPlane = pixeldepth;
|
|
||||||
updateHeaderData();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns the pixel depth in bits.
|
|
||||||
*/
|
|
||||||
int SER::getPixelDepth(void) {
|
|
||||||
return header.PixelDepthPerPlane;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns the number of bytes in an allocated frame.
|
|
||||||
*/
|
|
||||||
size_t SER::getFrameSize(void) {
|
|
||||||
updateHeaderData();
|
|
||||||
return FrameSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the image width.
|
|
||||||
*/
|
|
||||||
int SER::setWidth(int width) {
|
|
||||||
header.ImageWidth = width;
|
|
||||||
updateHeaderData();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets the image width.
|
|
||||||
*/
|
|
||||||
int SER::getWidth(void) {
|
|
||||||
return header.ImageWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the image height.
|
|
||||||
*/
|
|
||||||
int SER::setHeight(int height) {
|
|
||||||
header.ImageHeight = height;
|
|
||||||
updateHeaderData();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets the image height.
|
|
||||||
*/
|
|
||||||
int SER::getHeight(void) {
|
|
||||||
return header.ImageHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the color ID.
|
|
||||||
*/
|
|
||||||
int SER::setColorID(int id) {
|
|
||||||
header.ColorID = id;
|
|
||||||
updateHeaderData();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Allocates memory for a single frame. Reading/writing could be done
|
|
||||||
on this memory block.
|
|
||||||
*/
|
|
||||||
void * SER::allocFrame(void) {
|
|
||||||
|
|
||||||
/* Drop old frame data. */
|
|
||||||
if(Frame) {
|
|
||||||
free(Frame);
|
|
||||||
Frame = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try allocating new frame data. */
|
|
||||||
if((Frame = malloc(FrameSize)) == NULL) {
|
|
||||||
fprintf(stderr, "Error: failed to allocate %lu bytes for frame\n", (long)FrameSize);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return Frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function reads a single frame at the current file position.
|
|
||||||
Frame size is determined by internal header data.
|
|
||||||
*/
|
|
||||||
int SER::readFrame(void *data) {
|
|
||||||
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* read frame data */
|
|
||||||
if((err = fread(data, FrameSize, 1, FileDesc)) != 1) {
|
|
||||||
fprintf(stderr, "Error: failed reading SER frame (%d, %s)\n", err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* goto next frame */
|
|
||||||
FramePointer++;
|
|
||||||
|
|
||||||
/* reached end of file? */
|
|
||||||
if(FramePointer >= getNumberOfFrames()) {
|
|
||||||
|
|
||||||
/* goto first frame beginning */
|
|
||||||
if((err = fseek(FileDesc, sizeof(header), SEEK_SET)) == -1) {
|
|
||||||
fprintf(stderr, "Error: failed seeking SER file frame #%d (%d, %s)\n",
|
|
||||||
0, err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start over at beginning */
|
|
||||||
FramePointer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function reads a single frame at the given file position.
|
|
||||||
Frame size is determined by internal header data.
|
|
||||||
*/
|
|
||||||
int SER::readFrame(void *data, int frame) {
|
|
||||||
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* goto frame beginning */
|
|
||||||
if((err = fseek(FileDesc, sizeof(header) + frame * FrameSize, SEEK_SET)) == -1) {
|
|
||||||
fprintf(stderr, "Error: failed seeking SER file frame #%d (%d, %s)\n",
|
|
||||||
frame, err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read frame data */
|
|
||||||
if((err = fread(data, FrameSize, 1, FileDesc)) != 1) {
|
|
||||||
fprintf(stderr, "Error: failed reading SER frame (%d, %s)\n", err, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FramePointer = frame + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the number of frames in the header.
|
|
||||||
*/
|
|
||||||
void SER::setNumberOfFrames(int32_t frames) {
|
|
||||||
header.FrameCount = frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns the number of frames in the header.
|
|
||||||
*/
|
|
||||||
int32_t SER::getNumberOfFrames(void) {
|
|
||||||
return header.FrameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the current timestamps in the header.
|
|
||||||
*/
|
|
||||||
int64_t SER::setDateTime(void) {
|
|
||||||
|
|
||||||
int64_t hundred_nano_seconds = currentDateTimeUTC();
|
|
||||||
|
|
||||||
header.DateTimeUTC = hundred_nano_seconds;
|
|
||||||
header.DateTime = hundred_nano_seconds + differenceLocalUTC();
|
|
||||||
return header.DateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Timestamps in SER
|
|
||||||
-----------------
|
|
||||||
Holds IEEE 64-bit (8-byte) values that represent dates ranging from
|
|
||||||
January 1 of the year 0001 through December 31 of the year 9999, and
|
|
||||||
times from 12:00:00 AM (midnight) through 11:59:59.9999999 PM. Each
|
|
||||||
increment represents 100 nanoseconds of elapsed time since the
|
|
||||||
beginning of January 1 of the year 1 in the Gregorian calendar. The
|
|
||||||
maximum value represents 100 nanoseconds before the beginning of
|
|
||||||
January 1 of the year 10000.
|
|
||||||
*/
|
|
||||||
int64_t SER::currentDateTimeUTC(void) {
|
|
||||||
|
|
||||||
int64_t hundred_nano_seconds;
|
|
||||||
struct timeval current_time;
|
|
||||||
|
|
||||||
/* get time since 01.01.1970 00:00 */
|
|
||||||
gettimeofday (¤t_time, NULL);
|
|
||||||
hundred_nano_seconds = (62135596800L + current_time.tv_sec) * 10000000L +
|
|
||||||
current_time.tv_usec * 10L;
|
|
||||||
return hundred_nano_seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Determines the difference between local time and UTC time.
|
|
||||||
*/
|
|
||||||
int64_t SER::differenceLocalUTC(void) {
|
|
||||||
|
|
||||||
time_t abs_ts, loc_ts, gmt_ts;
|
|
||||||
struct tm loc_time_info, gmt_time_info;
|
|
||||||
|
|
||||||
/* Absolute time stamp.*/
|
|
||||||
time (&abs_ts);
|
|
||||||
|
|
||||||
/* Now get once the local time for this time stamp,
|
|
||||||
and once the GMT (UTC without summer time) time stamp.*/
|
|
||||||
localtime_r (&abs_ts, &loc_time_info);
|
|
||||||
gmtime_r (&abs_ts, &gmt_time_info);
|
|
||||||
|
|
||||||
/* Convert them back.*/
|
|
||||||
loc_ts = mktime (&loc_time_info);
|
|
||||||
gmt_ts = mktime (&gmt_time_info);
|
|
||||||
|
|
||||||
/* Unfortunately, GMT still has summer time. Get rid of it:*/
|
|
||||||
if (gmt_time_info.tm_isdst == 1) gmt_ts -= 3600;
|
|
||||||
|
|
||||||
fprintf(stdout, "Debug: difference between local time and UTC is %lld hours\n",
|
|
||||||
(long long int)(loc_ts - gmt_ts) / 3600);
|
|
||||||
return ((int64_t)loc_ts - (int64_t)gmt_ts) * 10000000L;
|
|
||||||
}
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
#ifndef _SER_H_
|
|
||||||
#define _SER_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
Example usage of the class:
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
SER *ser = new SER();
|
|
||||||
ser->setWidth(640);
|
|
||||||
ser->setHeight(480);
|
|
||||||
ser->setColorID(SER_COLORID_RGB);
|
|
||||||
ser->setPixelDepth(8);
|
|
||||||
ser->setFile((char *)"test.ser");
|
|
||||||
ser->setObserver((char *)"Steffen Pohle");
|
|
||||||
ser->setTelescope((char *)"Sky-Watcher EVOSTAR 102");
|
|
||||||
ser->setInstrument((char *)"Svbony SV305");
|
|
||||||
ser->setNumberOfFrames(1);
|
|
||||||
ser->writeHeader();
|
|
||||||
uint8_t * data = (uint8_t *) ser->allocFrame();
|
|
||||||
memset(data, 0, ser->getFrameSize());
|
|
||||||
for(int y = 0; y < ser->getHeight()/3; y++) {
|
|
||||||
for(int x = 0; x < ser->getWidth(); x++) {
|
|
||||||
data[y*ser->getWidth()*3 + x*3 + 0] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int y = ser->getHeight()/3; y < 2*ser->getHeight()/3; y++) {
|
|
||||||
for(int x = 0; x < ser->getWidth(); x++) {
|
|
||||||
data[y*ser->getWidth()*3 + x*3 + 1] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int y = 2*ser->getHeight()/3; y < 3*ser->getHeight()/3; y++) {
|
|
||||||
for(int x = 0; x < ser->getWidth(); x++) {
|
|
||||||
data[y*ser->getWidth()*3 + x*3 + 2] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ser->appendFrame(data);
|
|
||||||
delete ser;
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ser_convert_type_to_ser (int v4l2_fmt, int *pixeldepth, int *serformat);
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
SER_COLORID_MONO = 0,
|
|
||||||
SER_COLORID_BAYER_RGGB = 8,
|
|
||||||
SER_COLORID_BAYER_GRBG = 9,
|
|
||||||
SER_COLORID_BAYER_GBRG = 10,
|
|
||||||
SER_COLORID_BAYER_BGGR = 11,
|
|
||||||
SER_COLORID_BAYER_CYYM = 16,
|
|
||||||
SER_COLORID_BAYER_YCMY = 17,
|
|
||||||
SER_COLORID_BAYER_YMCY = 18,
|
|
||||||
SER_COLORID_BAYER_MYYC = 19,
|
|
||||||
SER_COLORID_RGB = 100,
|
|
||||||
SER_COLORID_BGR = 101
|
|
||||||
};
|
|
||||||
|
|
||||||
struct __attribute__((__packed__)) SER_Header {
|
|
||||||
char FileID[14]; /* "LUCAM-RECORDER" (fix) */
|
|
||||||
int32_t LuID; /* Lumenera camera series ID (currently unused; default = 0) */
|
|
||||||
int32_t ColorID; /* see SER_COLORID_* */
|
|
||||||
int32_t LittleEndian; /* 0 (FALSE) for big-endian, 1 (TRUE) for little-endian */
|
|
||||||
int32_t ImageWidth; /* Width of every image in pixel */
|
|
||||||
int32_t ImageHeight; /* Height of every image in pixel */
|
|
||||||
int32_t PixelDepthPerPlane; /* True bit depth per pixel per plane */
|
|
||||||
int32_t FrameCount; /* Number of image frames in SER file */
|
|
||||||
char Observer[40]; /* Name of observer */
|
|
||||||
char Instrument[40]; /* Name of used camera */
|
|
||||||
char Telescope[40]; /* Name of used telescope */
|
|
||||||
int64_t DateTime; /* Start time of image stream (local time) */
|
|
||||||
int64_t DateTimeUTC; /* Start time of image stream in UTC */
|
|
||||||
};
|
|
||||||
|
|
||||||
class SER {
|
|
||||||
|
|
||||||
private:
|
|
||||||
/* header data */
|
|
||||||
struct SER_Header header;
|
|
||||||
|
|
||||||
/* internal data */
|
|
||||||
FILE * FileDesc;
|
|
||||||
int NumberOfPlanes;
|
|
||||||
int BytesPerPixel;
|
|
||||||
size_t FrameSize;
|
|
||||||
void * Frame;
|
|
||||||
int FramePointer;
|
|
||||||
int Reading;
|
|
||||||
int64_t * TimeStamps;
|
|
||||||
int NumberOfTimeStamps;
|
|
||||||
|
|
||||||
void updateHeaderData(void);
|
|
||||||
int64_t differenceLocalUTC(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
SER();
|
|
||||||
~SER();
|
|
||||||
|
|
||||||
int setObserver(char *);
|
|
||||||
int setInstrument(char *);
|
|
||||||
int setTelescope(char *);
|
|
||||||
int setWidth(int);
|
|
||||||
int setHeight(int);
|
|
||||||
int getWidth(void);
|
|
||||||
int getHeight(void);
|
|
||||||
int setColorID(int);
|
|
||||||
int setPixelDepth(int);
|
|
||||||
int getPixelDepth(void);
|
|
||||||
int32_t getNumberOfFrames(void);
|
|
||||||
void setNumberOfFrames(int32_t);
|
|
||||||
int64_t setDateTime(void);
|
|
||||||
int64_t currentDateTimeUTC(void);
|
|
||||||
size_t getFrameSize(void);
|
|
||||||
|
|
||||||
int setFile(char *);
|
|
||||||
int writeHeader(void);
|
|
||||||
int readHeader(void);
|
|
||||||
int appendFrame(void *);
|
|
||||||
int readFrame(void *);
|
|
||||||
int readFrame(void *, int);
|
|
||||||
void * allocFrame(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _SIMPLESKYCAM_H_
|
|
||||||
#define _SIMPLESKYCAM_H_
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
extern void errorexit(char *fmt, ...);
|
|
||||||
extern void calc_vec2anglelen(position_f_2d *p, vector_2d *v);
|
|
||||||
|
|
||||||
#define sindeg(_angle_) sin((M_PI * (_angle_) / 180.0))
|
|
||||||
#define cosdeg(_angle_) cos((M_PI * (_angle_) / 180.0))
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,107 +0,0 @@
|
|||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "videodev-dummy.h"
|
|
||||||
|
|
||||||
VideoDev_Dummy::VideoDev_Dummy() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VideoDev_Dummy::~VideoDev_Dummy() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (running > 0) CaptureStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* return a list of /dev/video* devices found on the system, and read out its human friendly name
|
|
||||||
* output will be a lit of: "V4L2 /dev/videoX [Name]"
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::GetDeviceList(std::list<std::string> *list) {
|
|
||||||
std::string device;
|
|
||||||
int devnum;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (list == NULL) return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open Device
|
|
||||||
* prepare the buffer, InitMMAP and read all controls
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::Open() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close Device
|
|
||||||
* Free videobuffer
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::Close() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* VideoGrabbing
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send the start capture signal to the cam
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::CaptureStart() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_Dummy::CaptureStop() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try to grab one frame and convert it into RGB32.
|
|
||||||
* If something goes wrong return an error code.
|
|
||||||
* Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read.
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::Grab(VideoFrame *vf) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Controls
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::SetDevCtrl(unsigned int id, int value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_Dummy::GetDevCtrl(unsigned int id, int *value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _H_VIDEODEV_DUMPFILE_H_
|
|
||||||
#define _H_VIDEODEV_DUMPFILE_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
class VideoDev_Dummy: public VideoDev {
|
|
||||||
private:
|
|
||||||
ConvertData cdata;
|
|
||||||
|
|
||||||
int Grab(VideoFrameRaw *vf);
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int CaptureStart();
|
|
||||||
int CaptureStop();
|
|
||||||
int SetDevCtrl(unsigned int id, int value);
|
|
||||||
int GetDevCtrl(unsigned int id, int *value);
|
|
||||||
public:
|
|
||||||
VideoDev_Dummy();
|
|
||||||
~VideoDev_Dummy();
|
|
||||||
int GetDeviceList(std::list<std::string> *list);
|
|
||||||
int GetDeviceFormats(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,410 +0,0 @@
|
|||||||
/************************************************************************************
|
|
||||||
* videodev-dumpfile:
|
|
||||||
* raw videodump input file support. It will scan the directory givin by the command
|
|
||||||
* line argument -rd DIRECTORY and for each it will create an own device. This file
|
|
||||||
* will be read in a loop.
|
|
||||||
*
|
|
||||||
* This is needed only for debugging.
|
|
||||||
************************************************************************************/
|
|
||||||
|
|
||||||
/* enable files > 2GB on 32 bit systems */
|
|
||||||
#define _LARGEFILE64_SOURCE 1
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "videodev-dumpfile.h"
|
|
||||||
|
|
||||||
VideoDev_Dumpfile::VideoDev_Dumpfile() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
filesize = 0;
|
|
||||||
filepos = 0;
|
|
||||||
fd = -1;
|
|
||||||
w = 0;
|
|
||||||
h = 0;
|
|
||||||
pixformat = 0;
|
|
||||||
inframe = NULL;
|
|
||||||
inframe_size = 0;
|
|
||||||
inframe_maxsize = 0;
|
|
||||||
inframe_nexttime = 0;
|
|
||||||
fixedframesize = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VideoDev_Dumpfile::~VideoDev_Dumpfile() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (running > 0) CaptureStop();
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* searchs in the given path for any videodump files and present them as
|
|
||||||
* video device.
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::GetDeviceList(std::list<std::string> *list) {
|
|
||||||
std::string device;
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *de = NULL;
|
|
||||||
char fname[256];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (list == NULL || config.readdumppath == NULL) return 0;
|
|
||||||
|
|
||||||
if ((dir = opendir (config.readdumppath)) == NULL) {
|
|
||||||
printf ("%s:%d could not read directory '%s'\n", __FILE__, __LINE__, config.readdumppath);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((de = readdir (dir))) {
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
if (de->d_type & DT_REG) {
|
|
||||||
#endif
|
|
||||||
for (i = 0; i < 255 && de->d_name[i] != 0; i++) fname[i] = toupper(de->d_name[i]);
|
|
||||||
fname[i] = 0;
|
|
||||||
if (strstr (fname, ".VIDEODUMP") != NULL) {
|
|
||||||
device = (std::string) "VIDEODUMP " + (std::string) de->d_name;
|
|
||||||
list->push_back(device);
|
|
||||||
}
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open Device
|
|
||||||
* prepare the buffer, InitMMAP and read all controls
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::Open() {
|
|
||||||
if (config.readdumppath == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
VideoDevCtrl vctl;
|
|
||||||
uint32_t inbuf[3];
|
|
||||||
int i;
|
|
||||||
struct stat s;
|
|
||||||
|
|
||||||
std::string fname = config.readdumppath;
|
|
||||||
fname = fname + "/" + conf_device;
|
|
||||||
|
|
||||||
printf ("%s:%d %s file %s\n", __FILE__, __LINE__, __FUNCTION__, fname.c_str());
|
|
||||||
|
|
||||||
if (fd >= 0) close (fd);
|
|
||||||
fd = -1;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// read filesize
|
|
||||||
if (stat (fname.c_str(), &s) != 0) {
|
|
||||||
printf ("%s:%d %s could not read stat of file '%s'. Error:%s\n", __FILE__, __LINE__, __FUNCTION__,
|
|
||||||
fname.c_str(), strerror(errno));
|
|
||||||
Close();
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
filesize = s.st_size;
|
|
||||||
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
if ((fd = open(fname.c_str(), O_RDONLY | O_BINARY)) == -1) {
|
|
||||||
#else
|
|
||||||
if ((fd = open(fname.c_str(), O_RDONLY)) == -1) {
|
|
||||||
#endif
|
|
||||||
printf ("%s:%d could not open file '%s' error:%s\n", __FILE__, __LINE__, fname.c_str(), strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// read header
|
|
||||||
if (read (fd, inbuf, 12) != 12) {
|
|
||||||
printf ("%s:%d could not read all header data.\n", __FILE__, __LINE__);
|
|
||||||
close (fd);
|
|
||||||
fd = -1;
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
filepos = 12;
|
|
||||||
conf_width = w = ntohl(inbuf[i++]);
|
|
||||||
conf_height = h = ntohl(inbuf[i++]);
|
|
||||||
pixformat = ntohl(inbuf[i++]);
|
|
||||||
conf_format = convert_from_pixelformat (pixformat);
|
|
||||||
|
|
||||||
vidctrls.clear();
|
|
||||||
vctl.name = "FilePosition";
|
|
||||||
vctl.id = 1;
|
|
||||||
vctl.min = 0;
|
|
||||||
vctl.max = 255;
|
|
||||||
vctl.value = 0;
|
|
||||||
vidctrls.push_back(vctl);
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close Device
|
|
||||||
* Free videobuffer
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::Close() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
filesize = 0;
|
|
||||||
filepos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* VideoGrabbing
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send the start capture signal to the cam
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::CaptureStart() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
Close();
|
|
||||||
if (Open() != VDEV_STATUS_OK) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
// read timestamp and first header and frame
|
|
||||||
gettimeofday(&starttv, NULL);
|
|
||||||
pixelformat = pixformat;
|
|
||||||
ReadFrame();
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_Dumpfile::CaptureStop() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inframe != NULL) {
|
|
||||||
free (inframe);
|
|
||||||
inframe_size = 0;
|
|
||||||
inframe = NULL;
|
|
||||||
}
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try to grab one frame and convert it into RGB32.
|
|
||||||
* If something goes wrong return an error code.
|
|
||||||
* Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read.
|
|
||||||
*/
|
|
||||||
#define SIZE_FRAMEHEADER 8
|
|
||||||
#define SIZE_DUMPHEADER 12
|
|
||||||
int VideoDev_Dumpfile::Grab(VideoFrameRaw *vf) {
|
|
||||||
struct timeval curtv;
|
|
||||||
unsigned int diff = 0;
|
|
||||||
std::list<VideoDevCtrl>::iterator ctrl;
|
|
||||||
|
|
||||||
if (fd == -1) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
//
|
|
||||||
// is it time?
|
|
||||||
do {
|
|
||||||
gettimeofday(&curtv, NULL);
|
|
||||||
diff = 1000 * (curtv.tv_sec - starttv.tv_sec) +
|
|
||||||
(curtv.tv_usec - starttv.tv_usec) / 1000;
|
|
||||||
|
|
||||||
if (diff < inframe_nexttime)
|
|
||||||
usleep ((inframe_nexttime-diff)*1000);
|
|
||||||
} while (diff < inframe_nexttime);
|
|
||||||
|
|
||||||
// if (diff - inframe_nexttime > 1000)
|
|
||||||
// printf ("%s:%d time difference to big. (%dms) Maybe to slow hard drive?\n",
|
|
||||||
// __FILE__, __LINE__, (diff - inframe_nexttime));
|
|
||||||
|
|
||||||
LockMutex();
|
|
||||||
vf->CopyFrom(pixformat, w, h, inframe_size, inframe);
|
|
||||||
UnLockMutex();
|
|
||||||
|
|
||||||
ctrl = vidctrls.begin();
|
|
||||||
if (ctrl->value == 0) {
|
|
||||||
// fixed framesize -> calculate frames
|
|
||||||
switch (pixformat) {
|
|
||||||
case(V4L2_PIX_FMT_RGB24):
|
|
||||||
case(V4L2_PIX_FMT_BGR24):
|
|
||||||
fixedframesize = 3 * w * h;
|
|
||||||
break;
|
|
||||||
case(V4L2_PIX_FMT_RGB32):
|
|
||||||
case(V4L2_PIX_FMT_BGR32):
|
|
||||||
fixedframesize = 4 * w * h;
|
|
||||||
break;
|
|
||||||
case(V4L2_PIX_FMT_SGRBG8):
|
|
||||||
fixedframesize = 1 * w * h;
|
|
||||||
break;
|
|
||||||
case(V4L2_PIX_FMT_SGRBG16):
|
|
||||||
fixedframesize = 2 * w * h;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ctrl->max = 0;
|
|
||||||
ctrl->value = -1;
|
|
||||||
fixedframesize = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fixedframesize > 0)
|
|
||||||
ctrl->max = (filesize-SIZE_DUMPHEADER) / (fixedframesize + SIZE_FRAMEHEADER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctrl->value != -1) ctrl->value++;
|
|
||||||
|
|
||||||
//
|
|
||||||
// read next frame
|
|
||||||
LockMutex();
|
|
||||||
ReadFrame();
|
|
||||||
UnLockMutex();
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Read Frame
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::ReadFrame() {
|
|
||||||
uint32_t inbuf[2];
|
|
||||||
|
|
||||||
if (fd < 0) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
//
|
|
||||||
// check position, if end of file restart from beginning
|
|
||||||
if (filepos == filesize) {
|
|
||||||
printf ("%s:%d end of file start with first frame\n", __FILE__, __LINE__);
|
|
||||||
std::list<VideoDevCtrl>::iterator ctrl;
|
|
||||||
ctrl = vidctrls.begin();
|
|
||||||
ctrl->value = 0;
|
|
||||||
if (lseek(fd, 12, SEEK_SET) != 12) {
|
|
||||||
printf ("%s:%d %s lseek returned: %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
else { // reset filepos and starttime
|
|
||||||
filepos = 12;
|
|
||||||
gettimeofday(&starttv, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// read frame
|
|
||||||
if (read (fd, inbuf, 4*2) != 4*2) {
|
|
||||||
printf ("%s:%d could not read frame header: %s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
filepos += (4*2);
|
|
||||||
inframe_size = ntohl(inbuf[0]);
|
|
||||||
inframe_nexttime = ntohl(inbuf[1]);
|
|
||||||
|
|
||||||
// read header
|
|
||||||
if (inframe == NULL) {
|
|
||||||
inframe = (unsigned char*) malloc (inframe_size);
|
|
||||||
inframe_maxsize = inframe_size;
|
|
||||||
}
|
|
||||||
else if (inframe_maxsize < inframe_size) {
|
|
||||||
inframe = (unsigned char*) realloc (inframe, inframe_size);
|
|
||||||
inframe_maxsize = inframe_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate memory and read frame
|
|
||||||
if (inframe == NULL) {
|
|
||||||
Close();
|
|
||||||
printf ("%s:%d could not allocate enough memory\n", __FILE__, __LINE__);
|
|
||||||
return VDEV_CBSTATUS_ERROR;
|
|
||||||
}
|
|
||||||
if (read (fd, inframe, inframe_size) != inframe_size) {
|
|
||||||
printf ("%s:%d could not read frame: %s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
filepos += inframe_size;
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Controls
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::SetDevCtrl(unsigned int id, int value) {
|
|
||||||
std::list<VideoDevCtrl>::iterator ctrl;
|
|
||||||
int framerest;
|
|
||||||
off_t newfilepos = 0;
|
|
||||||
printf ("%s:%d VideoDev_Dumpfile::SetDevCtrl Set Offset to %d id:%d fixedframesize:%d\n", __FILE__, __LINE__, value, id, fixedframesize);
|
|
||||||
struct timeval curtv;
|
|
||||||
|
|
||||||
if (id == 1) {
|
|
||||||
ctrl = vidctrls.begin();
|
|
||||||
if (value != ctrl->value && value < ctrl->max) {
|
|
||||||
filepos = SIZE_DUMPHEADER + ((off_t)value * (SIZE_FRAMEHEADER + (off_t)fixedframesize));
|
|
||||||
printf ("%s:%d filepos:%ld\n", __FILE__, __LINE__, filepos);
|
|
||||||
|
|
||||||
if ((newfilepos = lseek (fd, filepos, SEEK_SET)) < 0) {
|
|
||||||
printf ("%s:%d ******* lseek error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
framerest = (newfilepos - SIZE_DUMPHEADER)%(SIZE_FRAMEHEADER + fixedframesize);
|
|
||||||
ctrl->value = (newfilepos - SIZE_DUMPHEADER)/(SIZE_FRAMEHEADER + fixedframesize);
|
|
||||||
if (ctrl->value != value || framerest != 0) {
|
|
||||||
printf ("%s:%d could not set file to correct position. ctrl->value:%d value:%d Framerest:%d\n", __FILE__, __LINE__, ctrl->value, value, framerest);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//
|
|
||||||
// read first frame
|
|
||||||
ReadFrame();
|
|
||||||
gettimeofday(&curtv, NULL);
|
|
||||||
starttv.tv_sec = curtv.tv_sec - (inframe_nexttime/1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// else printf ("%s:%d could not set video position (ctrl->value:%d value:%d max:%d)\n",
|
|
||||||
// __FILE__, __LINE__, ctrl->value, value, ctrl->max);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_Dumpfile::GetDevCtrl(unsigned int id, int *value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _H_VIDEODEV_DUMPFILE_H_
|
|
||||||
#define _H_VIDEODEV_DUMPFILE_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
// #include <sys/ioctl.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
// #include <sys/mman.h>
|
|
||||||
// #include <linux/videodev2.h>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "gui.h"
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
|
|
||||||
class VideoDev_Dumpfile: public VideoDev {
|
|
||||||
private:
|
|
||||||
ConvertData cdata;
|
|
||||||
int fd;
|
|
||||||
uint32_t w;
|
|
||||||
uint32_t h;
|
|
||||||
uint32_t pixformat;
|
|
||||||
off_t filesize;
|
|
||||||
off_t filepos;
|
|
||||||
struct timeval starttv;
|
|
||||||
unsigned char *inframe;
|
|
||||||
uint32_t inframe_nexttime;
|
|
||||||
int inframe_maxsize;
|
|
||||||
int inframe_size;
|
|
||||||
int fixedframesize;
|
|
||||||
|
|
||||||
int Grab(VideoFrameRaw *vf);
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int CaptureStart();
|
|
||||||
int CaptureStop();
|
|
||||||
int SetDevCtrl(unsigned int id, int value);
|
|
||||||
int GetDevCtrl(unsigned int id, int *value);
|
|
||||||
|
|
||||||
int ReadFrame();
|
|
||||||
public:
|
|
||||||
VideoDev_Dumpfile();
|
|
||||||
~VideoDev_Dumpfile();
|
|
||||||
int GetDeviceList(std::list<std::string> *list);
|
|
||||||
int GetDeviceFormats(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,372 +0,0 @@
|
|||||||
/************************************************************************************
|
|
||||||
* videodev-simulation:
|
|
||||||
* creates an black screen with an small white circle at a simulated movement
|
|
||||||
* needed for testing the PID functionality
|
|
||||||
*
|
|
||||||
* This is needed only for debugging.
|
|
||||||
************************************************************************************/
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
#include "windows.h"
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "convert.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "videodev-simulation.h"
|
|
||||||
|
|
||||||
#define SIMULATION_MOTORSPEEDUP 1.0
|
|
||||||
|
|
||||||
Simulation simulation;
|
|
||||||
gpointer simulation_threadprocess_wrapper (gpointer data);
|
|
||||||
|
|
||||||
void cb_posctl_btnsimreset (GtkWidget *widget, gpointer data) {
|
|
||||||
simulation.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VideoDev_Simulation::VideoDev_Simulation() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
conf_width = 1920;
|
|
||||||
conf_height = 1080;
|
|
||||||
inframe = NULL;
|
|
||||||
simulation_thread = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VideoDev_Simulation::~VideoDev_Simulation() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (inframe != NULL) Close();
|
|
||||||
inframe = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* searchs in the given path for any videodump files and present them as
|
|
||||||
* video device.
|
|
||||||
*/
|
|
||||||
int VideoDev_Simulation::GetDeviceList(std::list<std::string> *list) {
|
|
||||||
list->push_back("SIMULATION");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open Device
|
|
||||||
* prepare the buffer, InitMMAP and read all controls
|
|
||||||
*/
|
|
||||||
int VideoDev_Simulation::Open() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (inframe != NULL) Close();
|
|
||||||
|
|
||||||
conf_format = convert_from_pixelformat (V4L2_PIX_FMT_RGB24);
|
|
||||||
simulation.SetResolution(conf_width, conf_height);
|
|
||||||
|
|
||||||
simulation_thread = g_thread_new("Simulation", simulation_threadprocess_wrapper, NULL);
|
|
||||||
|
|
||||||
inframe = (unsigned char *) malloc (conf_width * conf_height * 3);
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close Device
|
|
||||||
* Free videobuffer
|
|
||||||
*/
|
|
||||||
int VideoDev_Simulation::Close() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (inframe != NULL) {
|
|
||||||
free (inframe);
|
|
||||||
inframe = NULL;
|
|
||||||
}
|
|
||||||
simulation.Stop();
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* VideoGrabbing
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send the start capture signal to the cam
|
|
||||||
*/
|
|
||||||
int VideoDev_Simulation::CaptureStart() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (inframe != NULL) Close();
|
|
||||||
if (Open() != VDEV_STATUS_OK) return VDEV_STATUS_ERROR;
|
|
||||||
pixelformat = V4L2_PIX_FMT_RGB24;
|
|
||||||
get_cycletime(&lastframetv);
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_Simulation::CaptureStop() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (inframe != NULL) Close();
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try to grab one frame and convert it into RGB32.
|
|
||||||
* If something goes wrong return an error code.
|
|
||||||
* Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read.
|
|
||||||
*/
|
|
||||||
#define SIMULATION_SIZE 16
|
|
||||||
#define SIMULATION_NOISE 15
|
|
||||||
int VideoDev_Simulation::Grab(VideoFrameRaw *vf) {
|
|
||||||
int posx, posy, x ,y, r, radius;
|
|
||||||
double a, dsec;
|
|
||||||
|
|
||||||
// try to match a speed of 20Hz
|
|
||||||
dsec = get_cycletime(&lastframetv);
|
|
||||||
if (dsec < 0.040) usleep (50000 - dsec*1000.0);
|
|
||||||
|
|
||||||
memset (inframe, 0x0, conf_width*conf_height*3);
|
|
||||||
simulation.GetPos(&posx, &posy);
|
|
||||||
|
|
||||||
radius = conf_width * SIMULATION_SIZE / 1920;
|
|
||||||
for (r = 1; r < radius; r++) for (a = 0; a < M_PI * 2.0; a += 0.1) {
|
|
||||||
x = posx + (sin(a) * r) + (SIMULATION_NOISE/2 - SIMULATION_NOISE *(float) rand()/ (float)RAND_MAX);
|
|
||||||
y = posy + (cos(a) * r) + (SIMULATION_NOISE/2 - SIMULATION_NOISE *(float) rand()/ (float)RAND_MAX);
|
|
||||||
if (x >= 0 && x < conf_width && y >= 0 && y < conf_height) {
|
|
||||||
inframe[3*(x+y*conf_width)+0] = 200;
|
|
||||||
inframe[3*(x+y*conf_width)+1] = 200;
|
|
||||||
inframe[3*(x+y*conf_width)+2] = 200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LockMutex();
|
|
||||||
vf->CopyFrom(V4L2_PIX_FMT_RGB24, conf_width, conf_height, (conf_width*conf_height*3), inframe);
|
|
||||||
UnLockMutex();
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Controls
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_Simulation::SetDevCtrl(unsigned int id, int value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_Simulation::GetDevCtrl(unsigned int id, int *value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************************************
|
|
||||||
* Simulation
|
|
||||||
*/
|
|
||||||
|
|
||||||
gpointer simulation_threadprocess_wrapper (gpointer data) {
|
|
||||||
simulation.ThreadProcess();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Simulation::Simulation() {
|
|
||||||
w = 1920;
|
|
||||||
h = 1080;
|
|
||||||
posX = w/2;
|
|
||||||
posY = h/2;
|
|
||||||
running = 0;
|
|
||||||
|
|
||||||
#ifdef DEBUG_POSCTL
|
|
||||||
debug_tofile((char*)"simulation.log", 1, (char*)"dAngle,dLen,x,y,dx,dy,timedelay,a1.defAngle,a1.defLen,a1.v,a1.dx,a1.dy,a2.defAngle,a2.defLen,a2.v,a2.dx,a2.dy,finalX,finalY\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::Reset() {
|
|
||||||
int i;
|
|
||||||
static int first = 1;
|
|
||||||
|
|
||||||
LockMutex();
|
|
||||||
|
|
||||||
if(first) {
|
|
||||||
time_t t = time(NULL);
|
|
||||||
srand (t);
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// object movement
|
|
||||||
dAngle = 360.0 * (double)rand() / (double) RAND_MAX;
|
|
||||||
dLen = 1.0 + 5.0 * (double)rand() / (double) RAND_MAX;
|
|
||||||
printf ("%s:%d %s dAngle:%f dLen:%f\n", __FILE__, __LINE__, __FUNCTION__, dAngle, dLen);
|
|
||||||
|
|
||||||
//
|
|
||||||
// axis movement
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
axis[i % 2].defAngle = 180.0 + dAngle + (10.0 * (double)rand() / ((double) RAND_MAX)) - 5.0;
|
|
||||||
axis[i % 2].defLen = dLen + ((dLen/2.0) * (double)rand() / ((double) RAND_MAX) - (dLen/4.0));
|
|
||||||
axis[i % 2].v = 1.0;
|
|
||||||
axis[i % 2].vdest = 1.0;
|
|
||||||
axis[i % 2].active = 1;
|
|
||||||
|
|
||||||
i++;
|
|
||||||
axis[i % 2].defAngle = 180.0 + dAngle + (10.0 * (double)rand() / ((double) RAND_MAX)) + 85.0;
|
|
||||||
axis[i % 2].defLen = dLen + ((dLen/2.0) * (double)rand() / ((double) RAND_MAX) - (dLen/4.0));
|
|
||||||
axis[i % 2].v = 1.0;
|
|
||||||
axis[i % 2].vdest = 1.0;
|
|
||||||
axis[i % 2].active = 1;
|
|
||||||
|
|
||||||
// normalize angle between 0..360°
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
while (axis[i].defAngle < 0.0) axis[i].defAngle += 360.0;
|
|
||||||
while (axis[i].defAngle > 360.0) axis[i].defAngle -= 360.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf ("%s:%d %s Axis1: %f° Len:%f Axis2: %f° Len:%f\n", __FILE__, __LINE__, __FUNCTION__,
|
|
||||||
axis[0].defAngle,axis[0].defLen, axis[1].defAngle,axis[1].defLen);
|
|
||||||
UnLockMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
Simulation::~Simulation() {
|
|
||||||
LockMutex ();
|
|
||||||
running = 0;
|
|
||||||
UnLockMutex ();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::GetPos (int *nx, int *ny) {
|
|
||||||
LockMutex();
|
|
||||||
if (nx != NULL) *nx = (int)posX;
|
|
||||||
if (ny != NULL) *ny = (int)posY;
|
|
||||||
UnLockMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::ThreadProcess() {
|
|
||||||
int r = 1;
|
|
||||||
struct timeval tv;
|
|
||||||
double ms;
|
|
||||||
double dx[3], dy[3];
|
|
||||||
#ifdef DEBUG_POSCTL
|
|
||||||
double x, y;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
get_cycletime (&tv);
|
|
||||||
if (running) return;
|
|
||||||
running = 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
usleep (20000);
|
|
||||||
ms = get_cycletime(&tv);
|
|
||||||
LockMutex();
|
|
||||||
|
|
||||||
//
|
|
||||||
// simulate rotation movement
|
|
||||||
|
|
||||||
// calculate movement
|
|
||||||
dx[0] = sindeg(dAngle) * dLen * ms;
|
|
||||||
dy[0] = cosdeg(dAngle) * dLen * ms;
|
|
||||||
|
|
||||||
//
|
|
||||||
// simulate motor axis movement
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
if (axis[i].active) {
|
|
||||||
dx[i+1] = sindeg(axis[i].defAngle) * axis[i].defLen * (1.0 + axis[i].v) * ms;
|
|
||||||
dy[i+1] = cosdeg(axis[i].defAngle) * axis[i].defLen * (1.0 + axis[i].v) * ms;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dx[i+1] = 0.0;
|
|
||||||
dy[i+1] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is needed for debugging
|
|
||||||
#ifdef DEBUG_POSCTL
|
|
||||||
x = posX; y = posY;
|
|
||||||
#endif
|
|
||||||
posX = posX + dx[0] + dx[1] + dx[2];
|
|
||||||
posY = posY + dy[0] + dy[1] + dy[2];
|
|
||||||
if (posX < 0) posX = w - 1.0;
|
|
||||||
if (posY < 0) posY = h - 1.0;
|
|
||||||
if (posX > w) posX = 0.0;
|
|
||||||
if (posY > h) posY = 0.0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
axis[i].v = axis[i].v * (1.0-SIMULATION_MOTORSPEEDUP) + axis[i].vdest * SIMULATION_MOTORSPEEDUP;
|
|
||||||
}
|
|
||||||
// printf ("%s:%d axis %f (%f) %f (%f)\n", __FILE__, __LINE__, axis[0].v, axis[0].vdest, axis[1].v, axis[1].vdest);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_POSCTL
|
|
||||||
debug_tofile((char*)"simulation.log", 0, (char*)"%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g\n",
|
|
||||||
dAngle, dLen, x, y, dx[0], dy[0], ms,
|
|
||||||
axis[0].defAngle,axis[0].defLen,axis[0].v,dx[1],dy[1],
|
|
||||||
axis[1].defAngle,axis[1].defLen,axis[1].v,dx[2],dy[2],
|
|
||||||
posX, posY
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
r = running;
|
|
||||||
UnLockMutex();
|
|
||||||
} while (r);
|
|
||||||
|
|
||||||
running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Simulation::Start() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::Stop() {
|
|
||||||
running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::SetResolution (int w, int h) {
|
|
||||||
LockMutex();
|
|
||||||
this->w = w;
|
|
||||||
this->h = h;
|
|
||||||
posX = w / 2;
|
|
||||||
posY = h / 2;
|
|
||||||
UnLockMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::AxisSetValue (int a, double v) {
|
|
||||||
// printf ("%s:%d %s Axis:%d Value:%f\n", __FILE__, __LINE__, __FUNCTION__, a, v);
|
|
||||||
if (a < 0 || a > 1) return;
|
|
||||||
axis[a].vdest = v;
|
|
||||||
axis[a].active = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Simulation::AxisStop() {
|
|
||||||
// printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
axis[0].vdest = axis[0].v = 0.0;
|
|
||||||
axis[1].vdest = axis[1].v = 0.0;
|
|
||||||
axis[0].active = 0;
|
|
||||||
axis[1].active = 0;
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _H_VIDEODEV_SIMULATION_H_
|
|
||||||
#define _H_VIDEODEV_SIMULATION_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
//#include <sys/ioctl.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
//#include <sys/mman.h>
|
|
||||||
//#include <linux/videodev2.h>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
struct SimAxisCtl {
|
|
||||||
int active;
|
|
||||||
double vdest;
|
|
||||||
double v;
|
|
||||||
double defLen;
|
|
||||||
double defAngle;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Simulation {
|
|
||||||
private:
|
|
||||||
int w;
|
|
||||||
int h;
|
|
||||||
double posX;
|
|
||||||
double posY;
|
|
||||||
double dAngle;
|
|
||||||
double dLen;
|
|
||||||
int running;
|
|
||||||
struct SimAxisCtl axis[2];
|
|
||||||
GMutex mutex;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Simulation();
|
|
||||||
~Simulation();
|
|
||||||
void GetPos (int *nx, int *ny);
|
|
||||||
void ThreadProcess();
|
|
||||||
|
|
||||||
void Start();
|
|
||||||
void Stop();
|
|
||||||
void Reset();
|
|
||||||
void AxisSetValue(int a, double v);
|
|
||||||
void AxisStop();
|
|
||||||
|
|
||||||
void SetResolution (int w, int h);
|
|
||||||
void LockMutex() { g_mutex_lock(&mutex); };
|
|
||||||
void UnLockMutex() { g_mutex_unlock(&mutex); };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class VideoDev_Simulation: public VideoDev {
|
|
||||||
private:
|
|
||||||
struct timeval lastframetv;
|
|
||||||
unsigned char *inframe;
|
|
||||||
ConvertData cdata;
|
|
||||||
GThread *simulation_thread;
|
|
||||||
|
|
||||||
int Grab(VideoFrameRaw *vf);
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int CaptureStart();
|
|
||||||
int CaptureStop();
|
|
||||||
int SetDevCtrl(unsigned int id, int value);
|
|
||||||
int GetDevCtrl(unsigned int id, int *value);
|
|
||||||
public:
|
|
||||||
VideoDev_Simulation();
|
|
||||||
~VideoDev_Simulation();
|
|
||||||
int GetDeviceList(std::list<std::string> *list);
|
|
||||||
int GetDeviceFormats(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,550 +0,0 @@
|
|||||||
/*
|
|
||||||
* module to read video data from SVBcams.
|
|
||||||
* maybe you have to add something like: /etc/udev.d/90-svbony.rules to get read/wirte access for users in 'plugdev'
|
|
||||||
* SUBSYSTEMS=="usb", ATTRS{idVendor}=="f266", ATTRS{idProduct}=="9a0a", GROUP="plugdev", MODE="0660"
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#ifdef USE_SVBONY
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <SVBCameraSDK.h>
|
|
||||||
#include "convert.h"
|
|
||||||
#include "videodev-svbcam.h"
|
|
||||||
|
|
||||||
VideoDev_SVBCam::VideoDev_SVBCam() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
inframe = NULL;
|
|
||||||
inframe_size = 0;
|
|
||||||
inframe_pixfmt = 0;
|
|
||||||
inframe_w = 0;
|
|
||||||
inframe_h = 0;
|
|
||||||
camid = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VideoDev_SVBCam::~VideoDev_SVBCam() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (running > 0) CaptureStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void VideoDev_SVBCam::print_error(int err) {
|
|
||||||
switch (err) {
|
|
||||||
case SVB_ERROR_INVALID_ID:
|
|
||||||
printf ("SVB_ERROR_INVALID_ID\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_CAMERA_REMOVED:
|
|
||||||
printf ("SVB_ERROR_CAMERA_REMOVED\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_CAMERA_CLOSED:
|
|
||||||
printf ("SVB_ERROR_CAMERA_CLOSED\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_INVALID_SIZE:
|
|
||||||
printf ("SVB_ERROR_INVALID_SIZE\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_INVALID_IMGTYPE:
|
|
||||||
printf ("SVB_ERROR_INVALID_IMGTYPE\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_INVALID_MODE:
|
|
||||||
printf ("SVB_ERROR_INVALID_MODE\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_EXPOSURE_IN_PROGRESS:
|
|
||||||
printf("SVB_ERROR_EXPOSURE_IN_PROGRESS\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_GENERAL_ERROR:
|
|
||||||
printf("SVB_ERROR_GENERAL_ERROR\n");
|
|
||||||
break;
|
|
||||||
case SVB_ERROR_TIMEOUT:
|
|
||||||
printf("SVB_ERROR_TIMEOUT\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf ("unknown %d\n", err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check for connected devices and return the result in a lite.
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::GetDeviceList(std::list<std::string> *list) {
|
|
||||||
int iNumofConnectCameras = SVBGetNumOfConnectedCameras();
|
|
||||||
std::string device;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (list == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
// from sample code
|
|
||||||
SVB_CAMERA_INFO *caminfo = (SVB_CAMERA_INFO *)malloc(sizeof(SVB_CAMERA_INFO)*iNumofConnectCameras);
|
|
||||||
for (int i = 0; i < iNumofConnectCameras; i++) {
|
|
||||||
SVBGetCameraInfo(&caminfo[i], i);
|
|
||||||
device = "SVBCAM " + to_string(caminfo[i].CameraID) + " [" + caminfo[i].FriendlyName + "]";
|
|
||||||
list->push_back(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open Device
|
|
||||||
* prepare the buffer
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::Open() {
|
|
||||||
int camnumcontrols, err;
|
|
||||||
SVB_CONTROL_CAPS *camcontrols = NULL;
|
|
||||||
SVB_CAMERA_PROPERTY camprop;
|
|
||||||
VideoDevCtrl vctl;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
camid = atoi (conf_device.c_str());
|
|
||||||
printf ("%s:%d %s opening cam %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
||||||
|
|
||||||
if ((err = SVBOpenCamera(camid)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// get cam property
|
|
||||||
if ((err = SVBGetCameraProperty(camid, &camprop)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
Close();
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
printf ("%s:%d %s MaxHeight: %ld MaxWidth: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth);
|
|
||||||
|
|
||||||
for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] != SVB_IMG_END; i++) {
|
|
||||||
printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i);
|
|
||||||
switch (camprop.SupportedVideoFormat[i]) {
|
|
||||||
case SVB_IMG_RAW8:
|
|
||||||
printf("\t\tSVB_IMG_RAW8\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW10:
|
|
||||||
printf("\t\tSVB_IMG_RAW10\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW12:
|
|
||||||
printf("\t\tSVB_IMG_RAW12\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW14:
|
|
||||||
printf("\t\tSVB_IMG_RAW14\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW16:
|
|
||||||
printf("\t\tSVB_IMG_RAW16\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y8:
|
|
||||||
printf("\t\tSVB_IMG_Y8\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y10:
|
|
||||||
printf("\t\tSVB_IMG_Y10\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y12:
|
|
||||||
printf("\t\tSVB_IMG_Y12\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y14:
|
|
||||||
printf("\t\tSVB_IMG_Y14\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y16:
|
|
||||||
printf("\t\tSVB_IMG_Y16\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RGB24:
|
|
||||||
printf("\t\tSVB_IMG_RGB24\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RGB32:
|
|
||||||
printf("\t\tSVB_IMG_RGB32\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_END:
|
|
||||||
printf("\t\tSVB_IMG_END\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf ("\t\tunknown\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// get controls
|
|
||||||
vidctrls.clear();
|
|
||||||
if ((err = SVBGetNumOfControls(camid, &camnumcontrols)) != SVB_SUCCESS) print_error(err);
|
|
||||||
camcontrols = (SVB_CONTROL_CAPS*) malloc (sizeof(SVB_CONTROL_CAPS) * camnumcontrols);
|
|
||||||
for (int i = 0; i < camnumcontrols; i++) {
|
|
||||||
if ((err = SVBGetControlCaps(camid, i, &camcontrols[i])) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
printf ("%s:%d %s Control-%02d name:%s desc:%s [%ld:%ld-%ld] auto:%ld write:%ld type:%d\n", __FILE__, __LINE__, __FUNCTION__,
|
|
||||||
i, camcontrols[i].Name, camcontrols[i].Description,
|
|
||||||
(long)camcontrols[i].DefaultValue, (long)camcontrols[i].MinValue, (long)camcontrols[i].MaxValue,
|
|
||||||
(long)camcontrols[i].IsAutoSupported, (long)camcontrols[i].IsWritable, (unsigned int)camcontrols[i].ControlType);
|
|
||||||
vctl.name = (char*)camcontrols[i].Name;
|
|
||||||
vctl.id = camcontrols[i].ControlType;
|
|
||||||
vctl.min = camcontrols[i].MinValue;
|
|
||||||
vctl.max = camcontrols[i].MaxValue;
|
|
||||||
GetDevCtrl(i, &vctl.value);
|
|
||||||
vidctrls.push_back(vctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// set ROI (region of interest)
|
|
||||||
if ((err = SVBSetROIFormat(camid, 0, 0, camprop.MaxWidth, camprop.MaxHeight, 1)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Mode and IMG Format
|
|
||||||
if ((err = SVBSetCameraMode(camid, SVB_MODE_NORMAL)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
inframe_pixfmt = convert_to_pixelformat(conf_format);
|
|
||||||
switch (inframe_pixfmt) {
|
|
||||||
case (V4L2_PIX_FMT_SGRBG16):
|
|
||||||
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RAW16)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_SGRBG8):
|
|
||||||
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RAW8)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR32):
|
|
||||||
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB32)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case (V4L2_PIX_FMT_BGR24):
|
|
||||||
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
conf_format = convert_from_pixelformat(V4L2_PIX_FMT_BGR24);
|
|
||||||
inframe_pixfmt = V4L2_PIX_FMT_BGR24;
|
|
||||||
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// preprare buffer
|
|
||||||
conf_width = inframe_w = camprop.MaxWidth;
|
|
||||||
conf_height = inframe_h = camprop.MaxHeight;
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close Device
|
|
||||||
* Free videobuffer
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::Close() {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if ((err = SVBCloseCamera(camid)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* VideoGrabbing
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* prepare inframe for raw picture data, will hold a video frame with 16bit per channel or BGR32/BGR24
|
|
||||||
* inframe size = 4*W*H
|
|
||||||
* send the start capture signal to the cam
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::CaptureStart() {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
// start video capture
|
|
||||||
if ((err = SVBStartVideoCapture(camid)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// allocate memory for frame data
|
|
||||||
if (inframe != NULL) free (inframe);
|
|
||||||
inframe_size = get_bytesperpixel(inframe_pixfmt) * inframe_w * inframe_h;
|
|
||||||
inframe = (unsigned char*) malloc(inframe_size);
|
|
||||||
if (inframe == NULL) {
|
|
||||||
errorexit ((char*)"%s:%d could not allocate memory for framebuffer. Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
}
|
|
||||||
pixelformat = inframe_pixfmt;
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* free inbuffer
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::CaptureStop() {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if ((err = SVBStopVideoCapture(camid)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// free inframe memory
|
|
||||||
if (inframe) {
|
|
||||||
free (inframe);
|
|
||||||
inframe_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try to grab one frame and convert it into RGB32.
|
|
||||||
* If something goes wrong return an error code.
|
|
||||||
* Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read.
|
|
||||||
*/
|
|
||||||
// FIXME: SVBGetVideoData needs to be outside of Lock/UnLockMutex - using inside thread inbuffer
|
|
||||||
int VideoDev_SVBCam::Grab(VideoFrameRaw *vfr) {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (inframe == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
if ((err = SVBGetVideoData(camid, inframe, (long)inframe_size, 50)) != SVB_SUCCESS) {
|
|
||||||
if (err != SVB_ERROR_TIMEOUT) {
|
|
||||||
print_error(err);
|
|
||||||
// UnLockMutex(); <-- Warum?
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return VDEV_STATUS_AGAIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LockMutex();
|
|
||||||
|
|
||||||
vfr->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, inframe_size, inframe);
|
|
||||||
UnLockMutex();
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_SVBCam::GetDeviceFormats(string device, std::list<string> *formats) {
|
|
||||||
int camid_;
|
|
||||||
std::string result = "";
|
|
||||||
int err;
|
|
||||||
SVB_CAMERA_PROPERTY camprop;
|
|
||||||
VideoDevCtrl vctl;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
LockMutex();
|
|
||||||
|
|
||||||
if (camid == -1) {
|
|
||||||
camid_ = atoi (device.c_str());
|
|
||||||
printf ("%s:%d %s opening cam %d\n", __FILE__, __LINE__, __FUNCTION__, camid_);
|
|
||||||
|
|
||||||
if ((err = SVBOpenCamera(camid_)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else camid_ = camid;
|
|
||||||
|
|
||||||
//
|
|
||||||
// get cam property
|
|
||||||
if ((err = SVBGetCameraProperty(camid_, &camprop)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
Close();
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
printf ("%s:%d %s MaxHeight:%ld MaxWidth:%ld MaxDepth:%d\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight,
|
|
||||||
camprop.MaxWidth, camprop.MaxBitDepth);
|
|
||||||
char pattern[5];
|
|
||||||
switch(camprop.BayerPattern) {
|
|
||||||
case SVB_BAYER_RG:
|
|
||||||
strcpy(pattern, "RGGB");
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_BG:
|
|
||||||
strcpy(pattern, "BGGR");
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_GR:
|
|
||||||
strcpy(pattern, "GRBG");
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_GB:
|
|
||||||
strcpy(pattern, "GBRG");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
strcpy(pattern, "NONE");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
printf ("%s:%d %s BayerPattern:%s Color:%d Binning: \n", __FILE__, __LINE__, __FUNCTION__, pattern, camprop.IsColorCam);
|
|
||||||
for(int i=0; i < 16 && camprop.SupportedBins[i] != 0; i++) {
|
|
||||||
printf ("%s:%d %s Binning Index:%d ", __FILE__, __LINE__, __FUNCTION__, i);
|
|
||||||
printf ("\t\t%dx%d\n", camprop.SupportedBins[i], camprop.SupportedBins[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] != SVB_IMG_END; i++) {
|
|
||||||
printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i);
|
|
||||||
switch (camprop.SupportedVideoFormat[i]) {
|
|
||||||
case SVB_IMG_RAW8:
|
|
||||||
printf("\t\tSVB_IMG_RAW8\n");
|
|
||||||
switch(camprop.BayerPattern) {
|
|
||||||
case SVB_BAYER_RG:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SRGGB8));
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_BG:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SBGGR8));
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_GR:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG8));
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_GB:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGBRG8));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW10:
|
|
||||||
printf("\t\tSVB_IMG_RAW10\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW12:
|
|
||||||
printf("\t\tSVB_IMG_RAW12\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW14:
|
|
||||||
printf("\t\tSVB_IMG_RAW14\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RAW16:
|
|
||||||
printf("\t\tSVB_IMG_RAW16\n");
|
|
||||||
switch(camprop.BayerPattern) {
|
|
||||||
case SVB_BAYER_RG:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SRGGB16));
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_BG:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SBGGR16));
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_GR:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG16));
|
|
||||||
break;
|
|
||||||
case SVB_BAYER_GB:
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGBRG16));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y8:
|
|
||||||
printf("\t\tSVB_IMG_Y8\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y10:
|
|
||||||
printf("\t\tSVB_IMG_Y10\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y12:
|
|
||||||
printf("\t\tSVB_IMG_Y12\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y14:
|
|
||||||
printf("\t\tSVB_IMG_Y14\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_Y16:
|
|
||||||
printf("\t\tSVB_IMG_Y16\n");
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RGB24:
|
|
||||||
printf("\t\tSVB_IMG_RGB24\n");
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_BGR24));
|
|
||||||
break;
|
|
||||||
case SVB_IMG_RGB32:
|
|
||||||
printf("\t\tSVB_IMG_RGB32\n");
|
|
||||||
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_BGR32));
|
|
||||||
break;
|
|
||||||
case SVB_IMG_END:
|
|
||||||
printf("\t\tSVB_IMG_END\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf ("\t\tunknown\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (camid == -1) {
|
|
||||||
if ((err = SVBCloseCamera(camid_)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UnLockMutex();
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Controls
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::SetDevCtrl(unsigned int id, int value) {
|
|
||||||
int err;
|
|
||||||
int oldv;
|
|
||||||
|
|
||||||
if (value < 0) { // enable auto
|
|
||||||
GetDevCtrl (id, &oldv);
|
|
||||||
if ((err = SVBSetControlValue(camid, static_cast<SVB_CONTROL_TYPE>(id), oldv, SVB_TRUE)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ((err = SVBSetControlValue(camid, static_cast<SVB_CONTROL_TYPE>(id), value, SVB_FALSE)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_SVBCam::GetDevCtrl(unsigned int id, int *value) {
|
|
||||||
int err;
|
|
||||||
long pvalue;
|
|
||||||
SVB_BOOL ctlauto;
|
|
||||||
|
|
||||||
if ((err = SVBGetControlValue(camid, static_cast<SVB_CONTROL_TYPE>(id), &pvalue, &ctlauto)) != SVB_SUCCESS) {
|
|
||||||
print_error(err);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
*value = (int) pvalue;
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _H_VIDEODEV_SVBCAM_H_
|
|
||||||
#define _H_VIDEODEV_SVBCAM_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#ifndef BUILD_WINDOWS
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef BUILD_WINDOWS
|
|
||||||
#include "windows.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
|
|
||||||
class VideoDev_SVBCam: public VideoDev {
|
|
||||||
private:
|
|
||||||
unsigned char *inframe;
|
|
||||||
int inframe_size;
|
|
||||||
int inframe_w, inframe_h;
|
|
||||||
int inframe_pixfmt;
|
|
||||||
|
|
||||||
ConvertData cdata;
|
|
||||||
int camid;
|
|
||||||
|
|
||||||
int Grab(VideoFrameRaw *vfr);
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int CaptureStart();
|
|
||||||
int CaptureStop();
|
|
||||||
int SetDevCtrl(unsigned int id, int value);
|
|
||||||
int GetDevCtrl(unsigned int id, int *value);
|
|
||||||
|
|
||||||
void print_error(int err);
|
|
||||||
public:
|
|
||||||
VideoDev_SVBCam();
|
|
||||||
~VideoDev_SVBCam();
|
|
||||||
int GetDeviceList(std::list<std::string> *list);
|
|
||||||
int GetDeviceFormats(string device, std::list<string> *formats);
|
|
||||||
int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,581 +0,0 @@
|
|||||||
|
|
||||||
#include "convert.h"
|
|
||||||
|
|
||||||
#ifdef USE_V4L2
|
|
||||||
|
|
||||||
#include "videodev-v4l2.h"
|
|
||||||
|
|
||||||
VideoDev_V4L2::VideoDev_V4L2() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
io = IOMODE_MMAP;
|
|
||||||
fd = -1;
|
|
||||||
inbuffer_idx = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
VideoDev_V4L2::~VideoDev_V4L2() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (running > 0) CaptureStop();
|
|
||||||
if (fd >= 0) Close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try to send ioctl command as long as EINTR is valid. But abort after 2 seconds.
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::xioctl(int fd, int request, void *arg) {
|
|
||||||
int r;
|
|
||||||
int errnoioctl;
|
|
||||||
struct timeval to1;
|
|
||||||
struct timeval to2;
|
|
||||||
float to;
|
|
||||||
|
|
||||||
gettimeofday(&to1, NULL);
|
|
||||||
do {
|
|
||||||
r = ioctl(fd, request, arg);
|
|
||||||
errnoioctl = errno;
|
|
||||||
gettimeofday(&to2, NULL);
|
|
||||||
to = (float)(to2.tv_sec - to1.tv_sec) + ((to2.tv_usec - to1.tv_usec) / 1000000.0);
|
|
||||||
} while (r == -1 && errnoioctl == EINTR && to < 2.0);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* return a list of /dev/video* devices found on the system, and read out its human friendly name
|
|
||||||
* output will be a lit of: "V4L2 /dev/videoX [Name]"
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::GetDeviceList(std::list<std::string> *list) {
|
|
||||||
std::string device;
|
|
||||||
int devnum;
|
|
||||||
|
|
||||||
if (list == NULL) return 0;
|
|
||||||
|
|
||||||
for (devnum = 0; devnum < 255; devnum++) {
|
|
||||||
device = "/dev/video"+std::to_string(devnum);
|
|
||||||
|
|
||||||
if (device.compare (conf_device) != 0) {
|
|
||||||
int fd;
|
|
||||||
struct v4l2_capability vcap;
|
|
||||||
|
|
||||||
if((fd = open(device.c_str(), O_RDONLY)) == -1){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ioctl(fd, VIDIOC_QUERYCAP, &vcap) == -1)
|
|
||||||
strncpy ((char*)&vcap.card, "unknown", sizeof(vcap.card));
|
|
||||||
close(fd);
|
|
||||||
device += " [" + (std::string) ((char*)vcap.card) + "]";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
device += " [" + (std::string) conf_devicename + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
list->push_back("V4L2 " + device);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* print out the important capabilities, which are reported by the V4L2 device
|
|
||||||
*/
|
|
||||||
void VideoDev_V4L2::PrintCaps(uint32_t caps) {
|
|
||||||
printf ("%s:%d %s Caps: %x\n", __FILE__, __LINE__, __FUNCTION__, caps);
|
|
||||||
|
|
||||||
if (caps & V4L2_CAP_VIDEO_CAPTURE) printf (" V4L2_CAP_VIDEO_CAPTURE\n");
|
|
||||||
if (caps & V4L2_CAP_EXT_PIX_FORMAT) printf (" V4L2_CAP_EXT_PIX_FORMAT\n");
|
|
||||||
#ifdef V4L2_CAP_META_CAPTURE
|
|
||||||
if (caps & V4L2_CAP_META_CAPTURE) printf (" V4L2_CAP_META_CAPTURE\n");
|
|
||||||
#endif
|
|
||||||
if (caps & V4L2_CAP_STREAMING) printf (" V4L2_CAP_STREAMING\n");
|
|
||||||
if (caps & V4L2_CAP_DEVICE_CAPS) printf (" V4L2_CAP_DEVICE_CAPS\n");
|
|
||||||
if (caps & V4L2_CAP_TUNER) printf (" V4L2_CAP_TUNER\n");
|
|
||||||
if (caps & V4L2_CAP_MODULATOR) printf (" V4L2_CAP_MODULATOR\n");
|
|
||||||
if (caps & V4L2_CAP_READWRITE) printf (" V4L2_CAP_READWRITE\n");
|
|
||||||
if (caps & V4L2_CAP_ASYNCIO) printf (" V4L2_CAP_ASYNCIO\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* convert the V4L2 Format data into a text humans can read.
|
|
||||||
* the pixelformat is coded in 4 chars, maybe we need a general coding table
|
|
||||||
* convert still need the v4l2 pixelformats.
|
|
||||||
* as soon as we support GPhoto or something else we need our own pixelformat table.
|
|
||||||
*/
|
|
||||||
void VideoDev_V4L2::PrintFmt(struct v4l2_format *f) {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
printf (" type : %u\n", f->type);
|
|
||||||
printf (" fmt.pix.width : %d\n", f->fmt.pix.width);
|
|
||||||
printf (" fmt.pix.height : %d\n", f->fmt.pix.height);
|
|
||||||
printf (" fmt.fmt.pix.pixelformat : %c%c%c%c\n", ((char*)&f->fmt.pix.pixelformat)[0],
|
|
||||||
((char*)&f->fmt.pix.pixelformat)[1],
|
|
||||||
((char*)&f->fmt.pix.pixelformat)[2],
|
|
||||||
((char*)&f->fmt.pix.pixelformat)[3]);
|
|
||||||
printf (" fmt.pix.field : %d\n", f->fmt.pix.field);
|
|
||||||
printf (" fmt.pix.bytesperline : %d\n", f->fmt.pix.bytesperline);
|
|
||||||
printf (" fmt.pix.sizeimage : %d\n", f->fmt.pix.sizeimage);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open Device
|
|
||||||
* prepare the buffer, InitMMAP and read all controls
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::Open() {
|
|
||||||
int i;
|
|
||||||
struct v4l2_capability vcap;
|
|
||||||
VideoDevCtrl vctl;
|
|
||||||
char txt[32];
|
|
||||||
|
|
||||||
printf ("%s:%d %s Device: '%s'\n", __FILE__, __LINE__, __FUNCTION__, conf_device.c_str());
|
|
||||||
if (fd != -1) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
//
|
|
||||||
// open device and get device name and capabilities | O_NONBLOCK
|
|
||||||
if((fd = open(conf_device.c_str(), O_RDWR)) == -1){
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ioctl(fd, VIDIOC_QUERYCAP, &vcap) == -1)
|
|
||||||
strncpy ((char*)&vcap.card, "unknown", sizeof(vcap.card));
|
|
||||||
conf_devicename = (char*) vcap.card;
|
|
||||||
|
|
||||||
printf ("%s:%d %s Capabilities: %u\n", __FILE__, __LINE__, __FUNCTION__, vcap.capabilities);
|
|
||||||
PrintCaps(vcap.capabilities);
|
|
||||||
printf ("%s:%d %s Device Capabilities: %u\n", __FILE__, __LINE__, __FUNCTION__, vcap.device_caps);
|
|
||||||
PrintCaps(vcap.device_caps);
|
|
||||||
|
|
||||||
if (!(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
|
||||||
printf ("%s:%d %s device has no video capture capabilities\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// query controls
|
|
||||||
struct v4l2_queryctrl queryctrl;
|
|
||||||
uint32_t min;
|
|
||||||
|
|
||||||
vidctrls.clear();
|
|
||||||
memset (&queryctrl, 0, sizeof (queryctrl));
|
|
||||||
for (i = V4L2_CID_BASE; i < V4L2_CID_DETECT_CLASS_BASE+0x1000; i++) {
|
|
||||||
queryctrl.id = i;
|
|
||||||
if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
|
|
||||||
vctl.name = (char*)queryctrl.name;
|
|
||||||
vctl.id = queryctrl.id;
|
|
||||||
vctl.min = queryctrl.minimum;
|
|
||||||
vctl.max = queryctrl.maximum;
|
|
||||||
GetDevCtrl(queryctrl.id, &vctl.value);
|
|
||||||
vidctrls.push_back(vctl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// check for cropping.. if we have it setup default
|
|
||||||
CLEAR (cropcap);
|
|
||||||
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
|
|
||||||
if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
|
|
||||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
crop.c = cropcap.defrect; // reset to default
|
|
||||||
|
|
||||||
if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
|
|
||||||
printf ("%s:%d %s VIDEOC_S_CROP Errorcode: %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// prepare resolution and pixelformat
|
|
||||||
CLEAR (fmt);
|
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
if (conf_height != -1 && conf_width != -1) { // resolution
|
|
||||||
fmt.fmt.pix.width = conf_width;
|
|
||||||
fmt.fmt.pix.height = conf_height;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fmt.fmt.pix.width = 1920;
|
|
||||||
fmt.fmt.pix.height = 1080;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixme: hardcoded video format?????
|
|
||||||
fmt.fmt.pix.pixelformat = convert_to_pixelformat(conf_format);
|
|
||||||
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
|
||||||
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) {
|
|
||||||
fprintf (stderr, "%s:%d VIDIOC_S_FMT : %s\n", __FILE__, __LINE__, strerror (errno));
|
|
||||||
close (fd);
|
|
||||||
fd = -1;
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note VIDIOC_S_FMT may change width and height.
|
|
||||||
// Buggy driver paranoia. - as written in the v4l2 api documentation
|
|
||||||
min = fmt.fmt.pix.width * 2;
|
|
||||||
if (fmt.fmt.pix.bytesperline < min)
|
|
||||||
fmt.fmt.pix.bytesperline = min;
|
|
||||||
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
|
|
||||||
if (fmt.fmt.pix.sizeimage < min)
|
|
||||||
fmt.fmt.pix.sizeimage = min;
|
|
||||||
conf_width = fmt.fmt.pix.width;
|
|
||||||
conf_height = fmt.fmt.pix.height;
|
|
||||||
snprintf (txt, 32, "%c%c%c%c", ((char*)&fmt.fmt.pix.pixelformat)[0],
|
|
||||||
((char*)&fmt.fmt.pix.pixelformat)[1],
|
|
||||||
((char*)&fmt.fmt.pix.pixelformat)[2],
|
|
||||||
((char*)&fmt.fmt.pix.pixelformat)[3]);
|
|
||||||
conf_format = txt;
|
|
||||||
PrintFmt (&fmt);
|
|
||||||
|
|
||||||
// init buffers
|
|
||||||
switch (io) {
|
|
||||||
case IOMODE_MMAP:
|
|
||||||
if (InitMMap() == VDEV_STATUS_ERROR)
|
|
||||||
Close();
|
|
||||||
break;
|
|
||||||
case IOMODE_READ:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* prepare memory mapped buffers
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::InitMMap() {
|
|
||||||
struct v4l2_requestbuffers bufreq;
|
|
||||||
struct v4l2_buffer bufinfo;
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
CLEAR(bufreq);
|
|
||||||
CLEAR(bufinfo);
|
|
||||||
|
|
||||||
bufreq.count = VDEV_INBUFFERS;
|
|
||||||
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
bufreq.memory = V4L2_MEMORY_MMAP;
|
|
||||||
|
|
||||||
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufreq)) {
|
|
||||||
if (EINVAL == errno) {
|
|
||||||
printf("%s does not support memory mapping", conf_device.c_str());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
} else {
|
|
||||||
printf ("%s:%d %s Error %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufreq.count < 1) {
|
|
||||||
printf ( "Insufficient buffer memory on %s\n", conf_device.c_str());
|
|
||||||
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 = i;
|
|
||||||
|
|
||||||
if(ioctl(fd, VIDIOC_QUERYBUF, &bufinfo) < 0){
|
|
||||||
perror("VIDIOC_QUERYBUF");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close Device
|
|
||||||
* Free videobuffer
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::Close() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
|
||||||
UnInit();
|
|
||||||
close (fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_device = "";
|
|
||||||
conf_devicename = "";
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_V4L2::UnInit() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
switch (io) {
|
|
||||||
case IOMODE_READ:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IOMODE_MMAP:
|
|
||||||
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:
|
|
||||||
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* VideoGrabbing
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send the start capture signal to the cam
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::CaptureStart() {
|
|
||||||
enum v4l2_buf_type type;
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
switch (io) {
|
|
||||||
case IOMODE_READ:
|
|
||||||
/* Nothing to do. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IOMODE_MMAP:
|
|
||||||
struct v4l2_buffer 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 = inbuffer_idx;
|
|
||||||
|
|
||||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
|
||||||
printf ( "%s:%d error on VIDIOC_QBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
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));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixelformat = fmt.fmt.pix.pixelformat;
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_V4L2::CaptureStop() {
|
|
||||||
enum v4l2_buf_type type;
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
switch (io) {
|
|
||||||
case IOMODE_READ:
|
|
||||||
/* Nothing to do. */
|
|
||||||
break;
|
|
||||||
case IOMODE_MMAP:
|
|
||||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) {
|
|
||||||
fprintf(stderr, "%s:%d VIDIOC_STREAMOFF Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If something goes wrong return an error code.
|
|
||||||
* Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read.
|
|
||||||
* To reduce the time of malloc/free reuse the destination buffer.
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::Grab(VideoFrameRaw *vf) {
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (vf == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
switch (io) {
|
|
||||||
case IOMODE_READ:
|
|
||||||
if ((len = read (fd, inbuffer[0].data, fmt.fmt.pix.sizeimage)) == -1) {
|
|
||||||
switch (errno) {
|
|
||||||
case EAGAIN:
|
|
||||||
return VDEV_STATUS_AGAIN;
|
|
||||||
case EIO:
|
|
||||||
default:
|
|
||||||
printf ("v4l2_grab IOM_READ: %s dest:%p size:%d\n", strerror (errno), vf, fmt.fmt.pix.sizeimage);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LockMutex();
|
|
||||||
|
|
||||||
UnLockMutex();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IOMODE_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 VDEV_STATUS_AGAIN;
|
|
||||||
|
|
||||||
case EIO:
|
|
||||||
printf ( "%s:%d error on VIDIOC_DQBUF EIO %s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf ( "%s:%d error on VIDIOC_DQBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf.index >= 0 && buf.index < VDEV_INBUFFERS) {
|
|
||||||
LockMutex();
|
|
||||||
vf->CopyFrom(fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height, buf.bytesused, inbuffer[buf.index].data);
|
|
||||||
UnLockMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
|
||||||
printf ( "%s:%d error on VIDIOC_QBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR; }
|
|
||||||
|
|
||||||
if (++inbuffer_idx >= VDEV_INBUFFERS) inbuffer_idx = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int VideoDev_V4L2::GetDeviceFormats(string device, std::list<string> *formats) {
|
|
||||||
int i, fd_;
|
|
||||||
struct v4l2_format format = {0};
|
|
||||||
std::string result = "";
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
LockMutex();
|
|
||||||
|
|
||||||
if (fd == -1){
|
|
||||||
//
|
|
||||||
// open device and get device name and capabilities | O_NONBLOCK
|
|
||||||
if((fd_ = open(device.c_str(), O_RDWR)) == -1) {
|
|
||||||
printf ("%s could not open device %s: %s\n", __FUNCTION__, device.c_str(), strerror(errno));
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else fd_ = fd;
|
|
||||||
|
|
||||||
for(i = 0; convert_pixelformats[i] != 0; i++){
|
|
||||||
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
format.fmt.pix.width = -1;
|
|
||||||
format.fmt.pix.height = -1;
|
|
||||||
format.fmt.pix.pixelformat = convert_pixelformats[i];
|
|
||||||
if(xioctl(fd_, VIDIOC_S_FMT, &format) != -1) {
|
|
||||||
if (format.fmt.pix.pixelformat == convert_pixelformats[i]) {
|
|
||||||
formats->push_back(convert_from_pixelformat(format.fmt.pix.pixelformat));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf ("error: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd == -1) {
|
|
||||||
close (fd_);
|
|
||||||
}
|
|
||||||
|
|
||||||
UnLockMutex();
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Controls
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::SetDevCtrl(unsigned int id, int value) {
|
|
||||||
struct v4l2_control ctrl;
|
|
||||||
|
|
||||||
CLEAR(ctrl);
|
|
||||||
ctrl.id = id;
|
|
||||||
ctrl.value = value;
|
|
||||||
if (-1 == xioctl (fd, VIDIOC_S_CTRL, &ctrl)) {
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_V4L2::GetDevCtrl(unsigned int id, int *value) {
|
|
||||||
struct v4l2_control ctrl;
|
|
||||||
|
|
||||||
CLEAR(ctrl);
|
|
||||||
ctrl.id = id;
|
|
||||||
if (-1 == xioctl (fd, VIDIOC_G_CTRL, &ctrl)) {
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
*value = ctrl.value;
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _H_VIDEODEV_V4L2_H_
|
|
||||||
#define _H_VIDEODEV_V4L2_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
IOMODE_READ,
|
|
||||||
IOMODE_MMAP
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define VDEV_INBUFFERS 3
|
|
||||||
class VideoDev_V4L2: public VideoDev {
|
|
||||||
private:
|
|
||||||
int io; // IO Mode
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
int inbuffer_idx;
|
|
||||||
VideoInBuffer inbuffer[VDEV_INBUFFERS];
|
|
||||||
struct v4l2_cropcap cropcap;
|
|
||||||
struct v4l2_crop crop;
|
|
||||||
struct v4l2_format fmt;
|
|
||||||
|
|
||||||
int Grab(VideoFrameRaw *vf);
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int CaptureStart();
|
|
||||||
int CaptureStop();
|
|
||||||
int SetDevCtrl(unsigned int id, int value);
|
|
||||||
int GetDevCtrl(unsigned int id, int *value);
|
|
||||||
|
|
||||||
int InitMMap();
|
|
||||||
int UnInit();
|
|
||||||
|
|
||||||
void PrintCaps(uint32_t caps);
|
|
||||||
void PrintFmt (struct v4l2_format *f);
|
|
||||||
int xioctl(int fd, int request, void *arg);
|
|
||||||
public:
|
|
||||||
VideoDev_V4L2();
|
|
||||||
~VideoDev_V4L2();
|
|
||||||
int GetDeviceList(std::list<std::string> *list);
|
|
||||||
int GetDeviceFormats(string device, std::list<string> *formats);
|
|
||||||
int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,477 +0,0 @@
|
|||||||
/*
|
|
||||||
* Module to grab video data from VfW interface. The interface is
|
|
||||||
* poorly documented for which some odd comments maybe found here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <windowsx.h>
|
|
||||||
#include <vfw.h>
|
|
||||||
#include <aviriff.h>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "convert.h"
|
|
||||||
#include "videodev-vfw.h"
|
|
||||||
|
|
||||||
static char classNameVfW[] = "VFW-Class";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
VideoDev_VFW::VideoDev_VFW() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
hwnd = cap = NULL;
|
|
||||||
camid = -1;
|
|
||||||
inframe_pixfmt = 0x0;
|
|
||||||
inframe_w = -1;
|
|
||||||
inframe_h = -1;
|
|
||||||
inframe = NULL;
|
|
||||||
inframe_size = 0;
|
|
||||||
vfw_size = 0;
|
|
||||||
hclass = NULL;
|
|
||||||
hinst = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
VideoDev_VFW::~VideoDev_VFW() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (running > 0)
|
|
||||||
CaptureStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for connected devices and returns the result in a list.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::GetDeviceList(std::list<std::string> *list) {
|
|
||||||
|
|
||||||
char name[256];
|
|
||||||
char desc[256];
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (list == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
// go through a list of 10 (maximum number defined by VfW)
|
|
||||||
for(int i=0; i < 10; i++)
|
|
||||||
if(capGetDriverDescription(i, name, sizeof(name), desc, sizeof(desc))) {
|
|
||||||
// create a driver for the return list
|
|
||||||
std::string device;
|
|
||||||
device = "VFW " + to_string(i) + " " + (string)name + " [" + (string)desc + "]";
|
|
||||||
printf ("%s:%d %s Found device '%s'\n", __FILE__, __LINE__, __FUNCTION__, device.c_str());
|
|
||||||
list->push_back(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Destroy and unregister window class.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::DestroyClass() {
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (hclass) {
|
|
||||||
if(!UnregisterClass(classNameVfW, hinst)) {
|
|
||||||
printf ("%s:%d %s Could not unregister VFW class\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free (hclass);
|
|
||||||
hclass = NULL;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create and register window class.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::CreateClass() {
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if (hclass) return 1;
|
|
||||||
|
|
||||||
hclass = (WNDCLASSEX *)malloc(sizeof(WNDCLASSEX));
|
|
||||||
hclass->hInstance = hinst;
|
|
||||||
hclass->lpszClassName = classNameVfW;
|
|
||||||
hclass->lpfnWndProc = DefWindowProc;
|
|
||||||
hclass->style = CS_DBLCLKS;
|
|
||||||
hclass->cbSize = sizeof(WNDCLASSEX);
|
|
||||||
hclass->hIcon = LoadIcon(NULL,IDI_APPLICATION);
|
|
||||||
hclass->hIconSm = LoadIcon(NULL,IDI_APPLICATION);
|
|
||||||
hclass->hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
||||||
hclass->lpszMenuName = NULL;
|
|
||||||
hclass->cbClsExtra = 0;
|
|
||||||
hclass->cbWndExtra = 0;
|
|
||||||
hclass->hbrBackground = (HBRUSH)COLOR_BACKGROUND;
|
|
||||||
|
|
||||||
if(!RegisterClassEx (hclass)) {
|
|
||||||
printf ("%s:%d %s Could not register VFW class\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print driver capabilities.
|
|
||||||
*/
|
|
||||||
void VideoDev_VFW::GetCapabilities() {
|
|
||||||
|
|
||||||
CAPDRIVERCAPS caps;
|
|
||||||
if(!capDriverGetCaps(cap, &caps, sizeof(caps))) {
|
|
||||||
printf ("%s:%d %s Unable to get driver capabilities\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf ("%s:%d %s Id: %d\n", __FILE__, __LINE__, __FUNCTION__, caps.wDeviceIndex);
|
|
||||||
printf ("%s:%d %s Overlay: %d\n", __FILE__, __LINE__, __FUNCTION__, caps.fHasOverlay);
|
|
||||||
printf ("%s:%d %s VideoSource Dialog: %d\n", __FILE__, __LINE__, __FUNCTION__, caps.fHasDlgVideoSource);
|
|
||||||
printf ("%s:%d %s VideoFormat Dialog: %d\n", __FILE__, __LINE__, __FUNCTION__, caps.fHasDlgVideoFormat);
|
|
||||||
printf ("%s:%d %s VideoDisplay Dialog: %d\n", __FILE__, __LINE__, __FUNCTION__, caps.fHasDlgVideoDisplay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The callback is run when an error in the capture driver occurred.
|
|
||||||
*/
|
|
||||||
LRESULT VFW_error_callback (HWND h, int nID, LPCSTR lpsz) {
|
|
||||||
printf("%s:%d %s id=%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, nID, lpsz);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The callback is run when a status update in the capture driver occurred.
|
|
||||||
*/
|
|
||||||
LRESULT VFW_status_callback (HWND h, int nID, LPCSTR lpsz) {
|
|
||||||
printf("%s:%d %s id=%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, nID, lpsz);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define USE_PREVIEW 0
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Opens the device.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::Open() {
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
// extract camera id from device name
|
|
||||||
camid = atoi (conf_device.c_str());
|
|
||||||
printf ("%s:%d %s Opening VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
||||||
|
|
||||||
// find application instance handle for later use
|
|
||||||
hinst = GetModuleHandle(NULL);
|
|
||||||
|
|
||||||
// create and register window class
|
|
||||||
if (!CreateClass())
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
// now create the parent window for capture devicey
|
|
||||||
// some notes:
|
|
||||||
// - the minimum possible size of 3x3
|
|
||||||
// - the WS_POPUPWINDOW removes window decorations
|
|
||||||
// - it does not need a parent window
|
|
||||||
// - the window MUST be visible, otherwise video grabbing does not work (no callbacks run)
|
|
||||||
#if USE_PREVIEW
|
|
||||||
hwnd = CreateWindowEx(0, classNameVfW, "CameraPreview", WS_POPUPWINDOW|WS_VISIBLE, 0, 0, 3, 3, NULL, NULL, hinst, NULL);
|
|
||||||
#else
|
|
||||||
hwnd = CreateWindowEx(0, classNameVfW, "CameraPreview", WS_POPUPWINDOW|WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, hinst, NULL);
|
|
||||||
#endif
|
|
||||||
if (!hwnd) {
|
|
||||||
printf ("%s:%d %s Could not create window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
#if USE_PREVIEW
|
|
||||||
if(!ShowWindow(hwnd, SW_SHOW)) {
|
|
||||||
printf ("%s:%d %s Could not show window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if(!ShowWindow(hwnd, SW_HIDE)) {
|
|
||||||
printf ("%s:%d %s Could not hide window (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// create capture driver window handle, also here minim size is 1x1
|
|
||||||
#if USE_PREVIEW
|
|
||||||
cap = capCreateCaptureWindow("VFW", WS_CHILD|WS_VISIBLE, 0, 0, 1, 1, hwnd, camid);
|
|
||||||
#else
|
|
||||||
cap = capCreateCaptureWindow("VFW", WS_CHILD, 0, 0, 0, 0, hwnd, camid);
|
|
||||||
#endif
|
|
||||||
if(!cap) {
|
|
||||||
printf ("%s:%d %s Could not open VFW id %d window\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
if(!capSetCallbackOnStatus(cap, VFW_status_callback)) {
|
|
||||||
printf ("%s:%d %s Could not set status callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
if(!capSetCallbackOnError(cap, VFW_error_callback)) {
|
|
||||||
printf ("%s:%d %s Could not set error callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to driver
|
|
||||||
if(!capDriverConnect(cap, camid)) {
|
|
||||||
printf ("%s:%d %s Could not connect to VFW id %d\n", __FILE__, __LINE__, __FUNCTION__, camid);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check capabilities
|
|
||||||
GetCapabilities();
|
|
||||||
|
|
||||||
// let the callbacks know this class pointer
|
|
||||||
capSetUserData(cap, this);
|
|
||||||
|
|
||||||
// set video source, capture format and size
|
|
||||||
//capDlgVideoSource(cap);
|
|
||||||
//capDlgVideoFormat(cap);
|
|
||||||
|
|
||||||
CAPTUREPARMS cp;
|
|
||||||
if(!capCaptureGetSetup(cap, &cp, sizeof(cp))) {
|
|
||||||
printf ("%s:%d %s Could not get VFW capture setup\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
cp.dwRequestMicroSecPerFrame = 10000; // rate in us
|
|
||||||
cp.fMakeUserHitOKToCapture = 0;
|
|
||||||
cp.wPercentDropForError = 10;
|
|
||||||
cp.fYield = TRUE;
|
|
||||||
cp.wNumVideoRequested = 1;
|
|
||||||
cp.fCaptureAudio = 0;
|
|
||||||
cp.vKeyAbort = 0;
|
|
||||||
cp.fAbortLeftMouse = 0;
|
|
||||||
cp.fAbortRightMouse = 0;
|
|
||||||
cp.fLimitEnabled = 0;
|
|
||||||
if(!capCaptureSetSetup(cap, &cp, sizeof(cp))) {
|
|
||||||
printf ("%s:%d %s Could not set VFW capture setup\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get current valid width/height
|
|
||||||
BITMAPINFO bi;
|
|
||||||
int i = 0;
|
|
||||||
capGetVideoFormat(cap, &bi, sizeof(BITMAPINFO));
|
|
||||||
inframe_w = bi.bmiHeader.biWidth;
|
|
||||||
inframe_h = bi.bmiHeader.biHeight;
|
|
||||||
printf ("%s:%d %s Current capture size is %dx%d\n", __FILE__, __LINE__, __FUNCTION__, inframe_w, inframe_h);
|
|
||||||
conf_format = convert_from_pixelformat(bi.bmiHeader.biCompression);
|
|
||||||
inframe_pixfmt = bi.bmiHeader.biCompression;
|
|
||||||
printf ("%s:%d %s Current capture format is %s\n", __FILE__, __LINE__, __FUNCTION__, conf_format.c_str());
|
|
||||||
|
|
||||||
// try to set the configured width/height
|
|
||||||
if(conf_width != -1) {
|
|
||||||
inframe_w = bi.bmiHeader.biWidth = conf_width;
|
|
||||||
inframe_h = bi.bmiHeader.biHeight = conf_height;
|
|
||||||
bi.bmiHeader.biCompression = inframe_pixfmt;
|
|
||||||
if(!capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) {
|
|
||||||
printf ("%s:%d %s Could not set capture size %dx%d (%s)\n", __FILE__, __LINE__, __FUNCTION__, conf_width, conf_height, conf_format.c_str());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find out maximum resolution
|
|
||||||
else {
|
|
||||||
int sizes[][2] = {{320, 240}, {640, 480}, {800, 600}, {1024, 768}, {1280, 720}, {1280, 1024}, {1920, 1080}, {-1, -1}};
|
|
||||||
|
|
||||||
while(sizes[i][0] != -1) {
|
|
||||||
inframe_w = bi.bmiHeader.biWidth = sizes[i][0];
|
|
||||||
inframe_h = bi.bmiHeader.biHeight = sizes[i][1];
|
|
||||||
bi.bmiHeader.biCompression = inframe_pixfmt;
|
|
||||||
if(capSetVideoFormat(cap, &bi, sizeof(BITMAPINFO))) {
|
|
||||||
printf ("%s:%d %s Resolution %dx%d (%s) works\n", __FILE__, __LINE__, __FUNCTION__, inframe_w, inframe_h, conf_format.c_str());
|
|
||||||
if (inframe_w >= conf_width && inframe_h >= conf_height) {
|
|
||||||
conf_width = inframe_w;
|
|
||||||
conf_height = inframe_h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// translate this special format to what our convert functions can work with
|
|
||||||
if (inframe_pixfmt == V4L2_PIX_FMT_YUY2) {
|
|
||||||
inframe_pixfmt = V4L2_PIX_FMT_YUYV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close the device.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::Close() {
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
if(cap) {
|
|
||||||
capDriverDisconnect(cap);
|
|
||||||
DestroyWindow(cap);
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
hwnd = cap = NULL;
|
|
||||||
}
|
|
||||||
DestroyClass();
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* VideoGrabbing
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The callback is run when a new frame is available. It copies the
|
|
||||||
* available data into the framebuffer of the class instance.
|
|
||||||
*/
|
|
||||||
LRESULT CALLBACK VFW_frame_callback (HWND h, LPVIDEOHDR v) {
|
|
||||||
VideoDev_VFW * obj = (VideoDev_VFW *)capGetUserData(h);
|
|
||||||
obj->SetFrameBufferSize(v->dwBytesUsed);
|
|
||||||
if (obj->GetFrameBuffer()) {
|
|
||||||
memcpy(obj->GetFrameBuffer(), v->lpData, obj->GetFrameBufferSize());
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare inframe for raw picture data, will hold a video frame with
|
|
||||||
* maximum size of inframe size = 4*W*H. Setup capture
|
|
||||||
* callbacks. Then send the start capture signal to the camera.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::CaptureStart() {
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
// allocate memory for frame data
|
|
||||||
if (inframe != NULL) free (inframe);
|
|
||||||
inframe_size = 4 * inframe_w * inframe_h;
|
|
||||||
inframe = (unsigned char *) malloc(inframe_size);
|
|
||||||
|
|
||||||
pixelformat = inframe_pixfmt;
|
|
||||||
|
|
||||||
#if USE_PREVIEW
|
|
||||||
if(!capSetCallbackOnFrame(cap, VFW_frame_callback)) {
|
|
||||||
printf ("%s:%d %s Could not set frame callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if(!capSetCallbackOnVideoStream(cap, VFW_frame_callback)) {
|
|
||||||
printf ("%s:%d %s Could not set videostream callback to VFW id %d (%ld)\n", __FILE__, __LINE__, __FUNCTION__, camid, GetLastError());
|
|
||||||
return VDEV_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// disable overlay
|
|
||||||
capOverlay(cap, FALSE);
|
|
||||||
|
|
||||||
#if USE_PREVIEW
|
|
||||||
// use preview window for grabbing
|
|
||||||
capPreviewRate (cap, 10); // rate in ms
|
|
||||||
capPreviewScale (cap, FALSE);
|
|
||||||
capPreview (cap, TRUE);
|
|
||||||
#else
|
|
||||||
// otherwise use other capture
|
|
||||||
capPreview (cap, FALSE);
|
|
||||||
if(!capCaptureSequenceNoFile (cap)) {
|
|
||||||
printf ("%s:%d %s Could not start capture (%ld)\n", __FILE__, __LINE__, __FUNCTION__, GetLastError());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stop capture and free framebuffer.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::CaptureStop() {
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
|
|
||||||
capCaptureAbort(cap);
|
|
||||||
capSetCallbackOnFrame(cap, NULL);
|
|
||||||
capSetCallbackOnVideoStream(cap, NULL);
|
|
||||||
capSetCallbackOnStatus(cap, NULL);
|
|
||||||
capSetCallbackOnError(cap, NULL);
|
|
||||||
|
|
||||||
// free inframe memory
|
|
||||||
if (inframe) {
|
|
||||||
free (inframe);
|
|
||||||
inframe_size = 0;
|
|
||||||
inframe = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function needed to continue running the capture window.
|
|
||||||
*/
|
|
||||||
void VideoDev_VFW::HandleMessages() {
|
|
||||||
MSG msg;
|
|
||||||
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to grab one frame and copy it into raw video buffer. If
|
|
||||||
* something goes wrong return an error code. Return code
|
|
||||||
* VDEV_STATUS_AGAIN is not an error. There was no video image ready
|
|
||||||
* to read.
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::Grab(VideoFrameRaw *vf) {
|
|
||||||
|
|
||||||
// Do not know exactly why, but needed to translate/dispatch window message
|
|
||||||
HandleMessages();
|
|
||||||
|
|
||||||
if (inframe == NULL) return VDEV_STATUS_ERROR;
|
|
||||||
|
|
||||||
if (GetFrameBufferSize() > 0) {
|
|
||||||
LockMutex();
|
|
||||||
vf->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, GetFrameBufferSize(), inframe);
|
|
||||||
SetFrameBufferSize(0);
|
|
||||||
UnLockMutex();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return VDEV_STATUS_AGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For VfW this seems difficult / impossible to obtain the supported
|
|
||||||
* video formats, but they must be selected via capDlgVideoFormat().
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::GetDeviceFormats(string device, std::list<string> *formats) {
|
|
||||||
|
|
||||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
|
||||||
* Controls
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::SetDevCtrl(unsigned int id, int value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get video control identified by id
|
|
||||||
*/
|
|
||||||
int VideoDev_VFW::GetDevCtrl(unsigned int id, int *value) {
|
|
||||||
return VDEV_STATUS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _H_VIDEODEV_VFW_H_
|
|
||||||
#define _H_VIDEODEV_VFW_H_
|
|
||||||
|
|
||||||
#include "videodev.h"
|
|
||||||
|
|
||||||
class VideoDev_VFW: public VideoDev {
|
|
||||||
private:
|
|
||||||
unsigned char *inframe;
|
|
||||||
int inframe_size;
|
|
||||||
int inframe_w, inframe_h;
|
|
||||||
int inframe_pixfmt;
|
|
||||||
int vfw_size;
|
|
||||||
|
|
||||||
ConvertData cdata;
|
|
||||||
int camid;
|
|
||||||
HWND cap, hwnd;
|
|
||||||
WNDCLASSEX * hclass;
|
|
||||||
HINSTANCE hinst;
|
|
||||||
|
|
||||||
int Grab(VideoFrameRaw *vf);
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int CaptureStart();
|
|
||||||
int CaptureStop();
|
|
||||||
int SetDevCtrl(unsigned int id, int value);
|
|
||||||
int GetDevCtrl(unsigned int id, int *value);
|
|
||||||
int CreateClass();
|
|
||||||
int DestroyClass();
|
|
||||||
void HandleMessages();
|
|
||||||
void GetCapabilities();
|
|
||||||
|
|
||||||
void print_error(int err);
|
|
||||||
public:
|
|
||||||
VideoDev_VFW();
|
|
||||||
~VideoDev_VFW();
|
|
||||||
int GetDeviceList(std::list<std::string> *list);
|
|
||||||
int GetDeviceFormats(string device, std::list<string> *formats);
|
|
||||||
int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
unsigned char * GetFrameBuffer(void) { return inframe; };
|
|
||||||
void SetFrameBufferSize(int s) { vfw_size = s; };
|
|
||||||
int GetFrameBufferSize(void) { return vfw_size; };
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,179 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _VIDEODEV_H_
|
|
||||||
#define _VIDEODEV_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <jpeglib.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "simpleskycam.h"
|
|
||||||
#include "json.h"
|
|
||||||
#include "gui.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "convert.h"
|
|
||||||
#include "video.h"
|
|
||||||
#include "videoframe.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
VDEV_STATUS_UNKNOWN,
|
|
||||||
VDEV_STATUS_OK,
|
|
||||||
VDEV_STATUS_AGAIN,
|
|
||||||
VDEV_STATUS_ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// jpeg error handling
|
|
||||||
//
|
|
||||||
struct jpg_error_mgr {
|
|
||||||
struct jpeg_error_mgr pub; /* "public" fields */
|
|
||||||
|
|
||||||
jmp_buf setjmp_buffer; /* for return to caller */
|
|
||||||
};
|
|
||||||
typedef struct jpg_error_mgr *jpg_error_ptr;
|
|
||||||
|
|
||||||
|
|
||||||
// callback status
|
|
||||||
enum {
|
|
||||||
VDEV_CBSTATUS_NOTHING = 1,
|
|
||||||
VDEV_CBSTATUS_NEWFRAME,
|
|
||||||
VDEV_CBSTATUS_ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct {
|
|
||||||
unsigned int id;
|
|
||||||
int min;
|
|
||||||
int max;
|
|
||||||
int value;
|
|
||||||
std::string name;
|
|
||||||
} typedef VideoDevCtrl;
|
|
||||||
|
|
||||||
|
|
||||||
struct {
|
|
||||||
unsigned int size;
|
|
||||||
unsigned char* data;
|
|
||||||
} typedef VideoInBuffer;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* data which we send to the main thread
|
|
||||||
*/
|
|
||||||
struct {
|
|
||||||
int running;
|
|
||||||
VideoFrame vf;
|
|
||||||
VideoFrameRaw vfr;
|
|
||||||
} typedef VideoDevThreadData;
|
|
||||||
|
|
||||||
#ifndef CLEAR
|
|
||||||
#define CLEAR(x) memset (&(x), 0, sizeof (x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* the run Start(..) needs to be called from a created thread process. It will not return until
|
|
||||||
* another thread called the Stop() function or an error occured.
|
|
||||||
*
|
|
||||||
* New Devices will need to rewrite the following virtual functions:
|
|
||||||
* Grab(), Open(), Close(), SetDevCtrl(), GetDevGtrl(), GetDeviceList(), GetCtrlList()
|
|
||||||
*/
|
|
||||||
class VideoDev {
|
|
||||||
private:
|
|
||||||
std::string conf_device; // device or filename to connect to
|
|
||||||
std::string conf_devicename; // human friendly name of the device
|
|
||||||
std::string conf_format; // video or image format (should every device have)
|
|
||||||
std::string conf_parameter; // can hold additional parameters
|
|
||||||
uint32_t pixelformat; // pixelformat
|
|
||||||
int conf_height;
|
|
||||||
int conf_width;
|
|
||||||
|
|
||||||
int running; // 0 ... not running
|
|
||||||
// 1 ... initialized (init, first frame)
|
|
||||||
// 2 ... running
|
|
||||||
ConvertData cdata;
|
|
||||||
|
|
||||||
GMutex mutex;
|
|
||||||
gboolean (*callback)(gpointer data);
|
|
||||||
|
|
||||||
VideoDevThreadData threaddata;
|
|
||||||
|
|
||||||
std::list<VideoDevCtrl> vidctrls;
|
|
||||||
|
|
||||||
/* grabs a single frame, writes the RGB24 converted frame to the VideoFrame pointer */
|
|
||||||
virtual int Grab(VideoFrameRaw *vf) { return VDEV_STATUS_AGAIN; };
|
|
||||||
|
|
||||||
/* opens the device, will need to fill the controls as well */
|
|
||||||
virtual int Open() { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
/* close the device */
|
|
||||||
virtual int Close() { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
/* close the device */
|
|
||||||
virtual int CaptureStart() { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
/* close the device */
|
|
||||||
virtual int CaptureStop() { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
/* set the control */
|
|
||||||
virtual int SetDevCtrl(unsigned int id, int value) { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
/* read a value from the control */
|
|
||||||
virtual int GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
friend class VideoDev_Dumpfile;
|
|
||||||
friend class VideoDev_Simulation;
|
|
||||||
friend class VideoDev_V4L2;
|
|
||||||
#ifdef USE_SVBONY
|
|
||||||
friend class VideoDev_SVBCam;
|
|
||||||
#endif
|
|
||||||
#ifdef USE_VFW
|
|
||||||
friend class VideoDev_VFW;
|
|
||||||
#endif
|
|
||||||
public:
|
|
||||||
VideoDev();
|
|
||||||
virtual ~VideoDev();
|
|
||||||
|
|
||||||
static int get_bytesperpixel (uint32_t pixfmt);
|
|
||||||
|
|
||||||
void SetConfig(std::string dev, int w, int h, std::string format, std::string parameter, gboolean (*callback_func)(gpointer data));
|
|
||||||
void ThreadProcess();
|
|
||||||
void Stop();
|
|
||||||
int IsRunning() { return running; };
|
|
||||||
void LockMutex() { g_mutex_lock(&mutex); };
|
|
||||||
void UnLockMutex() { g_mutex_unlock(&mutex); };
|
|
||||||
|
|
||||||
void GetVideoInfo(int *w, int *h, std::string *format);
|
|
||||||
std::string GetDevice() { return conf_device; };
|
|
||||||
|
|
||||||
int GetCtrlMinMaxValue(std::string name, int *min, int *max, int *value);
|
|
||||||
int SetCtrlValue(std::string name, int value);
|
|
||||||
|
|
||||||
/* fills the list with all found device */
|
|
||||||
virtual int GetDeviceList(std::list<std::string> *list) { return VDEV_STATUS_OK; };
|
|
||||||
virtual int GetDeviceFormats(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
virtual int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
|
|
||||||
|
|
||||||
int GetCtrlList(std::list<std::string> *list);
|
|
||||||
|
|
||||||
/* returns a list with all control and thier parameters */
|
|
||||||
list<VideoDevCtrl> GetCtrlsMinMaxValue();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#include "videodev-dumpfile.h"
|
|
||||||
#include "videodev-simulation.h"
|
|
||||||
|
|
||||||
#ifdef USE_V4L2
|
|
||||||
#include "videodev-v4l2.h"
|
|
||||||
#endif
|
|
||||||
#ifdef USE_SVBONY
|
|
||||||
#include "videodev-svbcam.h"
|
|
||||||
#endif
|
|
||||||
#ifdef USE_VFW
|
|
||||||
#include "videodev-vfw.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "windows.h"
|
|
||||||
|
|
||||||
void strfromd (char* dest, int len, char *fmt,...) {
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start (args, fmt);
|
|
||||||
vsnprintf (dest, len-1, fmt, args);
|
|
||||||
va_end (args);
|
|
||||||
dest[len-1] = 0;
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _WINDOWS_H_
|
|
||||||
#define _WINDOWS_H_
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
|
|
||||||
#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000
|
|
||||||
#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver)
|
|
||||||
|
|
||||||
#ifndef _WIN32_WINNT
|
|
||||||
# define _WIN32_WINNT 0x501
|
|
||||||
#endif
|
|
||||||
#ifndef NTDDI_VERSION
|
|
||||||
# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// #include <winsock.h>
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define socklen_t size_t
|
|
||||||
|
|
||||||
#ifndef bzero
|
|
||||||
#define bzero(__z__, __x__) memset (__z__, 0x0, __x__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MSG_NOSIGNAL
|
|
||||||
# define MSG_NOSIGNAL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void strfromd (char* dest, int len, char *fmt,...);
|
|
||||||
|
|
||||||
|
|
||||||
#define __u32 uint32_t
|
|
||||||
|
|
||||||
/*
|
|
||||||
* since this application is ported from linux and uses some linux based definitions
|
|
||||||
* we needed to copy some of the definitions and information.
|
|
||||||
*
|
|
||||||
* the following part comes from the Video 4 Linux 2 source more details can be found
|
|
||||||
* at https://linuxtv.org.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
|
|
||||||
#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */
|
|
||||||
#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
|
|
||||||
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */
|
|
||||||
#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */
|
|
||||||
#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */
|
|
||||||
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */
|
|
||||||
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
|
|
||||||
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */
|
|
||||||
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */
|
|
||||||
#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */
|
|
||||||
#define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16 GRGR.. BGBG.. */
|
|
||||||
#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */
|
|
||||||
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */
|
|
||||||
#define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16 RGRG.. GBGB.. */
|
|
||||||
#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */
|
|
||||||
#define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16 GBGB.. RGRG.. */
|
|
||||||
#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */
|
|
||||||
|
|
||||||
#define V4L2_PIX_FMT_YUY2 v4l2_fourcc('Y', 'U', 'Y', '2') /* ??? */
|
|
||||||
|
|
||||||
#define v4l2_fourcc(a, b, c, d)\
|
|
||||||
((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
|
|
||||||
#define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1U << 31))
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Loading…
Reference in new issue