diff --git a/README.md b/README.md index 344b637..cb871a7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ # 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. + +# 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: diff --git a/SampleOutput/SER-Output-File1.ser.bz2 b/SampleOutput/SER-Output-File1.ser.bz2 new file mode 100644 index 0000000..48997ae Binary files /dev/null and b/SampleOutput/SER-Output-File1.ser.bz2 differ diff --git a/SampleOutput/screenshot-2024_04_13.png b/SampleOutput/screenshot-2024_04_13.png new file mode 100644 index 0000000..5f97184 Binary files /dev/null and b/SampleOutput/screenshot-2024_04_13.png differ diff --git a/convert.cc b/convert.cc index 508d899..e2334e2 100644 --- a/convert.cc +++ b/convert.cc @@ -54,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; diff --git a/gui.h b/gui.h index bea6f07..88dec85 100644 --- a/gui.h +++ b/gui.h @@ -16,6 +16,9 @@ #include #include +#define LEN_FILENAME 64 +#define LEN_FULLFILENAME 256 + enum { VID_ENTERDATA_NONE = 0, VID_ENTERDATA_POS, diff --git a/output.cc b/output.cc index fe3536e..f88f9d0 100644 --- a/output.cc +++ b/output.cc @@ -42,16 +42,29 @@ gboolean cb_thread_output (gpointer data) { } +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__); - GtkWidget *inputdest = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath")); - std::string s = gtk_entry_get_text(GTK_ENTRY(inputdest)); - output.SERStart(s); + 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) { @@ -76,15 +89,17 @@ gpointer _OutputThread (gpointer data) { 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); - mode = 0; }; @@ -95,12 +110,23 @@ void Output::NotifyGTK () { /* * 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) { - printf ("%s:%d SERStart Destination Folder: %s\n", __FILE__, __LINE__, destpath.c_str()); +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; - // start SER output NotifyGTK(); }; @@ -110,7 +136,11 @@ void Output::SERStart (std::string destpath) { */ void Output::SERStop () { mode &= ~(OUTPUT_MODE_SER_STARTED); - // stop SER output + if (outputser) { + // close SER and delete object --> deleting the object should also rewrite the write the header + delete outputser; + outputser = NULL; + } NotifyGTK(); }; @@ -128,7 +158,7 @@ Output::~Output() { 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()); + // 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__); } @@ -151,9 +181,50 @@ void Output::Thread() { if (inFrameNew == 1) { if (mode & OUTPUT_MODE_SER_STARTED) { - // for now display error message - errormessage_display((char*)"windows-main", (char*)"Error", (char*)"Writing SER files is not finished yet."); - SERStop(); + 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(); + outputser->setWidth(outputserw); + outputser->setHeight(outputserh); + outputser->setColorID(serformat); + 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(); + } + outputser->setObserver((char *)"FIXME:read username from OS"); + outputser->setTelescope((char *)"FIXME:not implemented yet"); + outputser->setInstrument((char *)"FIXME:just read device from dirver"); + outputser->setNumberOfFrames(0); + 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 != NULL) { // we need to check in case outputser got deleted. + // + // write frame + outputser->appendFrame(inFrame.data); + } } inFrameNew = 0; } diff --git a/output.h b/output.h index 00965f9..5bb6925 100644 --- a/output.h +++ b/output.h @@ -12,6 +12,7 @@ #include "config.h" #include "video.h" #include "videoframe.h" +#include "ser.h" #define OUTPUT_MODE_SER_STARTED 0x0001 @@ -27,9 +28,15 @@ private: GMutex mutex; // general mutex for changing settings GThread *thread; 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: Output(); ~Output(); @@ -54,7 +61,7 @@ public: void SetObject (VideoFrame objFrame, int newx, int newy); void GetObjectPos (int *x, int *y); - void SERStart(std::string destpath); + void SERStart(std::string destpath, std::string sufix); void SERStop(); int GetStatus() { return mode; }; diff --git a/ser.cc b/ser.cc index 650c2f6..4d7125f 100644 --- a/ser.cc +++ b/ser.cc @@ -12,6 +12,31 @@ #include #include #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; + default: return 0; + } + + return 1; +} + SER::SER() { /* clear header */ diff --git a/ser.h b/ser.h index cbd2628..7253c30 100644 --- a/ser.h +++ b/ser.h @@ -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, diff --git a/simpleskycam.ui b/simpleskycam.ui index 6c3f921..0861635 100644 --- a/simpleskycam.ui +++ b/simpleskycam.ui @@ -2487,6 +2487,11 @@ Flat DarkFlat + + + False + + False diff --git a/videoframe.cc b/videoframe.cc index 96a7776..5167c37 100644 --- a/videoframe.cc +++ b/videoframe.cc @@ -54,7 +54,7 @@ int VideoFrameRaw::CopyFrom(VideoFrameRaw *src) { int VideoFrameRaw::CopyFrom(VideoFrame *src) { if (src == NULL) return 0; - return CopyFrom(V4L2_PIX_FMT_RGB32, src->w, src->h, src->size, src->data); + return CopyFrom(V4L2_PIX_FMT_RGB24, src->w, src->h, src->size, src->data); }