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,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
|
||||
#
|
||||
@ -1,20 +1,3 @@
|
||||
# SimpleSkyCam
|
||||
|
||||
Simple application to create images using a teleskope and a cameramodul.
|
||||
We have basic support for follow any object seen by the cammera.
|
||||
|
||||
One SER sample Outputfile can be found in the SampleOutput folder.
|
||||
|
||||
# Command Line Options
|
||||
|
||||
-d <debugpath> destination for video debugging path
|
||||
-dd disable debugging path
|
||||
-rd <debugpath> read video from dumpfile folder
|
||||
|
||||
If the video debugging path is set, all videodata received by the video adapter will be written to disc. Be carefull with this option. Some RAW formats can take serval GB within seconds.
|
||||
|
||||
# Screenshots
|
||||
|
||||

|
||||
|
||||
|
||||
Simple application to create images using a teleskope and a cameramodul.
|
||||
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