diff --git a/Makefile b/Makefile index e7e5401..305e21f 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ APP = simpleskycam -include Makefile.rules -OBJECTS = gui.oo main.oo video.oo videodev.oo +OBJECTS = gui.oo main.oo video.oo videoframe.oo videodev.oo filter.oo DISTNAME=simpleskycam-$(VERSION) ifeq ($(TARGET),) diff --git a/filter.cc b/filter.cc index 669ac6b..3ca1d28 100644 --- a/filter.cc +++ b/filter.cc @@ -7,8 +7,8 @@ #include "filter.h" extern Filter filter; -gboolean cb_filtertemp_thread (gpointer data); -gboolean cb_filterout_thread (gpointer data); +//gboolean cb_filtertemp_thread (gpointer data); +//gboolean cb_filterout_thread (gpointer data); // // C / C++ Wrapper for the thread function @@ -21,8 +21,10 @@ gpointer _FilterThread (gpointer data) { Filter::Filter() { // @suppress("Class members should be properly initialized") + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + g_mutex_init (&mutexin); - g_mutex_init (&mutexout); + g_mutex_init (&muteximage); g_mutex_init (&mutextmp); g_mutex_init (&mutex); running = 1; @@ -49,11 +51,12 @@ Filter::~Filter() { int Filter::NewFrame(VideoFrame *newframe) { + if (newframe == NULL) return -1; LockInMutex(); inFrame.CopyFrom(newframe); inFrameNew = 1; UnLockInMutex(); - return -1; + return 0; }; @@ -61,16 +64,18 @@ int Filter::NewFrame(VideoFrame *newframe) { // NewFrame: will set new frame // Thread: newFrame |------> Find Object --- not found ---> send gui information void Filter::Thread() { + int _run_once = 1; + while (running) { // check for new frame LockInMutex(); if (inFrameNew == 1) { inFrameNew = 0; + // // do some input detection improvement InputDetect(); - oldFrame.CopyFrom(&inFrame); UnLockInMutex(); @@ -78,17 +83,17 @@ void Filter::Thread() { LockTempMutex(); tempgtk.CopyFrom(&temp); UnLockTempMutex(); - gdk_threads_add_idle(cb_filtertemp_thread , &tempgtk); + gdk_threads_add_idle(cb_thread_filtertemp , &tempgtk); // // do some other stuff use if possible only the oldFrame data ComposeOutput(); // copy output image for gtk - LockOutMutex(); + LockImageMutex(); imagegtk.CopyFrom(&image); - UnLockOutMutex(); - gdk_threads_add_idle(cb_filterout_thread , &imagegtk); + UnLockImageMutex(); + gdk_threads_add_idle(cb_thread_filterimage , &imagegtk); } else UnLockInMutex(); @@ -104,7 +109,6 @@ void Filter::InputDetect() { unsigned char *pxs, *pxso, *pxstemp; unsigned char pixel; int idx; - FloatImage fi;; float fmin, fmax; temp.SetSize (inFrame.w, inFrame.h); @@ -136,22 +140,24 @@ void Filter::InputDetect() { -#define FACTOR 100.0 +#define FACTOR 25.0 void Filter::ComposeOutput() { int x, y, idx, i; - float *pixd; // destination - unsigned char *pixs; // source + float *pixd = NULL; // destination + unsigned char *pixs = NULL; // source image.SetSize(oldFrame.w, oldFrame.h); pixd = image.data; pixs = oldFrame.data; + if (pixd == NULL || pixs == NULL) return; + for (x = 0; x < temp.w && x < inFrame.w && x < oldFrame.w; x++) for (y = 0; y < temp.h && y < inFrame.h && y < oldFrame.h; y++) { idx = 3 * (oldFrame.w * y + x); for (i = 0; i < 3; i++) - pixd[idx+i] = (FACTOR * pixd[idx+i]/FACTOR) + (pixs[idx+i] / FACTOR); + pixd[idx+i] = ((FACTOR-1) * pixd[idx+i]/FACTOR) + (pixs[idx+i] / FACTOR); } } diff --git a/filter.h b/filter.h index dd69aaf..d5898b8 100644 --- a/filter.h +++ b/filter.h @@ -24,11 +24,12 @@ private: VideoFrame tempgtk; // temp image for gtk FloatImage image; // output image VideoFrame imagegtk; // output image -- send to gtk - GMutex mutexout; + GMutex muteximage; GMutex mutexin; GMutex mutextmp; // for access the temp image GMutex mutex; // general mutex for changing settings GThread *thread; + FloatImage fi; int objectW; // object Image Size Width int objectH; // object Image Size Height @@ -54,9 +55,9 @@ public: void LockTempMutex() { g_mutex_lock(&mutextmp);}; void UnLockTempMutex() { g_mutex_unlock(&mutextmp);}; - int TryLockOutMutex() { return g_mutex_trylock(&mutexout); }; - void LockOutMutex() { g_mutex_lock(&mutexout);}; - void UnLockOutMutex() { g_mutex_unlock(&mutexout);}; + int TryLockImageMutex() { return g_mutex_trylock(&muteximage); }; + void LockImageMutex() { g_mutex_lock(&muteximage);}; + void UnLockImageMutex() { g_mutex_unlock(&muteximage);}; void LockMutex() { g_mutex_lock(&mutex);}; void UnLockMutex() { g_mutex_unlock(&mutex);}; diff --git a/gui.cc b/gui.cc index 1ae6b37..37ecd63 100644 --- a/gui.cc +++ b/gui.cc @@ -12,8 +12,18 @@ #include #include "gui.h" #include "config.h" +#include "video.h" +#include "filter.h" extern GtkBuilder *_builder_; // work around for threads +extern Filter filter; + +GtkWidget *temp_da = NULL; +GdkPixbuf *temp_pixbuf = NULL; + +GtkWidget *image_da = NULL; +GdkPixbuf *image_pixbuf = NULL; + ////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -55,3 +65,116 @@ void displayerror (std::string error) { +// +// callback from filter thread. Data will point to the output VideoFrame. +// Access to this data must be Locked before use. +gboolean cb_thread_filterimage (gpointer data) { + VideoFrame *vf = (VideoFrame *) data; + int pix_h, pix_w; + + if (image_da == NULL) + image_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "image-da")); + + if (vf == NULL) { + return false; + } + + filter.LockImageMutex(); + + if (image_pixbuf) { + pix_h = gdk_pixbuf_get_height(image_pixbuf); + pix_w = gdk_pixbuf_get_width(image_pixbuf); + } + else pix_h = 0; + + if (image_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) { + if (image_pixbuf != NULL) g_object_unref (image_pixbuf); + + printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h); + image_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h); + pix_w = vf->w; + pix_h = vf->h; + } + videoframe_to_pixbuf(image_pixbuf, vf); + gdk_window_invalidate_rect(gtk_widget_get_window(image_da), NULL, true); + + filter.UnLockImageMutex(); + + return false; +}; + + +// +// callback from filter 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_filtertemp (gpointer data) { + VideoFrame *vf = (VideoFrame *) data; + int pix_h, pix_w; + + if (temp_da == NULL) + temp_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "temp-da")); + + if (vf == NULL) { + return false; + } + + filter.LockTempMutex(); + + if (temp_pixbuf) { + pix_h = gdk_pixbuf_get_height(temp_pixbuf); + pix_w = gdk_pixbuf_get_width(temp_pixbuf); + } + else pix_h = 0; + + if (temp_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) { + if (temp_pixbuf != NULL) g_object_unref (temp_pixbuf); + + printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h); + temp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h); + pix_w = vf->w; + pix_h = vf->h; + } + videoframe_to_pixbuf(temp_pixbuf, vf); + gdk_window_invalidate_rect(gtk_widget_get_window(temp_da), NULL, true); + + filter.UnLockTempMutex(); + + return false; +}; + + + +void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) { + int clientw, clienth, pixbufw, pixbufh; + float clientar, pixbufar; + + GdkPixbuf *pixbuf = NULL; + GdkPixbuf *src = NULL; + + if (area == temp_da) src = temp_pixbuf; + else if (area == image_da) src = image_pixbuf; + else return; + + clienth = gtk_widget_get_allocated_height(area); + clientw = gtk_widget_get_allocated_width(area); + clientar = (float)clientw/(float)clienth; + pixbufh = gdk_pixbuf_get_height(src); + pixbufw = gdk_pixbuf_get_width(src); + pixbufar = (float)pixbufw/(float)pixbufh; + + if (pixbufar < clientar) { + clientw = (pixbufar * (float) clienth); + } + else { + clienth = ((float) clientw / pixbufar); + } + + pixbuf = gdk_pixbuf_scale_simple (src, clientw, clienth, GDK_INTERP_NEAREST); + + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); + cairo_paint(cr); + cairo_fill (cr); + g_object_unref (pixbuf); +}; + diff --git a/gui.h b/gui.h index 165e85e..13e2fb8 100644 --- a/gui.h +++ b/gui.h @@ -16,7 +16,6 @@ #include #define BUILDER_FILE "simpleskycam.ui" -extern GtkBuilder *_builder_; void displayerror (std::string error); @@ -48,14 +47,20 @@ gboolean videoctrl_update(gpointer data); // -// thread handles +// thread new inframe G_MODULE_EXPORT gboolean cb_thread_video (gpointer data); + +// +// filter new temp 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_filterimage (gpointer data); +G_MODULE_EXPORT gboolean cb_thread_filtertemp (gpointer data); + #ifdef __cplusplus } #endif - extern float get_cycletime(struct timeval *t); #endif // _GUI_H_ diff --git a/main.cc b/main.cc index 69d8176..af12239 100644 --- a/main.cc +++ b/main.cc @@ -8,6 +8,7 @@ #include "config.h" #include "gui.h" +#include "filter.h" ////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -15,6 +16,7 @@ // GtkBuilder *_builder_ = NULL; // work around for the thread situation +Filter filter; int main (int argc, char **argv) { GtkBuilder *builder; diff --git a/simpleskycam.ui b/simpleskycam.ui index de6c469..dc4c50b 100644 --- a/simpleskycam.ui +++ b/simpleskycam.ui @@ -214,10 +214,230 @@ - + True False - nix da - page 2 + vertical + + + + True + False + 8 + 8 + 8 + 8 + 8 + + + True + False + 8 + 8 + 8 + 8 + Position + + + 0 + 0 + + + + + True + False + Size: + + + 0 + 1 + + + + + True + False + 8 + 8 + 8 + 8 + 4 + 4 + X: + + + 1 + 0 + + + + + True + False + 4 + 4 + W: + + + 1 + 1 + + + + + True + True + 4 + 4 + 4 + 4 + 4 + 4 + 5 + 5 + 5 + digits + + + 2 + 0 + + + + + True + True + 4 + 4 + 4 + 4 + 4 + 4 + 5 + 5 + + + 2 + 1 + + + + + True + False + 4 + 4 + Y: + + + 3 + 0 + + + + + True + False + 4 + 4 + H: + + + 3 + 1 + + + + + True + True + 4 + 4 + 4 + 4 + 4 + 4 + 5 + 5 + + + 4 + 0 + + + + + True + True + 4 + 4 + 4 + 4 + 4 + 4 + 5 + 5 + + + 4 + 1 + + + + + Auto + True + True + False + 10 + 8 + 10 + 8 + True + + + 5 + 1 + + + + + Set Object + True + True + True + 8 + 8 + 8 + 8 + 4 + 4 + + + 5 + 0 + + + + + + + + + + + False + True + 0 + + + + + + + + 1 @@ -281,10 +501,10 @@ True True - + True False - Video Object + False @@ -292,10 +512,10 @@ - + True False - Image Filtered + True diff --git a/video.cc b/video.cc index 05ca2ac..cf237ae 100644 --- a/video.cc +++ b/video.cc @@ -9,12 +9,13 @@ #include #include "gui.h" #include "video.h" +#include "filter.h" VideoDev videodev; GtkWidget *video_da = NULL; GdkPixbuf *video_pixbuf = NULL; - - +extern GtkBuilder *_builder_; // work around for threads +extern Filter filter; gboolean videoctrl_update(gpointer data) { GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid")); @@ -48,12 +49,15 @@ void videoframe_to_pixbuf(GdkPixbuf* dest, VideoFrame *src) { if (dest == NULL || src == NULL) return; - destw = gdk_pixbuf_get_height(dest); - desth = gdk_pixbuf_get_width(dest); + desth = gdk_pixbuf_get_height(dest); + destw = gdk_pixbuf_get_width(dest); destpixel = gdk_pixbuf_get_pixels(dest); - if (destw > src->w) destw = src->w; - if (desth > src->h) destw = src->h; + if (destw * desth < src->h * src->w) { + destw = src->w; + desth = src->h; + } + memcpy (destpixel, src->data, 3*destw*desth); } @@ -93,69 +97,6 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) }; -void video_draw_image (VideoFrame *vf) { - int pix_w; - int pix_h; - int x, y; - - if (video_da == NULL) { - video_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "video-da")); - if (video_da == NULL) { - printf ("%s:%d could not find drawingarea.\n", __FILE__, __LINE__); - return; - } - } - - // check if the pixbuf is already allocated? - if (video_pixbuf) { - pix_h = gdk_pixbuf_get_height(video_pixbuf); - pix_w = gdk_pixbuf_get_width(video_pixbuf); - } - else pix_h = 0; - - // display error screen? - if (vf == NULL) { - unsigned char *pixels; - - // need to allocate? - if (video_pixbuf == NULL) { - printf ("%s:%d new pixbuf\n", __FILE__, __LINE__); - video_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, 640, 480); - pix_w = 640; - pix_h = 480; - } - pixels = gdk_pixbuf_get_pixels(video_pixbuf); - for (y = 0; y < pix_h; y++) for (x = 0; x < pix_w; x++) { - if ((x & 1) && (y & 1)) { - *(++pixels) = 0xFF; - *(++pixels) = 0xFF; - *(++pixels) = 0xFF; - } - else { - *(++pixels) = 0x0; - *(++pixels) = 0x0; - *(++pixels) = 0x0; - } - } - - } - else { - // - // changes in resolution? - - if (video_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) { - if (video_pixbuf != NULL) g_object_unref (video_pixbuf); - - printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h); - video_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h); - pix_w = vf->w; - pix_h = vf->h; - } - videoframe_to_pixbuf(video_pixbuf, vf); - } - gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true); -}; - // // refresh the possible devices @@ -273,7 +214,6 @@ void cb_video_btnstop (GtkWidget *widget, gpointer data) { }; - // // callback from videodev thread. data will point to the latest VideoFrame. // Access to this data must be Locked before use. @@ -285,16 +225,43 @@ gboolean cb_thread_video (gpointer data) { 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")); + if (video_da == NULL) + video_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "video-da")); + if (vf == NULL) { printf ("%s:%d %s something went wrong\n", __FILE__, __LINE__, __FUNCTION__); videodev.Stop(); - video_draw_image(NULL); + if (video_pixbuf == NULL) { + video_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, 100, 100); + } + memset (gdk_pixbuf_get_pixels(video_pixbuf), 0, 3 * gdk_pixbuf_get_height(video_pixbuf) * gdk_pixbuf_get_width(video_pixbuf)); + gtk_widget_set_sensitive(btnstart, true); gtk_widget_set_sensitive(btnstop, false); } - videodev.LockMutex(); - video_draw_image(vf); - videodev.UnLockMutex(); + else { + int pix_h, pix_w; + + videodev.LockMutex(); + if (video_pixbuf) { + pix_h = gdk_pixbuf_get_height(video_pixbuf); + pix_w = gdk_pixbuf_get_width(video_pixbuf); + } + else pix_h = 0; + + if (video_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) { + if (video_pixbuf != NULL) g_object_unref (video_pixbuf); + + printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h); + video_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h); + pix_w = vf->w; + pix_h = vf->h; + } + videoframe_to_pixbuf(video_pixbuf, vf); + filter.NewFrame(vf); + videodev.UnLockMutex(); + } + gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true); return false; }; diff --git a/video.h b/video.h index ca8b63a..16a3619 100644 --- a/video.h +++ b/video.h @@ -16,6 +16,7 @@ #include "gui.h" #include "config.h" +#include "videoframe.h" enum { @@ -65,14 +66,7 @@ struct { } typedef VideoInBuffer; -struct { - int w; - int h; - uint32_t size; - unsigned char *data; -} typedef VideoFrame; - -#define VDEV_INBUFFERS 2 +#define VDEV_INBUFFERS 3 class VideoDev { private: std::string conf_device; @@ -130,13 +124,14 @@ public: void PrintCaps (uint32_t caps); void PrintFmt(struct v4l2_format *f); - void LockMutex(); - void UnLockMutex(); + void LockMutex() { g_mutex_lock(&mutex); }; + void UnLockMutex() { g_mutex_unlock(&mutex); }; }; extern VideoDev videodev; +extern void videoframe_to_pixbuf(GdkPixbuf* dest, VideoFrame *src); #endif // _VIDEO_H_ diff --git a/videodev.cc b/videodev.cc index 41f1995..8bcf952 100644 --- a/videodev.cc +++ b/videodev.cc @@ -465,8 +465,8 @@ int VideoDev::OpenInit() { fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 1920; fmt.fmt.pix.height = 1080; - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; -// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; +// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; fmt.fmt.pix.field = V4L2_FIELD_NONE; if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) { @@ -918,14 +918,3 @@ int VideoDev::Convert (VideoFrame *dest, unsigned char *ptrsrc, int srcsize, uin }; -void VideoDev::LockMutex() { - g_mutex_lock(&mutex); -}; - - -void VideoDev::UnLockMutex() { - g_mutex_unlock(&mutex); -}; - - - diff --git a/videoframe.cc b/videoframe.cc index 13bafbd..b759477 100644 --- a/videoframe.cc +++ b/videoframe.cc @@ -28,7 +28,7 @@ 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 * h * w; + uint32_t newsize = VIDEOFRAME_DEPTH_BYTES * nh * nw; if (newsize > size || data == NULL) { unsigned char *newdata = (unsigned char *) malloc (newsize); @@ -81,6 +81,7 @@ void VideoFrame::CopyFrom(FloatImage *source) { for (i = 0; i < 3; i++) { idx = 3 * (y * w + x); v = (float)(256.0 * (source->data[idx+i]-min) / (max-min)); + data[idx+i] = v; } } @@ -110,7 +111,7 @@ FloatImage::~FloatImage() { // // we will only allocate a new image if the needed size increases void FloatImage::SetSize(int nw, int nh) { - uint32_t newsize = 3 * h * w * sizeof(float); + uint32_t newsize = 3 * nh * nw * sizeof(float); if (newsize > size || data == NULL) { float *newdata = (float *) malloc (newsize); diff --git a/videoframe.h b/videoframe.h index f697d91..a9229ab 100644 --- a/videoframe.h +++ b/videoframe.h @@ -4,9 +4,6 @@ #include "gui.h" #include "config.h" - - - class FloatImage { public: int w;