Compare commits
157 Commits
@ -0,0 +1,32 @@
|
||||
|
||||
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,20 +1,34 @@
|
||||
|
||||
include Makefile.config
|
||||
|
||||
USE_V4L2 = 1
|
||||
TARGET = $(APP)
|
||||
|
||||
CPP = c++
|
||||
CPPFLAGS = -std=c++11 -ggdb -Wall -Werror -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
|
||||
CPPFLAGS = -std=c++11 -pg -ggdb -Wall -Werror -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
|
||||
INCLUDES =
|
||||
LDFLAGS =
|
||||
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -ljpeg
|
||||
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -ljpeg -pg
|
||||
OBJECTS =
|
||||
|
||||
|
||||
#
|
||||
# Uncomment to enable support for SVBONY Cammeras.
|
||||
# add makefile configuration for svbony cams
|
||||
#
|
||||
ifeq ($(USE_SVBONY),1)
|
||||
CPPFLAGS := $(CPPFLAGS) -I/usr/local/include
|
||||
LDFLAGS := $(LDFLAGS) -lSVBCameraSDK -L/usr/local/lib
|
||||
LDFLAGS := $(LDFLAGS) -lSVBCameraSDK -L/usr/local/lib `pkg-config --libs libusb-1.0`
|
||||
OBJECTS := $(OBJECTS) videodev-svbcam.oo
|
||||
#
|
||||
endif
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# add makefile configuration for svbony cams
|
||||
#
|
||||
ifeq ($(USE_V4L2),1)
|
||||
OBJECTS := $(OBJECTS) videodev-v4l2.oo
|
||||
endif
|
||||
#
|
||||
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
|
||||
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,6 +1,20 @@
|
||||
# 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
|
||||
|
||||

|
||||
|
||||
Screenshots and other stuff can be found at: <https://steffen.gulpe.de/progs/SimpleSkyCam>
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 734 KiB |
@ -0,0 +1,38 @@
|
||||
#!/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
|
||||
|
@ -0,0 +1,10 @@
|
||||
#!/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
|
||||
|
@ -0,0 +1,366 @@
|
||||
#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;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
#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
|
@ -0,0 +1,119 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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);
|
||||
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,177 @@
|
||||
|
||||
#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
|
||||
};
|
||||
|
@ -0,0 +1,34 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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
|
@ -0,0 +1,102 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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_
|
@ -1,120 +0,0 @@
|
||||
|
||||
|
||||
#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 = (unsigned char*)inFrame.GetData();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,252 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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_
|
||||
|
@ -0,0 +1,239 @@
|
||||
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
<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>
|
@ -0,0 +1,30 @@
|
||||
#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
|
@ -0,0 +1 @@
|
||||
<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>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,372 @@
|
||||
/************************************************************************************
|
||||
* 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;
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
|
||||
#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
|
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
@ -0,0 +1,45 @@
|
||||
|
||||
#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
|
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
#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;
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
|
||||
#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