From b03406e31c5e5d4f8a4e065b03e68330885a3832 Mon Sep 17 00:00:00 2001
From: deva <deva>
Date: Sun, 10 Apr 2005 20:38:45 +0000
Subject: lots of styff!

---
 TODO              | 64 ++++++++++++++++++++++++++++++++++++++++++++---
 src/camera.cc     |  4 +--
 src/camera.h      |  3 ++-
 src/encoder.cc    |  9 +++----
 src/encoder.h     |  4 ++-
 src/img_encoder.h | 14 ++++++++---
 src/mainwindow.cc | 75 ++++++++++++++++++++++++++++++++++++++++++-------------
 src/mainwindow.h  |  9 +++++++
 src/messagebox.cc | 41 ++++++++++++++++++++++++++++--
 src/messagebox.h  |  9 +++++--
 src/miav.conf     | 14 +++++++----
 src/package.h     |  8 ++++++
 src/server.cc     | 25 +++++++++++++------
 src/util.h        |  3 +++
 14 files changed, 230 insertions(+), 52 deletions(-)

diff --git a/TODO b/TODO
index 1bbef10..7e9ff73 100644
--- a/TODO
+++ b/TODO
@@ -16,9 +16,10 @@ Mainwindow:
  [x]	- Make generic gui layout code.
  [x]	- Make icons.
  [x]	- Make statusbar.
- [ ]	- Make flashing record bar.
- [ ]	- Show network connection in statusbar.
- [ ]	- Show camera connection in statusbar.
+ [x]	- Make flashing record bar.
+ [ ]	- Show network connection status in statusbar.
+ [ ]	- Show camera connection status in statusbar.
+ [x]	- Save movie messagebox (yes/no/dunno)
  [ ]	- Test it.
 
 CPRQueryDialog:
@@ -30,6 +31,10 @@ CPRQueryDialog:
  [ ]	- Make icons?
  [ ]	- Test it.
 
+Encoder:
+ [ ]	- Send savestate signal.
+ [ ]	- Make all data sent before deleting network object. (flush)
+
 Decoder:
  [ ]	- Enable sound decoding for the network stream.
 
@@ -47,6 +52,9 @@ ImgEncoder:
 MovEncoder:
  [ ]	- Enable sound.
 
+Main:
+ [ ]	- Save movie signal handling.
+
 ==========================================================================
  TASKS (common)
 ==========================================================================
@@ -85,4 +93,52 @@ Destructor:
 	- Cleanup
 
 getNextFrame:
-	- returns: AVframe pointer
\ No newline at end of file
+	- returns: AVframe pointer
+
+==========================================================================
+ SAVE THE MOVIE?
+==========================================================================
+When the stop button is clicked, a msg box pops up, "Save? [yes, no, dunno]"
+network connection is no killed before this has been answered, and an empty 
+frame has been send to the server with the answer.
+
+On the serverside, a variable describing wether the file is to be saved (SAVE), 
+deleted (DELETE), og scheduled for later descision (LATER).
+
+It is initialized with LATER, in order to prevent errors due to a malfunction
+leading to a disconnection.
+
+If a flag is recieved, the state is overwritten.
+
+If the state is SAVE, when the connection is terminated, the file is moved to
+a folder containing permanent data store.
+
+If the state is DELETE, the file is moved to a folder containing files scheduled
+for deletion, when more space is needed (no files are removed at this point)
+
+If the state is LATER, the file is moved to a folder containing files with this
+purpose.
+
+A cron job examines this folder regularly (test how often).
+If a file has been here for more than a week, the administrator is contacted by
+email.
+
+==========================================================================
+ Semphores and mutexes in the client network architechture
+==========================================================================
+,-----------.
+| DV stream |
+`-----------'
+      |
+      V
+,-----------.
+| Decoder   |
+`-----------'
+      |      \
+      V       \
+,-----------.  \
+| Player    |   \
+`-----------'    \
+                  \  ,-----------.
+                   ->| Encoder   |
+                     `-----------'
diff --git a/src/camera.cc b/src/camera.cc
index 9e9fd82..772d48a 100644
--- a/src/camera.cc
+++ b/src/camera.cc
@@ -146,9 +146,9 @@ void Camera::start()
   else errorstatus->pushError("Camera not initialized.");
 }
 
-void Camera::stop()
+void Camera::stop(n_savestate save)
 {
-  if(initialized) encoder->stop();
+  if(initialized) encoder->stop(save);
   else errorstatus->pushError("Camera not initialized.");
 }
 
diff --git a/src/camera.h b/src/camera.h
index 25e1972..e5b4cee 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -43,6 +43,7 @@ using namespace std;
 #include "decoder.h"
 #include "encoder.h"
 #include "player.h"
+#include "package.h"
 
 #include "thread.h"
 #include "ffframe.h"
@@ -65,7 +66,7 @@ public:
 
   // Camera actions
   void start();
-  void stop();
+  void stop(n_savestate save);
   void freeze();
   void unfreeze();
   void snapshot();
diff --git a/src/encoder.cc b/src/encoder.cc
index 3a4ade2..ca8fb4f 100644
--- a/src/encoder.cc
+++ b/src/encoder.cc
@@ -69,18 +69,14 @@ Encoder::~Encoder()
 void Encoder::encode()
 { 
   DVFrame *f;
-  printf("0\n");
 
   while(*running) {
-    printf("1\n");
     sem_wait(sem);
 
-    printf("2\n");
     pthread_mutex_lock(mutex);
     f = queue->pop();
     pthread_mutex_unlock(mutex);
     
-    printf("3\n");
     if((f && record) || 
        (freeze_request != freeze_value) || 
        (shoot_request != shoot_value)) {
@@ -91,6 +87,7 @@ void Encoder::encode()
       h.header.h_data.freeze = (freeze_request != freeze_value);
       h.header.h_data.snapshot = (shoot_request != shoot_value);
       h.header.h_data.record = record;
+      h.header.h_data.savestate = NO_CHANGE;
         
       if(freeze_request != freeze_value) freeze_value = freeze_request;
       if(shoot_request != shoot_value) shoot_value = shoot_request;
@@ -147,7 +144,9 @@ void Encoder::start() {
 }
 
 
-void Encoder::stop() {
+void Encoder::stop(n_savestate save) {
+  // TODO: set save state in package header.
+  // TODO: Flush not yet sent video packages.
   record = 0;
   if(s) {
     if(n) delete n;
diff --git a/src/encoder.h b/src/encoder.h
index 554839c..75788b4 100644
--- a/src/encoder.h
+++ b/src/encoder.h
@@ -37,6 +37,8 @@
 #include "util.h"
 #include <queue.h>
 
+#include "package.h"
+
 #include "thread.h"
 #include <dvframe.h>
 
@@ -62,7 +64,7 @@ public:
   void setCpr(char *newcpr);
 
   void start();
-  void stop();
+  void stop(n_savestate save);
 
   void freeze();
   void shoot();
diff --git a/src/img_encoder.h b/src/img_encoder.h
index 25779ce..79f4184 100644
--- a/src/img_encoder.h
+++ b/src/img_encoder.h
@@ -23,16 +23,22 @@
 #ifndef __RTVIDEOREC_IMGENCODER_H
 #define __RTVIDEOREC_IMGENCODER_H
 
+#include "dvframe.h"
+#include "util.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <avformat.h>
 extern "C" {
+#ifdef HAVE_STDLIB_H
+#undef HAVE_STDLIB_H
+#endif
 #include <jpeglib.h>
+#ifdef HAVE_STDLIB_H
+#undef HAVE_STDLIB_H
+#endif
 }
-#include <dvframe.h>
-
-#include "util.h"
 
 #define VIDEO_BUFFER_SIZE	(1024*1024)	// FIXME: One size fits all...
 
@@ -60,5 +66,5 @@ class ImgEncoder {
   //  AVPacket pkt;
 };
 
-#endif
+#endif /*__RTVIDEOREC_IMGENCODER_H*/
 
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index 8bfc53e..85b04cd 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -52,6 +52,9 @@ MainWindow::MainWindow( QWidget* parent, const char* name )
 {
   error = new Error();
   MiavConfig cfg("miav.conf", error);
+  video_width = cfg.readInt("video_width");
+  video_height = cfg.readInt("video_height");
+
   int resolution_w = cfg.readInt("pixel_width");
   int resolution_h = cfg.readInt("pixel_height");
   while(error->hasError()) {
@@ -65,16 +68,6 @@ MainWindow::MainWindow( QWidget* parent, const char* name )
   resize(resolution_w, resolution_h);
 
   // Load images
-/*
-	QPainter *paint = new QPainter();
-	QPicture *pic = new QPicture();
-	pic->load(fname, "svg");
-	paint->begin(this);
-	paint->setWindow(pic->boundingRect());
-	paint->drawPicture(0, 0, *pic);
-	paint->end();
- */
-
   pix_record = new QPixmap();
   pix_record->load( PIXMAP_RECORD );
 
@@ -99,6 +92,10 @@ MainWindow::MainWindow( QWidget* parent, const char* name )
   pix_logo = new QPixmap();
   pix_logo->load( PIXMAP_LOGO_SMALL );
 
+  timer = new QTimer(this);
+  connect(timer, SIGNAL(timeout()), SLOT(redraw_edge()));
+  rec_edge_counter = 0.0f;
+
   createGui();
   show();
 
@@ -158,11 +155,11 @@ void MainWindow::createGui()
 
   img_recedge = new QLabel(this);
   img_recedge->setBackgroundColor(QColor(160,160,160));
-  img_recedge->setFixedSize(740,596);
+  img_recedge->setFixedSize(video_width + 20, video_height + 20);
   
   img_live = new VideoWidget(img_recedge);
   //  img_live->setErasePixmap( *pix_dummy );
-  img_live->setFixedSize(720,576);
+  img_live->setFixedSize(video_width, video_height);
   img_live->move(10,10);
   g1->addMultiCellWidget ( img_recedge, 0, 0, 0, 2, Qt::AlignHCenter);
 
@@ -216,6 +213,17 @@ void MainWindow::createGui()
   status->message( TXT_READY );
 }
 
+#define GREY 160
+#define SPEED 0.1f
+void MainWindow::redraw_edge()
+{
+  rec_edge_counter += SPEED;
+  float val = abs(sin(rec_edge_counter));
+  img_recedge->setBackgroundColor(QColor((int) ((255 - GREY) * val + GREY),
+                                         (int) (GREY - (GREY * val)),
+                                         (int) (GREY - (GREY * val))));
+}
+
 QPushButton *MainWindow::createButton(char *caption, int width, int height)
 {
   QPushButton *btn = new QPushButton(caption, this);
@@ -264,16 +272,47 @@ void MainWindow::checkErrors()
 
 void MainWindow::rec_clicked()
 {
-  recording = 1 - recording;
-  if(recording) {
-    img_recedge->setBackgroundColor(red);
+  if(!recording) {
+    recording = 1;
+    // Start flashing the edge
+    rec_edge_counter = 0.0f;
+    timer->start(200);
     btn_rec->setPixmap(*pix_stop);
     camera->start();
     checkErrors();
   } else {
-    img_recedge->setBackgroundColor(QColor(160,160,160));
-    btn_rec->setPixmap(*pix_record);
-    camera->stop();
+    switch(MessageBox(this, 
+                      TXT_ASK_SAVE_TITLE, 
+                      TXT_ASK_SAVE, 
+                      TYPE_YES_NO_MAYBE_CANCEL, 
+                      ICON_QUESTION).exec()) {
+    case MSG_YES:
+      recording = 0;
+      camera->stop(SAVE);
+      timer->stop();
+      img_recedge->setBackgroundColor(QColor(160,160,160));
+      btn_rec->setPixmap(*pix_record);
+      break;
+
+    case MSG_NO:
+      recording = 0;
+      camera->stop(DELETE);
+      timer->stop();
+      img_recedge->setBackgroundColor(QColor(160,160,160));
+      btn_rec->setPixmap(*pix_record);
+      break;
+
+    case MSG_MAYBE:
+      recording = 0;
+      camera->stop(LATER);
+      timer->stop();
+      img_recedge->setBackgroundColor(QColor(160,160,160));
+      btn_rec->setPixmap(*pix_record);
+      break;
+
+    case MSG_CANCEL:
+      break;
+    }
     checkErrors();
   }
 }
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 25a938b..3b8f73c 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -35,6 +35,7 @@ using namespace std;
 #include <qlabel.h>
 #include <qpushbutton.h>
 #include <qstatusbar.h>
+#include <qtimer.h>
 
 #include "videowidget.h"
 #include "camera.h"
@@ -50,6 +51,8 @@ using namespace std;
 #define TXT_ERROR_TITLE "Der er opst�et en fejl!"
 #define TXT_READY "Klar..."
 #define TXT_CPRDLG_TITLE "CPRQueryDialog"
+#define TXT_ASK_SAVE_TITLE "Vil du gemme filmen?"
+#define TXT_ASK_SAVE "Vil du gemme filmen permanent?"
 
 /** 
  * Images
@@ -80,6 +83,7 @@ public slots:
   void rec_clicked();
   void shoot_clicked();
   void freeze_clicked();
+  void redraw_edge();
  
 private:
   Error *error;
@@ -103,6 +107,8 @@ private:
   QLabel *lbl_cpr;
   QLabel *lbl_name;
 
+  float rec_edge_counter;
+  QTimer *timer;
   QLabel *img_recedge;
   QLabel *img_history[NUM_HISTORY];
   
@@ -119,7 +125,10 @@ private:
   bool recording;
   bool frozen;
 
+  // Configuration values
   float unit;
+  int video_width;
+  int video_height;
 
   QPushButton *createButton(char *caption, int width, int height);
   QLabel *createLabel(char *caption, int width, int height);
diff --git a/src/messagebox.cc b/src/messagebox.cc
index 63bbeee..1975eac 100644
--- a/src/messagebox.cc
+++ b/src/messagebox.cc
@@ -72,9 +72,9 @@ MessageBox::MessageBox(QWidget* parent,
         pix_icon->load( PIXMAP_WARNING );
         break;
       case TYPE_YES_NO: 
-        pix_icon->load( PIXMAP_QUESTION );
-        break;
+      case TYPE_YES_NO_MAYBE: 
       case TYPE_YES_NO_CANCEL: 
+      case TYPE_YES_NO_MAYBE_CANCEL: 
         pix_icon->load( PIXMAP_QUESTION );
         break;
       }
@@ -134,6 +134,20 @@ MessageBox::MessageBox(QWidget* parent,
       connect(bno, SIGNAL( clicked() ), SLOT(bno_clicked()));	
       break;
     }
+  case TYPE_YES_NO_MAYBE: 
+    {
+      QPushButton *byes = createButton(f, TXT_YES );
+      QPushButton *bno = createButton(f, TXT_NO );
+      QPushButton *bmaybe = createButton(f, TXT_MAYBE );
+      QGridLayout *glayout = new QGridLayout(f, 1, 3, 20, 20);
+      glayout->addWidget(bno, 0, 0);
+      glayout->addWidget(byes, 0, 1);
+      glayout->addWidget(bmaybe, 0, 2);
+      connect(byes, SIGNAL( clicked() ), SLOT(byes_clicked()));
+      connect(bno, SIGNAL( clicked() ), SLOT(bno_clicked()));	
+      connect(bmaybe, SIGNAL( clicked() ), SLOT(bmaybe_clicked()));	
+      break;
+    }
   case TYPE_YES_NO_CANCEL: 
     {
       QPushButton *byes = createButton(f, TXT_YES );
@@ -148,6 +162,23 @@ MessageBox::MessageBox(QWidget* parent,
       connect(bno, SIGNAL( clicked() ), SLOT(bno_clicked()));	
       break;
     }
+  case TYPE_YES_NO_MAYBE_CANCEL: 
+    {
+      QPushButton *byes = createButton(f, TXT_YES );
+      QPushButton *bcancel = createButton(f, TXT_CANCEL );
+      QPushButton *bno = createButton(f, TXT_NO );
+      QPushButton *bmaybe = createButton(f, TXT_MAYBE );
+      QGridLayout *glayout = new QGridLayout(f, 1, 4, 20, 20);
+      glayout->addWidget(bno, 0, 0);
+      glayout->addWidget(bcancel, 0, 1);
+      glayout->addWidget(byes, 0, 2);
+      glayout->addWidget(bmaybe, 0, 3);
+      connect(bmaybe, SIGNAL( clicked() ), SLOT(bmaybe_clicked()));
+      connect(byes, SIGNAL( clicked() ), SLOT(byes_clicked()));
+      connect(bcancel, SIGNAL( clicked() ), SLOT(bcancel_clicked()));	
+      connect(bno, SIGNAL( clicked() ), SLOT(bno_clicked()));	
+      break;
+    }
   }
 
 }
@@ -185,4 +216,10 @@ void MessageBox::bno_clicked()
 {
 	done(MSG_NO);
 }	
+
+void MessageBox::bmaybe_clicked() 
+{
+	done(MSG_MAYBE);
+}	
+
 #endif/*USE_GUI*/
diff --git a/src/messagebox.h b/src/messagebox.h
index 313d395..72b703f 100644
--- a/src/messagebox.h
+++ b/src/messagebox.h
@@ -50,14 +50,17 @@ typedef enum {
   MSG_YES,
   MSG_NO,
   MSG_CANCEL,
-  MSG_OK
+  MSG_OK,
+  MSG_MAYBE
 } msg_val;
 
 typedef enum {
   TYPE_OK,
   TYPE_OK_CANCEL,
   TYPE_YES_NO,
+  TYPE_YES_NO_MAYBE,
   TYPE_YES_NO_CANCEL,
+  TYPE_YES_NO_MAYBE_CANCEL,
 } msg_type;
 
 
@@ -65,9 +68,10 @@ typedef enum {
  * Textstrings
  */
 #define TXT_OK     "Ok"
-#define TXT_CANCEL "Annuler"
+#define TXT_CANCEL "Annul�r"
 #define TXT_YES    "Ja"
 #define TXT_NO     "Nej"
+#define TXT_MAYBE  "M�ske"
 
 /** 
  * Images
@@ -94,6 +98,7 @@ public slots:
   void bcancel_clicked();
   void byes_clicked();
   void bno_clicked();
+  void bmaybe_clicked();
 
 private:
   QPixmap *pix_icon;
diff --git a/src/miav.conf b/src/miav.conf
index ba2ceda..c0f5c89 100644
--- a/src/miav.conf
+++ b/src/miav.conf
@@ -3,16 +3,20 @@
 #
 
 # Cpr Database configuration
-fisk		=	
- 		= true
 cpr_host	= "cpr.j.auh.dk"
 cpr_port	= 10301
 cpr_timeout	= 10000
 
+# Video source
+#video_width	= 720
+#video_height	= 576
+video_width	= 500
+video_height	= 370
+
 # Size of the screen in inches
-screensize	= 19.0
-pixel_width	= 1024
-pixel_height	= 768
+screensize	= 14.0
+pixel_width	= 800
+pixel_height	= 600
 
 # How and where to connect to the miav server?
 server_addr	= "192.168.0.10"
diff --git a/src/package.h b/src/package.h
index db0e5a0..94580ee 100644
--- a/src/package.h
+++ b/src/package.h
@@ -27,6 +27,13 @@
 #ifndef __MIAVLIB_PACKAGE_H__
 #define __MIAVLIB_PACKAGE_H__
 
+typedef enum {
+  NO_CHANGE = 0,
+  SAVE,
+  DELETE,
+  LATER
+} n_savestate;
+
 typedef enum {
   DATA_HEADER = 0x0001,
   INFO_HEADER = 0x0002
@@ -40,6 +47,7 @@ typedef struct {
       bool record;
       bool freeze;
       bool snapshot;
+      n_savestate savestate;
     } h_data;
     struct {
       int fisk; 
diff --git a/src/server.cc b/src/server.cc
index 22b691f..44abe2d 100644
--- a/src/server.cc
+++ b/src/server.cc
@@ -63,14 +63,20 @@ MovEncoder *newMovEncoder(char* cpr)
   char fname[256];
   time_t t = time(NULL);
   ltime = localtime(&t);
-  sprintf(fname, "%.2d%.2d%.2d%.2d%.2d%.2d-%s.mpg", ltime->tm_year + 1900, ltime->tm_mon, 
-          ltime->tm_mday, ltime->tm_hour, ltime->tm_min, ltime->tm_sec, cpr);
+  sprintf(fname, "%.2d%.2d%.2d%.2d%.2d%.2d-%s.mpg", 
+          ltime->tm_year + 1900, 
+          ltime->tm_mon, 
+          ltime->tm_mday, 
+          ltime->tm_hour, 
+          ltime->tm_min, 
+          ltime->tm_sec, cpr);
   enc = new MovEncoder(fname);
   return enc;
 }
 
 void newConnection(Socket *s)
-{  
+{
+  n_savestate savestate = LATER;
   n_header h;
   DVFrame *f;
   DVFrame *freeze_frame = NULL;
@@ -91,6 +97,7 @@ void newConnection(Socket *s)
     printf("\tcpr: %s\t", h.header.h_data.cpr);
     printf("\tfrz: %d\t", h.header.h_data.freeze);
     printf("\tsht: %d\n", h.header.h_data.snapshot);
+    printf("\tsave: %d\n", h.header.h_data.savestate);
 
     if(h.header.h_data.snapshot) {
       if(freeze_frame) {
@@ -107,6 +114,10 @@ void newConnection(Socket *s)
       enc->encode(f);
     }
 
+    if(h.header.h_data.savestate) {
+      savestate = h.header.h_data.savestate;
+    }
+
     if(h.header.h_data.freeze) {
       if(freeze_frame) delete freeze_frame;
       freeze_frame = f;
@@ -116,14 +127,12 @@ void newConnection(Socket *s)
 
     f = new DVFrame();
   }
+
+  // TODO: Use save state
+
   delete f;
   if(enc) delete enc;
 
   printf("Connection end[pid: %d]...\n", getpid());
   
 }
-/*
-int main(int argc, char *argv[])
-{
-}
-*/
diff --git a/src/util.h b/src/util.h
index b82b782..7921e41 100644
--- a/src/util.h
+++ b/src/util.h
@@ -22,6 +22,9 @@
 #ifndef __RTVIDEOREC_UTIL_H
 #define __RTVIDEOREC_UTIL_H
 
+#include <stdio.h>
+//#include <stdlib.h>
+
 //#ifdef __cplusplus
 //extern "C" {
 //#endif
-- 
cgit v1.2.3