From d904fead378a43f0e92f8c11312eec6e32e2809a Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Mon, 21 Nov 2022 22:38:06 +0100 Subject: [PATCH] adding support of 16bit per channel data - highly experimental --- convert.cc | 42 ++++++++++------ detect.cc | 12 ++--- filter.cc | 2 +- video.cc | 2 +- videodev-v4l2.cc | 9 ++-- videoframe.cc | 125 ++++++++++++++++++++++++++++++++++------------- videoframe.h | 13 +++-- 7 files changed, 139 insertions(+), 66 deletions(-) diff --git a/convert.cc b/convert.cc index 18fc44a..ebc9dea 100644 --- a/convert.cc +++ b/convert.cc @@ -6,6 +6,7 @@ #include #include +#include "simpleskycam.h" #include "convert.h" #include "gui.h" #include "video.h" @@ -225,21 +226,11 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr if (dest == NULL || ptrsrc == NULL) return VDEV_STATUS_ERROR; - if (dest->data != NULL && dest->w != srcw && dest->h != srch) { - free (dest->data); - dest->data = NULL; - } - - if (dest->data == NULL) { - dest->w = srcw; - dest->h = srch; - dest->size = srcw * srch * 3; - dest->data = (unsigned char*) malloc (dest->size); - } - ptrdst = dest->data; - switch (pixelformat) { case (V4L2_PIX_FMT_RGB32): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ @@ -267,6 +258,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_BGR32): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ @@ -293,6 +287,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr } break; case (V4L2_PIX_FMT_RGB24): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ @@ -319,6 +316,10 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_BGR24): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); + for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ @@ -345,6 +346,10 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_UYVY): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); + for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ @@ -380,6 +385,10 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_YUYV): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); + for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { if (yd < dest->h) { for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { @@ -416,6 +425,10 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_MJPEG): + dest->SetSize(srcw, srch); + dest->SetPixelSize(3); // 8 bits per pixel + ptrdst = (unsigned char *)dest->GetData(); + cdata->cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpg_error_exit; if (setjmp(jerr.setjmp_buffer)) { @@ -437,8 +450,7 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; default: - printf ("%s:%d Error no default possible, need to finish\n", __FILE__, __LINE__); - exit (-1); + errorexit ((char*)"%s:%d Error no default possible, need to finish\n", __FILE__, __LINE__); break; } diff --git a/detect.cc b/detect.cc index 5fd2a86..643f025 100644 --- a/detect.cc +++ b/detect.cc @@ -180,8 +180,8 @@ void Detect::InputDetect(int *posx, int *posy) { image.SetSize (objectW, objectH); SetInputSize(inFrame.w, inFrame.h); - pxs = inFrame.data; - pxi = image.data; + pxs = (unsigned char*)inFrame.GetData(); + pxi = (unsigned char*)image.GetData(); *posx = 0; *posy = 0; @@ -258,8 +258,8 @@ void Detect::InputDetectCrossC(int *posx, int *posy) { image.SetSize (objectW, objectH); SetInputSize(inFrame.w, inFrame.h); - pxi = inFrame.data; - pxo = oldFrame.data; + pxi = (unsigned char*)inFrame.GetData(); + pxo = (unsigned char*)oldFrame.GetData(); mxx = mxy = 0; for (shifty = 0; shifty < DET_MAXSHIFT; shifty++) { @@ -316,8 +316,8 @@ void Detect::CopyObjectImage(int objx, int objy) { unsigned char *pxi; // input image unsigned char *pxd; // destination image - pxi = inFrame.data; - pxd = image.data; + pxi = (unsigned char*)inFrame.GetData(); + pxd = (unsigned char*)image.GetData(); // // copy image data to destination diff --git a/filter.cc b/filter.cc index 0b2e8d0..4915320 100644 --- a/filter.cc +++ b/filter.cc @@ -99,7 +99,7 @@ void Filter::ComposeOutput() { image.SetSize(inFrame.w, inFrame.h); pixd = image.data; - pixs = inFrame.data; + pixs = (unsigned char*)inFrame.GetData(); if (pixd == NULL || pixs == NULL) return; if (newimage) { diff --git a/video.cc b/video.cc index ba39db0..9b6512e 100644 --- a/video.cc +++ b/video.cc @@ -484,7 +484,7 @@ gboolean cb_thread_video (gpointer data) { videoctrl_grid_build(); cbdata->running = 2; } - if (vf->w <= 0 || vf->h <= 0 || vf->data == NULL) vf = NULL; + if (vf->w <= 0 || vf->h <= 0) vf = NULL; } if (videodev == NULL) return false; diff --git a/videodev-v4l2.cc b/videodev-v4l2.cc index ff7b4ee..f770f17 100644 --- a/videodev-v4l2.cc +++ b/videodev-v4l2.cc @@ -1,4 +1,5 @@ +#include "simpleskycam.h" #include "convert.h" #include "videodev-v4l2.h" @@ -280,15 +281,14 @@ int VideoDev_V4L2::InitMMap() { if(ioctl(fd, VIDIOC_QUERYBUF, &bufinfo) < 0){ perror("VIDIOC_QUERYBUF"); - exit(1); + errorexit((char*)"%s:%d\n", __FILE__, __LINE__); } inbuffer[i].size = bufinfo.length; inbuffer[i].data = (unsigned char*)mmap(NULL, bufinfo.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bufinfo.m.offset); if (inbuffer[i].data == MAP_FAILED) { - printf ( "%s:%d error on mmap %s\n", __FILE__, __LINE__, strerror(errno)); - exit (1); + errorexit ((char*)"%s:%d error on mmap %s\n", __FILE__, __LINE__, strerror(errno)); } } return VDEV_STATUS_OK; @@ -327,8 +327,7 @@ int VideoDev_V4L2::UnInit() { for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) if (inbuffer[inbuffer_idx].data) { if (-1 == munmap(inbuffer[inbuffer_idx].data, inbuffer[inbuffer_idx].size)){ - fprintf(stderr, "Fatal Error @ %s:%d munmap Error:%s\n", __FILE__, __LINE__, strerror(errno)); - exit(1); + errorexit((char*)"Fatal Error @ %s:%d munmap Error:%s\n", __FILE__, __LINE__, strerror(errno)); } inbuffer[inbuffer_idx].data = NULL; inbuffer[inbuffer_idx].size = 0; diff --git a/videoframe.cc b/videoframe.cc index 26fc97e..3f0d4a2 100644 --- a/videoframe.cc +++ b/videoframe.cc @@ -3,14 +3,14 @@ #include "video.h" #include "config.h" #include "gui.h" - -#define VIDEOFRAME_DEPTH_BYTES 3 +#include "simpleskycam.h" VideoFrame::VideoFrame() { data = NULL; w = 0; h = 0; size = 0; + pixelsize = 3; }; @@ -28,8 +28,8 @@ VideoFrame::~VideoFrame() { // // we will only allocate a new image if the needed size increases -void VideoFrame::SetSize(int nw, int nh) { - uint32_t newsize = VIDEOFRAME_DEPTH_BYTES * nh * nw; +void VideoFrame::SetMemorySize(int nw, int nh, int nps) { + uint32_t newsize = nps * nh * nw; if (newsize > size || data == NULL) { unsigned char *newdata = (unsigned char *) malloc (newsize); @@ -39,12 +39,14 @@ void VideoFrame::SetSize(int nw, int nh) { } w = nw; h = nh; + pixelsize = nps; }; VideoFrame VideoFrame::operator=(VideoFrame rightside) { w = rightside.w; h = rightside.h; + pixelsize = rightside.pixelsize; size = rightside.size; if (size > 0) data = (unsigned char *) malloc (rightside.size); if (rightside.data != NULL && size > 0) { @@ -55,16 +57,20 @@ VideoFrame VideoFrame::operator=(VideoFrame rightside) { void VideoFrame::CopyFrom(VideoFrame *source) { + SetPixelSize(source->pixelsize); SetSize (source->w, source->h); - memcpy(data, source->data, VIDEOFRAME_DEPTH_BYTES * w * h); + memcpy(data, source->data, pixelsize * w * h); } +/* + * will copy the FloatImage to VideoFrame + * with respect of the bits per pixel (3 or 6). + */ void VideoFrame::CopyFrom(FloatImage *source) { float min, max, f; int x, y, i, idx; - unsigned char v; SetSize (source->w, source->h); @@ -78,30 +84,67 @@ void VideoFrame::CopyFrom(FloatImage *source) { if (max < source->data[idx+i]) max = source->data[idx+i]; } - for (y = 0; y < h; y++) for (x = 0; x < w; x++) - for (i = 0; i < 3; i++) { - idx = 3 * (y * w + x); - f = (float)(255.0 * (source->data[idx+i]-min) / (max-min)); - if (f < 0.0) v = 0; - else if (f > 255.0) v = 255; - else v = f; - data[idx+i] = v; - } + // + // 3 bytes per pixel (each channel ^ 1 byte) + if (pixelsize == 3) { + unsigned char v; + + for (y = 0; y < h; y++) for (x = 0; x < w; x++) + for (i = 0; i < 3; i++) { + idx = pixelsize * (y * w + x); + f = (float)(255.0 * (source->data[idx+i]-min) / (max-min)); + if (f < 0.0) v = 0; + else if (f > 255.0) v = 255; + else v = f; + data[idx+i] = v; + } + } + // + // 6 bytes per pixel (each channel ^ 2 byte) + else if (pixelsize == 6) { + uint16_t v; + int max = (2^16)-1; + + for (y = 0; y < h; y++) for (x = 0; x < w; x++) + for (i = 0; i < 3; i++) { + idx = pixelsize * (y * w + x); + f = (float)(double(max) * (source->data[idx+i]-min) / (max-min)); + if (f < 0.0) v = 0; + else if (f > double(max)) v = max; + else v = f; + memcpy(data+(idx+2*i), &v, 2); + } + } + else { + errorexit((char*)"Pixelsize not known or implemented. pixelsize should be 3 or 6, current value is:%d\n", pixelsize); + } } void VideoFrame::CopyTo(FloatImage *dest) { int x, y, i, idx; - if (dest == NULL) return; - dest->SetSize (w, h); - for (y = 0; y < h; y++) for (x = 0; x < w; x++) - for (i = 0; i < 3; i++) { - idx = 3 * (y * w + x); - dest->data[idx+i] = data[idx+i]; - } + + if (pixelsize == 3) { + for (y = 0; y < h; y++) for (x = 0; x < w; x++) + for (i = 0; i < 3; i++) { + idx = 3 * (y * w + x); + dest->data[idx+i] = data[idx+i]; + } + } + else if (pixelsize == 6) { + uint16_t *sdata = (uint16_t*)data; + for (y = 0; y < h; y++) for (x = 0; x < w; x++) + for (i = 0; i < 3; i++) { + idx = 3 * (y * w + x); + dest->data[idx+i] = sdata[idx+i]; + } + } + else { + errorexit ((char*) "pixelsize not supported.\n"); + } } @@ -112,23 +155,37 @@ void VideoFrame::ToPixbuf(GdkPixbuf* dest) { if (dest == NULL) return; - desth = gdk_pixbuf_get_height(dest); - destw = gdk_pixbuf_get_width(dest); - destpixel = gdk_pixbuf_get_pixels(dest); + if (pixelsize == 3) { + desth = gdk_pixbuf_get_height(dest); + destw = gdk_pixbuf_get_width(dest); + destpixel = gdk_pixbuf_get_pixels(dest); - if (destw * desth < h * w) { - destw = w; - desth = h; - } + if (destw * desth < h * w) { + destw = w; + desth = h; + } - memcpy (destpixel, data, 3*destw*desth); + memcpy (destpixel, data, 3*destw*desth); + } + else if (pixelsize == 6) { + desth = gdk_pixbuf_get_height(dest); + destw = gdk_pixbuf_get_width(dest); + destpixel = gdk_pixbuf_get_pixels(dest); + uint16_t *sdata = (uint16_t*)data; + int x, y, idx, i; + + for (y = 0; y < desth; y++) for (x = 0; x < destw; x++) + for (i = 0; i < 3; i++) { + idx = 3 * (y * w + x); + destpixel[idx+i] = sdata[idx+i]; + } + } + else { + errorexit ((char*) "pixelsize (%d) not supported.\n", pixelsize); + } } - - - - FloatImage::FloatImage() { data = NULL; w = 0; diff --git a/videoframe.h b/videoframe.h index 7e46673..e9810e3 100644 --- a/videoframe.h +++ b/videoframe.h @@ -26,20 +26,25 @@ public: class VideoFrame { private: + void SetMemorySize (int nw, int nh, int nps); + unsigned char *data; public: int w; int h; + uint32_t pixelsize; + uint32_t size; - unsigned char *data; VideoFrame(); ~VideoFrame(); VideoFrame operator=(VideoFrame rightside); - void SetSize(int nw, int nh); - void SetW(int nw) { SetSize(nw, h); }; - void SetH(int nh) { SetSize(w, nh); }; + void SetSize(int nw, int nh) { SetMemorySize (nw, nh, pixelsize); }; + void* GetData() { return data; }; + void SetPixelSize(uint32_t nps) { SetMemorySize (w, h, nps); }; + void SetW(int nw) { SetMemorySize(nw, h, pixelsize); }; + void SetH(int nh) { SetMemorySize(w, nh, pixelsize); }; void CopyFrom(VideoFrame *source); void CopyFrom(FloatImage *source); void CopyTo(FloatImage *dest);