working on running version

main
Steffen Pohle 3 months ago
parent 3171c860a5
commit 5682fcd9b8

@ -0,0 +1,64 @@
# .SILENT:
DEPENDFILE=.depend
VERSION=0.1
PREFIX=/usr/local
DATAPREFIX=/var/lib
RUNPID=/var/run/miniwebcam.pid
ETCPREFIX=/etc
DEFAULT_SERVERPORT=20010
CXX=g++
CXXFLAGS= -ggdb -fPIC -Wall -std=c++11 -I/usr/local/include
LDFLAGS= -lUDPTCPNetwork -L/usr/local/lib -ljpeg
OBJFILES= webserver.o configuration.o main.o video.o convert.o debayer.o
all: dep miniwebcam
miniwebcam: dep $(OBJFILES)
$(CXX) $(OBJFILES) -o $@ -L./ -I./ $(LDFLAGS)
install: miniwebcam
cp -rf miniwebcam $(PREFIX)/bin
uninstall:
rm -rf $(PREFIX)/bin/miniwebcam
config:
echo "#ifndef _CONFIG_H_" > config.h
echo "#define _CONFIG_H_" >> config.h
echo "" >> config.h
echo "#define VERSION \"$(VERSION)\"" >> config.h
echo "" >> config.h
echo "#define PREFIX \"$(PREFIX)\"" >> config.h
echo "#define RUNPID \"$(RUNPID)\"" >> config.h
echo "#define ETCPREFIX \"$(ETCPREFIX)\"" >> config.h
echo "" >> config.h
echo "#define DEFAULT_SERVERPORT \""$(DEFUALT_SERVERPORT)"\"" >> config.h
echo "" >> config.h
echo "#endif" >> config.h
echo "" >> config.h
rebuild: clean all
dep:
$(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE)
clean:
rm *.s -rf
rm *.o -rf
rm *.oo -rf
rm *~ -rf
rm -rf .depend
rm -rf *.so
rm -rf *.so.*
rm -rf miniwebcam
rm -rf config.h
rm -rf Makefile.rules
cleanall: clean
source: cleanall
-include $(DEPENDFILE)

@ -5,9 +5,8 @@
#include <string.h> #include <string.h>
#include <string> #include <string>
#include "configuration.h"
#include "miniwebcam.h" #include "miniwebcam.h"
#include "json.h" #include "configuration.h"
Configuration config; Configuration config;

@ -1,12 +1,16 @@
#ifndef _CONFIGURATION_H_ #ifndef _CONFIGURATION_H_
#define _CONFIGURATION_H_ #define _CONFIGURATION_H_
#include <UDPTCPNetwork.h>
#include <string> #include <string>
#include "config.h"
#define DEFAULT_HTTP_PORT 10080 #define DEFAULT_HTTP_PORT 10080
#define DEFAULT_HTTPS_PORT 10081 #define DEFAULT_HTTPS_PORT 10081
#define DEFAULT_CONFIG_FILE "/etc/miniwebcam.conf.json" #define DEFAULT_CONFIG_FILE "/etc/miniwebcam.conf"
#define CONF_INITFLAGS_PRINT 0x0001 #define CONF_INITFLAGS_PRINT 0x0001
#define CONF_INITFLAGS_HELP 0x0002 #define CONF_INITFLAGS_HELP 0x0002

@ -0,0 +1,423 @@
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef BUILD_WINDOWS
#include "windows.h"
#else
#include <arpa/inet.h>
#endif
#include "convert.h"
#include "video.h"
#include "configuration.h"
#include "debayer.h"
int debayer_mode = 0; // testing 0 or 1
uint32_t convert_pixelformats [] = {
V4L2_PIX_FMT_MJPEG,
V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_RGB32,
V4L2_PIX_FMT_BGR32,
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_BGR24,
V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_SGRBG16,
V4L2_PIX_FMT_SGRBG8,
0
};
/*
* helper part for converting different video types
*/
//
// jpeg: replacement for error_exit
//
METHODDEF(void) jpg_error_exit (j_common_ptr cinfo) {
jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
//
// clamp and convert2rgb is build on the sample of the v4l2 api documentation
//
inline unsigned char clamp (double x) {
int r = (int)x;
if (r < 0) return 0;
else if (r > 255) return 255;
else return r;
};
inline void convert2rgb (unsigned char Y1, unsigned char Cb, unsigned char Cr,
unsigned char *ER, unsigned char *EB, unsigned char *EG) {
int y1, pb, pr;
y1 = Y1 - 16;
pb = Cb - 128;
pr = Cr - 128;
*ER = clamp (y1 + 1.402 * pr);
*EB = clamp (y1 - 0.344 * pb - 0.714 * pr);
*EG = clamp (y1 + 1.772 * pb);
};
int ConvertStart(ConvertData *cdata, uint32_t pixelformat) {
if (cdata == NULL) return 0;
if (pixelformat == V4L2_PIX_FMT_MJPEG) {
jpeg_create_decompress(&cdata->cinfo);
}
return 1;
};
int ConvertStop(ConvertData *cdata, uint32_t pixelformat) {
if (cdata == NULL) return 0;
if (pixelformat == V4L2_PIX_FMT_MJPEG) jpeg_destroy_decompress(&cdata->cinfo);
return 1;
};
/*
* converts the video from input type to RGB24 type - 24Bit
*/
int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch) {
int xs, ys;
int xd, yd;
unsigned char r,g,b;
unsigned char cb, cr, y1;
unsigned char *ptrdst = NULL;
struct jpg_error_mgr jerr;
if (cdata == NULL) return 0;
// check if there is a destination and that the destination is large to keep
// the full image
if (dest == NULL || ptrsrc == NULL)
return 0;
dest->SetSize(srcw, srch);
ptrdst = dest->GetPixBuf();
switch (pixelformat) {
case (V4L2_PIX_FMT_RGB32):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
r = *(ptrsrc++);
g = *(ptrsrc++);
b = *(ptrsrc++);
ptrsrc++;
/* only paint the image if the source is within the destination */
if (xd < srcw) {
/* set the pixel */
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
/* if the source image is too small ignore the other places.. */
if (xd < srcw)
ptrdst += 3 * (srcw - xd);
yd++;
}
break;
case (V4L2_PIX_FMT_BGR32):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
ptrsrc++;
b = *(ptrsrc++);
g = *(ptrsrc++);
r = *(ptrsrc++);
/* only paint the image if the source is within the destination */
if (xd < srcw) {
/* set the pixel */
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
/* if the source image is too small ignore the other places.. */
if (xd < srcw)
ptrdst += 3 * (srcw - xd);
yd++;
}
break;
case (V4L2_PIX_FMT_RGB24):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
r = *(ptrsrc++);
g = *(ptrsrc++);
b = *(ptrsrc++);
/* only paint the image if the source is within the destination */
if (xd < srcw) {
/* set the pixel */
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
/* if the source image is too small ignore the other places.. */
if (xd < srcw)
ptrdst += 3 * (srcw - xd);
yd++;
}
break;
case (V4L2_PIX_FMT_BGR24):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
b = *(ptrsrc++);
g = *(ptrsrc++);
r = *(ptrsrc++);
/* only paint the image if the source is within the destination */
if (xd < srcw) {
/* set the pixel */
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
/* if the source image is too small ignore the other places.. */
if (xd < srcw)
ptrdst += 3 * (srcw - xd);
yd++;
}
break;
case (V4L2_PIX_FMT_SGRBG16):
if (debayer_mode == 0)
debayer_grbg16_simple ((uint16_t *)ptrsrc, srcw, srch, ptrdst, srcw, srch);
else
debayer_grbg16_bilinear ((uint16_t *)ptrsrc, srcw, srch, ptrdst, srcw, srch);
break;
case (V4L2_PIX_FMT_SGRBG8):
if (debayer_mode == 0)
debayer_grbg8_simple ((uint8_t *)ptrsrc, srcw, srch, ptrdst, srcw, srch);
else
debayer_grbg8_bilinear ((uint8_t *)ptrsrc, srcw, srch, ptrdst, srcw, srch);
break;
case (V4L2_PIX_FMT_UYVY):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
if (xs & 1) {
y1 = (unsigned char)*(ptrsrc + 1);
cr = (unsigned char)*(ptrsrc);
cb = (unsigned char)*(ptrsrc - 2);
}
else {
y1 = (unsigned char)*(ptrsrc + 1);
cr = (unsigned char)*(ptrsrc + 2);
cb = (unsigned char)*(ptrsrc);
}
convert2rgb (y1, cr, cb, &r, &g, &b);
ptrsrc += 2;
/* only paint the image if the source is within the destination */
if (xd < srcw) {
/* set the pixel */
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
/* if the source image is too small ignore the other places.. */
if (xd < srcw)
ptrdst += 3 * (srcw - xd);
yd++;
}
break;
case (V4L2_PIX_FMT_YUYV):
for (ys = 0, yd = 0; ys < (signed int)srch; ys++) {
if (yd < srch) {
for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) {
/* read the pixel */
if (xs & 1) {
y1 = *(ptrsrc);
cb = *(ptrsrc + 1);
cr = *(ptrsrc - 1);
}
else {
y1 = *(ptrsrc);
cb = *(ptrsrc + 3);
cr = *(ptrsrc + 1);
}
convert2rgb (y1, cr, cb, &r, &g, &b);
ptrsrc += 2;
/* only paint the image if the source is within the destination */
if (xd < srcw) {
/* set the pixel */
*(ptrdst++) = r;
*(ptrdst++) = g;
*(ptrdst++) = b;
xd++;
}
}
/* if the source image is too small ignore the other places.. */
if (xd < srcw)
ptrdst += 3 * (srcw - xd);
yd++;
}
}
break;
case (V4L2_PIX_FMT_MJPEG):
cdata->cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpg_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
// jpeg data and allocations will be destroyed via StopCapture.
printf ("%s:%d %s JPEG Error\n", __FILE__, __LINE__, __FUNCTION__);
return 0;
}
jpeg_mem_src(&cdata->cinfo, ptrsrc, srcsize);
jpeg_read_header(&cdata->cinfo, TRUE);
jpeg_start_decompress(&cdata->cinfo);
while (cdata->cinfo.output_scanline < cdata->cinfo.output_height) {
unsigned char *temp_array[] = {ptrdst + (cdata->cinfo.output_scanline) * srcw * 3};
jpeg_read_scanlines(&cdata->cinfo, temp_array, 1);
}
jpeg_finish_decompress(&cdata->cinfo);
break;
default:
printf ("%s:%d Error no default possible, need to finish\n", __FILE__, __LINE__);
exit (-1);
break;
}
return 1;
};
std::string convert_from_pixelformat (uint32_t fmt) {
char txt[5];
snprintf (txt, 5, "%c%c%c%c", ((char*)&fmt)[0], ((char*)&fmt)[1], ((char*)&fmt)[2], ((char*)&fmt)[3]);
return txt;
};
uint32_t convert_to_pixelformat(std::string s) {
uint32_t u = 0;
u = ((unsigned char) s[0]) + ((unsigned char) s[1] << 8) +
((unsigned char) s[2] << 16) + ((unsigned char) s[3] << 24);
return u;
};
/*
* copy part of an raw image
* destination must be pointer in case we need to align the size of the destination image.
* this function will also realloc needed memory if needed. (only if: givin size < needed size)
*
* crop image to event set of dimensions
*/
int PixCopy(unsigned char *srcdata, uint32_t srcpixfmt, int srcw, int srch,
unsigned char **dstdataptr, int *dstsize, int *dstw, int *dsth,
int regionx, int regiony, int regionw, int regionh) {
if (srcpixfmt == 0 || srcpixfmt == V4L2_PIX_FMT_MJPEG) return 0;
if (srcdata == NULL || dstdataptr == NULL) return 0;
// crop size to an even number
(*dsth) = regionw & ~1;
(*dstw) = regionh & ~1;
int bytesperpixel = 3;
int dsize = 0;
switch (srcpixfmt) {
case (V4L2_PIX_FMT_SGRBG8):
bytesperpixel = 1;
break;
case (V4L2_PIX_FMT_SGRBG16):
bytesperpixel = 2;
break;
case (V4L2_PIX_FMT_BGR32):
case (V4L2_PIX_FMT_RGB32):
bytesperpixel = 4;
break;
case (V4L2_PIX_FMT_BGR24):
case (V4L2_PIX_FMT_RGB24):
bytesperpixel = 3;
break;
default:
return 0;
}
//
// calculate image size and allocate memory if needed
dsize = (*dsth) * (*dstw) * bytesperpixel;
if ((*dstsize) < dsize || (*dstdataptr) == NULL) {
*dstdataptr = (unsigned char*) realloc (*dstdataptr, dsize);
if (*dstdataptr == NULL) {
errorexit((char*)"%s:%d could not realloc memory. dsize:%d error:%s\n", __FILE__, __LINE__, dsize, strerror(errno));
}
*dstsize = dsize;
printf ("%s:%d reallocate memory for destination raw image\n", __FILE__, __LINE__);
}
unsigned char *dptr, *sptr;
int y, dy, x;
// debug_drawraw(srcdata, srcpixfmt, srcw, srch);
for (y = regiony & (~1), dy = 0; dy < *dsth && y < srch; y++, dy++) {
x = regionx & (~1);
dptr = (*dstdataptr) + bytesperpixel * (dy * *dstw);
sptr = (srcdata) + bytesperpixel * ( y * srcw + x);
memcpy (dptr, sptr, *dstw * bytesperpixel);
}
return 1;
}

@ -0,0 +1,34 @@
#ifndef _CONVERT_H_
#define _CONVERT_H_
#include <list>
#include <string>
#include <stdint.h>
#include <jpeglib.h>
#include <setjmp.h>
#include "video.h"
#ifndef CLEAR
#define CLEAR(x) memset (&(x), 0, sizeof (x))
#endif
struct {
struct jpeg_decompress_struct cinfo;
} typedef ConvertData;
int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch);
int ConvertStart(ConvertData *cdata, uint32_t pixelformat);
int ConvertStop(ConvertData *cdata, uint32_t pixelformat);
int PixCopy(unsigned char *srcdata, uint32_t srcpixfmt, int srcw, int srch,
unsigned char **dstdataptr, int *dstsize, int *dstw, int *dsth,
int regionx, int regiony, int regionw, int regionh);
extern uint32_t convert_pixelformats[];
std::string convert_from_pixelformat (uint32_t fmt);
uint32_t convert_to_pixelformat(std::string s);
#endif

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

@ -1,534 +0,0 @@
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fstream>
#include <list>
#include <string>
#include "json.h"
/***********************************************************************
***********************************************************************
*
* JSONParse
*
***********************************************************************
***********************************************************************
*/
enum {
STEP_NONE = 0,
STEP_STARTNAME,
STEP_NAME,
STEP_STARTVALUE,
STEP_VALUE,
STEP_END
};
/*
* clear out all data
*/
void JSONParse::Clear() {
jsondata = "";
names.clear();
}
/*
* read every element and keep only this in memory.
*/
int JSONParse::Set(string json) {
int i;
int step;
int level;
bool ignorenext;
JSONElement jelement;
Clear();
// find start and read until end
for (step = STEP_NONE, i = 0, ignorenext = false; (unsigned int)i < json.length(); i++) {
// need to copy next character
if (ignorenext) {
ignorenext = false;
if (step == STEP_NAME) jelement.name += json[i];
if (step == STEP_VALUE) jelement.value += json[i];
}
// searching for startname
else if (step == STEP_NONE) {
if (json[i] == '{') {
step = STEP_STARTNAME;
continue;
}
}
// searching for startname
else if (step == STEP_STARTNAME) {
if (json[i] == '"') {
step = STEP_NAME;
continue;
}
}
// copy name
else if (step == STEP_NAME) {
if (json[i] == '"') {
step = STEP_STARTVALUE;
continue;
}
else {
jelement.name += json[i];
continue;
}
}
// searching for startvalue
else if (step == STEP_STARTVALUE) {
if (json[i] == '"') {
step = STEP_VALUE;
jelement.type = JSON_T_STRING;
continue;
}
if (json[i] == '{') {
step = STEP_VALUE;
level = 0;
jelement.type = JSON_T_OBJECT;
jelement.value = "{";
continue;
}
if (json[i] == '[') {
step = STEP_VALUE;
level = 0;
jelement.type = JSON_T_ARRAY;
jelement.value = "[";
continue;
}
if ((json[i] >= '0' && json[i] <= '9') ||
(json[i] == '+' || json[i] == '-')) {
step = STEP_VALUE;
level = 0;
jelement.type = JSON_T_NUMBER;
jelement.value = json[i];
continue;
}
}
// copy value
else if (step == STEP_VALUE) {
if (jelement.type == JSON_T_STRING) {
if (json[i] == '"') step = STEP_END;
else jelement.value += json[i];
continue;
}
else if (jelement.type == JSON_T_OBJECT) {
if (json[i] == '}' && level == 0) {
jelement.value += json[i];
step = STEP_END;
}
else {
if (json[i] == '{') level++; // increase level
if (json[i] == '}') level--; // decrease level
jelement.value += json[i];
}
continue;
}
else if (jelement.type == JSON_T_ARRAY) {
if (json[i] == ']' && level == 0) {
jelement.value += json[i];
step = STEP_END;
}
else {
if (json[i] == '[') level++; // increase level
if (json[i] == ']') level--; // decrease level
jelement.value += json[i];
}
continue;
}
else if (jelement.type == JSON_T_NUMBER) {
if ((json[i] < '0' || json[i] > '9') && json[i] != '.' &&
json[i] != '+' && json[i] != 'e' && json[i] != 'E') step = STEP_END;
else {
jelement.value += json[i];
continue;
}
}
}
// another element?
if (step == STEP_END) {
if (json[i] == ',') {
if (jelement.type != JSON_T_NONE) {
names.push_back (jelement);
}
jelement.Clear();
step = STEP_STARTNAME;
}
continue;
}
}
if (jelement.type != JSON_T_NONE) {
names.push_back (jelement);
}
return 0;
};
int JSONParse::GetValue(string varname, string *dest) {
list<JSONElement>::iterator iter;
if (dest == NULL) return 0;
*dest = "";
for (iter = names.begin(); iter != names.end(); iter++) {
if (varname.compare(iter->name) == 0) {
*dest = iter->value;
return 1;
}
}
return 0;
};
int JSONParse::GetValueInt(string varname, int *dest) {
string s;
int res = GetValue(varname, &s);
if (res) {
*dest = atoi (s.c_str());
return 1;
}
return 0;
};
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);
if (res) {
*dest = atol (s.c_str());
return 1;
}
return 0;
};
int JSONParse::GetObjectJson(string varname, JSONParse *dest) {
list<JSONElement>::iterator iter;
if (dest == NULL) return 0;
for (iter = names.begin(); iter != names.end(); iter++) {
if (varname.compare(iter->name) == 0) {
dest->Set(iter->value);
return 1;
}
}
return 0;
};
#define MAXRECURSIVE 255
int JSONParse::GetIdx(string src, int idx, string *dest) {
char recursive[MAXRECURSIVE];
int i = 0, rcnt = 0, cnt = 0;
(*dest) = "";
for (i = 0; i < MAXRECURSIVE; i++) recursive[i] = 0;
for (i = 0; (unsigned int) i < src.length() && rcnt < MAXRECURSIVE && cnt <= idx; i++) {
if (src[i] == '[') {
recursive[rcnt++] = src[i];
continue;
}
else if (src[i] == '{' && recursive[rcnt] != '"') recursive[++rcnt] = src[i];
else if (src[i] == '}' && recursive[rcnt] == '{') rcnt--;
else if (src[i] == '"' && recursive[rcnt] == '"') rcnt--;
else if (src[i] == '"') recursive[++rcnt] = src[i];
else if (src[i] == ',' && rcnt == 1) {
cnt++;
continue;
}
else if (src[i] == ']' && rcnt == 1) {
continue;
}
if (rcnt > 0 && cnt == idx) {
(*dest) += src[i];
if (src[i] == '\\') (*dest) += src[i];
}
else {
if (src[i] == '\\')i++;
}
}
//
// final checks
if (cnt == 0 && idx == 0 && // empty source/array?
dest->size() == 0) return 0; //
if (cnt >= idx) return 1; // found the right element
return 0; // element not found
}
#undef MAXRECURSIVE
int JSONParse::GetValueIdx(string varname, int idx, string *dest) {
list<JSONElement>::iterator iter;
if (dest == NULL) return 0;
for (iter = names.begin(); iter != names.end(); iter++) {
if (varname.compare(iter->name) == 0) {
return GetIdx(iter->value, idx, dest);
}
}
return 0;
};
int JSONParse::GetObjectIdx(string varname, int idx, JSONParse *dest) {
list<JSONElement>::iterator iter;
string deststr;
int ret = 0;
if (dest == NULL) return 0;
for (iter = names.begin(); iter != names.end(); iter++) {
if (varname.compare(iter->name) == 0) {
ret = GetIdx(iter->value, idx, &deststr);
if (ret == 1) dest->Set(deststr);
return ret;
}
}
return 0;
};
list<JSONElement> JSONParse::GetElements() {
list<JSONElement> l;
list<JSONElement>::iterator iter;
l.clear();
for (iter = names.begin(); iter != names.end(); iter++) {
l.push_back(*iter);
}
return l;
};
void JSONParse::AddObject (JSONElement element) {
names.push_back (element);
};
void JSONParse::AddObject (string name, JSONParse jp) {
JSONElement je;
je.SetObject(name, jp.ToString());
names.push_back(je);
};
void JSONParse::AddObject (string name, int val) {
JSONElement je;
je.Set(name, val);
names.push_back(je);
};
void JSONParse::AddObject (string name, int64_t val) {
JSONElement je;
je.Set(name, val);
names.push_back(je);
};
void JSONParse::AddObject (string name, string val) {
JSONElement je;
je.Set(name, val);
names.push_back(je);
};
void JSONParse::AddObject (string name, double val) {
JSONElement je;
je.Set(name, val);
names.push_back(je);
};
string JSONParse::ToString() {
list<JSONElement>::iterator iter;
string output;
int level, i;
output = "{";
for (level = 1, iter = names.begin(); iter != names.end(); iter++) {
if (iter != names.begin()) output += ",";
output += "\n";
for (i = 0; i < 4*level; i++) output += " ";
output += iter->GetString();
}
output += "\n}\n";
return output;
};
/*
* Load/Save elements to a file.
* Return Value: -1 .. on Error, errno will be set
* 0 .. on Success
*/
int JSONParse::LoadFromFile(string filename) {
int fd;
struct stat fs;
char *buffer;
if (stat(filename.c_str(), &fs) != 0) return -1;
buffer = (char *) malloc (fs.st_size+1);
memset (buffer, 0x0, fs.st_size+1);
fd = open(filename.c_str(), O_RDONLY);
if (fd < 0) return -1;
read (fd, buffer, fs.st_size);
close (fd);
Set(buffer);
free (buffer);
return 0;
};
int JSONParse::SaveToFile(string filename) {
ofstream out(filename);
if (!out) return -1;
out << ToString();
out.close();
return 0;
};
/***********************************************************************
***********************************************************************
*
* JSONElement
*
***********************************************************************
***********************************************************************
*/
void JSONElement::Set (string n, double v) {
name = n;
value = to_string(v);
type = JSON_T_NUMBER;
};
void JSONElement::Set (string n, int v) {
name = n;
value = to_string(v);
type = JSON_T_NUMBER;
};
void JSONElement::Set (string n, int64_t v) {
name = n;
value = to_string(v);
type = JSON_T_NUMBER;
};
void JSONElement::Set (string n, string v) {
name = n;
value = v;
type = JSON_T_STRING;
};
void JSONElement::SetArray (string n, list<JSONElement> *l) {
list<JSONElement>::iterator iter;
name = n;
value = "[";
type = JSON_T_STRING;
for (iter = l->begin(); iter != l->end(); iter++) {
if (iter != l->begin()) value += ",";
value += iter->GetString();
}
value += "]";
};
void JSONElement::SetObject (string n, string s) {
name = n;
value = s;
type = JSON_T_OBJECT;
};
string JSONElement::GetString () {
string output = "";
string filename = __FILE__;
switch (type) {
case(JSON_T_NUMBER):
output += "\"" + name + "\" : " + value;
break;
case(JSON_T_STRING):
if (value.length()==0) {
output += "\"" + name + "\" : \"\"";
}
else if (value[0] != '"') {
output += "\"" + name + "\" : \"" + value + "\"";
}
else output += "\"" + name + "\" : " + value;
break;
case(JSON_T_OBJECT):
output += "\"" + name + "\" : " + value;
break;
case(JSON_T_ARRAY):
if (value.length()==0) {
output += "\"" + name + "\" : []";
}
else if (value[0] != '[') {
output += "\"" + name + "\" : [" + value + "]";
}
else output += "\"" + name + "\" : " + value;
break;
default:
output += "\"error\" : \""+ filename + ":" + to_string(__LINE__) + " JSONElement unknown type error\"("+to_string(type)+")";
break;
}
return output;
};

@ -1,80 +0,0 @@
//
//
//
#ifndef _JSON_H_
#define _JSON_H_
#include <list>
#include <string>
#include <string.h>
using namespace std;
enum {
JSON_T_NONE,
JSON_T_STRING,
JSON_T_NUMBER,
JSON_T_OBJECT,
JSON_T_ARRAY
};
class JSONElement {
public:
int type;
string name;
string value;
JSONElement() { Clear(); };
~JSONElement() {};
void Clear() { type = JSON_T_NONE; name = ""; value = ""; };
void Set (string n, double v);
void Set (string n, int v);
void Set (string n, int64_t v);
void Set (string n, string v);
void SetArray (string n, list<JSONElement> *l);
void SetObject (string n, string s);
string GetString();
};
class JSONParse {
private:
string jsondata;
list<JSONElement> names;
public:
JSONParse() { Set("{}"); };
JSONParse(string json) { Set(json); };
~JSONParse() {};
void Clear();
int Set(string json);
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 GetObjectJson(string varname, JSONParse *dest);
int GetIdx(string src, int idx, string *dest);
int GetValueIdx(string varname, int idx, string *dest);
int GetObjectIdx(string varname, int idx, JSONParse *dest);
list<JSONElement> GetElements();
void AddObject (JSONElement element);
void AddObject (string name, int val);
void AddObject (string name, int64_t val);
void AddObject (string name, string val);
void AddObject (string name, double val);
void AddObject (string name, JSONParse jp);
int LoadFromFile(string filename);
int SaveToFile(string filename);
string ToString();
};
#endif // _JSON_H_

@ -10,7 +10,7 @@
void ErrorExit(std::string text, int errorcode) { void ErrorExit(std::string text, int errorcode) {
printf ("Error: %s\n", text.c_str()); printf ("Error: %s\n", text.c_str());
exit (errorcode); exit (errorcode);
} };
int main(int argc, char **argv) { int main(int argc, char **argv) {
config.LoadArgs (argc, argv); config.LoadArgs (argc, argv);
@ -26,6 +26,14 @@ int main(int argc, char **argv) {
} }
printf ("MiniWebCam:\n"); printf ("MiniWebCam:\n");
VideoFrame v;
VideoFrameFloat vf;
printf ("VideoFrame Size:\n");
v.SetSize(100,100);
printf ("VideoFrameFloat Size:\n");
vf.SetSize(100,100);
return 0; return 0;
}; };

@ -1,25 +0,0 @@
project('miniwebcam', 'cpp', default_options: [
'cpp_std=gnu++14'
])
miniwebcam_src = [
'main.cc',
'configuration.cc',
'webserver.cc',
'json.cc'
]
miniwebcam_headers = [
'configuration.h',
'miniwebcam.h',
'json.h'
]
executable('miniwebcam',
install : true,
sources: miniwebcam_src,
extra_files: miniwebcam_headers
)

@ -1,9 +1,16 @@
#ifndef _MINIWEBCAM_H_ #ifndef _MINIWEBCAM_H_
#define _MINIWEBCAM_H_ #define _MINIWEBCAM_H_
#include <UDPTCPNetwork.h>
#include <string> #include <string>
#include "configuration.h"
#include "miniwebcam.h"
#include "video.h"
void ErrorExit(std::string text, int errorcode); void ErrorExit(std::string text, int errorcode);
#endif #endif

@ -0,0 +1,108 @@
#include "miniwebcam.h"
#include "video.h"
#include <stdio.h>
#include <stdlib.h>
VideoFrame::VideoFrame() {
mem = NULL;
width = 0;
height = 0;
mem_allocated = 0;
};
VideoFrame::~VideoFrame() {
FreeFrame();
};
void VideoFrame::FreeFrame() {
if (mem != NULL) {
free (mem);
mem = NULL;
width = 0;
height = 0;
mem_allocated = 0;
}
};
void VideoFrame::AllocateFrame() {
printf ("VideoFrame::AllocateFrame()\n");
int memnewsize = width * height * 3;
if (memnewsize >= mem_allocated) return;
else if (memnewsize == 0) FreeFrame();
mem = (unsigned char *) realloc (mem, memnewsize);
mem_allocated = memnewsize;
if (mem == NULL) {
debug ("Error on allocation new frame\n");
exit (1);
}
};
int VideoFrame::SetSize(int w, int h) {
if (w < 0 && h < 0) return 0;
width = w;
height = h;
AllocateFrame();
return 1;
};
/*********************************************************************/
void VideoFrameFloat::AllocateFrame() {
printf ("VideoFrameFloat::AllocateFrame()\n");
int memnewsize = width * height * 3 * sizeof(float);
if (memnewsize >= mem_allocated) return;
else if (memnewsize == 0) FreeFrame();
mem = (unsigned char *) realloc (mem, memnewsize);
mem_allocated = memnewsize;
if (mem == NULL) {
debug ("Error on allocation new frame\n");
exit (1);
}
};
/*********************************************************************/
VideoDevice::VideoDevice() {
videofd = 0;
};
VideoDevice::~VideoDevice() {
};
int VideoDevice::SetDevice() {
return 0;
};
int VideoDevice::Start(int w, int h) {
return 0;
};
int VideoDevice::Stop() {
return 0;
};
int VideoDevice::GetFrame(VideoFrame *destframe) {
return 0;
};

@ -0,0 +1,90 @@
#ifndef _VIDEO_H_
#define _VIDEO_H_
#include <stdint.h>
#include <setjmp.h>
#include <string.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 <jpeglib.h>
enum {
IOMODE_READ,
IOMODE_MMAP
};
//
// jpeg error handling
//
struct jpg_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct jpg_error_mgr *jpg_error_ptr;
//
// only contain 24bit each color 8Bit
class VideoFrame {
private:
virtual void AllocateFrame();
protected:
void FreeFrame();
int mem_allocated;
unsigned char *mem;
int height;
int width;
public:
VideoFrame();
~VideoFrame();
int GetHeight() { return height; };
int GetWidth() { return width; };
unsigned char *GetPixBuf() { return mem; };
int SetSize(int w, int h);
};
class VideoFrameFloat : public VideoFrame {
private:
void AllocateFrame();
protected:
public:
};
class VideoDevice {
private:
int videofd;
protected:
public:
VideoDevice();
~VideoDevice();
int SetDevice();
int Start(int w, int h);
int Stop();
int GetFrame(VideoFrame *destframe);
};
#endif

@ -0,0 +1,2 @@
#include "webserver.h"

@ -0,0 +1,6 @@
#ifndef _WEBSERVER_H_
#define _WEBSERVER_H_
#include "miniwebcam.h"
#endif
Loading…
Cancel
Save