Compare commits

...

157 Commits

Author SHA1 Message Date
Stefan Jahn f508372fcd Compiles now also in Windows
1 year ago
Steffen Pohle 7c4f88b596 fixed alot of bugs..
1 year ago
Steffen Pohle eb98013780 fixed ser write segfault
1 year ago
Steffen Pohle c01339b7b9 SER should now work with RAW video data
1 year ago
Steffen Pohle ef6100dee0 adding debugging messages and windows. raw to ser still in progress...
1 year ago
Steffen Pohle 06fe855aed video vctrl.value is not reset to 0 when the video starts from begining.
1 year ago
Steffen Pohle 2fb85a0f5d ignore slow dumpfile read warnings
1 year ago
Steffen Pohle 6374acc547 positioning in videodump playbacks work
1 year ago
Steffen Pohle a99e1b52cf updating readme
1 year ago
Steffen Pohle 0a982b869b writing SER file works.
1 year ago
Steffen Pohle 173d4bc01d finished with the gui. writing SER files next.
1 year ago
Steffen Pohle 9670beb903 output object should have now Raw data
1 year ago
Steffen Pohle 052b61e5d3 copy raw image to output thread
1 year ago
Steffen Pohle d2378f014f another approach for 2step control
1 year ago
Steffen Pohle 539e49b28f trying 2 step calibration and justify of the output values, but not working yet
1 year ago
Steffen Pohle d216628ac8 tests tests tests
2 years ago
Steffen Pohle 06d5235c63 ...
2 years ago
Steffen Pohle 7274530fae if follow is not working use default detection.
2 years ago
Stefan Jahn c54953fcc8 Fixed GUI output of RA/DEC d and out values
2 years ago
Stefan Jahn 4830b0fd1f Fixed warnings about date formatting in strings
2 years ago
Steffen Pohle c6d7cd3310 solving compiler warnings
2 years ago
Steffen Pohle fd623c74c3 solving compiler warnings
2 years ago
Stefan Jahn 03b9395dd2 Add config file to be ignored
2 years ago
Stefan Jahn 1a7837df83 Using RA/DEC axis names
2 years ago
Stefan Jahn a41c7566ae Using AXIS_RA/DEC consistently
2 years ago
Steffen Pohle 62fd3c84fc rename axes final steps..
2 years ago
Steffen Pohle fe87365e51 Merge branch 'master' of steffen.gulpe.de:steffen/SimpleSkyCam
2 years ago
Steffen Pohle b32ed39387 rename axis
2 years ago
Stefan Jahn ae3f0b784a Ignoring some windows files
2 years ago
Stefan Jahn da6709d17c Start renaming ra/dec axes
2 years ago
Steffen Pohle e40389368f rename axis
2 years ago
Steffen Pohle 61dc951317 rename axis
2 years ago
Steffen Pohle 281be07ed4 posctl should work now.
2 years ago
Steffen Pohle bffbea0637 adding calibration debuging information
2 years ago
Steffen Pohle da15e98d2d need wait steps for motor control.
2 years ago
Steffen Pohle 94043ab330 posctl calibration maximum time increased and added max distance for detection of rotation and axis movement
2 years ago
Steffen Pohle 67e0d160af renaming filter to output... preparing raw output to save
2 years ago
Steffen Pohle 5ac24490d3 posctl: command without feedback will cause false error message
2 years ago
Steffen Pohle 1b449d5454 wir habends
2 years ago
Steffen Pohle aa3f5a5a71 positioning and hiding on current gnome/wayland installation did not work
2 years ago
Steffen Pohle ce2ef38c40 use of new SVBONY Camera needs to be linked against libusb
2 years ago
Steffen Pohle efc16f772a windows position on XWayland does not work
2 years ago
Steffen Pohle f3afb9dd8a Merge branch 'master' of steffen.gulpe.de:steffen/SimpleSkyCam
2 years ago
Steffen Pohle 7d58e3ca28 litte gui issues with simulation reset button
2 years ago
Steffen Pohle bc11438ee3 linux will compile again. O_BINARY does only exist in the windows world.
2 years ago
Stefan Jahn 5c05d1b7f9 Removed video source / format dialog calls in the Open() function
3 years ago
Stefan Jahn 94155b3ba4 Reduced calibration times to 5sec from 10sec
3 years ago
Stefan Jahn 12c144a77a Videodump reading now also works in Windows
3 years ago
Stefan Jahn d7786fa8b1 Video grabbing now works for VfW even without visible preview window
3 years ago
Stefan Jahn ec7caf8b22 Added some more documentation. Larger previews, e.g. 1280x720 seem possible.
3 years ago
Stefan Jahn 57810f80b4 Small tweak
3 years ago
Stefan Jahn a2e2cce4c9 Merge branch 'master' of https://steffen.gulpe.de/gitea/steffen/SimpleSkyCam
3 years ago
Stefan Jahn e70384ff12 VfW works now, but only with preview, probably only a fixed resolution
3 years ago
Steffen Pohle 80d22347f5 some code cleanup
3 years ago
Steffen Pohle 18e018ee7c code cleanup
3 years ago
Stefan Jahn ead6e260c8 Just fixed compilation issue in Windows
3 years ago
Steffen Pohle 2a635f0e40 Merge branch 'master' of steffen.gulpe.de:steffen/SimpleSkyCam
3 years ago
Steffen Pohle 0f9e1e8bd3 convert moved out of the videodev device interface to the videodev class
3 years ago
Stefan Jahn 4b8ce579d3 Disabling tty logging in windows part
3 years ago
Stefan Jahn 1df63e55b1 Fixed video controls for SVBONY
3 years ago
Stefan Jahn 8447b59b0f Fixed randomization on Windows platform
3 years ago
Steffen Pohle 3a11f81658 posctl works finally.
3 years ago
Stefan Jahn 2a6b5b099f Still playing with VfW... no real progress
3 years ago
Stefan Jahn 245c9f582a Tried to improve VfW interface, though no video data yet :(
3 years ago
Stefan Jahn f47074adfb Very preliminary code for VfW
3 years ago
U-INFINEON\jahnst 0a504ba742 Serial interface in Windows working
3 years ago
U-INFINEON\jahnst b4cbaa7bf8 Compilation of dng class and videosdev-svbcam works now
3 years ago
U-INFINEON\jahnst 6d34dfa61e Added packing target for native Windows
3 years ago
U-INFINEON\jahnst 539bf8b726 Avoid name clash with some GetObject() windows definition
3 years ago
U-INFINEON\jahnst 10351217c4 Added build system for Windows msys2
3 years ago
Steffen Pohle 809540875d logging issue
3 years ago
Steffen Pohle c666ab1c3f first runnable windows build.
3 years ago
Steffen Pohle 94216b0741 adding some more logging. enableing cross compiling.
3 years ago
Steffen Pohle 3f93d5ab9f in position control: fixed never ending errormessage on wrong output control device.
3 years ago
Steffen Pohle 7ce366d2ec somthing works finally.
3 years ago
Steffen Pohle 0b33a8d153 enable edit of values
3 years ago
Steffen Pohle cf65c10456 enable edit of values
3 years ago
Steffen Pohle b8308e26ba some more work... and no solution
3 years ago
Steffen Pohle f5715a1b63 adding debug angles screen.
3 years ago
Steffen Pohle 6e75dea4e0 adding debug files.
3 years ago
Stefan Jahn 4f1d3a1a26 Fixed typo from last commit
3 years ago
Stefan Jahn c8de10a208 Changed some labels in GUI to make it clearer
3 years ago
Stefan Jahn afe3af70ff Tried to debug position control... no success though so far
3 years ago
Stefan Jahn f95e0037b9 Adjust simulation planet radius according resolution
3 years ago
Steffen Pohle 047c075a99 pid first experiments..
3 years ago
Steffen Pohle ac0bedbdbe pid seem to work..
3 years ago
Steffen Pohle 62de813110 pid function ... not working yet...
3 years ago
Steffen Pohle 41ae9d13df winkel
3 years ago
Steffen Pohle f027cbb2e0 some fixes..
3 years ago
Steffen Pohle 155d093109 should work
3 years ago
Steffen Pohle 8908f0f82d calibration something is working. don't know what and if it is usefull
3 years ago
Steffen Pohle f236912d34 Merge branch 'master' of steffen.gulpe.de:steffen/SimpleSkyCam
3 years ago
Steffen Pohle 47d9be6e34 adding simulation device
3 years ago
Stefan Jahn 80097f0dbc Serial interface tested, works now with the changes including the non-blocking read
3 years ago
Steffen Pohle 0e4346d525 needing more information during calibration
3 years ago
Steffen Pohle 1352442ddd error handling on device open improved.
3 years ago
Steffen Pohle 5100b26927 Merge branch 'master' of steffen.gulpe.de:steffen/SimpleSkyCam
3 years ago
Steffen Pohle cc518e4577 adding errormessage
3 years ago
Steffen Pohle 15cf7fe3f5 adding errormessage
3 years ago
Steffen Pohle 85f228fe9e adding error message diablog
3 years ago
Stefan Jahn 932d493f8a Corrected RAW8 initialization of the camera
3 years ago
Steffen Pohle e7ba99c1b6 axis manuel control
3 years ago
Steffen Pohle 6f32058a7b adding basic tty support
3 years ago
Steffen Pohle fa92473951 preparing the position control. PID settings will be saved into the configuration file. Writing the output is still missing and the PID logic.
3 years ago
Steffen Pohle b74fe3af68 gui improvement on calibration
3 years ago
Steffen Pohle 4a9d471ca1 rotation is now calculated on calibration.
3 years ago
Steffen Pohle 68f68489f7 posctl ... gui basic implemention. Thread seperated and seem to work. only gui testing functionality now
3 years ago
Steffen Pohle 171df9f20d working on gui
3 years ago
Steffen Pohle 3c08b6623c detect and follow improved... but still not fine
3 years ago
Steffen Pohle a3adb374cb detect and follow improved... but still not fine
3 years ago
Steffen Pohle a1c39f672c control pannel is getting to live
3 years ago
Steffen Pohle 651cd8ef37 preparations for position stabilisation
3 years ago
Steffen Pohle 51f4a97ea3 preparations for position stabilisation
3 years ago
Stefan Jahn 69e0de0fc8 Improved PID regulator functionality a little, added documentation
3 years ago
Stefan Jahn 89f921fe22 Added simple implementtion of PID regulator
3 years ago
Steffen Pohle bb87f38375 dumpfile will now loop
3 years ago
Steffen Pohle cd9d76c1f5 fixing gui
3 years ago
Steffen Pohle 306d04ae7e fixed: dumpfile is not setting the frame size to the videodev.conf_height and width variable
3 years ago
Steffen Pohle 5f798ad905 fixed: dumpfile is not setting the frame size to the videodev.conf_height and width variable
3 years ago
Steffen Pohle 5c1c0a94b4 pre scale buttons are working
3 years ago
Steffen Pohle f8a576e676 save windows position and visibility
3 years ago
Steffen Pohle 2ccc66a359 testing ui
3 years ago
Steffen Pohle c213b00b84 adding debug message
3 years ago
Steffen Pohle 18fbecceed adding buttons, no function yet.
3 years ago
Steffen Pohle b99e4bd975 adding buttons, no function yet.
3 years ago
Steffen Pohle 7a82b2c33d read out monitor geometry, in case we need it
3 years ago
Steffen Pohle e3b65f1c9d saving and restoring windows position and size on exit and startup
3 years ago
Stefan Jahn bf30a38282 Fixed typo
3 years ago
Stefan Jahn eacab6a56d Added RAW8 support for SVB camera, fixed RGB24 format; also fixed RGB conversions
3 years ago
Stefan Jahn 3a95c90f7c Frame saving bug fixes
3 years ago
Stefan Jahn 6a12c34087 Fix in bilenar debayering; is this already real color
3 years ago
Stefan Jahn 36b734d58b Small fix for bilinear debayering
3 years ago
Stefan Jahn e1f9d581c4 Enable files >2GB on 32bit systems; some fix for simple debayering
3 years ago
Steffen Pohle 294723388d ok
3 years ago
Steffen Pohle 1b5fed363a fixed: video for linux device is busy causes fatal error
3 years ago
Steffen Pohle ae7db254f6 menu did not set the histogram mode right
3 years ago
Steffen Pohle 98051d6b7c crash on invalid or not givin dumppath solved.
3 years ago
Steffen Pohle e5c5b90cad closing and reopening windows will works. As well as the menus for some settings
3 years ago
Steffen Pohle 3485300d28 spelling issues..
3 years ago
Steffen Pohle 974281ef66 gtk fixed .. detection display should work now.
3 years ago
Stefan Jahn 839d5d7c6d Avoid to write into smaller (in height) destination image
3 years ago
Stefan Jahn e6566646c6 Fixed another possible bug in the simple version of debayering GRBG16
3 years ago
Stefan Jahn 032cbdc0cf Added bilinear debayer of GRBG16, not yet tested
3 years ago
Steffen Pohle 59c59e557a using key to change histogram scale setting value
3 years ago
Stefan Jahn 7046b2edc9 Logarithmic scale depending on variable
3 years ago
Stefan Jahn c4b45efb9a Removed off-by-one error in zoomed histogram
3 years ago
Stefan Jahn ca56050ec5 Logarithmic histogram for testing...
3 years ago
Stefan Jahn 8cbf46d78e Added zoom functionality in histogram
3 years ago
Stefan Jahn c879097e89 small optimization
3 years ago
Steffen Pohle d9c22be57e save some time
3 years ago
Steffen Pohle 21b771a025 adding input for histogram
3 years ago
Steffen Pohle d4f71a7847 histogram
3 years ago
Steffen Pohle 1877e5951c adding histogram
3 years ago
Steffen Pohle f26d9e7396 fixed compilse warnings, added -ltiff to the librarys neeeded to compile
3 years ago
Stefan Jahn 209cbf9b43 Added some comments about DNG file endianess
3 years ago
Steffen Pohle b115537323 split application into different windows.
3 years ago
Steffen Pohle 03b12788cf adding RAW16 format
3 years ago

7
.gitignore vendored

@ -6,6 +6,11 @@ config.h
*.oo
simpleskycam
*~
*.bkp
U2SM200C-AST_Cfg_A.bin
U2SM200C-AST_Cfg_SAVE.bin
gmon.out
*.log
*.exe
*.bz2
Makefile.config

@ -1,3 +1,34 @@
2023-02-16:
- fixed positioncontrol. made some misstakes in calculating the angle
of the axsis vectors.
- changed: convert function is now only presend in videodef class.
2023-02-07:
- position control is now working. has still some glitches
with negative Kp, Ki and Kd values. But in general it is working.
- fixed: set mode to POSCTL_MODE_OFF if an output error occured.
2022-12-07:
- dump files will continussly loop
- fixed: dumpfile is not setting the frame size to the videodev.conf_height
and width variable
2022-12-06:
- saving and restoring windows position and size on exit and startup
2022-12-04:
- RAW8 format support for SVB camera, also fixed RGB24 format
- many bug fixes for RGB conversions
- DNG and SER file format fixes
2022-11-29:
- Crash on invalid dumpfile solved.
- closing and reopening of windows is working now.
- RGB16 debayer mode simple/bilinear can now be choosen in the settings menu
2022-11-26:
- adding histogram
2022-11-10:
- support for DNG file export

@ -1,26 +1,76 @@
.SILENT: help
#
# all configuration is set in the Makefile.config file.
#
VERSION = 0.0.1
APP = simpleskycam
-include Makefile.config
-include Makefile.rules
OBJECTS := $(OBJECTS) gui.oo main.oo \
OBJECTS := $(OBJECTS) gui.oo main.oo error.oo debug.oo \
video.oo videoframe.oo \
videodev.oo videodev-v4l2.oo videodev-dumpfile.oo \
convert.oo filter.oo detect.oo json.oo configuration.oo ser.oo
videodev.oo videodev-dumpfile.oo videodev-simulation.oo \
convert.oo output.oo detect.oo histogram.oo pid.oo \
posctl.oo json.oo configuration.oo debayer.oo
DISTNAME=simpleskycam-$(VERSION)
#
# add configuration for debug_angles
#
ifeq ($(DEBUG_ANGLES),1)
CPPFLAGS := $(CPPFLAGS)
OBJECTS := $(OBJECTS) debug-angles.oo
endif
#
#
# compile and use DNG files
#
ifeq ($(USE_DNG),1)
LDFLAGS := $(LDFLAGS) -ltiff
OBJECTS := $(OBJECTS) dng.oo
endif
#
ifeq ($(TARGET),)
noconfig: configlinux help
#
# compile and use DNG files
#
ifeq ($(USE_SER),1)
OBJECTS := $(OBJECTS) ser.oo
endif
#
ifeq ($(TARGET),)
noconfig: defaultconfig help
endif
all: Makefile.rules $(TARGET)
defaultconfig:
ifeq ($(MAKEFILE_CONFIG),)
echo "MAKEFILE_CONFIG = 1" > Makefile.config
echo "" >> Makefile.config
echo "USE_SVBONY = 1" >> Makefile.config
echo "USE_DNG = 1" >> Makefile.config
echo "USE_SER = 1" >> Makefile.config
echo "" >> Makefile.config
echo "DEBUG_ANGLES = 0" >> Makefile.config
echo "DEBUG_POSCTL = 0" >> Makefile.config
endif
help:
echo "set up configuration"
echo " make configlinux to generate the linix build"
echo " make configcross to generate the windows build using cross tools."
echo " make configwindows to generate the windows build using msys2."
echo " "
echo " make checkdumpfile to create a test tool for videodumps."
checkdumpfile: checkdumpfile.cc
@ -43,20 +93,76 @@ config: Makefile.rules
echo "#define _CONFIG_H_" >> config.h
echo "" >> config.h
echo "#define VERSION \"$(VERSION)\"" >> config.h
ifeq ($(USE_SVBONY),1)
echo "#define USE_SVBONY" >> config.h
endif
ifeq ($(USE_SER),1)
echo "#define USE_SER" >> config.h
endif
ifeq ($(USE_DNG),1)
echo "#define USE_DNG" >> config.h
endif
ifeq ($(USE_V4L2),1)
echo "#define USE_V4L2" >> config.h
endif
ifeq ($(USE_VFW),1)
echo "#define USE_VFW" >> config.h
endif
echo "" >> config.h
ifeq ($(DEBUG_ANGLES),1)
echo "#define DEBUG_ANGLES" >> config.h
endif
ifeq ($(DEBUG_POSCTL),1)
echo "#define DEBUG_POSCTL" >> config.h
endif
echo "" >> config.h
echo "#endif" >> config.h
buildwindows: clean
make configcross
make $(TARGET) -j 9
mkdir SimpleSkyCam-$(VERSION)
cp *.exe SimpleSkyCam-$(VERSION)/
cp simpleskycam.ui SimpleSkyCam-$(VERSION)/
cp README.md SimpleSkyCam-$(VERSION)/
cp ChangeLog SimpleSkyCam-$(VERSION)/
cp LICENSE SimpleSkyCam-$(VERSION)/
./copydlls.sh
./copydlls.sh
./copyshare.sh
mv *.dll SimpleSkyCam-$(VERSION)/
mv share SimpleSkyCam-$(VERSION)/
cp /usr/lib/gcc/x86_64-w64-mingw32/12-win32/*.dll SimpleSkyCam-$(VERSION)/
cp /opt/W64-cross-compile/lib/libtiff4.dll SimpleSkyCam-$(VERSION)/libtiff-6.dll
cp /opt/W64-cross-compile/lib/SVBCamera* SimpleSkyCam-$(VERSION)/
packwindows:
rm -rf SimpleSkyCam-$(VERSION) *.bz2
mkdir SimpleSkyCam-$(VERSION)
cp *.exe SimpleSkyCam-$(VERSION)/
cp simpleskycam.ui SimpleSkyCam-$(VERSION)/
cp README.md SimpleSkyCam-$(VERSION)/
cp ChangeLog SimpleSkyCam-$(VERSION)/
cp LICENSE SimpleSkyCam-$(VERSION)/
for i in `ldd simpleskycam.exe |grep -vi "/c/windows" | cut -d" " -f3`; do cp $$i SimpleSkyCam-$(VERSION)/; done
tar cvohif SimpleSkyCam-0.0.1-win64.tar.bz2 SimpleSkyCam-0.0.1/
$(TARGET): $(OBJECTS)
$(CPP) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .oo
-include $(DEPENDFILE)
.cc.oo : $(INCLUDES)
$(CPP) -o $@ -c $(CPPFLAGS) $<
cleanall: clean
rm -rf Makefile.config
clean:
rm -f *.o *.oo *.c~ *.h~ *.cc~ *.ui~ $(APP) Makefile~
rm -rf config.h
@ -66,8 +172,9 @@ clean:
rm -rf checkdumpfile
rm -rf U2SM200C-AST_Cfg_A.bin
rm -rf U2SM200C-AST_Cfg_SAVE.bin
rm -rf SimpleSkyCam-$(VERSION)
dist: clean
dist: cleanall
rm -rf $(DISTNAME)
mkdir $(DISTNAME)
cp Makefile* $(DISTNAME)
@ -80,11 +187,6 @@ dist: clean
tar cvzf $(DISTNAME).tgz $(DISTNAME)
rm -rf $(DISTNAME)
dep:
$(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE)
-include $(DEPENDFILE)
.PHONY: all
.PHONY: count
.PHONY: clean

@ -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
![Screenshot](https://steffen.gulpe.de/gitea/steffen/SimpleSkyCam/raw/branch/master/SampleOutput/screenshot-2024_04_13.png)
Screenshots and other stuff can be found at: <https://steffen.gulpe.de/progs/SimpleSkyCam>

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 KiB

@ -2,12 +2,19 @@
* tool to check and gain some basic information about videodum-files
*/
/* enable files > 2GB on 32 bit systems */
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef BUILD_WINDOWS
#else
#include <arpa/inet.h>
#endif
#include <string>
@ -20,25 +27,142 @@ std::string convert_from_pixelformat (uint32_t fmt) {
int main(int argc, char **argv) {
int fd;
int fixfile(char *src, char *dest) {
int fd, fd2;
int cnt = 0;
char *inbuf = NULL;
int inbufsize = 0;
int frmcnt = 0;
uint32_t i;
uint32_t size;
uint32_t size, size2;
if (argc != 2) {
printf ("please give a file name as parameter.\n");
printf ("checkdumpfile FILE\n");
printf ("\n");
printf ("fix file:'%s' output file:'%s'\n", src, dest);
if ((fd = open (src, O_RDONLY)) < 0) {
printf ("could not open input file: %s\n", strerror(errno));
return -1;
}
if ((fd2 = open (dest, O_WRONLY | O_CREAT | O_TRUNC), S_IRUSR | S_IWUSR) < 0) {
printf ("could not open output file: %s\n", strerror(errno));
close (fd);
return -1;
}
//
// read header w, h, pixfmt
if (read (fd, &i, 4) != 4) {
printf ("could not read all bytes.\n");
close (fd);
return -1;
}
if (write (fd2, &i, 4) != 4) {
printf ("could not write all bytes.\n");
close (fd2);
close (fd);
return -1;
}
printf (" Width: %d\n", ntohl(i));
if (read (fd, &i, 4) != 4) {
printf ("could not read all bytes.\n");
close (fd);
return -1;
}
if (write (fd2, &i, 4) != 4) {
printf ("could not write all bytes.\n");
close (fd2);
close (fd);
return -1;
}
printf (" Height: %d\n", ntohl(i));
if (read (fd, &i, 4) != 4) {
printf ("could not read all bytes.\n");
close (fd);
return -1;
}
if (write (fd2, &i, 4) != 4) {
printf ("could not write all bytes.\n");
close (fd2);
close (fd);
return -1;
}
printf(" Pixfmt: %s\n", convert_from_pixelformat(ntohl(i)).c_str());
//
// read frame
while (read (fd, &size, 4) == 4) {
size = ntohl(size);
size2 = htonl(size / 2);
if (write (fd2, &size2, 4) != 4) {
printf ("could not write framesize of frame %d.\n", frmcnt);
close (fd2);
close (fd);
return -1;
}
if (read (fd, &i, 4) != 4) {
printf ("could not read all bytes.\n");
close (fd);
return -1;
}
if (write (fd2, &i, 4) != 4) {
printf ("could not write timestamp of frame %d.\n", frmcnt);
close (fd2);
close (fd);
return -1;
}
i = ntohl(i);
if (inbuf == NULL){
inbuf = (char*) malloc (size);
inbufsize = size;
}
else if (inbufsize < size) {
inbuf = (char*)realloc(inbuf, size);
inbufsize = size;
}
if (inbuf == NULL) {
printf ("Error could not allocate enough memory\n");
close (fd);
return -1;
}
if (read (fd, inbuf, size) != size) {
printf ("could not read to next frame.\n");
close (fd);
return -1;
}
if (write (fd2, inbuf, size/2) != size/2) {
printf ("could not write frame %d.\n", frmcnt);
close (fd2);
close (fd);
return -1;
}
printf ("reading file :'%s'\n", argv[1]);
printf ("Frame: %-9d Timestamp:%-9d Size:%d\n", cnt++, i, size);
}
close (fd);
close (fd2);
return 0;
}
int checkfile(char *src) {
uint32_t i;
uint32_t size;
int fd;
int cnt = 0;
char *inbuf = NULL;
int inbufsize = 0;
printf ("reading file :'%s'\n", src);
if ((fd = open (argv[1], O_RDONLY)) < 0) {
if ((fd = open (src, O_RDONLY)) < 0) {
printf ("could not open file: %s\n", strerror(errno));
}
@ -104,5 +228,22 @@ int main(int argc, char **argv) {
close (fd);
return 0;
}
};
int main(int argc, char **argv) {
if (argc == 2) {
checkfile(argv[1]);
}
else if (argc == 3) {
fixfile(argv[1], argv[2]);
}
else {
printf ("please give a file name as parameter.\n");
printf ("checkdumpfile FILE to check file\n");
printf ("checkdumpfile SRCFILE DESTFILE to fix file\n");
printf ("\n");
}
return 0;
}

@ -2,17 +2,21 @@
#include "configuration.h"
#include "video.h"
#include "gui.h"
#include "detect.h"
#include <stdlib.h>
#include <string>
// extern VideoDev *videodev;
extern GtkBuilder *_builder_; // work around for threads
extern PosCtl posctl;
Configuration::Configuration() {
debugpath = NULL;
readdumppath = NULL;
destpath = "./";
show_debugwin = 0;
};
@ -64,6 +68,9 @@ void Configuration::SaveConfig(std::string filename) {
GtkWidget *cb;
GtkWidget *cbe;
std::string s = setlocale(LC_ALL, NULL);
setlocale (LC_ALL, "C");
//
// Add resolution, format and video device to config json element
cb = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videores"));
@ -76,6 +83,37 @@ void Configuration::SaveConfig(std::string filename) {
cbe = gtk_bin_get_child(GTK_BIN(cb));
jp.AddObject("device", (string) gtk_entry_get_text(GTK_ENTRY(cbe)));
//
// save posctl settings
double amin, amax, akp, aki, akd;
JSONParse jaxis;
posctl.LockMutex();
for (i = 0; i < 2; i++) {
posctl.GetAxisParam(i, &amin, &amax, &akp, &aki, &akd);
jaxis.Clear();
jaxis.AddObject("min", amin);
jaxis.AddObject("max", amax);
jaxis.AddObject("kp", akp);
jaxis.AddObject("ki", aki);
jaxis.AddObject("kd", akd);
printf ("%s:%d save config axis %d Out Range: %f - %f kP:%g kI:%g kD:%g\n",
__FILE__, __LINE__, i, amin, amax, akp, aki, akd);
jp.AddObject("posctl_axis" + to_string(i), jaxis);
}
jp.AddObject("posctl_filter", posctl.GetFilter());
jp.AddObject("posctl_device", posctl.GetDevice());
posctl.UnLockMutex();
//
// histogram settings and debayer mode
jp.AddObject("histogram_log", histogram_log);
jp.AddObject("debayer_mode", debayer_mode);
//
// save destination path
jp.AddObject("destination_path", destpath);
//
// save button config
for (i = 0; i < BTN_PRESET_MAX; i++) {
@ -101,12 +139,57 @@ void Configuration::SaveConfig(std::string filename) {
jp.AddObject(je);
}
//
// save windows position
printf ("%s:%d Xwayland is not able to retrieve the current position.\n", __FILE__, __LINE__);
for (i = 0; i < 6; i++) {
int x, y, w, h, show;
string name;
switch (i) {
case 0:
name = "window-main";
break;
case 1:
name = "window-input";
break;
case 2:
name = "window-output";
break;
case 3:
name = "window-detect";
break;
case 4:
name = "window-histogram";
break;
case 5:
name = "window-posctl";
break;
}
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), name.c_str()));
if (wnd) {
g_object_get (wnd, "visible", &show, NULL);
gtk_widget_show (wnd);
gtk_window_get_position (GTK_WINDOW(wnd), &x, &y);
gtk_window_get_size (GTK_WINDOW(wnd), &w, &h);
jp.AddObject(name+"_x", x);
jp.AddObject(name+"_y", y);
jp.AddObject(name+"_w", w);
jp.AddObject(name+"_h", h);
jp.AddObject(name+"_show", show);
}
}
//
// save config
if (jp.SaveToFile(filename)) {
printf ("%s:%d %s could not save to file [%s] Error: %s\n", __FILE__, __LINE__, __FUNCTION__,
filename.c_str(), strerror(errno));
}
setlocale (LC_ALL, s.c_str());
};
@ -116,6 +199,9 @@ void Configuration::LoadConfig(std::string filename) {
int i;
JSONElement je;
std::string s = setlocale(LC_ALL, NULL);
setlocale (LC_ALL, "C");
if (jp.LoadFromFile(filename)) {
printf ("%s:%d %s could not load from file [%s] Error: %s\n", __FILE__, __LINE__, __FUNCTION__,
filename.c_str(), strerror(errno));
@ -137,6 +223,42 @@ void Configuration::LoadConfig(std::string filename) {
gtk_entry_set_text(GTK_ENTRY(cbdevice), vstr.c_str());
}
//
// load posctl
double amin, amax, akp, aki, akd, f;
JSONParse jaxis;
posctl.LockMutex();
for (i = 0; i < 2; i++) {
if (jp.GetObjectJson("posctl_axis"+to_string(i), &jaxis)) {
jaxis.GetValueDouble("min", &amin);
jaxis.GetValueDouble("max", &amax);
jaxis.GetValueDouble("kp", &akp);
jaxis.GetValueDouble("ki", &aki);
jaxis.GetValueDouble("kd", &akd);
}
printf ("%s:%d load config axis %d Out Range: %f - %f kP:%f kI:%f kD:%f\n",
__FILE__, __LINE__, i, amin, amax, akp, aki, akd);
posctl.SetAxisParam(i, amin, amax, akp, aki, akd);
}
if (jp.GetValue("posctl_device", &vstr))
posctl.SetDevice(vstr);
if (jp.GetValueDouble("posctl_filter", &f))
posctl.SetFilter(f);
jp.AddObject("posctl_filter", posctl.GetFilter());
posctl.UnLockMutex();
jp.GetValueInt("histogram_log", &i);
SetHistogramLog(i);
jp.GetValueInt("debayer_mode", &i);
SetDebayerMode(i);
if (jp.GetValue("destination_path", &destpath)) {
GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath"));
gtk_entry_set_text(GTK_ENTRY(entry), destpath.c_str());
}
//
// start streaming if a device was selected.
@ -173,7 +295,79 @@ void Configuration::LoadConfig(std::string filename) {
ctrli++;
}
}
//
// check is the windows are inside the screen
// not really needed since gnome seem to take care about the windows positions
// and placement quite well.
GdkDisplay *dsp = gdk_display_get_default();
int n_monitor = -1;
if (dsp) {
n_monitor = gdk_display_get_n_monitors (dsp);
}
if (dsp && n_monitor > 0) {
GdkMonitor *g_monitor;
GdkRectangle geometry;
for (i = 0; i < n_monitor; i++) {
g_monitor = gdk_display_get_monitor(dsp, i);
if (g_monitor) {
gdk_monitor_get_geometry(g_monitor, &geometry);
printf ("%s:%d Monitor %d Pos:%d,%d Size:%d x %d\n", __FILE__, __LINE__, i,
geometry.x, geometry.y, geometry.width, geometry.height);
}
}
}
//
// load windows position
for (i = 0; i < 6; i++) {
int x, y, w, h, show;
string name;
switch (i) {
case 0:
name = "window-main";
break;
case 1:
name = "window-input";
break;
case 2:
name = "window-output";
break;
case 3:
name = "window-detect";
break;
case 4:
name = "window-histogram";
break;
case 5:
name = "window-posctl";
break;
}
if (jp.GetValueInt(name+"_x", &x) && jp.GetValueInt(name+"_y", &y) &&
jp.GetValueInt(name+"_w", &w) && jp.GetValueInt(name+"_h", &h) &&
jp.GetValueInt(name+"_show", &show)) {
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), name.c_str()));
if (wnd) {
printf ("%s:%d window '%s' set geometry %d,%d : %d x %d\n", __FILE__, __LINE__, name.c_str(), x, y, w, h);
gtk_window_move (GTK_WINDOW(wnd), x, y);
gtk_window_resize (GTK_WINDOW(wnd), w, h);
gtk_widget_show(wnd);
// g_object_set (wnd, "visible", &show, NULL);
}
}
}
}
setlocale (LC_ALL, s.c_str());
// we need to update the gui so floating numbers will displayed with the correct
// language setting.
gdk_threads_add_idle(cb_thread_posctl, NULL);
};
@ -193,3 +387,18 @@ list<VideoDevCtrl> Configuration::GetPresetButton (int btn) {
};
void Configuration::SetHistogramLog(int trueorfalse) {
GtkWidget *cfg_logh = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "menu-settings-loghistogram"));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(cfg_logh), (trueorfalse == 1));
histogram_log = trueorfalse;
};
void Configuration::SetDebayerMode(int trueorfalse) {
GtkWidget *cfg_debayer = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "menu-settings-bilinearrgb"));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(cfg_debayer), (trueorfalse == 1));
debayer_mode = trueorfalse;
};

@ -3,7 +3,7 @@
#define _CONFIGURATION_H_
/*
* all read and saved data will have to be in a
* all configuration data will loaded and saved from here.
*/
#include <string>
@ -17,12 +17,17 @@
class Configuration {
private:
int histogram_log = 1; // logarithmic or linear scale
int calibration_showdata = 0; // needed for debugging calibration
std::string destpath; // destination path
JSONParse config;
std::string GetDefaultFileName();
list<VideoDevCtrl> presetbtn[BTN_PRESET_MAX];
public:
char *debugpath;
char *readdumppath;
int debayer_mode = 0; // 0..simple mode, 1..bilinear
int show_debugwin = 0;
Configuration();
~Configuration();
@ -33,6 +38,17 @@ public:
void LoadConfig(std::string filename);
void SaveConfig(std::string filename);
void SetDebayerMode(int trueorfalse);
void SetDestPath (std::string dest) { destpath = dest; };
std::string GetDestPath() { return destpath; };
void SetHistogramLog(int trueorfalse);
int GetHistogramLog() { return histogram_log; };
void SetCalibrationShowData(int enabled) { calibration_showdata = enabled; };
int GetCalibrationShowData() { return calibration_showdata; };
void SetPresetButton (int btn, list<VideoDevCtrl> *parameters);
list<VideoDevCtrl> GetPresetButton (int btn);
};

@ -4,12 +4,18 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef BUILD_WINDOWS
#include "windows.h"
#else
#include <arpa/inet.h>
#endif
#include "convert.h"
#include "gui.h"
#include "video.h"
#include "configuration.h"
#include "debayer.h"
uint32_t convert_pixelformats [] = {
V4L2_PIX_FMT_MJPEG,
@ -19,6 +25,8 @@ uint32_t convert_pixelformats [] = {
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_BGR24,
V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_SGRBG16,
V4L2_PIX_FMT_SGRBG8,
0
};
@ -46,8 +54,6 @@ struct timeval convert_debug_tv;
/*
* will be called on first frame
*/
#define LEN_FILENAME 64
#define LEN_FULLFILENAME 256
int convert_debug_open(uint32_t pixelformat, int srcw, int srch) {
time_t t = time(NULL);
struct tm *tmptr;
@ -61,7 +67,7 @@ int convert_debug_open(uint32_t pixelformat, int srcw, int srch) {
//
// check to create file, if not possible try creating the directory and create the file again
tmptr = localtime(&t);
strftime(fname, LEN_FILENAME, "%F-%R", tmptr);
strftime(fname, LEN_FILENAME, "%Y%m%d-%H%M%S", tmptr);
snprintf (fullfname, LEN_FULLFILENAME, "%s/%s.videodump", config.debugpath, fname);
if ((convert_debug_fd = creat (fullfname, 0666)) == -1) {
@ -69,11 +75,15 @@ int convert_debug_open(uint32_t pixelformat, int srcw, int srch) {
printf ("%s:%d try to create folder\n", __FILE__, __LINE__);
// create folder
// FIXME: how to do thin on windows
#ifdef BUILD_WINDOWS
if ((mkdir (config.debugpath)) == -1) {
#else
if ((mkdir (config.debugpath, 0777)) == -1) {
#endif
printf ("%s:%d could not create debug folder.\n", __FILE__, __LINE__);
return -1;
}
if ((convert_debug_fd = creat (fullfname, 0666)) == -1) {
printf ("%s:%d could again not create file '%s'. Error:%s\n", __FILE__, __LINE__, fullfname, strerror(errno));
return -1;
@ -132,9 +142,6 @@ void convert_debug_dumpframe(unsigned char *ptrsrc, int srcsize, uint32_t pixelf
* close file and reset all data
*/
void convert_debug_close() {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
if (convert_debug_fd != -1) {
close (convert_debug_fd);
convert_debug_fd = -1;
@ -174,7 +181,7 @@ inline unsigned char clamp (double x) {
inline void convert2rgb (unsigned char Y1, unsigned char Cb, unsigned char Cr,
unsigned char *ER, unsigned char *EB, unsigned char *EG) {
register int y1, pb, pr;
int y1, pb, pr;
y1 = Y1 - 16;
pb = Cb - 128;
@ -205,6 +212,7 @@ int ConvertStop(ConvertData *cdata, uint32_t pixelformat) {
return VDEV_STATUS_OK;
};
/*
* converts the video from input type to RGB24 type - 24Bit
*/
@ -244,17 +252,17 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
ptrsrc++;
r = *(ptrsrc++);
g = *(ptrsrc++);
b = *(ptrsrc++);
ptrsrc++;
/* only paint the image if the source is within the destination */
if (xd < dest->w) {
/* set the pixel */
*(ptrdst++) = b;
*(ptrdst++) = g;
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
@ -271,17 +279,17 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
ptrsrc++;
b = *(ptrsrc++);
g = *(ptrsrc++);
r = *(ptrsrc++);
ptrsrc++;
/* only paint the image if the source is within the destination */
if (xd < dest->w) {
/* set the pixel */
*(ptrdst++) = b;
*(ptrdst++) = g;
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
@ -304,9 +312,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
/* only paint the image if the source is within the destination */
if (xd < dest->w) {
/* set the pixel */
*(ptrdst++) = b;
*(ptrdst++) = g;
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
@ -330,9 +338,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
/* only paint the image if the source is within the destination */
if (xd < dest->w) {
/* set the pixel */
*(ptrdst++) = b;
*(ptrdst++) = g;
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
@ -344,6 +352,20 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
}
break;
case (V4L2_PIX_FMT_SGRBG16):
if (config.debayer_mode == 0)
debayer_grbg16_simple ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
else
debayer_grbg16_bilinear ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
break;
case (V4L2_PIX_FMT_SGRBG8):
if (config.debayer_mode == 0)
debayer_grbg8_simple ((uint8_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
else
debayer_grbg8_bilinear ((uint8_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h);
break;
case (V4L2_PIX_FMT_UYVY):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
@ -365,9 +387,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
/* only paint the image if the source is within the destination */
if (xd < dest->w) {
/* set the pixel */
*(ptrdst++) = b;
*(ptrdst++) = g;
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
@ -465,3 +487,72 @@ uint32_t convert_to_pixelformat(std::string s) {
};
/*
* copy part of an raw image
* destination must be pointer in case we need to align the size of the destination image.
* this function will also realloc needed memory if needed. (only if: givin size < needed size)
*
* crop image to event set of dimensions
*/
int PixCopy(unsigned char *srcdata, uint32_t srcpixfmt, int srcw, int srch,
unsigned char **dstdataptr, int *dstsize, int *dstw, int *dsth,
int regionx, int regiony, int regionw, int regionh) {
if (srcpixfmt == 0 || srcpixfmt == V4L2_PIX_FMT_MJPEG) return 0;
if (srcdata == NULL || dstdataptr == NULL) return 0;
// crop size to an even number
(*dsth) = regionw & ~1;
(*dstw) = regionh & ~1;
int bytesperpixel = 3;
int dsize = 0;
switch (srcpixfmt) {
case (V4L2_PIX_FMT_SGRBG8):
bytesperpixel = 1;
break;
case (V4L2_PIX_FMT_SGRBG16):
bytesperpixel = 2;
break;
case (V4L2_PIX_FMT_BGR32):
case (V4L2_PIX_FMT_RGB32):
bytesperpixel = 4;
break;
case (V4L2_PIX_FMT_BGR24):
case (V4L2_PIX_FMT_RGB24):
bytesperpixel = 3;
break;
default:
return 0;
}
//
// calculate image size and allocate memory if needed
dsize = (*dsth) * (*dstw) * bytesperpixel;
if ((*dstsize) < dsize || (*dstdataptr) == NULL) {
*dstdataptr = (unsigned char*) realloc (*dstdataptr, dsize);
if (*dstdataptr == NULL) {
errorexit((char*)"%s:%d could not realloc memory. dsize:%d error:%s\n", __FILE__, __LINE__, dsize, strerror(errno));
}
*dstsize = dsize;
printf ("%s:%d reallocate memory for destination raw image\n", __FILE__, __LINE__);
}
unsigned char *dptr, *sptr;
int y, dy, x;
// debug_drawraw(srcdata, srcpixfmt, srcw, srch);
for (y = regiony & (~1), dy = 0; dy < *dsth && y < srch; y++, dy++) {
x = regionx & (~1);
dptr = (*dstdataptr) + bytesperpixel * (dy * *dstw);
sptr = (srcdata) + bytesperpixel * ( y * srcw + x);
memcpy (dptr, sptr, *dstw * bytesperpixel);
}
if (config.show_debugwin) debug_drawraw(*dstdataptr, srcpixfmt, *dstw, *dsth);
return 1;
}

@ -21,6 +21,10 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
int ConvertStart(ConvertData *cdata, uint32_t pixelformat);
int ConvertStop(ConvertData *cdata, uint32_t pixelformat);
int PixCopy(unsigned char *srcdata, uint32_t srcpixfmt, int srcw, int srch,
unsigned char **dstdataptr, int *dstsize, int *dstw, int *dsth,
int regionx, int regiony, int regionw, int regionh);
extern uint32_t convert_pixelformats[];
std::string convert_from_pixelformat (uint32_t fmt);
uint32_t convert_to_pixelformat(std::string s);

@ -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

@ -5,11 +5,15 @@
#include <mmintrin.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include "config.h"
#include "gui.h"
#include "detect.h"
#include "convert.h"
#include "configuration.h" // needed to get V4L formats
extern Detect detect;
extern PosCtl posctl;
//
// C / C++ Wrapper for the thread function
@ -31,7 +35,7 @@ Detect::Detect() { // @suppress("Class members should be properly initialized")
inFrame.SetSize(64, 64);
oldFrame.SetSize(64, 64);
image.SetSize(64, 64);
imagegtk.SetSize(64, 64);
imageRGBout.SetSize(64, 64);
thread = NULL;
thread = g_thread_new("Detect", _DetectThread, NULL);
objectW = 300;
@ -59,59 +63,87 @@ Detect::~Detect() {
int Detect::NewFrame(VideoFrame *newframe) {
/*
* copy the framedata into the next thread. Source data must be already mutex locked.
* raw data will only be copied if the source is not an compressed stream
*/
int Detect::CopyNewFrame(VideoFrame *newframe, VideoFrameRaw *rawframe) {
if (newframe == NULL) return -1;
LockInMutex();
if (rawframe->pixfmt != V4L2_PIX_FMT_MJPEG)
inRawFrame.CopyFrom(rawframe);
else
inRawFrame.Delete();
inFrame.CopyFrom(newframe);
inFrameNew = 1;
UnLockInMutex();
return 0;
};
//
// NewFrame: will set new frame
// Thread: newFrame |------> Find Object --- not found ---> send gui information
/*
* NewFrame: will set new frame
* Thread: newFrame |------> Find Object --- not found ---> send gui information
*/
void Detect::Thread() {
DetectOutput output;
DetectOutput doutput;
struct timeval timestamp;
double dt;
int oldX, oldY;
objectX = -1;
objectY = -1;
output.detmatrix = (uint32_t*)malloc (sizeof(uint32_t) * DET_MAXSHIFT * DET_MAXSHIFT);
doutput.detmatrix = (uint32_t*)malloc (sizeof(uint32_t) * DET_MAXSHIFT * DET_MAXSHIFT);
gettimeofday (&timestamp, NULL);
while (running) {
// check for new frame
dt = get_cycletime(&timestamp);
LockInMutex();
if (inFrameNew == 1) {
inFrameNew = 0;
oldX = objectX;
oldY = objectY;
LockMutex(); // lock Config
//
// 1. if no position of the object is known, search brightest
// object on the inFrame image.
if (objectX < objectW/2 || objectX > (inFrame.w-objectW/2) ||
objectY < objectH/2 || objectY > (inFrame.h-objectH/2))
// 1. check near the last known position.
//
if (objectX >= objectW/2 && objectX <= (inFrame.w-objectW/2) &&
objectY >= objectH/2 && objectY <= (inFrame.h-objectH/2))
{
switch (autodetecttype) {
case AUTODETECT_BRIGHT:
switch (autofollowtype) {
case AUTOFOLLOW_BRIGHT:
InputDetect(&objectX, &objectY);
break;
case AUTOFOLLOW_CROSSC:
InputDetectCrossC(&objectX, &objectY);
break;
default:
break;
}
if (abs(oldX - objectX) >= DET_MAXSHIFT/5 || abs(oldY - objectY) >= DET_MAXSHIFT/5) {
objectX = -1;
objectY = -1;
}
}
//
// 2. check near the last known position.
//
else {
switch (autofollowtype) {
case AUTOFOLLOW_BRIGHT:
// 2. if no position of the object is known, search brightest
// object on the inFrame image.
if (objectX < objectW/2 || objectX > (inFrame.w-objectW/2) ||
objectY < objectH/2 || objectY > (inFrame.h-objectH/2))
{
switch (autodetecttype) {
case AUTODETECT_BRIGHT:
InputDetect(&objectX, &objectY);
break;
case AUTOFOLLOW_CROSSC:
InputDetectCrossC(&objectX, &objectY);
break;
default:
break;
}
@ -122,25 +154,30 @@ void Detect::Thread() {
// copy output image for gtk
LockImageMutex();
imagegtk.CopyFrom(&image);
imageRGBout.CopyFrom(&image);
if (imageRawout.RectCopyFrom(&inRawFrame, (objectX-objectW/2), (objectY-objectH/2), objectW, objectH) == 0)
imageRawout.CopyFrom(&imageRGBout);
UnLockImageMutex();
output.posx = objectX;
output.posy = objectY;
output.image = &imagegtk;
doutput.posx = objectX;
doutput.posy = objectY;
doutput.image = &imageRGBout;
doutput.rawimage = &imageRawout;
if (detmatrix != NULL)
memcpy (output.detmatrix, detmatrix, sizeof(uint32_t) * DET_MAXSHIFT * DET_MAXSHIFT);
memcpy (doutput.detmatrix, detmatrix, sizeof(uint32_t) * DET_MAXSHIFT * DET_MAXSHIFT);
UnLockMutex(); // unlock Config
posctl.Loop (objectX, objectY, dt);
gdk_threads_add_idle(cb_thread_detect , &output);
UnLockMutex(); // unlock detect dataset
gdk_threads_add_idle(cb_thread_detect , &doutput);
}
else
UnLockInMutex();
usleep (10000);
usleep (10000); // FIXME:: why is it here?
}
free (output.detmatrix);
free (doutput.detmatrix);
}
@ -213,6 +250,8 @@ void Detect::InputDetect(int *posx, int *posy) {
didx = 3* (image.w * dy + dx);
for (i = 0; i < 3; i++) pxi[didx+i] = pxs[idx+i];
}
return;
}
/* returns approx. 8-bit gray value */
@ -308,6 +347,7 @@ void Detect::InputDetectCrossC(int *posx, int *posy) {
*posx += (mxx-DET_MAXSHIFT/2);
*posy += (mxy-DET_MAXSHIFT/2);
CopyObjectImage (*posx, *posy);
return;
}

@ -8,6 +8,26 @@
#ifndef _DETECT_H_
#define _DETECT_H_
#ifdef BUILD_WINDOWS
#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 <winsock2.h>
#include <io.h>
#include <ws2tcpip.h>
#include <windows.h>
#endif
#include "pid.h"
#include "gui.h"
#include "config.h"
#include "video.h"
@ -26,24 +46,149 @@ enum {
AUTOFOLLOW_CROSSC
};
enum {
POSCTL_MODE_OFF = 0,
POSCTL_MODE_CALIB,
POSCTL_MODE_CONTROL,
POSCTL_MODE_2STEPWAIT,
POSCTL_MODE_2STEPRUN
};
enum {
POSCTL_CALIB_MODE_OFF = 0,
POSCTL_CALIB_MODE_START,
POSCTL_CALIB_MODE_STOP1,
POSCTL_CALIB_MODE_DELTAM,
POSCTL_CALIB_MODE_AXIS1START,
POSCTL_CALIB_MODE_AXIS1M,
POSCTL_CALIB_MODE_AXIS2START,
POSCTL_CALIB_MODE_AXIS2M,
POSCTL_CALIB_MODE_FINISH
};
enum {
POSCTL_DEVTYPE_TTY = 0,
POSCTL_DEVTYPE_SIM
};
struct PosCtl_2Step_Data {
int mode;
double pv[2];
double op[2];
double npv[2];
double ppv[2];
double nop[2];
double pop[2];
};
struct PosCtl_ThreadData {
position_2d c[2];
position_2d a1[2];
position_2d a2[2];
position_2d target_pos;
int calib_mode;
};
class PosCtl {
private:
GMutex mutex;
int mode;
PID pid_axis[2];
std::string device;
int device_type;
#ifdef BUILD_WINDOWS
HANDLE device_fd;
#else
int device_fd;
#endif
struct timeval calib_timestamp;
int calib_mode;
position_2d calib_pos;
position_f_2d pos;
double npv[2];
double ppv[2];
double nop[2];
double pop[2];
double posfilter;
struct PosCtl_ThreadData threaddata; // will be copied to gtk thread
void NotifyGtk();
void NotifyGtk2Step();
void CalibModeStart(int x, int y);
void CalibModeDelta(int x, int y);
void CalibModeAxis(int x, int y);
void CalibModeFinish();
void CalibModeWait(int x, int y);
int OutputClose();
int OutputOpen();
int WriteTTY(char *);
int ReadTTY(char *, int);
static double filteredvalue(double old_value, double new_value, double dt, double filter);
public:
PosCtl();
~PosCtl() {};
position_f_2d calib_rot_v;
vector_2d calib_rot;
position_f_2d calib_axis1_v;
vector_2d calib_axis1;
position_f_2d calib_axis2_v;
vector_2d calib_axis2;
position_f_2d target_pos;
position_f_2d current_pos;
double axis_pv[2];
double axis_op[2];
void LockMutex() { g_mutex_lock(&mutex); };
void UnLockMutex() { g_mutex_unlock(&mutex); };
void Stop ();
void StartCalibration ();
void StartControl ();
void Run2Step ();
void Reset2Step ();
int GetMode () { return mode; };
void SetAxisParam (int axis, double min, double max, double k, double i, double d);
void GetAxisParam (int axis, double *min, double *max, double *k, double *i, double *d);
void SetDevice(std::string d);
void SetFilter(double f) { posfilter = f; };
double GetFilter() { return posfilter; };
std::string GetDevice() { return device; };
void Loop (int posx, int posy, double dt);
int OutputWriteValue (int axis, double value);
int OutputWriteStop ();
int OutputWriteStart ();
};
struct {
VideoFrame *image; // detected image
VideoFrameRaw *rawimage; // detected rawimage
uint32_t *detmatrix;
int posx; // position of the detected object
int posy; // position of the detected object
int valid; // valid position detected
} typedef DetectOutput;
class Detect {
private:
int running;
VideoFrame inFrame; // input frame
VideoFrameRaw inRawFrame; // input RawFrame
VideoFrame oldFrame; // oldinput frame
int inFrameNew; // new input frame;
VideoFrame image; // output image
VideoFrame imagegtk; // output image -- send to gtk
VideoFrame imageRGBout; // output image -- send to gtk
VideoFrameRaw imageRawout; // output raw image
GMutex muteximage;
GMutex mutexin;
GMutex mutex; // general mutex for changing settings
@ -73,7 +218,7 @@ public:
Detect();
~Detect();
int NewFrame(VideoFrame *newframe);
int CopyNewFrame(VideoFrame *newframe, VideoFrameRaw *rawframe); // set new frame data
//
// Thread Releated Functions (maybe soon private?)
@ -108,4 +253,6 @@ public:
void Thread();
};
extern struct PosCtl_ThreadData posctl_threaddata;
#endif

@ -3,6 +3,7 @@
*/
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <tiffio.h>
#include "dng.h"
@ -26,11 +27,25 @@ DNG::~DNG() {
}
}
/*
Run-time detection if we are little- or big-endian.
*/
int DNG::IsBigEndian(void) {
int i = 1;
return ! *((char *)&i);
}
/*
Sets the file name of the DNG file to be written. Returns -1 on
failure, 0 on success.
*/
int DNG::setFile(char * file) {
/*
w = write
l = little endian
b = big endian
-> if neither l or b is given, data is written in native CPU format
*/
if (!(tif = TIFFOpen(file, "w"))) {
return -1;
}
@ -109,6 +124,7 @@ int DNG::writeFile(void * data) {
struct tm tm;
char timestamp[64];
/* get time stamp */
time (&abs_ts);
gmtime_r (&abs_ts, &tm);
sprintf(timestamp, "%04d:%02d:%02d %02d:%02d:%02d",
@ -134,12 +150,14 @@ int DNG::writeFile(void * data) {
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, SamplesPerPixel);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
if(ColorID == DNG_COLORID_RAW8 || ColorID == DNG_COLORID_RAW8) {
if(ColorID == DNG_COLORID_RAW8 || ColorID == DNG_COLORID_RAW16) {
static const short CFARepeatPattern[] = { 2,2 }; // 2x2 CFA
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, CFARepeatPattern);
TIFFSetField(tif, TIFFTAG_CFALAYOUT, 1);
TIFFSetField(tif, TIFFTAG_CFAPLANECOLOR, 3, "\000\001\002"); // RGB
// 0 = Red, 1 = Green, 2 = Blue
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\001\000\002\001"); // GRGB
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\001\000\002\001"); // GRBG
}
else if(ColorID == DNG_COLORID_RGB) {
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);

@ -1,6 +1,7 @@
#ifndef _DNG_H_
#define _DNG_H_
/*
Example usage of the class:
---------------------------
@ -48,6 +49,7 @@ class DNG {
int BitsPerSample;
int SamplesPerPixel;
int ColorID;
int IsBigEndian(void);
public:
DNG();

@ -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 = inFrame.data;
if (pixd == NULL || pixs == NULL) return;
if (newimage) {
inFrame.CopyTo(&image);
newimage = 0;
}
else {
for (x = 0; x < inFrame.w; x++)
for (y = 0; y < inFrame.h; y++) {
idx = 3 * (inFrame.w * y + x);
for (i = 0; i < 3; i++)
pixd[idx+i] = ((FACTOR-1.0) * (float)pixd[idx+i]/FACTOR) + (float)(pixs[idx+i] / FACTOR);
}
}
}

222
gui.cc

@ -14,12 +14,12 @@
#include "gui.h"
#include "config.h"
#include "video.h"
#include "filter.h"
#include "output.h"
#include "detect.h"
#include "configuration.h"
extern GtkBuilder *_builder_; // work around for threads
extern Filter filter;
extern Output output;
extern Detect detect;
//
@ -33,6 +33,11 @@ GdkPixbuf *detect_pixbuf = NULL;
GtkWidget *image_da = NULL;
GdkPixbuf *image_pixbuf = NULL;
extern GtkWidget *debug_da;
extern GdkPixbuf *debug_pixbuf;
std::string filename = "";
extern Configuration config;
@ -56,12 +61,12 @@ void cb_window_show (GtkWidget *widget, gpointer data) {
GtkWidget *btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-stop"));
GtkWidget *w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
GtkWidget *h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
GtkWidget *rboff = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff"));
GtkWidget *rbcrossc = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2"));
GtkWidget *rbdefdetect = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright"));
GtkWidget *rbdeffolow = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2"));
// changing the value, will cause the 'change' event to be triggered
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rboff), true);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbcrossc), true);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdefdetect), true);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdeffolow), true);
gtk_widget_set_sensitive(btnstart, true);
@ -72,32 +77,40 @@ void cb_window_show (GtkWidget *widget, gpointer data) {
detect.SetObjectSize(300, 300);
cb_video_btnrefreshlist (NULL, NULL);
//
// load config and setup elements
config.LoadDefault();
//
// show debug output window.
if (config.show_debugwin) {
printf ("%s:%d show debug window\n", __FILE__, __LINE__);
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-debug"));
if (wnd) gtk_widget_show (wnd);
}
GtkWidget *cfg_rgbenc = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "menu-settings-bilinearrgb"));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(cfg_rgbenc), (config.debayer_mode != 0));
//
// update the input video controls every 2 seconds.
g_timeout_add(2000, videoctrl_update, NULL);
};
void displayerror (std::string error) {
GtkWidget *dialog;
GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (_builder_, "main-window"));
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"%s", error.c_str());
gtk_window_set_title(GTK_WINDOW(dialog), "Error");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
};
void cb_menu_set_rgbenc (GtkCheckMenuItem *checkmenuitem, gpointer user_data) {
if (gtk_check_menu_item_get_active(checkmenuitem) == TRUE) config.debayer_mode = 1;
else config.debayer_mode = 0;
}
//
// callback from filter thread. Data will point to the output VideoFrame.
// Access to this data must be Locked before use.
gboolean cb_thread_filter (gpointer data) {
//
/* gboolean cb_thread_filter (gpointer data) {
VideoFrame *vf = (VideoFrame *) data;
int pix_h, pix_w;
@ -108,7 +121,7 @@ gboolean cb_thread_filter (gpointer data) {
return false;
}
filter.LockImageMutex();
output.LockImageMutex();
if (image_pixbuf) {
pix_h = gdk_pixbuf_get_height(image_pixbuf);
@ -127,14 +140,14 @@ gboolean cb_thread_filter (gpointer data) {
vf->ToPixbuf(image_pixbuf);
gdk_window_invalidate_rect(gtk_widget_get_window(image_da), NULL, true);
filter.UnLockImageMutex();
output.UnLockImageMutex();
return false;
};
*/
//
// callback from filter thread. Data will point to the temp VideoFrame.
// callback from detect thread. Data will point to the temp VideoFrame.
// this is propabely the object detection
// Access to this data must be Locked before use and pointers must be looked to
gboolean cb_thread_detect (gpointer data) {
@ -170,9 +183,9 @@ gboolean cb_thread_detect (gpointer data) {
pix_w = dout->image->w;
pix_h = dout->image->h;
}
dout->image->ToPixbuf(detect_pixbuf);
dout->image->ToPixbuf(&detect_pixbuf);
gdk_window_invalidate_rect(gtk_widget_get_window(detect_da), NULL, true);
filter.NewFrame(dout->image, dout->posx, dout->posy);
output.NewFrame(dout->rawimage);
detect.UnLockImageMutex();
@ -218,6 +231,7 @@ void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer da
if (area == image_da) src = image_pixbuf;
else if (area == detect_da) src = detect_pixbuf;
else if (area == debug_da && debug_pixbuf != NULL) src = debug_pixbuf;
else return;
clienth = gtk_widget_get_allocated_height(area);
@ -253,61 +267,6 @@ void cb_detect_btnsetsize (GtkWidget *widget, gpointer data) {
};
void cb_image_btnnew (GtkWidget *widget, gpointer data) {
filter.NewImage();
};
void cb_image_btnsave (GtkWidget *widget, gpointer data) {
GtkBuilder *builder = (GtkBuilder *) data;
GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "window-main"));
GtkWidget *dialog;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
GtkFileFilter *filter;
gint res;
if (image_pixbuf == NULL) return;
dialog = gtk_file_chooser_dialog_new ("Save File",
window,
action,
"_Cancel",
GTK_RESPONSE_CANCEL,
"_Save",
GTK_RESPONSE_ACCEPT,
NULL);
chooser = GTK_FILE_CHOOSER (dialog);
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.png");
gtk_file_filter_set_name(filter, "PNG File");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.*");
gtk_file_filter_set_name(filter, "All Files");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
if (filename.length () == 0)
gtk_file_chooser_set_current_name (chooser, "capture-001.png");
else
gtk_file_chooser_set_filename (chooser, filename.c_str());
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT) {
char *filename;
filename = gtk_file_chooser_get_filename (chooser);
gdk_pixbuf_save(image_pixbuf, filename, "png", NULL, "quality", "100", NULL);
g_free (filename);
}
gtk_widget_destroy (dialog);
};
void cb_detect_bright (GtkRange *range, gpointer data) {
double value;
@ -350,3 +309,106 @@ void cb_detect_btnsetpos (GtkWidget *widget, gpointer data) {
};
void cb_detect_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-detect"));
gtk_widget_show(wnd);
};
/*
* setup destination path
*/
void cb_input_btnsetdestpath (GtkWidget *widget, gpointer data) {
GtkBuilder *builder = (GtkBuilder *) data;
GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "windows-input"));
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
gint res;
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
dialog = gtk_file_chooser_dialog_new ("Open Folder",
window,
action,
"_Cancel",
GTK_RESPONSE_CANCEL,
"_Open",
GTK_RESPONSE_ACCEPT,
NULL);
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT) {
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
filename = gtk_file_chooser_get_filename (chooser);
config.SetDestPath(filename);
GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath"));
gtk_entry_set_text(GTK_ENTRY(entry), filename);
g_free (filename);
}
gtk_widget_destroy (dialog);
};
void cb_input_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-input"));
gtk_widget_show(wnd);
};
void draw_text (cairo_t *cr, int x, int y, float border, std::string text) {
cairo_pattern_t *t = NULL;
double r, g, b, a;
t = cairo_get_source(cr);
cairo_pattern_get_rgba(t, &r, &g, &b, &a);
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_rgba(cr, r, g, b, a);
dx = 0;
dy = 0;
break;
}
cairo_move_to (cr, x+dx, y+dy);
cairo_show_text(cr, text.c_str());
cairo_stroke(cr);
}
};
#define DRAW_PRINTF_LEN 512
void draw_printf(cairo_t *cr, int x, int y, float border, char *fmt,...) {
va_list args;
char buffer[DRAW_PRINTF_LEN];
va_start (args, fmt);
vsnprintf (buffer, (DRAW_PRINTF_LEN-1), fmt, args);
va_end (args);
buffer[DRAW_PRINTF_LEN-1] = 0;
draw_text (cr, x, y, border, buffer);
};

140
gui.h

@ -11,21 +11,93 @@
#include <gdk/gdk.h>
#include <glib.h>
#include <math.h>
#include <string>
#include <iostream>
#include <list>
#define LEN_FILENAME 64
#define LEN_FULLFILENAME 256
enum {
VID_ENTERDATA_NONE = 0,
VID_ENTERDATA_POS
VID_ENTERDATA_POS,
VID_ENTERDATA_SETDEST
};
#define BUILDER_FILE "simpleskycam.ui"
struct {
class position_2d {
public:
position_2d() { x = 0; y = 0; };
~position_2d() {};
position_2d operator + (position_2d const &obj) {
position_2d res;
res.x = x + obj.x;
res.y = y + obj.y;
return res;
}
position_2d operator - (position_2d const &obj) {
position_2d res;
res.x = x - obj.x;
res.y = y - obj.y;
return res;
}
int x;
int y;
} typedef position_2d;
};
class position_f_2d {
public:
position_f_2d() { x = NAN; y = NAN; };
~position_f_2d() {};
position_f_2d operator + (position_f_2d const &obj) {
position_f_2d res;
res.x = x + obj.x;
res.y = y + obj.y;
return res;
}
position_f_2d operator - (position_f_2d const &obj) {
position_f_2d res;
res.x = x - obj.x;
res.y = y - obj.y;
return res;
}
double cosalpha(position_f_2d &pos) {
return (x * pos.x + y * pos.y) / (length() * pos.length());
}
double sinalpha(position_f_2d &pos) {
return (x * pos.y - y * pos.x) / (length() * pos.length());
}
double perpendicular(position_f_2d &pos, position_f_2d &base) {
position_f_2d p = pos - base;
double l = p.length();
return l == 0.0 ? 0.0 : l * sinalpha(p);
}
double length() { return hypot(x, y); }
double x;
double y;
};
class vector_2d {
public:
double a;
double l;
vector_2d () { a = NAN; l = NAN; }
~vector_2d () {};
};
#define DETECT_MOVEMENT_SAMPLES 50
@ -39,7 +111,10 @@ struct {
float dy;
} typedef detect_movement;
void displayerror (std::string error);
void draw_text (cairo_t *cr, int x, int y, float border, std::string text);
void draw_printf(cairo_t *cr, int x, int y, float border, char *fmt,...);
#define gtk_entry_set_text_nofocus(__w__,__t__) if (!gtk_widget_has_focus(__w__)) gtk_entry_set_text (GTK_ENTRY(__w__), __t__)
#ifdef __cplusplus
extern "C" {
@ -79,24 +154,73 @@ gboolean video_pre_long(gpointer data);
//
// thread new inframe
G_MODULE_EXPORT gboolean cb_thread_video (gpointer data);
G_MODULE_EXPORT void cb_input_show_window (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_input_btncapture (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_input_btnsnapshot (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_input_btnstop (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_input_btnscale (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_input_btnsetdestpath (GtkWidget *widget, gpointer data);
//
// filter detect or image data
G_MODULE_EXPORT void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data);
G_MODULE_EXPORT gboolean cb_thread_filter (gpointer data);
G_MODULE_EXPORT gboolean cb_thread_detect (gpointer data);
G_MODULE_EXPORT void cb_image_btnnew (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_image_btnsave (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_detect_bright (GtkRange *range, gpointer data);
//
// detection elements
G_MODULE_EXPORT void cb_detect_bright (GtkRange *range, gpointer data);
G_MODULE_EXPORT void cb_detect_btnsetpos (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_detect_btnsetsize (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_detect_followtype (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_detect_detecttype (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_detect_show_window (GtkWidget *widget, gpointer data);
//
// histogram elements
G_MODULE_EXPORT void cb_histogramda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data);
G_MODULE_EXPORT void cb_histogramda_motion (GtkWidget *widget, GdkEvent *event, gpointer data);
G_MODULE_EXPORT void cb_histogramda_btnpress (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_histogramda_btnrelease (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_histogramda_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data);
G_MODULE_EXPORT void cb_histogram_show_window (GtkWidget *widget, gpointer data);
//
// position control elements
G_MODULE_EXPORT void cb_posctl_show (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_show_window (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btncalib (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btnstop (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btnsetdest (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btncontrol (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_entryanglelen (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_change_entry (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btn_axismove (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btnsimreset (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_angles_draw (GtkWidget *area, cairo_t *cr, int w, int h, gpointer data);
G_MODULE_EXPORT void cb_posctl_axis_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data);
G_MODULE_EXPORT void cb_posctl_track_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data);
G_MODULE_EXPORT void cb_posctl_btn2steprun (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT void cb_posctl_btn2stepreset (GtkWidget *widget, gpointer data);
//
// menu elements
G_MODULE_EXPORT void cb_menu_set_rgbenc (GtkCheckMenuItem *checkmenuitem, gpointer user_data);
G_MODULE_EXPORT void cb_menu_set_histlog (GtkCheckMenuItem *checkmenuitem, gpointer user_data);
G_MODULE_EXPORT void cb_menu_set_displaycalibdata(GtkCheckMenuItem *checkmenuitem, gpointer user_data);
//
// error handling and thread handling
G_MODULE_EXPORT gboolean errormessage_thread (gpointer data);
G_MODULE_EXPORT void errormessage_cb_btnok (GtkWidget *widget, gpointer data);
G_MODULE_EXPORT gboolean debug_thread_cb (gpointer data);
G_MODULE_EXPORT gboolean cb_thread_detect (gpointer data);
G_MODULE_EXPORT gboolean cb_thread_posctl (gpointer data);
G_MODULE_EXPORT gboolean cb_thread_output (gpointer data);
#ifdef __cplusplus
}

@ -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_

@ -210,6 +210,17 @@ int JSONParse::GetValueInt(string varname, int *dest) {
};
int JSONParse::GetValueDouble(string varname, double *dest) {
string s;
int res = GetValue(varname, &s);
if (res) {
*dest = atof (s.c_str());
return 1;
}
return 0;
};
int JSONParse::GetValueInt64(string varname, int64_t *dest) {
string s;
int res = GetValue(varname, &s);
@ -221,7 +232,7 @@ int JSONParse::GetValueInt64(string varname, int64_t *dest) {
};
int JSONParse::GetObject(string varname, JSONParse *dest) {
int JSONParse::GetObjectJson(string varname, JSONParse *dest) {
list<JSONElement>::iterator iter;
if (dest == NULL) return 0;
@ -521,4 +532,3 @@ string JSONElement::GetString () {
return output;
};

@ -54,8 +54,9 @@ public:
int GetValue(string varname, string *dest);
int GetValueInt(string varname, int *dest);
int GetValueDouble(string varname, double *dest);
int GetValueInt64(string varname, int64_t *dest);
int GetObject(string varname, JSONParse *dest);
int GetObjectJson(string varname, JSONParse *dest);
int GetIdx(string src, int idx, string *dest);
int GetValueIdx(string varname, int idx, string *dest);

@ -5,26 +5,25 @@
*****************************************************************************************/
#include <sys/time.h>
#include <execinfo.h>
#include <math.h>
#include "simpleskycam.h"
#include "config.h"
#include "configuration.h"
#include "gui.h"
#include "filter.h"
#include "output.h"
#include "detect.h"
#include "convert.h"
#include "ser.h"
#include "dng.h"
/**************************************************************************
* global variables
**************************************************************************/
GtkBuilder *_builder_ = NULL; // work around for the thread situation
Filter filter;
Output output;
Detect detect;
Configuration config;
PosCtl posctl;
int main (int argc, char **argv) {
GtkBuilder *builder;
@ -41,6 +40,7 @@ int main (int argc, char **argv) {
printf ("Command Line Options for testing purpose:\n");
printf (" -d <debugpath> destination for video debugging path\n");
printf (" -dd disable debugging path\n");
printf (" -dw show debug window\n");
printf ("\n");
printf (" -rd <debugpath> read video from dumpfile folder\n");
printf ("\n");
@ -52,9 +52,11 @@ int main (int argc, char **argv) {
config.debugpath = argv[i];
}
if (strcmp (argv[i], "-dd") == 0) {
i++;
config.debugpath = NULL;
}
if (strcmp (argv[i], "-dw") == 0) {
config.show_debugwin = 1;
}
if (strcmp (argv[i], "-rd") == 0) {
i++;
config.readdumppath = argv[i];
@ -91,38 +93,14 @@ float get_cycletime(struct timeval *t) {
}
/*
* 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);
//
// 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]);
}
exit (-1);
void calc_vec2anglelen(position_f_2d *p, vector_2d *v) {
if (v == NULL || p == NULL) return;
v->a = atan2(p->x, p->y) * 180.0 / M_PI;
while (v->a < 0.0) v->a += 360.0;
v->l = hypot(p->x, p->y);
}

@ -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
}
}

@ -1,44 +1,48 @@
/***************************************************************************************
*
* filter.h is part of SimpleSkyCam.
* output.h is part of SimpleSkyCam.
*
*****************************************************************************************/
#ifndef _FILTER_H_
#define _FILTER_H_
#ifndef _OUTPUT_H_
#define _OUTPUT_H_
#include "gui.h"
#include "config.h"
#include "video.h"
#include "videoframe.h"
#include "ser.h"
class Filter {
#define OUTPUT_MODE_SER_STARTED 0x0001
class Output {
private:
int running;
VideoFrame inFrame; // input frame
VideoFrameRaw inFrame; // input frame
int inFrameNew; // new input frame;
FloatImage image; // detected image
VideoFrame imagegtk; // output image -- send to gtk
GMutex muteximage;
GMutex mutexin;
GMutex mutextmp; // for access the temp image
GMutex mutex; // general mutex for changing settings
GThread *thread;
float *fpixels; //
int newimage;
unsigned int mode; // see OUTPUT_MODE_ flags
std::string outputfilename; // current output
void ComposeOutput();
void NotifyGTK ();
SER *outputser;
int outputserw; // to detect if the size
int outputserh; // changes white recording
uint32_t outputserfmt; //
public:
Filter();
~Filter();
Output();
~Output();
int NewFrame (VideoFrameRaw *rawframe);
int NewFrame (VideoFrame *newframe, int posx, int posy);
void NewImage ();
//
// Thread Releated Functions (maybe soon private?)
int TryLockInMutex() { return g_mutex_trylock(&mutexin); };
void LockInMutex() { g_mutex_lock(&mutexin);};
@ -51,13 +55,17 @@ public:
void LockMutex() { g_mutex_lock(&mutex);};
void UnLockMutex() { g_mutex_unlock(&mutex);};
//
// Object functions
void SetObjectSize (int neww, int newh);
void SetObject (VideoFrame objFrame, int newx, int newy);
void GetObjectPos (int *x, int *y);
void SERStart(std::string destpath, std::string sufix);
void SERStop();
int GetStatus() { return mode; };
void Thread();
};

147
pid.cc

@ -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 (&current_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>

30
pid.h

@ -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

File diff suppressed because it is too large Load Diff

@ -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>

@ -12,6 +12,39 @@
#include <time.h>
#include <sys/time.h>
#include "ser.h"
#include "videodev.h"
/*
* Convert v4l2 pixelformat to the corresponding ser format.
* Also return depth per channel.
*/
int ser_convert_type_to_ser (int v4l2_fmt, int *pixeldepth, int *serformat) {
if (pixeldepth == NULL || serformat == NULL) return 0;
switch (v4l2_fmt) {
case (V4L2_PIX_FMT_RGB24):
*serformat = SER_COLORID_RGB;
*pixeldepth = 8;
break;
case (V4L2_PIX_FMT_BGR24):
*serformat = SER_COLORID_BGR;
*pixeldepth = 8;
break;
case (V4L2_PIX_FMT_SGRBG8):
*serformat = SER_COLORID_BAYER_GRBG;
*pixeldepth = 8;
break;
case (V4L2_PIX_FMT_SGRBG16):
*serformat = SER_COLORID_BAYER_GRBG;
*pixeldepth = 16;
break;
default: return 0;
}
return 1;
}
SER::SER() {
/* clear header */
@ -21,7 +54,7 @@ SER::SER() {
memcpy(header.FileID, "LUCAM-RECORDER", strlen("LUCAM-RECORDER"));
header.LuID = 0;
header.ColorID = SER_COLORID_RGB;
header.LittleEndian = 1;
header.LittleEndian = 0; // opposite meaning of the specification
header.ImageWidth = 0;
header.ImageHeight = 0;
header.PixelDepthPerPlane = 8;
@ -51,7 +84,7 @@ SER::~SER() {
if(!Reading) {
int err;
long offset = (long)&header.FrameCount - (long)&header;
int64_t offset = (int64_t)&header.FrameCount - (int64_t)&header;
header.FrameCount = FramePointer;
/* goto file beginning */
@ -187,8 +220,8 @@ int SER::writeHeader(void) {
}
/* allocate some memory for the upcoming timestamps */
if((TimeStamps = (int64_t *)malloc(sizeof(header.DateTime) * NumberOfTimeStamps)) == NULL) {
fprintf(stderr, "Error: failed to allocate %lu bytes for timestamps\n",
sizeof(header.DateTime) * (long)NumberOfTimeStamps);
fprintf(stderr, "Error: failed to allocate %llu bytes for timestamps\n",
(long long unsigned int) sizeof(header.DateTime) * (long)NumberOfTimeStamps);
return -1;
}
@ -243,10 +276,11 @@ int SER::appendFrame(void *data) {
/* ensure we have enough memory allocated for timestamps */
if(FramePointer >= NumberOfTimeStamps) {
while(FramePointer >= NumberOfTimeStamps)
NumberOfTimeStamps *= 2;
if((TimeStamps = (int64_t *)realloc(TimeStamps, sizeof(header.DateTime) * NumberOfTimeStamps)) == NULL) {
fprintf(stderr, "Error: failed to re-allocate %lu bytes for timestamps\n",
sizeof(header.DateTime) * (long)NumberOfTimeStamps);
fprintf(stderr, "Error: failed to re-allocate %llu bytes for timestamps\n",
(long long unsigned int) sizeof(header.DateTime) * (long)NumberOfTimeStamps);
return -1;
}
}
@ -483,7 +517,7 @@ int64_t SER::differenceLocalUTC(void) {
/* Unfortunately, GMT still has summer time. Get rid of it:*/
if (gmt_time_info.tm_isdst == 1) gmt_ts -= 3600;
fprintf(stdout, "Debug: difference between local time and UTC is %ld hours\n",
(loc_ts - gmt_ts) / 3600);
fprintf(stdout, "Debug: difference between local time and UTC is %lld hours\n",
(long long int)(loc_ts - gmt_ts) / 3600);
return ((int64_t)loc_ts - (int64_t)gmt_ts) * 10000000L;
}

@ -38,6 +38,9 @@
*/
int ser_convert_type_to_ser (int v4l2_fmt, int *pixeldepth, int *serformat);
enum {
SER_COLORID_MONO = 0,
SER_COLORID_BAYER_RGGB = 8,

@ -2,7 +2,16 @@
#ifndef _SIMPLESKYCAM_H_
#define _SIMPLESKYCAM_H_
#include "config.h"
#include "gui.h"
#include "debug.h"
extern void errorexit(char *fmt, ...);
extern void calc_vec2anglelen(position_f_2d *p, vector_2d *v);
#define sindeg(_angle_) sin((M_PI * (_angle_) / 180.0))
#define cosdeg(_angle_) cos((M_PI * (_angle_) / 180.0))
#endif

File diff suppressed because it is too large Load Diff

@ -9,13 +9,16 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "gui.h"
#include "filter.h"
#include "output.h"
#include "detect.h"
#include "configuration.h"
#include "video.h"
#include "videodev.h"
#include "histogram.h"
#include "simpleskycam.h"
VideoDev *videodev = NULL;
GThread *videodev_thread = NULL;
@ -28,11 +31,9 @@ extern position_2d video_enterdata_pos;
extern detect_movement detectedpos_data;
extern Configuration config;
void videoctrl_grid_delete ();
void videoctrl_grid_build ();
/*
* stop video recording
*/
@ -121,10 +122,13 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data)
char txt2[255];
GdkRGBA color;
GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx"));
GtkWidget *e_y = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posy"));
GtkWidget *e_w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
GtkWidget *e_h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
static GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx"));
static GtkWidget *e_y = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posy"));
static GtkWidget *e_w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
static GtkWidget *e_h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
static GtkWidget *lbX = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "lb_input_xdelta"));
static GtkWidget *lbY = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "lb_input_ydelta"));
int x, y, w1, h1;
if (video_da == NULL) return;
@ -151,6 +155,38 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data)
g_object_unref (pixbuf);
//
// need to draw the new destination?
if (video_enterdata == VID_ENTERDATA_SETDEST) {
color.blue = 1.0;
color.red = 0.0;
color.green = 1.0;
color.alpha = 1.0;
gdk_cairo_set_source_rgba(cr, &color);
cairo_move_to(cr, S_X(video_enterdata_pos.x)-10, S_Y(video_enterdata_pos.y)-10);
cairo_line_to(cr, S_X(video_enterdata_pos.x)+10, S_Y(video_enterdata_pos.y)+10);
cairo_move_to(cr, S_X(video_enterdata_pos.x)+10, S_Y(video_enterdata_pos.y)-10);
cairo_line_to(cr, S_X(video_enterdata_pos.x)-10, S_Y(video_enterdata_pos.y)+10);
cairo_stroke(cr);
}
else if (posctl_threaddata.target_pos.x != -1 and posctl_threaddata.target_pos.y != -1) {
color.blue = 0.0;
color.red = 0.0;
color.green = 0.5;
color.alpha = 1.0;
gdk_cairo_set_source_rgba(cr, &color);
cairo_move_to(cr, S_X(posctl_threaddata.target_pos.x), S_Y(posctl_threaddata.target_pos.y)-5);
cairo_line_to(cr, S_X(posctl_threaddata.target_pos.x), S_Y(posctl_threaddata.target_pos.y)+5);
cairo_move_to(cr, S_X(posctl_threaddata.target_pos.x)-5, S_Y(posctl_threaddata.target_pos.y));
cairo_line_to(cr, S_X(posctl_threaddata.target_pos.x)+5, S_Y(posctl_threaddata.target_pos.y));
cairo_stroke(cr);
}
//
// need to draw the select new position cross
if (video_enterdata == VID_ENTERDATA_POS) {
@ -229,45 +265,50 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data)
}
// draw movement vector to screen
snprintf (txt1, 255, "%f", detectedpos_data.dx);
snprintf (txt2, 255, "%f", detectedpos_data.dy);
for (int i = 0; i < 5; i++) {
int dx, dy;
switch (i) {
case 0:
snprintf (txt1, 255, "X: %f", detectedpos_data.dx);
snprintf (txt2, 255, "Y: %f", detectedpos_data.dy);
gtk_label_set_text(GTK_LABEL(lbX), txt1);
gtk_label_set_text(GTK_LABEL(lbY), txt2);
if (config.GetCalibrationShowData()) {
// printf ("%s:%d posctl_threaddata.c : %d \t %d -> \t %d \t %d\n", __FILE__, __LINE__,
// posctl_threaddata.c[0].x, posctl_threaddata.c[0].y,
// posctl_threaddata.c[1].x, posctl_threaddata.c[1].y);
// printf ("%s:%d posctl_threaddata.a1: %d \t %d -> \t %d \t %d\n", __FILE__, __LINE__,
// posctl_threaddata.a1[0].x, posctl_threaddata.a1[0].y,
// posctl_threaddata.a1[1].x, posctl_threaddata.a1[1].y);
// printf ("%s:%d posctl_threaddata.a2: %d \t %d -> \t %d \t %d\n", __FILE__, __LINE__,
// posctl_threaddata.a2[0].x, posctl_threaddata.a2[0].y,
// posctl_threaddata.a2[1].x, posctl_threaddata.a2[1].y);
if (posctl_threaddata.c[0].x != -1 && posctl_threaddata.c[0].y != -1 &&
posctl_threaddata.c[1].x != -1 && posctl_threaddata.c[1].y != -1) {
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_set_line_width(cr, 1.0);
cairo_move_to(cr, S_X(posctl_threaddata.c[0].x), S_Y(posctl_threaddata.c[0].y));
cairo_line_to(cr, S_X(posctl_threaddata.c[1].x), S_Y(posctl_threaddata.c[1].y));
cairo_stroke(cr);
}
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, txt1);
if (posctl_threaddata.a1[0].x != -1 && posctl_threaddata.a1[0].y != -1 &&
posctl_threaddata.a1[1].x != -1 && posctl_threaddata.a1[1].y != -1) {
cairo_set_source_rgb(cr, 1.0, 0.5, 1.0);
cairo_set_line_width(cr, 1.0);
cairo_move_to(cr, S_X(posctl_threaddata.a1[0].x), S_Y(posctl_threaddata.a1[0].y));
cairo_line_to(cr, S_X(posctl_threaddata.a1[1].x), S_Y(posctl_threaddata.a1[1].y));
cairo_stroke(cr);
cairo_move_to (cr, 10+dx, 30+dy);
cairo_show_text(cr, txt2);
}
if (posctl_threaddata.a2[0].x != -1 && posctl_threaddata.a2[0].y != -1 &&
posctl_threaddata.a2[1].x != -1 && posctl_threaddata.a2[1].y != -1) {
cairo_set_source_rgb(cr, 1.0, 0.5, 1.0);
cairo_set_line_width(cr, 1.0);
cairo_move_to(cr, S_X(posctl_threaddata.a2[0].x), S_Y(posctl_threaddata.a2[0].y));
cairo_line_to(cr, S_X(posctl_threaddata.a2[1].x), S_Y(posctl_threaddata.a2[1].y));
cairo_stroke(cr);
}
}
#ifdef DEBUG_ANGLES
debug_angles_draw(cr);
#endif
};
@ -295,10 +336,16 @@ void cb_video_btnrefreshlist (GtkWidget *widget, gpointer data) {
devlist.clear();
VideoDev_Dumpfile vdef1; vdef1.GetDeviceList(&devlist);
#ifdef USE_V4L2
VideoDev_V4L2 vdef2; vdef2.GetDeviceList(&devlist);
#endif
#ifdef USE_SVBONY
VideoDev_SVBCam vdef3; vdef3.GetDeviceList(&devlist);
#endif
#ifdef USE_VFW
VideoDev_VFW vdef4; vdef4.GetDeviceList(&devlist);
#endif
VideoDev_Simulation vdef5; vdef5.GetDeviceList(&devlist);
for (iter = devlist.begin(); iter != devlist.end(); iter++) {
gtk_list_store_insert_with_values(GTK_LIST_STORE(model), NULL, -1,
@ -340,11 +387,17 @@ void cb_video_btnrec (GtkWidget *widget, gpointer data) {
//
// load the selected driver
if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2;
if (driver.compare("VIDEODUMP") == 0) videodev = new VideoDev_Dumpfile;
#ifdef USE_V4L2
else if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2;
#endif
#ifdef USE_SVBONY
else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam;
#endif
else if (driver.compare("VIDEODUMP") == 0) videodev = new VideoDev_Dumpfile;
#ifdef USE_VFW
else if (driver.compare("VFW") == 0) videodev = new VideoDev_VFW;
#endif
else if (driver.compare("SIMULATION") == 0) videodev = new VideoDev_Simulation;
else videodev = new VideoDev;
std::string format = gtk_entry_get_text(GTK_ENTRY(cbfmtentry));
@ -358,7 +411,7 @@ void cb_video_btnrec (GtkWidget *widget, gpointer data) {
videodev->SetConfig(device, w, h, format, parameter, cb_thread_video);
videodev_thread = g_thread_new(driver.c_str(), videodev_threadprocess_wrapper, NULL);
// FIXME: workaround, soltuion should be: create a timer and request all controls
// FIXME: workaround, solution should be: create a timer and request all controls
};
@ -421,7 +474,7 @@ void videoctrl_grid_build () {
gtk_range_set_value(GTK_RANGE(scale),value);
gtk_widget_set_hexpand (scale,true);
gtk_scale_set_draw_value(GTK_SCALE(scale), false);
g_signal_connect (GTK_RANGE(scale), "value-changed", G_CALLBACK(cb_vidctrl_scale_change), (void*)(long int)i);
g_signal_connect (GTK_RANGE(scale), "value-changed", G_CALLBACK(cb_vidctrl_scale_change), (void*)(size_t)i);
}
else {
printf ("%s:%d control %s check not valid min[%d] < max[%d]\n", __FILE__, __LINE__, iter->c_str(), min, max);
@ -431,7 +484,7 @@ void videoctrl_grid_build () {
// entry field
GtkWidget *entry = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(entry), std::to_string(value).c_str());
g_signal_connect (entry, "activate", G_CALLBACK(cb_vidctrl_entry_change), (void*)(long int)i);
g_signal_connect (entry, "activate", G_CALLBACK(cb_vidctrl_entry_change), (void*)(size_t)i);
gtk_grid_insert_row(GTK_GRID(grid), i);
if (i == 0) {
@ -471,26 +524,30 @@ void cb_video_btnstop (GtkWidget *widget, gpointer data) {
* Access to this data must be Locked before use.
*/
gboolean cb_thread_video (gpointer data) {
GtkWidget *btnstart;
GtkWidget *btnstop;
GtkWidget *btnstart = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-rec"));
GtkWidget *btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-stop"));
VideoDevThreadData *cbdata = (VideoDevThreadData*) data;
VideoFrame *vf = NULL;
VideoFrameRaw *vfr = NULL;
// printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
if (videodev == NULL) return false;
//
// after video starts, on the first frame
// read out all controls
if (cbdata != NULL) {
vf = &cbdata->vf;
vfr = &cbdata->vfr;
if (cbdata->running == 1) {
videoctrl_grid_build();
cbdata->running = 2;
}
if (vf->w <= 0 || vf->h <= 0 || vf->data == NULL) vf = NULL;
if (vfr->w <= 0 || vfr->h <= 0 || vfr->data == NULL) vfr = NULL;
}
if (videodev == NULL) return false;
btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-stop"));
btnstart = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-rec"));
//
// create video drawarea if needed
if (video_da == NULL)
video_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "video-da"));
@ -499,6 +556,9 @@ gboolean cb_thread_video (gpointer data) {
memset (gdk_pixbuf_get_pixels(video_pixbuf), 0, 3 * gdk_pixbuf_get_height(video_pixbuf) * gdk_pixbuf_get_width(video_pixbuf));
}
//
// if cbdata not set, we have a error on the video stream
// stop recording. Else push framedata into the detect thread.
if (cbdata == NULL) {
printf ("%s:%d %s something went wrong CBData == NULL\n", __FILE__, __LINE__, __FUNCTION__);
videodev->Stop();
@ -512,6 +572,9 @@ gboolean cb_thread_video (gpointer data) {
int pix_h, pix_w;
videodev->LockMutex();
//
// check and resize video_drawarea if needed
if (video_pixbuf) {
pix_h = gdk_pixbuf_get_height(video_pixbuf);
pix_w = gdk_pixbuf_get_width(video_pixbuf);
@ -526,9 +589,14 @@ gboolean cb_thread_video (gpointer data) {
pix_w = vf->w;
pix_h = vf->h;
}
vf->ToPixbuf(video_pixbuf);
detect.NewFrame(vf);
vf->ToPixbuf(&video_pixbuf); // convert Frame to pixeldata
histogram_update(vf); // update histogram
detect.CopyNewFrame(vf, vfr); // push new data to detect object
videodev->UnLockMutex();
// redraw drawarea on screen.
gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true);
}
@ -552,7 +620,7 @@ void cb_vidctrl_scale_change (GtkRange *range, gpointer data) {
GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid"));
GtkWidget *scale = NULL;
GtkWidget *label = NULL;
int idx = (long int)data;
int64_t idx = (int64_t)data;
double value;
label = gtk_grid_get_child_at(GTK_GRID(grid), 0, idx);
@ -571,7 +639,7 @@ void cb_vidctrl_entry_change (GtkWidget *widget, gpointer data) {
GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid"));
GtkWidget *label = NULL;
GtkWidget *entry = NULL;
int idx = (long int)data;
int64_t idx = (int64_t)data;
int value;
label = gtk_grid_get_child_at(GTK_GRID(grid), 0, idx);
@ -583,6 +651,9 @@ void cb_vidctrl_entry_change (GtkWidget *widget, gpointer data) {
};
/*
*
*/
void cb_videoda_motionevent (GtkWidget *widget, GdkEvent *event, gpointer data) {
int dw, dh, sw, sh;
float sar, dar;
@ -609,6 +680,10 @@ void cb_videoda_motionevent (GtkWidget *widget, GdkEvent *event, gpointer data)
gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true);
}
#ifdef DEBUG_ANGLES
debug_angles_motionevent(event);
#endif
};
@ -616,6 +691,10 @@ void cb_videoda_btnpress (GtkWidget *widget, GdkEvent *event, gpointer data) {
int x = event->motion.x;
int y = event->motion.y;
#ifdef DEBUG_ANGLES
debug_angles_btnpress(event);
#endif
printf ("%s:%d %s %d, %d\n", __FILE__, __LINE__, __FUNCTION__, x, y);
};
@ -752,11 +831,16 @@ void cb_video_cbox_videodev (GtkWidget *widget, gpointer data) {
//
// load the selected driver
if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2;
if (driver.compare("DUMMY") == 0) videodev = new VideoDev;
#ifdef USE_V4L2
else if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2;
#endif
#ifdef USE_SVBONY
else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam;
#endif
else if (driver.compare("DUMMY") == 0) videodev = new VideoDev;
#ifdef USE_VFW
else if (driver.compare("VFW") == 0) videodev = new VideoDev_VFW;
#endif
else videodev = new VideoDev;
videodev->GetDeviceFormats(device, &lst_format);
@ -771,17 +855,46 @@ void cb_video_cbox_videodev (GtkWidget *widget, gpointer data) {
videodev->GetDeviceResolutions(device, &lst_format);
delete videodev;
videodev = NULL;
};
//
// get resolution
/*
* resize windows depending on the button which was pressed
*/
void cb_input_btnscale (GtkWidget *widget, gpointer data) {
int dw, dh, ww, wh;
float scale = 1.0;
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
if (videodev == NULL || video_da == NULL) return;
//
// get controls
// what scale button was pressed
GtkWidget *btn11 = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputscale11"));
GtkWidget *btn12 = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputscale12"));
GtkWidget *btn14 = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputscale14"));
if (widget == btn11) scale = 1.0;
if (widget == btn12) scale = 0.5;
if (widget == btn14) scale = 0.25;
//
// close device
// read our video size from gui and calculate size of gui elements
GtkWidget *win = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-input"));
gtk_window_get_size(GTK_WINDOW(win), &ww, &wh);
dh = gtk_widget_get_allocated_height(video_da);
dw = gtk_widget_get_allocated_width(video_da);
dw = ww-dw;
dh = wh-dh;
delete videodev;
videodev = NULL;
videodev->GetVideoInfo(&ww, &wh, NULL);
ww = dw + (scale * ww) + 1;
wh = dh + (scale * wh);
gtk_window_resize(GTK_WINDOW(win), ww, wh);
};

@ -11,7 +11,6 @@
#include <list>
#include <stdint.h>
#include <jpeglib.h>
#include <linux/videodev2.h>
#include <setjmp.h>
#include "json.h"

@ -16,7 +16,9 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#ifndef BUILD_WINDOWS
#include <linux/videodev2.h>
#endif
#include <list>
#include <string>
@ -30,7 +32,7 @@ class VideoDev_Dummy: public VideoDev {
private:
ConvertData cdata;
int Grab(VideoFrame *vf);
int Grab(VideoFrameRaw *vf);
int Open();
int Close();
int CaptureStart();

@ -7,20 +7,31 @@
* This is needed only for debugging.
************************************************************************************/
/* enable files > 2GB on 32 bit systems */
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
#include <dirent.h>
#include <ctype.h>
#include <fcntl.h>
#include <arpa/inet.h>
#ifdef BUILD_WINDOWS
#include <winsock2.h>
#include <io.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
#include <sys/stat.h>
#include "convert.h"
#include "configuration.h"
#include "videodev-dumpfile.h"
VideoDev_Dumpfile::VideoDev_Dumpfile() {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
filesize = 0;
filepos = 0;
fd = -1;
w = 0;
h = 0;
@ -29,6 +40,7 @@ VideoDev_Dumpfile::VideoDev_Dumpfile() {
inframe_size = 0;
inframe_maxsize = 0;
inframe_nexttime = 0;
fixedframesize = 0;
};
@ -60,16 +72,19 @@ int VideoDev_Dumpfile::GetDeviceList(std::list<std::string> *list) {
}
while ((de = readdir (dir))) {
#ifndef BUILD_WINDOWS
if (de->d_type & DT_REG) {
#endif
for (i = 0; i < 255 && de->d_name[i] != 0; i++) fname[i] = toupper(de->d_name[i]);
fname[i] = 0;
if (strstr (fname, ".VIDEODUMP") != NULL) {
device = (std::string) "VIDEODUMP " + (std::string) de->d_name;
list->push_back(device);
}
#ifndef BUILD_WINDOWS
}
#endif
}
closedir(dir);
return 1;
@ -82,17 +97,37 @@ int VideoDev_Dumpfile::GetDeviceList(std::list<std::string> *list) {
* prepare the buffer, InitMMAP and read all controls
*/
int VideoDev_Dumpfile::Open() {
std::string fname = config.readdumppath;
fname = fname + "/" + conf_device;
if (config.readdumppath == NULL) return VDEV_STATUS_ERROR;
VideoDevCtrl vctl;
uint32_t inbuf[3];
int i;
struct stat s;
std::string fname = config.readdumppath;
fname = fname + "/" + conf_device;
printf ("%s:%d %s file %s\n", __FILE__, __LINE__, __FUNCTION__, fname.c_str());
if (fd >= 0) close (fd);
fd = -1;
//
// read filesize
if (stat (fname.c_str(), &s) != 0) {
printf ("%s:%d %s could not read stat of file '%s'. Error:%s\n", __FILE__, __LINE__, __FUNCTION__,
fname.c_str(), strerror(errno));
Close();
return VDEV_STATUS_ERROR;
}
filesize = s.st_size;
#ifdef BUILD_WINDOWS
if ((fd = open(fname.c_str(), O_RDONLY | O_BINARY)) == -1) {
#else
if ((fd = open(fname.c_str(), O_RDONLY)) == -1) {
#endif
printf ("%s:%d could not open file '%s' error:%s\n", __FILE__, __LINE__, fname.c_str(), strerror(errno));
return VDEV_STATUS_ERROR;
}
@ -106,9 +141,19 @@ int VideoDev_Dumpfile::Open() {
return VDEV_STATUS_ERROR;
}
i = 0;
w = ntohl(inbuf[i++]);
h = ntohl(inbuf[i++]);
filepos = 12;
conf_width = w = ntohl(inbuf[i++]);
conf_height = h = ntohl(inbuf[i++]);
pixformat = ntohl(inbuf[i++]);
conf_format = convert_from_pixelformat (pixformat);
vidctrls.clear();
vctl.name = "FilePosition";
vctl.id = 1;
vctl.min = 0;
vctl.max = 255;
vctl.value = 0;
vidctrls.push_back(vctl);
return VDEV_STATUS_OK;
};
@ -124,6 +169,8 @@ int VideoDev_Dumpfile::Close() {
if (fd >= 0) {
close(fd);
fd = -1;
filesize = 0;
filepos = 0;
}
return VDEV_STATUS_OK;
@ -147,8 +194,7 @@ int VideoDev_Dumpfile::CaptureStart() {
// read timestamp and first header and frame
gettimeofday(&starttv, NULL);
ConvertStart(&cdata, pixformat);
pixelformat = pixformat;
ReadFrame();
return VDEV_STATUS_OK;
@ -168,9 +214,6 @@ int VideoDev_Dumpfile::CaptureStop() {
inframe_size = 0;
inframe = NULL;
}
ConvertStop(&cdata, pixformat);
return VDEV_STATUS_OK;
};
@ -180,9 +223,12 @@ int VideoDev_Dumpfile::CaptureStop() {
* 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_Dumpfile::Grab(VideoFrame *vf) {
#define SIZE_FRAMEHEADER 8
#define SIZE_DUMPHEADER 12
int VideoDev_Dumpfile::Grab(VideoFrameRaw *vf) {
struct timeval curtv;
unsigned int diff = 0;
std::list<VideoDevCtrl>::iterator ctrl;
if (fd == -1) return VDEV_STATUS_ERROR;
@ -197,17 +243,49 @@ int VideoDev_Dumpfile::Grab(VideoFrame *vf) {
usleep ((inframe_nexttime-diff)*1000);
} while (diff < inframe_nexttime);
if (diff - inframe_nexttime > 1000)
printf ("%s:%d time difference to bit. (%dms) Maybe to slow hard drive?\n",
__FILE__, __LINE__, (diff - inframe_nexttime));
// if (diff - inframe_nexttime > 1000)
// printf ("%s:%d time difference to big. (%dms) Maybe to slow hard drive?\n",
// __FILE__, __LINE__, (diff - inframe_nexttime));
LockMutex();
Convert(&cdata, vf, inframe, inframe_size, pixformat, w, h);
vf->CopyFrom(pixformat, w, h, inframe_size, inframe);
UnLockMutex();
ctrl = vidctrls.begin();
if (ctrl->value == 0) {
// fixed framesize -> calculate frames
switch (pixformat) {
case(V4L2_PIX_FMT_RGB24):
case(V4L2_PIX_FMT_BGR24):
fixedframesize = 3 * w * h;
break;
case(V4L2_PIX_FMT_RGB32):
case(V4L2_PIX_FMT_BGR32):
fixedframesize = 4 * w * h;
break;
case(V4L2_PIX_FMT_SGRBG8):
fixedframesize = 1 * w * h;
break;
case(V4L2_PIX_FMT_SGRBG16):
fixedframesize = 2 * w * h;
break;
default:
ctrl->max = 0;
ctrl->value = -1;
fixedframesize = 0;
break;
}
if (fixedframesize > 0)
ctrl->max = (filesize-SIZE_DUMPHEADER) / (fixedframesize + SIZE_FRAMEHEADER);
}
if (ctrl->value != -1) ctrl->value++;
//
// read next frame
LockMutex();
ReadFrame();
UnLockMutex();
return VDEV_STATUS_OK;
}
@ -221,11 +299,30 @@ int VideoDev_Dumpfile::ReadFrame() {
if (fd < 0) return VDEV_STATUS_ERROR;
// read header
//
// check position, if end of file restart from beginning
if (filepos == filesize) {
printf ("%s:%d end of file start with first frame\n", __FILE__, __LINE__);
std::list<VideoDevCtrl>::iterator ctrl;
ctrl = vidctrls.begin();
ctrl->value = 0;
if (lseek(fd, 12, SEEK_SET) != 12) {
printf ("%s:%d %s lseek returned: %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
Close();
}
else { // reset filepos and starttime
filepos = 12;
gettimeofday(&starttv, NULL);
}
}
//
// read frame
if (read (fd, inbuf, 4*2) != 4*2) {
printf ("%s:%d could not read frame header\n", __FILE__, __LINE__);
printf ("%s:%d could not read frame header: %s\n", __FILE__, __LINE__, strerror(errno));
Close();
}
filepos += (4*2);
inframe_size = ntohl(inbuf[0]);
inframe_nexttime = ntohl(inbuf[1]);
@ -242,14 +339,14 @@ int VideoDev_Dumpfile::ReadFrame() {
// allocate memory and read frame
if (inframe == NULL) {
Close();
printf ("%s:%d cloud not allocate enought memory\n", __FILE__, __LINE__);
printf ("%s:%d could not allocate enough memory\n", __FILE__, __LINE__);
return VDEV_CBSTATUS_ERROR;
}
if (read (fd, inframe, inframe_size) != inframe_size) {
printf ("%s:%d could not read frame\n", __FILE__, __LINE__);
printf ("%s:%d could not read frame: %s\n", __FILE__, __LINE__, strerror(errno));
Close();
}
filepos += inframe_size;
return VDEV_STATUS_OK;
}
@ -264,6 +361,41 @@ int VideoDev_Dumpfile::ReadFrame() {
* set video control identified by id
*/
int VideoDev_Dumpfile::SetDevCtrl(unsigned int id, int value) {
std::list<VideoDevCtrl>::iterator ctrl;
int framerest;
off_t newfilepos = 0;
printf ("%s:%d VideoDev_Dumpfile::SetDevCtrl Set Offset to %d id:%d fixedframesize:%d\n", __FILE__, __LINE__, value, id, fixedframesize);
struct timeval curtv;
if (id == 1) {
ctrl = vidctrls.begin();
if (value != ctrl->value && value < ctrl->max) {
filepos = SIZE_DUMPHEADER + ((off_t)value * (SIZE_FRAMEHEADER + (off_t)fixedframesize));
printf ("%s:%d filepos:%ld\n", __FILE__, __LINE__, filepos);
if ((newfilepos = lseek (fd, filepos, SEEK_SET)) < 0) {
printf ("%s:%d ******* lseek error:%s\n", __FILE__, __LINE__, strerror(errno));
}
else {
framerest = (newfilepos - SIZE_DUMPHEADER)%(SIZE_FRAMEHEADER + fixedframesize);
ctrl->value = (newfilepos - SIZE_DUMPHEADER)/(SIZE_FRAMEHEADER + fixedframesize);
if (ctrl->value != value || framerest != 0) {
printf ("%s:%d could not set file to correct position. ctrl->value:%d value:%d Framerest:%d\n", __FILE__, __LINE__, ctrl->value, value, framerest);
}
else {
//
// read first frame
ReadFrame();
gettimeofday(&curtv, NULL);
starttv.tv_sec = curtv.tv_sec - (inframe_nexttime/1000);
}
}
}
// else printf ("%s:%d could not set video position (ctrl->value:%d value:%d max:%d)\n",
// __FILE__, __LINE__, ctrl->value, value, ctrl->max);
}
return VDEV_STATUS_OK;
};

@ -10,19 +10,17 @@
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#include <sys/ioctl.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 <sys/mman.h>
// #include <linux/videodev2.h>
#include <list>
#include <string>
#include "convert.h"
#include "gui.h"
#include "videodev.h"
@ -34,13 +32,16 @@ private:
uint32_t w;
uint32_t h;
uint32_t pixformat;
off_t filesize;
off_t filepos;
struct timeval starttv;
unsigned char *inframe;
uint32_t inframe_nexttime;
int inframe_maxsize;
int inframe_size;
int fixedframesize;
int Grab(VideoFrame *vf);
int Grab(VideoFrameRaw *vf);
int Open();
int Close();
int CaptureStart();

@ -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

@ -117,7 +117,7 @@ int VideoDev_SVBCam::Open() {
Close();
return VDEV_STATUS_ERROR;
}
printf ("%s:%d %s height: %ld width: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth);
printf ("%s:%d %s MaxHeight: %ld MaxWidth: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth);
for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] != SVB_IMG_END; i++) {
printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i);
@ -162,7 +162,7 @@ int VideoDev_SVBCam::Open() {
printf("\t\tSVB_IMG_END\n");
break;
default:
printf ("\t\tunbekannt\n");
printf ("\t\tunknown\n");
break;
}
}
@ -178,10 +178,12 @@ int VideoDev_SVBCam::Open() {
print_error(err);
return VDEV_STATUS_ERROR;
}
printf ("%s:%d %s Got Control idx: %d name:%s desc:%s [%ld - %ld]\n", __FILE__, __LINE__, __FUNCTION__,
i, camcontrols[i].Name, camcontrols[i].Description, (long)camcontrols[i].MinValue, (long)camcontrols[i].MaxValue);
printf ("%s:%d %s Control-%02d name:%s desc:%s [%ld:%ld-%ld] auto:%ld write:%ld type:%d\n", __FILE__, __LINE__, __FUNCTION__,
i, camcontrols[i].Name, camcontrols[i].Description,
(long)camcontrols[i].DefaultValue, (long)camcontrols[i].MinValue, (long)camcontrols[i].MaxValue,
(long)camcontrols[i].IsAutoSupported, (long)camcontrols[i].IsWritable, (unsigned int)camcontrols[i].ControlType);
vctl.name = (char*)camcontrols[i].Name;
vctl.id = i;
vctl.id = camcontrols[i].ControlType;
vctl.min = camcontrols[i].MinValue;
vctl.max = camcontrols[i].MaxValue;
GetDevCtrl(i, &vctl.value);
@ -203,21 +205,33 @@ int VideoDev_SVBCam::Open() {
inframe_pixfmt = convert_to_pixelformat(conf_format);
switch (inframe_pixfmt) {
case (V4L2_PIX_FMT_RGB32):
case (V4L2_PIX_FMT_SGRBG16):
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RAW16)) != SVB_SUCCESS) {
print_error(err);
return VDEV_STATUS_ERROR;
}
break;
case (V4L2_PIX_FMT_SGRBG8):
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RAW8)) != SVB_SUCCESS) {
print_error(err);
return VDEV_STATUS_ERROR;
}
break;
case (V4L2_PIX_FMT_BGR32):
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB32)) != SVB_SUCCESS) {
print_error(err);
return VDEV_STATUS_ERROR;
}
break;
case (V4L2_PIX_FMT_RGB24):
case (V4L2_PIX_FMT_BGR24):
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) {
print_error(err);
return VDEV_STATUS_ERROR;
}
break;
default:
conf_format = convert_from_pixelformat(V4L2_PIX_FMT_RGB24);
inframe_pixfmt = V4L2_PIX_FMT_RGB24;
conf_format = convert_from_pixelformat(V4L2_PIX_FMT_BGR24);
inframe_pixfmt = V4L2_PIX_FMT_BGR24;
if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) {
print_error(err);
return VDEV_STATUS_ERROR;
@ -258,8 +272,8 @@ int VideoDev_SVBCam::Close() {
/*
* prepare inframe for raw picture data, will hold a video frame with 16bit per channel
* inframe size = 2*3*W*H
* prepare inframe for raw picture data, will hold a video frame with 16bit per channel or BGR32/BGR24
* inframe size = 4*W*H
* send the start capture signal to the cam
*/
int VideoDev_SVBCam::CaptureStart() {
@ -275,10 +289,12 @@ int VideoDev_SVBCam::CaptureStart() {
//
// allocate memory for frame data
if (inframe != NULL) free (inframe);
inframe_size = 6 * inframe_w * inframe_h;
inframe_size = get_bytesperpixel(inframe_pixfmt) * inframe_w * inframe_h;
inframe = (unsigned char*) malloc(inframe_size);
ConvertStart(&cdata, inframe_pixfmt);
if (inframe == NULL) {
errorexit ((char*)"%s:%d could not allocate memory for framebuffer. Error:%s\n", __FILE__, __LINE__, strerror(errno));
}
pixelformat = inframe_pixfmt;
return VDEV_STATUS_OK;
};
@ -303,8 +319,6 @@ int VideoDev_SVBCam::CaptureStop() {
inframe_size = 0;
}
ConvertStop(&cdata, inframe_pixfmt);
return VDEV_STATUS_OK;
};
@ -315,19 +329,23 @@ int VideoDev_SVBCam::CaptureStop() {
* Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read.
*/
// FIXME: SVBGetVideoData needs to be outside of Lock/UnLockMutex - using inside thread inbuffer
int VideoDev_SVBCam::Grab(VideoFrame *vf) {
int VideoDev_SVBCam::Grab(VideoFrameRaw *vfr) {
int err;
if (inframe == NULL) return VDEV_STATUS_ERROR;
if ((err = SVBGetVideoData(camid, inframe, (long)inframe_size, 50)) != SVB_SUCCESS) {
if (err != SVB_ERROR_TIMEOUT) {
print_error(err);
UnLockMutex();
// UnLockMutex(); <-- Warum?
return VDEV_STATUS_ERROR;
}
else {
return VDEV_STATUS_AGAIN;
}
}
LockMutex();
Convert(&cdata, vf, inframe, inframe_size, inframe_pixfmt, inframe_w, inframe_h);
vfr->CopyFrom(inframe_pixfmt, inframe_w, inframe_h, inframe_size, inframe);
UnLockMutex();
return VDEV_STATUS_OK;
@ -362,13 +380,53 @@ int VideoDev_SVBCam::GetDeviceFormats(string device, std::list<string> *formats)
Close();
return VDEV_STATUS_ERROR;
}
printf ("%s:%d %s height: %ld width: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth);
printf ("%s:%d %s MaxHeight:%ld MaxWidth:%ld MaxDepth:%d\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight,
camprop.MaxWidth, camprop.MaxBitDepth);
char pattern[5];
switch(camprop.BayerPattern) {
case SVB_BAYER_RG:
strcpy(pattern, "RGGB");
break;
case SVB_BAYER_BG:
strcpy(pattern, "BGGR");
break;
case SVB_BAYER_GR:
strcpy(pattern, "GRBG");
break;
case SVB_BAYER_GB:
strcpy(pattern, "GBRG");
break;
default:
strcpy(pattern, "NONE");
break;
}
printf ("%s:%d %s BayerPattern:%s Color:%d Binning: \n", __FILE__, __LINE__, __FUNCTION__, pattern, camprop.IsColorCam);
for(int i=0; i < 16 && camprop.SupportedBins[i] != 0; i++) {
printf ("%s:%d %s Binning Index:%d ", __FILE__, __LINE__, __FUNCTION__, i);
printf ("\t\t%dx%d\n", camprop.SupportedBins[i], camprop.SupportedBins[i]);
}
for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] != SVB_IMG_END; i++) {
printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i);
switch (camprop.SupportedVideoFormat[i]) {
case SVB_IMG_RAW8:
printf("\t\tSVB_IMG_RAW8\n");
switch(camprop.BayerPattern) {
case SVB_BAYER_RG:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SRGGB8));
break;
case SVB_BAYER_BG:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SBGGR8));
break;
case SVB_BAYER_GR:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG8));
break;
case SVB_BAYER_GB:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGBRG8));
break;
default:
break;
}
break;
case SVB_IMG_RAW10:
printf("\t\tSVB_IMG_RAW10\n");
@ -381,6 +439,22 @@ int VideoDev_SVBCam::GetDeviceFormats(string device, std::list<string> *formats)
break;
case SVB_IMG_RAW16:
printf("\t\tSVB_IMG_RAW16\n");
switch(camprop.BayerPattern) {
case SVB_BAYER_RG:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SRGGB16));
break;
case SVB_BAYER_BG:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SBGGR16));
break;
case SVB_BAYER_GR:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG16));
break;
case SVB_BAYER_GB:
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGBRG16));
break;
default:
break;
}
break;
case SVB_IMG_Y8:
printf("\t\tSVB_IMG_Y8\n");
@ -399,17 +473,17 @@ int VideoDev_SVBCam::GetDeviceFormats(string device, std::list<string> *formats)
break;
case SVB_IMG_RGB24:
printf("\t\tSVB_IMG_RGB24\n");
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_RGB24));
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_BGR24));
break;
case SVB_IMG_RGB32:
printf("\t\tSVB_IMG_RGB32\n");
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_RGB32));
formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_BGR32));
break;
case SVB_IMG_END:
printf("\t\tSVB_IMG_END\n");
break;
default:
printf ("\t\tunbekannt\n");
printf ("\t\tunknown\n");
break;
}
}

@ -10,17 +10,24 @@
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#ifndef BUILD_WINDOWS
#include <sys/ioctl.h>
#endif
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#ifndef BUILD_WINDOWS
#include <sys/mman.h>
#include <linux/videodev2.h>
#endif
#include <list>
#include <string>
#ifdef BUILD_WINDOWS
#include "windows.h"
#endif
#include "convert.h"
#include "gui.h"
@ -37,7 +44,7 @@ private:
ConvertData cdata;
int camid;
int Grab(VideoFrame *vf);
int Grab(VideoFrameRaw *vfr);
int Open();
int Close();
int CaptureStart();

@ -1,5 +1,8 @@
#include "convert.h"
#ifdef USE_V4L2
#include "videodev-v4l2.h"
VideoDev_V4L2::VideoDev_V4L2() {
@ -204,6 +207,8 @@ int VideoDev_V4L2::Open() {
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) {
fprintf (stderr, "%s:%d VIDIOC_S_FMT : %s\n", __FILE__, __LINE__, strerror (errno));
close (fd);
fd = -1;
return VDEV_STATUS_ERROR;
}
@ -258,8 +263,7 @@ int VideoDev_V4L2::InitMMap() {
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufreq)) {
if (EINVAL == errno) {
printf("%s does not support "
"memory mappingn", conf_device.c_str());
printf("%s does not support memory mapping", conf_device.c_str());
return VDEV_STATUS_ERROR;
} else {
printf ("%s:%d %s Error %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
@ -390,7 +394,7 @@ int VideoDev_V4L2::CaptureStart() {
return VDEV_STATUS_ERROR;
}
ConvertStart(&cdata, fmt.fmt.pix.pixelformat);
pixelformat = fmt.fmt.pix.pixelformat;
return VDEV_STATUS_OK;
};
@ -400,8 +404,6 @@ int VideoDev_V4L2::CaptureStop() {
enum v4l2_buf_type type;
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
ConvertStop(&cdata, fmt.fmt.pix.pixelformat);
switch (io) {
case IOMODE_READ:
/* Nothing to do. */
@ -422,11 +424,11 @@ int VideoDev_V4L2::CaptureStop() {
/*
* 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.
* To reduce the time of malloc/free reuse the destination buffer.
*/
int VideoDev_V4L2::Grab(VideoFrame *vf) {
int VideoDev_V4L2::Grab(VideoFrameRaw *vf) {
struct v4l2_buffer buf;
int len;
@ -446,7 +448,7 @@ int VideoDev_V4L2::Grab(VideoFrame *vf) {
}
else {
LockMutex();
Convert(&cdata, vf, inbuffer[0].data, len, fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
UnLockMutex();
}
break;
@ -464,6 +466,8 @@ int VideoDev_V4L2::Grab(VideoFrame *vf) {
case EIO:
printf ( "%s:%d error on VIDIOC_DQBUF EIO %s\n", __FILE__, __LINE__, strerror(errno));
return VDEV_STATUS_ERROR;
default:
printf ( "%s:%d error on VIDIOC_DQBUF %s\n", __FILE__, __LINE__, strerror(errno));
return VDEV_STATUS_ERROR;
@ -472,7 +476,7 @@ int VideoDev_V4L2::Grab(VideoFrame *vf) {
if (buf.index >= 0 && buf.index < VDEV_INBUFFERS) {
LockMutex();
Convert(&cdata, vf, inbuffer[buf.index].data, buf.bytesused, fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
vf->CopyFrom(fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height, buf.bytesused, inbuffer[buf.index].data);
UnLockMutex();
}
@ -574,3 +578,4 @@ int VideoDev_V4L2::GetDevCtrl(unsigned int id, int *value) {
};
#endif

@ -46,9 +46,7 @@ private:
struct v4l2_crop crop;
struct v4l2_format fmt;
ConvertData cdata;
int Grab(VideoFrame *vf);
int Grab(VideoFrameRaw *vf);
int Open();
int Close();
int CaptureStart();

@ -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

@ -9,24 +9,25 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <jpeglib.h>
#include <list>
#include <string>
#include <setjmp.h>
#include "simpleskycam.h"
#include "gui.h"
#include "video.h"
#include "videoframe.h"
#include "videodev.h"
#include "convert.h"
VideoDev::VideoDev() {
@ -39,6 +40,7 @@ VideoDev::VideoDev() {
conf_width = 600;
running = 0;
callback = NULL;
pixelformat = 0x0;
g_mutex_init (&mutex);
};
@ -139,6 +141,7 @@ void VideoDev::SetConfig(std::string dev, int w, int h, std::string format, std:
#define CYCLETIME 0.050
void VideoDev::ThreadProcess() {
struct timeval cycle_timestamp;
int numframes = 0;
int lastsec = 0;
float cycle_time = 0.0;
float cycle_wait = 0.0;
@ -163,16 +166,21 @@ void VideoDev::ThreadProcess() {
running = 0;
}
if (running) {
ConvertStart(&cdata, pixelformat);
}
threaddata.running = 1; // prevent reading all controlls every time.
// will be set to 2 in callback function, after the first frame
// is read and all controls a loaded.
if (callback) gdk_threads_add_idle(callback, &threaddata);
while (running) {
i = Grab(&threaddata.vf);
i = Grab(&threaddata.vfr);
Convert(&cdata, &threaddata.vf, threaddata.vfr.data, threaddata.vfr.size, threaddata.vfr.pixfmt, threaddata.vfr.w, threaddata.vfr.h);
switch (i) {
case VDEV_STATUS_OK:
numframes++;
if (callback) gdk_threads_add_idle(callback, &threaddata);
break;
@ -183,13 +191,15 @@ void VideoDev::ThreadProcess() {
running = 0;
break;
}
//
// keep 25fps, write every second a message
cycle_time = get_cycletime(&cycle_timestamp);
cycle_wait = (CYCLETIME - cycle_time) + cycle_wait;
if (lastsec != cycle_timestamp.tv_sec) {
printf ("%s:%d %s cycle_time:%f Freq:%f Hz \r", __FILE__, __LINE__, __FUNCTION__, cycle_time, (1.0/cycle_time));
printf ("%s:%d %s Loop: cycle_time:%f Freq:%f Hz Frames:%d \n", __FILE__, __LINE__, __FUNCTION__, cycle_time, (1.0/cycle_time), numframes);
lastsec = cycle_timestamp.tv_sec;
numframes = 0;
}
if (cycle_wait > 0.0 && cycle_wait < 1.0 ) usleep ((int)(cycle_wait * 1000000.0));
}
@ -197,6 +207,7 @@ void VideoDev::ThreadProcess() {
//
// stop capturing
if (callback) gdk_threads_add_idle(callback, NULL);
ConvertStop(&cdata, pixelformat);
CaptureStop();
Close();
@ -214,9 +225,9 @@ void VideoDev::Stop() {
void VideoDev::GetVideoInfo(int *w, int *h, std::string *format) {
*format = conf_format;
*w = conf_width;
*h = conf_height;
if (format != NULL) *format = conf_format;
if (w != NULL) *w = conf_width;
if (h != NULL) *h = conf_height;
}
@ -225,3 +236,29 @@ list<VideoDevCtrl> VideoDev::GetCtrlsMinMaxValue() {
};
int VideoDev::get_bytesperpixel (uint32_t pixfmt) {
int bytesperpixel = 4;
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:
errorexit((char*)"%s:%d unsupported pixelformat %s\n", convert_from_pixelformat(pixfmt).c_str());
break;
}
return bytesperpixel;
}

@ -10,6 +10,7 @@
#include <string>
#include <list>
#include "simpleskycam.h"
#include "json.h"
#include "gui.h"
#include "config.h"
@ -65,6 +66,7 @@ struct {
struct {
int running;
VideoFrame vf;
VideoFrameRaw vfr;
} typedef VideoDevThreadData;
#ifndef CLEAR
@ -84,13 +86,14 @@ private:
std::string conf_devicename; // human friendly name of the device
std::string conf_format; // video or image format (should every device have)
std::string conf_parameter; // can hold additional parameters
uint32_t pixelformat; // pixelformat
int conf_height;
int conf_width;
int running; // 0 ... not running
// 1 ... initialized (init, first frame)
// 2 ... running
ConvertData cdata;
GMutex mutex;
gboolean (*callback)(gpointer data);
@ -100,7 +103,7 @@ private:
std::list<VideoDevCtrl> vidctrls;
/* grabs a single frame, writes the RGB24 converted frame to the VideoFrame pointer */
virtual int Grab(VideoFrame *vf) { return VDEV_STATUS_AGAIN; };
virtual int Grab(VideoFrameRaw *vf) { return VDEV_STATUS_AGAIN; };
/* opens the device, will need to fill the controls as well */
virtual int Open() { return VDEV_STATUS_OK; };
@ -121,14 +124,20 @@ private:
virtual int GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; };
friend class VideoDev_Dumpfile;
friend class VideoDev_Simulation;
friend class VideoDev_V4L2;
#ifdef USE_SVBONY
friend class VideoDev_SVBCam;
#endif
#ifdef USE_VFW
friend class VideoDev_VFW;
#endif
public:
VideoDev();
virtual ~VideoDev();
static int get_bytesperpixel (uint32_t pixfmt);
void SetConfig(std::string dev, int w, int h, std::string format, std::string parameter, gboolean (*callback_func)(gpointer data));
void ThreadProcess();
void Stop();
@ -154,10 +163,17 @@ public:
};
#include "videodev-v4l2.h"
#include "videodev-dumpfile.h"
#include "videodev-simulation.h"
#ifdef USE_V4L2
#include "videodev-v4l2.h"
#endif
#ifdef USE_SVBONY
#include "videodev-svbcam.h"
#endif
#ifdef USE_VFW
#include "videodev-vfw.h"
#endif
#endif

@ -1,11 +1,101 @@
#include <errno.h>
#include <string.h>
#include "video.h"
#include "config.h"
#include "gui.h"
#include "error.h"
#include "convert.h"
#include "videodev.h"
VideoFrameRaw::VideoFrameRaw() {
size = 0;
data = NULL;
w = 0;
h = 0;
pixfmt = 0x0;
}
VideoFrameRaw::~VideoFrameRaw() {
if (data != NULL) {
free (data);
data = NULL;
}
}
int VideoFrameRaw::CopyFrom(int spixfmt, int sw, int sh, int ssize, unsigned char *sdata) {
if (size != ssize) {
if (ReAlloc(ssize) != 0) {
errorexit((char*) "%s:%d %s could not reallocate memory. Error:%s\n",
__FILE__, __LINE__, __FUNCTION__, strerror(errno));
}
}
if (data == NULL) {
errorexit((char*) "%s:%d %s invalid pointer of data. Error:%s\n",
__FILE__, __LINE__, __FUNCTION__, strerror(errno));
}
w = sw;
h = sh;
pixfmt = spixfmt;
memcpy (data, sdata, ssize);
return 1;
}
int VideoFrameRaw::CopyFrom(VideoFrameRaw *src) {
if (src == NULL) return 0;
return CopyFrom(src->pixfmt, src->w, src->h, src->size, src->data);
}
int VideoFrameRaw::CopyFrom(VideoFrame *src) {
if (src == NULL) return 0;
return CopyFrom(V4L2_PIX_FMT_RGB24, src->w, src->h, src->size, src->data);
}
#define VIDEOFRAME_DEPTH_BYTES 3
int VideoFrameRaw::ReAlloc(int newsize) {
unsigned char *newdata = NULL;
if (newsize == 0) {
free (data);
data = NULL;
size = newsize;
return 0;
}
if (data == NULL) {
if ((data = (unsigned char*) malloc (newsize)) == NULL) return -1;
}
else if (size < newsize || size > newsize) {
if ((newdata = (unsigned char*) realloc (data, newsize)) == NULL) {
free (data);
data = NULL;
size = 0;
return -1;
}
data = newdata;
}
size = newsize;
return 0;
}
int VideoFrameRaw::RectCopyFrom(VideoFrameRaw *src, int rectx, int recty, int rectw, int recth) {
int res = 0;
pixfmt = src->pixfmt;
res = PixCopy (src->data, src->pixfmt, src->w, src->h,
&data, &size, &w, &h,
rectx, recty, rectw, recth);
return res;
}
#define VIDEOFRAME_DEPTH_BYTES 3
VideoFrame::VideoFrame() {
data = NULL;
w = 0;
@ -105,28 +195,33 @@ void VideoFrame::CopyTo(FloatImage *dest) {
}
void VideoFrame::ToPixbuf(GdkPixbuf* dest) {
int destw, desth;
void VideoFrame::ToPixbuf(GdkPixbuf** dest) {
int destw, desth, bytelen;
unsigned char *destpixel;
if (dest == NULL) return;
desth = gdk_pixbuf_get_height(dest);
destw = gdk_pixbuf_get_width(dest);
destpixel = gdk_pixbuf_get_pixels(dest);
desth = gdk_pixbuf_get_height(*dest);
destw = gdk_pixbuf_get_width(*dest);
if (destw * desth < h * w) {
destw = w;
desth = h;
// check if the memory allocation way ok.
if (destw != w || desth != h) {
g_object_unref (*dest);
*dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, w, h);
}
memcpy (destpixel, data, 3*destw*desth);
// copy data
destpixel = gdk_pixbuf_get_pixels(*dest);
bytelen = gdk_pixbuf_get_byte_length(*dest);
if (bytelen < h * w * 3) {
printf ("******* Error: %s:%d bytelen (set to:%d) is not %d\n", __FILE__, __LINE__, bytelen, (h * w * 3));
printf ("******* please inform the maintainer of this project.\n");
printf ("******* this should not have happened at all.\n");
exit (-1);
}
memcpy (destpixel, data, 3*w*h);
}
FloatImage::FloatImage() {

@ -21,9 +21,13 @@ public:
void SetW(int nw) { SetSize(nw, h); };
void SetH(int nh) { SetSize(w, nh); };
void CopyFrom(FloatImage *source);
void Delete() { w = 0; h = 0; };
};
/*
* contains RGB data
*/
class VideoFrame {
private:
public:
@ -43,7 +47,27 @@ public:
void CopyFrom(VideoFrame *source);
void CopyFrom(FloatImage *source);
void CopyTo(FloatImage *dest);
void ToPixbuf(GdkPixbuf* dest);
void ToPixbuf(GdkPixbuf** dest);
void Delete() { w = 0; h = 0; };
};
class VideoFrameRaw {
private:
public:
unsigned char *data;
int size;
int w;
int h;
uint32_t pixfmt;
VideoFrameRaw();
~VideoFrameRaw();
int ReAlloc(int newsize);
int CopyFrom(VideoFrame *src);
int CopyFrom(VideoFrameRaw *src);
int CopyFrom(int spixfmt, int sw, int sh, int ssize, unsigned char *sdata);
int RectCopyFrom(VideoFrameRaw *src, int rectx, int recty, int rectw, int recth);
void Delete() { w = 0; h = 0; pixfmt = 0;};
};

@ -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…
Cancel
Save