summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/aboutwindow.cc92
-rw-r--r--client/aboutwindow.h83
-rw-r--r--client/camera.cc182
-rw-r--r--client/camera.h109
-rw-r--r--client/config.h33
-rw-r--r--client/cprlisten.cc106
-rw-r--r--client/cprlisten.h62
-rw-r--r--client/cprquerydialog.cc486
-rw-r--r--client/cprquerydialog.h170
-rw-r--r--client/debug.h103
-rw-r--r--client/decoder.cc286
-rw-r--r--client/decoder.h99
-rw-r--r--client/dv.h33
-rw-r--r--client/dv1394.cc175
-rw-r--r--client/dv1394.h55
-rw-r--r--client/encoder.cc273
-rw-r--r--client/encoder.h118
-rw-r--r--client/historywidget.cc77
-rw-r--r--client/historywidget.h52
-rw-r--r--client/info_gui.cc144
-rw-r--r--client/info_gui.h86
-rw-r--r--client/mainwindow.cc575
-rw-r--r--client/mainwindow.h193
-rw-r--r--client/messagebox.cc245
-rw-r--r--client/messagebox.h112
-rw-r--r--client/miav_client.cc60
-rw-r--r--client/miav_client.h42
-rw-r--r--client/player.cc322
-rw-r--r--client/player.h142
-rw-r--r--client/videowidget.cc76
-rw-r--r--client/videowidget.h57
-rw-r--r--client/yuv_draw.cc241
-rw-r--r--client/yuv_draw.h70
33 files changed, 4959 insertions, 0 deletions
diff --git a/client/aboutwindow.cc b/client/aboutwindow.cc
new file mode 100644
index 0000000..8743ed8
--- /dev/null
+++ b/client/aboutwindow.cc
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * aboutwindow.cc
+ *
+ * Sun Aug 22 21:57:49 2004
+ * Copyright 2004 deva
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "aboutwindow.h"
+
+#include <qpainter.h>
+#include <qfont.h>
+
+#include <config.h>
+
+#define MARGIN 12
+AboutWindow::AboutWindow( QWidget* parent, const char* name )
+ : QDialog( parent, name )
+{
+ setModal(true);
+ pix_about = new QPixmap();
+ pix_about->load( PIXMAP_ABOUT );
+
+ resize(pix_about->width(), pix_about->height());
+
+ setBackgroundColor(QColor(200,200,200));
+
+ btn_ok = new QPushButton(this);
+ btn_ok->setText("OK");
+ btn_ok->resize( 140, 50 );
+ btn_ok->move(pix_about->width() - btn_ok->width() - MARGIN, pix_about->height() - btn_ok->height() - MARGIN);
+ btn_ok->setFont( QFont( "Arial", 12, QFont::Bold ) );
+
+ QObject::connect( btn_ok, SIGNAL(clicked()), this, SLOT(close()) );
+
+ show();
+}
+
+AboutWindow::~AboutWindow()
+{
+}
+
+void AboutWindow::mouseReleaseEvent(QMouseEvent *event)
+{
+ close();
+}
+
+void AboutWindow::paintEvent( QPaintEvent *event )
+{
+ int version_x = 58;
+ int version_y = 90;
+
+ if(!event) return; // Just to get rid og the compile warning!
+ QPainter painter;
+ painter.begin(this);
+
+ // Draw background
+ painter.drawPixmap(0,0, *pix_about);
+
+ // Draw title and version
+ painter.setBrush( SolidPattern );
+ painter.setFont( QFont( "Arial", 18, QFont::Bold ) );
+ painter.setPen( Qt::black );
+ painter.drawText(version_x, version_y, "MIAV-Grab v" VERSION);
+ painter.setPen( Qt::red );
+ painter.drawText(version_x + 2, version_y + 2, "MIAV-Grab v" VERSION);
+
+ painter.end();
+}
+
+#endif /*USE_GUI*/
diff --git a/client/aboutwindow.h b/client/aboutwindow.h
new file mode 100644
index 0000000..f87a10e
--- /dev/null
+++ b/client/aboutwindow.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * aboutwindow.h
+ *
+ * Sun Aug 22 21:58:22 2004
+ * Copyright 2004 deva
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __ABOUTWINDOW_H__
+#define __ABOUTWINDOW_H__
+
+#include <qdialog.h>
+//#include <qlabel.h>
+#include <qpixmap.h>
+//#include <qtextedit.h>
+#include <qpushbutton.h>
+
+#define PIXMAP_ABOUT PIXMAPS"/about.png"
+/*
+#define ABOUT_INFO "\
+Official homepage:\n\
+ http://www.aasimon.org/miav\n\
+Author:\n\
+ Bent Bisballe (deva@aasimon.org)\n\
+Copyright (c) 2004"
+
+#define GPL_LICENSE "\
+This program is free software; you can\n\
+redistribute it and/or modify it under the terms\n\
+of the GNU General Public License as published\n\
+by the Free Software Foundation; either version\n\
+2 of the License, or (at your option) any later\n\
+version.\n\
+ This program is distributed in the hope that\n\
+it will be useful, but WITHOUT ANY WARRANTY;\n\
+without even the implied warranty of\n\
+MERCHANTABILITY or FITNESS FOR A PARTI-\n\
+CULAR PURPOSE. See the GNU Library General\n\
+Public License for more details.\n\
+ You should have received a copy of the GNU\n\
+General Public License along with this program;\n\
+if not, write to the Free Software Foundation,\n\
+Inc., 59 Temple Place - Suite 330, Boston,\n\
+MA 02111-1307, USA."
+*/
+class AboutWindow : public QDialog
+{
+ Q_OBJECT
+public:
+ AboutWindow(QWidget* parent = 0, const char* name = 0);
+ ~AboutWindow();
+ virtual void paintEvent( QPaintEvent *event );
+ void mouseReleaseEvent(QMouseEvent *event);
+
+private:
+ QPushButton *btn_ok;
+ QPixmap *pix_about;
+};
+
+#endif /* __ABOUTWINDOW_H__ */
+
+#endif /*USE_GUI*/
diff --git a/client/camera.cc b/client/camera.cc
new file mode 100644
index 0000000..5dbec13
--- /dev/null
+++ b/client/camera.cc
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * camera.cc
+ *
+ * Fri Oct 29 12:46:38 CEST 2004
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "camera.h"
+
+Camera::Camera(Info *ginfo)
+{
+ info = ginfo;
+}
+
+void Camera::connect(const char *ip, const int port, int width, int height)
+{
+ initialized = false;
+
+ pthread_mutex_init (&mutex, NULL);
+ //mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ running = 1;
+
+ encode_queue = new Queue<Frame>(); // infinite size
+ player_queue = new Queue<Frame>(1); // fixed size of 1
+
+ sem_init(&encode_sem, 0, 0);
+ sem_init(&player_sem, 0, 0);
+
+ decoder = new Decoder(info,
+ &encode_sem,
+ &player_sem,
+ encode_queue,
+ player_queue,
+ &mutex,
+ &running);
+
+ encoder = new Encoder(info,
+ ip, port,
+ &encode_sem,
+ encode_queue,
+ &mutex,
+ &running);
+
+ player = new Player(info,
+ width, height,
+ &running,
+ &player_sem,
+ player_queue,
+ &mutex);
+
+ decoder->run();
+ encoder->run();
+ player->run();
+
+ initialized = true;
+}
+
+Camera::~Camera()
+{
+ // Signal to the threads to stop
+ running = 0;
+
+ // Wait for the threads to stop
+ decoder->wait_stop();
+ encoder->wait_stop();
+ player->wait_stop();
+
+ delete decoder;
+ delete encoder;
+ delete player;
+
+ sem_destroy(&encode_sem);
+ sem_destroy(&player_sem);
+
+ delete player_queue;
+ delete encode_queue;
+}
+
+void Camera::setCpr(char *newcpr, char* name)
+{
+
+ if(initialized) {
+ encoder->setCpr(newcpr);
+ player->setCpr(newcpr, name); // For the text overlay
+ } else {
+ info->error("Camera not initialized.");
+ }
+}
+
+
+void Camera::start()
+{
+ if(initialized) {
+ player->startrecord(); // For the text overlay
+ encoder->start();
+ decoder->start();
+ } else {
+ info->error("Camera not initialized.");
+ }
+}
+
+void Camera::stop(n_savestate save)
+{
+ if(initialized) {
+ player->stoprecord(); // For the textoverlay
+ encoder->stop(save);
+ decoder->stop(save);
+ } else {
+ info->error("Camera not initialized.");
+ }
+}
+
+void Camera::freeze()
+{
+ if(initialized) {
+ player->stop();
+ decoder->freeze();
+ } else {
+ info->error("Camera not initialized.");
+ }
+}
+
+void Camera::unfreeze()
+{
+ if(initialized) {
+ player->start();
+ decoder->unfreeze();
+ } else {
+ info->error("Camera not initialized.");
+ }
+}
+
+void Camera::snapshot(unsigned char *rgb)
+{
+ if(initialized) {
+ decoder->shoot(rgb);
+ encoder->shoot();
+ } else {
+ info->error("Camera not initialized.");
+ }
+}
+
+int Camera::getQueueLength()
+{
+ return encode_queue->length();
+}
+
+void Camera::resize(int w, int h, bool s)
+{
+ player->resize(w,h,s);
+}
+
+void Camera::setMute(bool mute)
+{
+ decoder->setMute(mute);
+ player->setMute(mute);
+}
+
+#endif/* USE_GUI */
diff --git a/client/camera.h b/client/camera.h
new file mode 100644
index 0000000..a0b849a
--- /dev/null
+++ b/client/camera.h
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * camera.h
+ *
+ * Fri Oct 29 12:46:38 CEST 2004
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __CAMERA_H__
+#define __CAMERA_H__
+
+#include <string>
+using namespace std;
+#include "info.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+//#include <avformat.h>
+
+#include "util.h"
+#include "queue.h"
+#include "decoder.h"
+#include "encoder.h"
+#include "player.h"
+#include "package.h"
+
+#include "thread.h"
+#include "frame.h"
+
+#include <qwidget.h>
+
+/**
+ * This class represents the symbolic representation of the camera and
+ * the network functionality.
+ */
+class Camera {
+public:
+ Camera(Info *ginfo);
+ ~Camera();
+ void connect(const char *ip,
+ const int port,
+ int width, int height);
+
+ void setCpr(char *newcpr, char* name);
+
+ // Camera actions
+ void start();
+ void stop(n_savestate save);
+ void freeze();
+ void unfreeze();
+ void snapshot(unsigned char *rgb);
+
+ int getQueueLength();
+
+ // Indirect call to player->resize
+ void resize(int width, int height, bool showtext);
+
+ void setMute(bool mute);
+
+private:
+ // Info object passed to all sub objects.
+ Info *info;
+ bool initialized;
+
+ /* // No need for these anymore
+ pthread_t playertid;
+ pthread_t decodetid;
+ pthread_t encodetid;
+ */
+ volatile int running;
+
+ Encoder *encoder;
+ Decoder *decoder;
+ Player *player;
+
+ Queue<Frame> *encode_queue;
+ Queue<Frame> *player_queue;
+ sem_t encode_sem;
+ sem_t player_sem;
+ pthread_mutex_t mutex;// = PTHREAD_MUTEX_INITIALIZER;
+};
+
+
+#endif/*__CAMERA_H__*/
+
+#endif/* USE_GUI */
diff --git a/client/config.h b/client/config.h
new file mode 100644
index 0000000..e7101c9
--- /dev/null
+++ b/client/config.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * config.h
+ *
+ * Thu Jul 28 12:46:38 CEST 2005
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __CONFIG_IS_LOADED__
+#define __CONFIG_IS_LOADED__
+
+#include "../config.h"
+
+#endif/*__CONFIG_IS_LOADED__*/
diff --git a/client/cprlisten.cc b/client/cprlisten.cc
new file mode 100644
index 0000000..0a4958e
--- /dev/null
+++ b/client/cprlisten.cc
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: tab; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * cprlisten.cc
+ *
+ * Tue Dec 27 17:05:42 CET 2005
+ * Copyright 2005 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of the Aasimon c++ framework.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * It is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with it; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cprlisten.h"
+#include "aa_socket.h"
+
+#include <iostream>
+#include <string>
+using namespace std;
+
+#define MAGIC_STOP_STRING "SHUTTHEFUCKUP"
+
+CPRListen::CPRListen(Info *info, unsigned short port)
+{
+ this->info = info;
+ this->port = port;
+ cpr = "N/A";
+ cprchanged = false;
+ running = true;
+}
+
+CPRListen::~CPRListen()
+{
+}
+
+void CPRListen::stop()
+{
+ running = false;
+ try {
+ AASocket socket;
+ socket.connect("localhost", port);
+ socket.send_string(MAGIC_STOP_STRING);
+ } catch(Network_error &e) {
+ info->error("In stop(): %s.", e.error.c_str());
+ }
+}
+
+void CPRListen::thread_main()
+{
+ info->log("Listening for CPRs.");
+ while(running) {
+ try {
+ string newcpr;
+ AASocket socket;
+ socket.listen(port);
+ newcpr = socket.receive_string();
+
+ if(newcpr == MAGIC_STOP_STRING) {
+ running = false;
+ } else {
+ mutex.lock();
+ cprchanged = true;
+ cpr = newcpr;
+ mutex.unlock();
+ info->log("Got CPR: %s.", cpr.c_str());
+ }
+
+ } catch(Network_error &e) {
+ info->error("In thread_main(): %s.", e.error.c_str());
+ running = false;
+ }
+ }
+ info->log("Stopped listening for CPRs.");
+}
+
+bool CPRListen::cprChanged()
+{
+ return cprchanged;
+}
+
+string CPRListen::getCpr()
+{
+ string cpr_copy;
+
+ mutex.lock();
+ cpr_copy = cpr;
+ mutex.unlock();
+
+ cprchanged = false;
+
+ return cpr_copy;
+}
diff --git a/client/cprlisten.h b/client/cprlisten.h
new file mode 100644
index 0000000..012fe4c
--- /dev/null
+++ b/client/cprlisten.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: tab; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * cprlisten.h
+ *
+ * Tue Dec 27 17:05:42 CET 2005
+ * Copyright 2005 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of the Aasimon c++ framework.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * It is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with it; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __AASIMON_FRAMEWORK_CPRLISTEN_H__
+#define __AASIMON_FRAMEWORK_CPRLISTEN_H__
+
+#include <string>
+
+#include "thread.h"
+#include "mutex.h"
+
+#include "aa_socket.h"
+#include "info.h"
+
+class CPRListen: public Thread {
+public:
+ CPRListen(Info *info, unsigned short port);
+ ~CPRListen();
+
+ bool cprChanged();
+ std::string getCpr();
+ void thread_main();
+
+ void stop(); // Stops the call to listen
+
+private:
+ Info *info;
+
+ volatile bool running;
+ AASocket *socket;
+
+ bool cprchanged;
+ unsigned short port;
+ std::string cpr;
+ Mutex mutex;
+};
+
+#endif/*__AASIMON_FRAMEWORK_CPRLISTEN_H__*/
diff --git a/client/cprquerydialog.cc b/client/cprquerydialog.cc
new file mode 100644
index 0000000..19337a4
--- /dev/null
+++ b/client/cprquerydialog.cc
@@ -0,0 +1,486 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * cprquerydialog.cc
+ *
+ * Sat Feb 19 17:05:43 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include <qframe.h>
+
+#include "messagebox.h"
+#include "cprquerydialog.h"
+#include "miav_config.h"
+
+CPRQueryDialog::CPRQueryDialog(Info *info,
+ QLabel *lcpr,
+ QLabel *lname,
+ QWidget *parent,
+ const char *name,
+ QStatusBar *status)
+ : QDialog(parent, name, TRUE)
+{
+ this->info = info;
+ setCaption(name);
+
+ // Load image
+ QPixmap pix_backspace;
+ pix_backspace.load( PIXMAP_BACKSPACE );
+
+ lbl_name = lname;
+ lbl_cpr = lcpr;
+ statusbar = status;
+
+ //Read configuration
+ CPR_HOST = config->readString("cpr_host");
+ CPR_PORT = config->readInt("cpr_port");
+ CPR_TIMEOUT = config->readInt("cpr_timeout");
+
+ cpr[0] = '\0';
+ internalCpr[0] = '\0';
+
+ cprSocket = new QSocket(this);
+ connect(cprSocket, SIGNAL(readyRead()), SLOT(cprSocket_readyRead()));
+ connect(cprSocket, SIGNAL(connected()), SLOT(cprSocket_connected()));
+ connect(cprSocket, SIGNAL(error(int)), SLOT(cprSocket_error(int)));
+
+ lbl_cpr->setText("Indtast CPR");
+
+ // Setup connection timer
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(cprSocket_timeout()));
+
+ // Generate input buttons
+ QGridLayout *gl = new QGridLayout(this, 4, 3, 10, 2);
+
+ QButton *b1 = createButton(this, "1", 1);
+ QButton *b2 = createButton(this, "2", 2);
+ QButton *b3 = createButton(this, "3", 3);
+ QButton *b4 = createButton(this, "4", 4);
+ QButton *b5 = createButton(this, "5", 5);
+ QButton *b6 = createButton(this, "6", 6);
+ QButton *b7 = createButton(this, "7", 7);
+ QButton *b8 = createButton(this, "8", 8);
+ QButton *b9 = createButton(this, "9", 9);
+ QButton *b0 = createButton(this, "0", 0);
+ QButton *bbs = createButton(this, "", 10);
+ bbs->setPixmap(pix_backspace);
+ QButton *bca = createButton(this, "CA", 11);
+
+ gl->addWidget(b1, 0,0);
+ gl->addWidget(b2, 0,1);
+ gl->addWidget(b3, 0,2);
+ gl->addWidget(b4, 1,0);
+ gl->addWidget(b5, 1,1);
+ gl->addWidget(b6, 1,2);
+ gl->addWidget(b7, 2,0);
+ gl->addWidget(b8, 2,1);
+ gl->addWidget(b9, 2,2);
+ gl->addWidget(b0, 3,1);
+ gl->addWidget(bbs, 3,2);
+ gl->addWidget(bca, 3,0);
+
+ // Setup signals
+ connect(b1, SIGNAL(clicked()), SLOT(b_1_clicked()));
+ connect(b2, SIGNAL(clicked()), SLOT(b_2_clicked()));
+ connect(b3, SIGNAL(clicked()), SLOT(b_3_clicked()));
+ connect(b4, SIGNAL(clicked()), SLOT(b_4_clicked()));
+ connect(b5, SIGNAL(clicked()), SLOT(b_5_clicked()));
+ connect(b6, SIGNAL(clicked()), SLOT(b_6_clicked()));
+ connect(b7, SIGNAL(clicked()), SLOT(b_7_clicked()));
+ connect(b8, SIGNAL(clicked()), SLOT(b_8_clicked()));
+ connect(b9, SIGNAL(clicked()), SLOT(b_9_clicked()));
+ connect(b0, SIGNAL(clicked()), SLOT(b_0_clicked()));
+ connect(bbs,SIGNAL(clicked()), SLOT(b_b_clicked()));
+ connect(bca,SIGNAL(clicked()), SLOT(b_c_clicked()));
+
+ this->move(175,150);
+
+ listen = new CPRListen(info, config->readInt("cprlisten_port"));
+ listen_timer = new QTimer(this);
+ connect(listen_timer, SIGNAL(timeout()), SLOT(listen_timeout()));
+ listen->run();
+ listen_timer->start(500); // Check every 500 ms
+
+ show();
+}
+
+CPRQueryDialog::~CPRQueryDialog()
+{
+ // Cleanup
+ // delete timer;
+ // delete cprSocket
+
+ // Cleanup after cpr listen
+ listen->stop();
+ // listen->wait_stop();
+ delete listen;
+ // delete listen_timer;
+}
+
+void CPRQueryDialog::listen_timeout()
+{
+ string newcpr;
+ if(listen->cprChanged()) {
+ char newcpr_buf[32];
+ newcpr = listen->getCpr();
+ sprintf(newcpr_buf, "%s-%s", newcpr.substr(0,6).c_str(), newcpr.substr(6,4).c_str());
+ // printf("cprbuf[%s]\n", newcpr_buf);
+ lbl_cpr->setText(newcpr_buf);
+ verifycpr(newcpr_buf);
+ }
+}
+
+/**
+ * createButton:
+ * A genric button-creater
+ */
+QPushButton *CPRQueryDialog::createButton(QWidget *parent, const char *text, int value)
+{
+ char buf[32];
+ sprintf(buf, "%d", value);
+ QPushButton *q = new QPushButton(this, buf);
+
+ QFont f("Lucida", 48);
+ q->setFixedSize(150, 100);
+ q->setText(text);
+ q->setFont(f);
+ return q;
+}
+
+/**
+ * Event functions for handling buttonclicks.
+ * For button 0-9 the values is sent back.
+ * Backspace and clear are handled via special
+ * signals.
+ * When 10 digits has been input we close the form
+ */
+void CPRQueryDialog::b_1_clicked() { insert_digit(1); }
+void CPRQueryDialog::b_2_clicked() { insert_digit(2); }
+void CPRQueryDialog::b_3_clicked() { insert_digit(3); }
+void CPRQueryDialog::b_4_clicked() { insert_digit(4); }
+void CPRQueryDialog::b_5_clicked() { insert_digit(5); }
+void CPRQueryDialog::b_6_clicked() { insert_digit(6); }
+void CPRQueryDialog::b_7_clicked() { insert_digit(7); }
+void CPRQueryDialog::b_8_clicked() { insert_digit(8); }
+void CPRQueryDialog::b_9_clicked() { insert_digit(9); }
+void CPRQueryDialog::b_0_clicked() { insert_digit(0);}
+void CPRQueryDialog::b_b_clicked() { remove_digit();}
+void CPRQueryDialog::b_c_clicked() { remove_all();}
+
+void CPRQueryDialog::b_clicked(int value)
+{
+ printf("%d\n", value);
+ switch(value) {
+ case 10:
+ if (digits>0) digits--;
+ emit bbs_clicked();
+ break;
+ case 11:
+ digits = 0;
+ emit bca_clicked();
+ break;
+ default:
+ digits++;
+ emit number_clicked(value);
+ }
+ if (digits == 10){
+ digits = 0;
+ accept();
+ }
+}
+
+/**
+ * remove_digit:
+ * Remove one digit from the selected cpr
+ * Used when the user pushes backspace in
+ * the inputwindow
+ */
+void CPRQueryDialog::remove_digit()
+{
+ int temp;
+ temp = strlen(cpr);
+ if (temp == 7) /* Remove two characters due to the hyphen */
+ strcpy(cpr+temp-2, "\0");
+ else if ((temp >0) && (temp <=11))
+ strcpy(cpr+temp-1, "\0");
+ lbl_cpr->setText(cpr);
+}
+
+/**
+ * remove_all:
+ * Clear the selected cpr
+ */
+void CPRQueryDialog::remove_all()
+{
+ strcpy(cpr, "");
+ lbl_cpr->setText(cpr);
+}
+
+/**
+ * insert_digit:
+ * Respond to what the user types in the inputWindow
+ */
+void CPRQueryDialog::insert_digit(int value)
+{
+ char temp[2];
+ switch(strlen(cpr)) {
+ case 5: // Automaticaly add a hyphen after the sixth digit
+ sprintf(temp, "%d-", value);
+ strcat(cpr, temp);
+ lbl_cpr->setText(cpr);
+ break;
+ case 10:
+ sprintf(temp, "%d", value);
+ strcat(cpr, temp);
+ lbl_cpr->setText(cpr);
+ verifycpr(cpr);
+ break;
+ default:
+ sprintf(temp, "%d", value);
+ strcat(cpr, temp);
+ lbl_cpr->setText(cpr);
+ break;
+ }
+}
+
+/**
+ * verifycpr:
+ * Test a cpr via test_cpr().
+ * If cpr is invalid, then ask user what
+ * to do via MessageBox
+ */
+void CPRQueryDialog::verifycpr(char *cpr)
+{
+ strncpy(internalCpr, cpr, 6);
+ strncpy(internalCpr+6, cpr+7, 4);
+ internalCpr[10] = 0;
+
+ if (!(test_cpr(internalCpr))) {
+ MessageBox ccw(this, CONFIRM_INVALID_CPR_TITLE, CONFIRM_INVALID_CPR, TYPE_YES_NO_CANCEL);
+ switch(ccw.exec()) {
+ case MSG_CANCEL:
+ bedit_clicked();
+ break;
+ case MSG_NO:
+ bcancel_clicked();
+ break;
+ case MSG_YES:
+ // Overwrite name from previous cpr.
+ lbl_name->setText(NAME_NOT_AVAILABLE);
+ accept();
+ break;
+ }
+ } else {
+ cprSocket->connectToHost(CPR_HOST->c_str(), CPR_PORT);
+ timer->start(CPR_TIMEOUT);
+ // accept();
+ }
+}
+
+
+/* Clears all data - alerts user if measurements are not stored */
+void CPRQueryDialog::bcancel_clicked()
+{
+ cpr[0]= '\0';
+ lbl_cpr->setText("Indtast CPR");
+ lbl_name->setText("");
+}
+
+/* This is used when the user enters a cpr that is not valid and wishes to edit
+ * the cpr.
+ */
+void CPRQueryDialog::bedit_clicked()
+{
+ cpr[10]= '\0';
+ lbl_cpr->setText(cpr);
+ lbl_name->setText("");
+}
+
+
+/**
+ * test_cpr:
+ * Checks that a cpr i valid via a modulo 11 test
+ */
+int CPRQueryDialog::test_cpr(const char *s)
+{
+ int sum = 0;
+ int ctl;
+ const char *cptr;
+
+ // Is the string to short to be a cpr?
+ if(strlen(s) != 10) return 0;
+
+ // Are all characters digits?
+ for(cptr = s; *cptr; cptr++) if(!isdigit(*cptr)) return 0;
+
+ // Calculate modulo 11 checksum
+ sum += (s[0] - '0') * 4;
+ sum += (s[1] - '0') * 3;
+ sum += (s[2] - '0') * 2;
+ sum += (s[3] - '0') * 7;
+ sum += (s[4] - '0') * 6;
+ sum += (s[5] - '0') * 5;
+ sum += (s[6] - '0') * 4;
+ sum += (s[7] - '0') * 3;
+ sum += (s[8] - '0') * 2;
+ ctl = 11 - (sum % 11);
+
+ // Is the checksum correct?
+ if(ctl == 11) ctl = 0;
+ return s[9] - '0' == ctl;
+}
+
+/**
+ * cprSocket_error
+ * Called if an error occurres in the corsocket connection.
+ * Writes out the appropriate error message.
+ */
+void CPRQueryDialog::cprSocket_error(int errnum)
+{
+ QString msg = QString("cprSocket encountered an error: ");
+ timer->stop();
+
+ lbl_name->setText(NAME_NOT_AVAILABLE);
+
+ // Print error message
+ switch(errnum) {
+ case QSocket::ErrConnectionRefused: // if the connection was refused
+ msg.append("ErrConnectionRefused");
+ break;
+ case QSocket::ErrHostNotFound: // if the host was not found
+ msg.append("ErrHostNotFound");
+ break;
+ case QSocket::ErrSocketRead: // if a read from the socket failed
+ msg.append("ErrSocketRead");
+ break;
+ }
+
+ if(statusbar) statusbar->message(msg, 5000);
+ MessageBox(this, "Fejl", msg, TYPE_OK, ICON_ERROR).exec();
+ //info->error(msg.c_str());
+ accept();
+}
+
+/**
+ * cprSocket_readyRead:
+ * Uses a patients cpr to look up his or hers name
+ * via the departments cpr-server.
+ * This is called by the cprSocket when the socket is ready
+ */
+void CPRQueryDialog::cprSocket_readyRead()
+{
+ QString name;
+ QString firstname;
+ QString lastname;
+ int timeout = 0;
+
+ if (!cprSocket->canReadLine()) return;
+
+ QString msg = QString("Recieving name from cpr database...");
+ if(statusbar) statusbar->message(msg, 5000);
+ timer->stop();
+
+ while(cprSocket->canReadLine()) {
+ QString s = cprSocket->readLine();
+ if (s.startsWith("0001")) {
+ name.append(s.right(s.length()-4));
+ lastname.append(s.right(s.length()-4));
+ name.setLength(name.length()-1);
+ if (name.length()) name += QString(", ");
+ }
+ if (s.startsWith("0002")) {
+ name.append(s.right(s.length()-4));
+ firstname.append(s.right(s.length()-4));
+ name.setLength(name.length()-1);
+ cprSocket->close();
+ lbl_name->setText(name);
+ accept();
+ return;
+ }
+ if (timeout>1000) {
+ lbl_name->setText(NAME_NOT_AVAILABLE);
+ MessageBox(this, NAME_NOT_AVAILABLE_TITLE, NAME_NOT_AVAILABLE, TYPE_OK, ICON_ERROR).exec();
+ accept();
+ return;
+ }
+ timeout++;
+ }
+
+ accept();
+}
+
+
+/**
+ * cprSocket_connected:
+ * Writes the selected cpr to the cpr-server
+ * when the cprSocket is connected.
+ */
+void CPRQueryDialog::cprSocket_connected()
+{
+ QString msg = QString("Connected to cpr database, sending cpr number...");
+ if(statusbar) statusbar->message(msg, 5000);
+ timer->stop();
+
+ cprSocket->writeBlock(internalCpr, 10);
+ cprSocket->writeBlock("\n", 1);
+}
+
+/**
+ * cprSocket_timeout:
+ * Called when the connection has not emitted a signal in CPR_TIMEOUT miliseconds.
+ */
+void CPRQueryDialog::cprSocket_timeout()
+{
+ QString msg = QString("cprSocket timed out doing: ");
+ timer->stop();
+
+ lbl_name->setText(NAME_NOT_AVAILABLE);
+
+
+ // Print connection status
+ switch(cprSocket->state()) {
+ case QSocket::Idle: // if there is no connection
+ msg.append("Idle");
+ break;
+ case QSocket::HostLookup: // during a DNS lookup
+ msg.append("HostLookup");
+ break;
+ case QSocket::Connecting: // during TCP connection establishment
+ msg.append("Connecting");
+ break;
+ case QSocket::Connected: // when there is an operational connection
+ msg.append("Conected");
+ break;
+ case QSocket::Closing: // if the socket is closing down, but is not yet closed.
+ msg.append("Closing");
+ break;
+ }
+
+ if(statusbar) statusbar->message(msg, 5000);
+ MessageBox(this, "Fejl", msg, TYPE_OK, ICON_ERROR).exec();
+ accept();
+}
+
+#endif /* USE_GUI */
diff --git a/client/cprquerydialog.h b/client/cprquerydialog.h
new file mode 100644
index 0000000..85b2659
--- /dev/null
+++ b/client/cprquerydialog.h
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * cprquerydialog.h
+ *
+ * Sat Feb 19 17:05:42 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __MIAV_CPRQUERYDIALOG_H__
+#define __MIAV_CPRQUERYDIALOG_H__
+
+/**
+ * Text
+ */
+#define NAME_NOT_AVAILABLE_TITLE "Databasefejl"
+#define NAME_NOT_AVAILABLE "Kunne ikke slĺ navn op i cpr-database."
+
+#define CONFIRM_INVALID_CPR_TITLE "Bekrćft"
+#define CONFIRM_INVALID_CPR "Ugyldigt CPR nummer, brug det alligevel?"
+
+
+/**
+ * Images
+ */
+#define PIXMAP_BACKSPACE PIXMAPS"/backspace.png"
+
+
+/**
+ * Includes
+ */
+#include <qdialog.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfont.h>
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qdialog.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+
+#include <qsocket.h>
+#include <qtextedit.h>
+#include <qstring.h>
+#include <qwidget.h>
+
+#include <qevent.h>
+
+#include <qpushbutton.h>
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qdialog.h>
+
+#include <string>
+using namespace std;
+
+#include <qdialog.h>
+#include <qlabel.h>
+#include <qsocket.h>
+#include <qtimer.h>
+#include <qstatusbar.h>
+
+#include "messagebox.h"
+
+#include "cprlisten.h"
+
+#include "info.h"
+
+class CPRQueryDialog : public QDialog {
+ Q_OBJECT
+public:
+ CPRQueryDialog(Info *info,
+ QLabel *lcpr,
+ QLabel *lname,
+ QWidget * parent = 0,
+ const char * name = 0,
+ QStatusBar *status = NULL);
+ ~CPRQueryDialog();
+
+public slots:
+ void bcancel_clicked();
+ void bedit_clicked();
+ void remove_digit();
+ void remove_all();
+ void insert_digit(int value);
+ void cprSocket_readyRead();
+ void cprSocket_connected();
+ void cprSocket_error(int errnum);
+ void cprSocket_timeout();
+ void listen_timeout();
+
+
+private:
+ Info *info;
+
+ CPRListen *listen;
+ QTimer *listen_timer;
+
+ QStatusBar *statusbar;
+
+ QLabel *lbl_cpr;
+ QLabel *lbl_name;
+
+ QSocket *cprSocket;
+ char cpr[12];
+ char internalCpr[11];
+
+ void verifycpr(char *cpr);
+ // void run(int pos);
+ int test_cpr(const char *s);
+
+ /*Configuration*/
+ string *CPR_HOST;
+ int CPR_PORT;
+ int CPR_TIMEOUT;
+
+signals:
+ void bbs_clicked();
+ void bca_clicked();
+ void number_clicked(int);
+
+public slots:
+ void b_1_clicked();
+ void b_2_clicked();
+ void b_3_clicked();
+ void b_4_clicked();
+ void b_5_clicked();
+ void b_6_clicked();
+ void b_7_clicked();
+ void b_8_clicked();
+ void b_9_clicked();
+ void b_0_clicked();
+ void b_b_clicked();
+ void b_c_clicked();
+
+private:
+ void b_clicked(int value);
+ QPushButton *createButton(QWidget *parent, const char *text, int value);
+ int digits;
+
+ QTimer *timer;
+};
+
+#endif /* USE_GUI */
+
+#endif/*__MIAV_CPRQUERYDIALOG_H__*/
diff --git a/client/debug.h b/client/debug.h
new file mode 100644
index 0000000..48c0830
--- /dev/null
+++ b/client/debug.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * debug.h
+ *
+ * Tue Apr 12 14:34:20 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifndef __MIAV_DEBUG_H__
+#define __MIAV_DEBUG_H__
+
+//#define DEBUG_ALLOC
+
+#ifdef DEBUG_ALLOC
+typedef struct _A_{
+ struct _A_* prev;
+ struct _A_* next;
+ char name[32];
+ void *addr;
+} __debug__;
+
+__debug__ *debug_first = NULL;
+
+inline void debugAlloc(void *p, char* name)
+{
+ __debug__ *d = debug_first;
+
+ fprintf(stderr, "Adding %d - %s\n", p, name);
+
+ debug_first = (__debug__*)malloc(sizeof(__debug__));
+ debug_first->prev = NULL;
+ debug_first->next = d;
+ if(d) d->prev = debug_first;
+ debug_first->addr = p;
+ strcpy(debug_first->name, name);
+}
+
+inline void debugFree(void *p)
+{
+ __debug__ *d = debug_first;
+
+ while(d && d->addr != p) {
+ d = d->next;
+ }
+
+ if(!d) {
+ fprintf(stderr, "ERROR: memory address not found %d - perhaps already freed!\n", p);
+ exit(1);
+ }
+
+ fprintf(stderr, "Removing %d - %s\n", p, d->name);
+ __debug__ *next = d->next;
+ __debug__ *prev = d->prev;
+ if(prev) prev->next = d->next;
+ if(next) next->prev = d->prev;
+ if(debug_first == d) debug_first = next;
+ free(d);
+}
+
+inline void debugPrint()
+{
+ __debug__ *d = debug_first;
+
+ fprintf(stderr, "Alloc List:\n");
+
+ while(d) {
+ fprintf(stderr, "\t[%d] %s\n", d->addr, d->name);
+ d = d->next;
+ }
+}
+
+#define FREE(x) debugFree(x)
+#define ALLOC(x, y) debugAlloc(x, y)
+#define PRINT() debugPrint()
+
+#else/*DEBUG_ALLOC*/
+
+#define FREE(x) {}
+#define ALLOC(x, y) {}
+#define PRINT() {}
+
+#endif/*DEBUG_ALLOC*/
+
+#endif/*__MIAV_DEBUG_H__*/
diff --git a/client/decoder.cc b/client/decoder.cc
new file mode 100644
index 0000000..0d56aca
--- /dev/null
+++ b/client/decoder.cc
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * decoder.cc
+ *
+ * Sat Feb 19 17:05:43 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * Originally from:
+ * RTVideoRec Realtime video recoder and encoder for Linux
+ *
+ * Copyright (C) 2004 B. Stultiens
+ * Copyright (C) 2004 Koen Otter and Glenn van der Meyden
+ */
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "frame_stream.h"
+
+#include "miav_config.h"
+
+#include <time.h>
+
+// Use libdv
+#include <libdv/dv.h>
+#include <libdv/dv_types.h>
+
+#include <SDL/SDL.h>
+
+#include "dv.h"
+#include "dvfile.h"
+#include "dv1394.h"
+
+#include "decoder.h"
+#include "debug.h"
+
+Decoder::Decoder(Info *ginfo,
+ sem_t *gencode_sem,
+ sem_t *gplayer_sem,
+ Queue<Frame> *gencode_queue,
+ Queue<Frame> *gplayer_queue,
+ pthread_mutex_t *gmutex,
+ volatile int *grunning)
+{
+ info = ginfo;
+
+ encode_sem = gencode_sem;
+ player_sem = gplayer_sem;
+ encode_queue = gencode_queue;
+ player_queue = gplayer_queue;
+ mutex = gmutex;
+ running = grunning;
+
+ b_shoot = false;
+ b_freeze = false;
+ b_record = false; // Initially no recording is done.
+
+ pthread_mutex_init (&shot_mutex, NULL);
+ shot = NULL;
+
+ mute = false;
+}
+
+Decoder::~Decoder()
+{
+ pthread_mutex_destroy(&shot_mutex);
+}
+
+void Decoder::decode()
+{
+ frame_stream *dvstream;
+
+ bool local_shoot;
+ int local_freeze;
+ bool local_record = false;
+ bool old_record;
+
+ bool skip_frames = config->readInt("player_skip_frames");
+
+ dv1394 dv1394_stream = dv1394(info); // Use default port and channel.
+ dvfile dvfile_stream = dvfile(info);
+ if(dv1394_stream.connect()) {
+ // Use the dv1394 stream for input.
+ dvstream = &dv1394_stream;
+ } else {
+ // Use the fallback dv filereader for input.
+ dvstream = &dvfile_stream;
+ }
+
+ while(*running) {
+ uint8_t *ptr;
+ SDL_Event user_event;
+
+ // Read a dvframe
+ ptr = dvstream->readFrame();
+ if(!ptr) return; // No frame read. (Due to dv read error)
+
+ old_record = local_record;
+ local_shoot = b_shoot;
+ b_shoot = false;
+ local_freeze = b_freeze;
+ b_freeze = false;
+ local_record = b_record;
+
+ if(local_shoot) {
+ pthread_mutex_lock(&shot_mutex);
+ if(!shot) shot = new Frame(ptr, DVPACKAGE_SIZE);
+ pthread_mutex_unlock(&shot_mutex);
+ }
+
+ if(local_freeze == 1) {
+ pthread_mutex_lock(&shot_mutex);
+ if(shot) delete shot;
+ shot = new Frame(ptr, DVPACKAGE_SIZE);
+ pthread_mutex_unlock(&shot_mutex);
+ }
+
+ static int showframe = 1;
+ if(skip_frames != 0) showframe = 1 - showframe;
+ if(showframe) {
+ Frame *pframe = new Frame(ptr, DVPACKAGE_SIZE);
+
+ pframe->shoot = local_shoot;
+ pframe->freeze = local_freeze;
+ pframe->record = local_record;
+
+ player_queue->push(pframe);
+
+ // Create and send SDL event.
+ user_event.type = SDL_USEREVENT;
+ user_event.user.code = 0;
+ user_event.user.data1 = NULL;
+ user_event.user.data2 = NULL;
+ SDL_PushEvent(&user_event);
+ }
+
+ if(local_record | (local_record != old_record) | local_shoot | local_freeze) {
+ Frame *eframe = new Frame(NULL, 0);
+ eframe->data = ptr;
+ eframe->size = DVPACKAGE_SIZE;
+
+ eframe->shoot = local_shoot;
+ eframe->freeze = local_freeze;
+ eframe->record = local_record;
+ eframe->mute = mute;
+
+ encode_queue->push(eframe);
+
+ sem_post(encode_sem);
+ } else {
+ free(ptr);
+ }
+ }
+
+ // Kick the others so they wake up with empty queues
+ sem_post(encode_sem);
+}
+
+void Decoder::thread_main() {
+ decode();
+ fprintf(stderr, "Decoder thread stopped.\n"); fflush(stderr);
+}
+
+/*
+ * Set freeze bit on current frame.
+ */
+void Decoder::freeze()
+{
+ b_freeze = 1;
+}
+
+/*
+ * Remove frozen frame.
+ */
+void Decoder::unfreeze()
+{
+ b_freeze = -1;
+
+ pthread_mutex_lock(&shot_mutex);
+ delete shot;
+ shot = NULL;
+ pthread_mutex_unlock(&shot_mutex);
+}
+
+/*
+ * Set shoot bit on current frame.
+ */
+void Decoder::shoot(unsigned char *rgb)
+{
+ struct timespec ts;
+
+ b_shoot = true;
+
+ // Wait for shot to be taken
+ while(1) {
+ pthread_mutex_lock(&shot_mutex);
+ if(shot) {
+ getScreenshot(shot, rgb);
+ delete shot;
+ shot = NULL;
+ pthread_mutex_unlock(&shot_mutex);
+ return;
+ }
+ pthread_mutex_unlock(&shot_mutex);
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100000000L; // 100ms
+ nanosleep(&ts, NULL);
+ }
+}
+
+/*
+ * Set the record bit to true in all following frames.
+ */
+void Decoder::start()
+{
+ b_record = true;
+}
+
+/*
+ * Set the record bit to false in all following frames.
+ */
+void Decoder::stop(n_savestate save)
+{
+ b_record = false;
+}
+
+void Decoder::getScreenshot(Frame *frame, unsigned char *rgb)
+{
+ unsigned char *pixels[3];
+ int pitches[3];
+
+ pixels[ 0 ] = rgb;
+ pixels[ 1 ] = NULL;
+ pixels[ 2 ] = NULL;
+
+ pitches[ 0 ] = 720 * 4;
+ pitches[ 1 ] = 0;
+ pitches[ 2 ] = 0;
+
+ dv_decoder_t *decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE);
+ decoder->quality = DV_QUALITY_BEST;
+
+ dv_parse_header(decoder, frame->data);
+
+ decoder->system = e_dv_system_625_50; // PAL lines, PAL framerate
+ decoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v
+ decoder->std = e_dv_std_iec_61834;
+ decoder->num_dif_seqs = 12;
+
+ // libdv img decode to rgb
+ dv_decode_full_frame(decoder,
+ frame->data,
+ e_dv_color_bgr0,
+ pixels,
+ pitches);
+
+ dv_decoder_free(decoder);
+}
+
+void Decoder::setMute(bool m)
+{
+ mute = m;
+}
+
+#endif /*USE_GUI*/
diff --git a/client/decoder.h b/client/decoder.h
new file mode 100644
index 0000000..20878c7
--- /dev/null
+++ b/client/decoder.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * decoder.h
+ *
+ * Sat Feb 19 17:05:42 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * Originally from:
+ * RTVideoRec Realtime video recoder and encoder for Linux
+ *
+ * Copyright (C) 2004 B. Stultiens
+ */
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __RTVIDEOREC_DECODER_H
+#define __RTVIDEOREC_DECODER_H
+
+#include "info.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "queue.h"
+#include "encoder.h"
+#include "player.h"
+
+#include "thread.h"
+#include "frame.h"
+
+class Decoder : public Thread {
+public:
+ Decoder(Info *ginfo,
+ sem_t *gencode_sem,
+ sem_t *gplayer_sem,
+ Queue<Frame> *gencode_queue,
+ Queue<Frame> *gplayer_queue,
+ pthread_mutex_t *gmutex,
+ volatile int *grunning);
+ ~Decoder();
+ void thread_main();
+
+ void freeze();
+ void unfreeze();
+ void shoot(unsigned char *rgb);
+ void start();
+ void stop(n_savestate save);
+ void setMute(bool mute);
+
+private:
+ volatile bool mute;
+
+ void getScreenshot(Frame *frame, unsigned char *rgb);
+
+ pthread_mutex_t shot_mutex;
+ Frame* shot;
+
+ volatile int b_freeze;
+ volatile bool b_shoot;
+ volatile bool b_record;
+
+ Info *info;
+ // AVCodecContext dvcodec;
+
+ sem_t *encode_sem;
+ sem_t *player_sem;
+ Queue<Frame> *encode_queue;
+ Queue<Frame> *player_queue;
+ pthread_mutex_t *mutex;
+ volatile int *running;
+
+ void decode();
+};
+
+#endif/* __RTVIDEOREC_DECODER_H*/
+
+#endif/*USE_GUI*/
diff --git a/client/dv.h b/client/dv.h
new file mode 100644
index 0000000..e346d03
--- /dev/null
+++ b/client/dv.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * dv.h
+ *
+ * Thu Apr 14 19:29:55 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifndef __MIAV_DV_H__
+#define __MIAV_DV_H__
+
+#define DVPACKAGE_SIZE 144000
+
+#endif/*__MIAV_DV_H__*/
diff --git a/client/dv1394.cc b/client/dv1394.cc
new file mode 100644
index 0000000..270da2e
--- /dev/null
+++ b/client/dv1394.cc
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * dv1394.cc
+ *
+ * Tue Apr 19 12:10:34 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#include "dv1394.h"
+
+#ifdef USE_GUI
+
+#include "dv.h"
+
+
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+
+/**
+ * Callback function for the firewire interface.
+ */
+static int raw_reader( raw1394handle_t handle, int channel, size_t length, quadlet_t *data )
+{
+ static char *framedata = NULL;
+
+ // Only process packets with reasonable length.
+ if ( length > 16 )
+ {
+ unsigned char * p = ( unsigned char* ) & data[ 3 ];
+ int section_type = p[ 0 ] >> 5; // section type is in bits 5 - 7
+ int dif_sequence = p[ 1 ] >> 4; // dif sequence number is in bits 4 - 7
+ int dif_block = p[ 2 ];
+
+ if ( section_type == 0 && dif_sequence == 0 )
+ {
+ if ( framedata != NULL )
+ {
+ raw1394_set_userdata(handle, (void *)framedata);
+ framedata = NULL;
+ }
+ }
+
+ if(!framedata)
+ {
+ framedata = (char *)malloc(DVPACKAGE_SIZE); // dvframe.h
+ if(!framedata)
+ {
+ // We're fucked
+ fprintf(stderr, "Framedata allocation error: %s.\n", strerror( errno ) ); fflush(stderr);
+ exit(1);
+ }
+ }
+
+ switch ( section_type )
+ {
+ case 0: // 1 Header block
+ // p[3] |= 0x80; // hack to force PAL data
+ memcpy( framedata + dif_sequence * 150 * 80, p, 480 );
+ break;
+
+ case 1: // 2 Subcode blocks
+ memcpy( framedata + dif_sequence * 150 * 80 + ( 1 + dif_block ) * 80, p, 480 );
+ break;
+
+ case 2: // 3 VAUX blocks
+ memcpy( framedata + dif_sequence * 150 * 80 + ( 3 + dif_block ) * 80, p, 480 );
+ break;
+
+ case 3: // 9 Audio blocks interleaved with video
+ memcpy( framedata + dif_sequence * 150 * 80 + ( 6 + dif_block * 16 ) * 80, p, 480 );
+ break;
+
+ case 4: // 135 Video blocks interleaved with audio
+ memcpy( framedata + dif_sequence * 150 * 80 + ( 7 + ( dif_block / 15 ) + dif_block ) * 80, p, 480 );
+ break;
+
+ default: // we can't handle any other data
+ break;
+ }
+ }
+ return 0;
+}
+
+dv1394::dv1394(Info *i, int p, int c)
+{
+ info = i;
+ port = p;
+ channel = c;
+}
+
+dv1394::~dv1394()
+{
+ // Close firewire connection.
+ if(handle) raw1394_destroy_handle(handle);
+}
+
+bool dv1394::connect()
+{
+ int n_ports;
+ struct raw1394_portinfo pinf[ 16 ];
+
+ // Get handle to firewire channels
+ handle = raw1394_new_handle();
+ if(!handle) {
+ info->error("raw1394 - failed to get handle: %s.", strerror( errno ) );
+ return false;
+ }
+
+ // how many adapters are hooked in?
+ if((n_ports = raw1394_get_port_info(handle, pinf, 16)) < 0 ) {
+ info->error("raw1394 - failed to get port info: %s.", strerror( errno ) );
+ raw1394_destroy_handle(handle);
+ handle = NULL;
+ return false;
+ }
+
+ // Tell raw1394 which host adapter to use
+ if(raw1394_set_port(handle, port) < 0 ) {
+ info->error("raw1394 - failed to set port: %s.", strerror( errno ) );
+ raw1394_destroy_handle(handle);
+ handle = NULL;
+ return false;
+ }
+
+ raw1394_set_iso_handler( handle, channel, raw_reader);
+ raw1394_set_userdata( handle, ( void* ) NULL);
+ raw1394_start_iso_rcv( handle, channel);
+
+ return true;
+}
+
+unsigned char *dv1394::readFrame()
+{
+ // Firewire port not correctly opened.
+ if(!handle) return NULL;
+
+ unsigned char *ptr;
+ while(1) {
+ raw1394_loop_iterate(handle);
+ ptr = (unsigned char *)raw1394_get_userdata(handle);
+ if(ptr) {
+ raw1394_set_userdata(handle, NULL);
+ break;
+ }
+ }
+ return ptr;
+}
+
+#endif/*USE_GUI*/
diff --git a/client/dv1394.h b/client/dv1394.h
new file mode 100644
index 0000000..7cea9d0
--- /dev/null
+++ b/client/dv1394.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * dv1394.h
+ *
+ * Tue Apr 19 12:10:34 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifndef __MIAV_DV1394_H__
+#define __MIAV_DV1394_H__
+
+#ifdef USE_GUI
+
+#include "frame_stream.h"
+#include <libraw1394/raw1394.h>
+
+#include "info.h"
+
+class dv1394 : public frame_stream {
+public:
+ dv1394(Info* info, int port = 0, int channel = 63); // 63 is default channel... sucks.
+ ~dv1394();
+
+ bool connect();
+
+ unsigned char *readFrame();
+
+private:
+ raw1394handle_t handle;
+ Info *info;
+ int port;
+ int channel;
+};
+
+#endif/*__MIAV_DV1394_H__*/
+#endif/*USE_GUI*/
diff --git a/client/encoder.cc b/client/encoder.cc
new file mode 100644
index 0000000..e7b79bf
--- /dev/null
+++ b/client/encoder.cc
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * encoder.cc
+ *
+ * Tue Apr 19 12:10:34 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * Originally from:
+ * RTVideoRec Realtime video recoder and encoder for Linux
+ *
+ * Copyright (C) 2004 B. Stultiens
+ * Copyright (C) 2004 Koen Otter and Glenn van der Meyden
+ */
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "util.h"
+#include "encoder.h"
+
+Encoder::Encoder(Info *ginfo,
+ const char *gip,
+ const int gport,
+ sem_t *gsem,
+ Queue<Frame> *gqueue,
+ pthread_mutex_t *gmutex,
+ volatile int *grunning)
+{
+ info = ginfo;
+
+ strcpy(ip, gip);
+ port = gport;
+ memset(cpr, 0, sizeof(cpr));
+
+ sem = gsem;
+ queue = gqueue;
+ mutex = gmutex;
+ running = grunning;
+
+ // record = 0;
+
+ sem_init(&record_sem, 0, 0);
+
+ s = NULL;
+ n = NULL;
+
+ frozen = false;
+
+ savestate_sent = false;
+ savestate = NO_CHANGE;
+
+ // shoot_request = 0;
+ // shoot_value = 0;
+ // freeze_request = 0;
+ // freeze_value = 0;
+}
+
+
+Encoder::~Encoder()
+{
+ // If a hanging connection exists, we better close it.
+ /* // Already deleted in thread_main
+ if(s) {
+ if(n) delete n;
+ delete s;
+ s = NULL;
+ n = NULL;
+ }
+ */
+}
+
+
+void Encoder::encode()
+{
+ Frame *frame;
+
+ while(*running) {
+ sem_wait(sem);
+
+ frame = queue->pop();
+
+ if(frame) {
+ if(frame->freeze == 1) frozen = true;
+ if(frame->freeze == -1) frozen = false;
+ if(frame->shoot) frozen = false;
+
+ if(frame->record ||
+ (frame->freeze == 1) ||
+ frame->shoot) {
+
+ // If no connection is present, make a new one
+ if(!s) {
+ s = new Socket(port, info);
+ s->sconnect(ip);
+ n = new Network(s, info);
+ }
+
+ n_header h;
+
+ if(savestate != NO_CHANGE) savestate_sent = true;
+
+ h.header_type = DATA_HEADER;
+ sprintf(h.header.h_data.cpr, cpr);
+ h.header.h_data.freeze = frame->freeze;
+ h.header.h_data.snapshot = frame->shoot;
+ h.header.h_data.record = frame->record;
+ h.header.h_data.savestate = savestate;//NO_CHANGE;
+ h.header.h_data.mute = frame->mute;
+
+ savestate = NO_CHANGE; // only transmit once!
+
+ // if(freeze_request != freeze_value) freeze_value = freeze_request;
+ // if(shoot_request != shoot_value) shoot_value = shoot_request;
+
+ n->sendPackage(&h, frame->data, frame->size);
+ } else {
+ // When frozen we need to preserve the connection in order to
+ // remember the frozen frame on the server side.
+ if(!frozen) {
+ // No data is to be sent, if we have a connection, destroy it.
+ if(s) {
+ if(n) delete n;
+ delete s;
+ s = NULL;
+ n = NULL;
+ }
+ }
+ }
+
+ if(frame->shoot && !frozen && !frame->record) {
+ // FIXME: This is ugly!
+ // Bugfix... connection not cleared, when an 'unfrozen' snapshot is taken,
+ // and no recording is done.
+ if(s) {
+ if(n) delete n;
+ delete s;
+ s = NULL;
+ n = NULL;
+ }
+ }
+
+ if(frame) delete frame;
+ }
+ }
+}
+
+
+void Encoder::setCpr(char *newcpr)
+{
+ strcpy(cpr, newcpr);
+}
+
+
+void Encoder::freeze()
+{
+ /*
+ if(!s) {
+ s = new Socket(port, errobj);
+ s->sconnect(ip);
+ n = new Network(s, errobj);
+ }
+ */
+ // if(!errobj->hasError()) freeze_request = 1 - freeze_request;
+}
+
+
+/*
+ * shoot
+ * Set the shoot bit in the network header on the current frame.
+ * return the decodet (rgba) version af that frame, for thumbnail show.
+ */
+void Encoder::shoot()
+{
+ /*
+ if(!s) {
+ s = new Socket(port, errobj);
+ s->sconnect(ip);
+ n = new Network(s, errobj);
+ }
+ */
+ // if(!errobj->hasError()) shoot_request = 1 - shoot_request;
+ // getScreenshot(rgb);
+}
+
+
+void Encoder::thread_main()
+{
+ encode();
+ if(s) {
+ if(n) delete n;
+ delete s;
+ s = NULL;
+ n = NULL;
+ }
+ fprintf(stderr, "Encoder thread stopped.\n"); fflush(stderr);
+}
+
+
+void Encoder::start()
+{
+ savestate = NO_CHANGE;
+ savestate_sent = false;
+ /*
+ if(!s) {
+ s = new Socket(port, errobj);
+ s->sconnect(ip);
+ n = new Network(s, errobj);
+ }
+ */
+ // if(!errobj->hasError()) record = 1;
+}
+
+
+void Encoder::stop(n_savestate save)
+{
+ savestate = save;
+ // Don't return until we are sure the savestate has been sent.
+ while(savestate_sent == false) {
+ // Just wait a while (in a while!)
+ sleep_0_2_frame();
+ }
+/*
+ struct timespec ts;
+ // TODO: set save state in package header.
+
+ // Lock the queue and wait until all elements are sent on the network.
+ queue->lock();
+ fprintf(stderr, "Emptying queue"); fflush(stderr);
+ while(queue->peek()) {
+ // Remove any late buffer
+ // We don't care, the encoder finishes them all
+ ts.tv_sec = 0;
+ ts.tv_nsec = 500000000L; // 100ms
+ fprintf(stderr, "."); fflush(stderr);
+ nanosleep(&ts, NULL);
+ }
+ fprintf(stderr, "done!\n"); fflush(stderr);
+
+ record = 0;
+
+ queue->unlock();
+*/
+/*
+ if(s) {
+ if(n) delete n;
+ delete s;
+ s = NULL;
+ n = NULL;
+ }
+*/
+}
+
+#endif /*USE_GUI*/
diff --git a/client/encoder.h b/client/encoder.h
new file mode 100644
index 0000000..0fada07
--- /dev/null
+++ b/client/encoder.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * encoder.h
+ *
+ * Thu Apr 14 19:29:55 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * Originally from:
+ * RTVideoRec Realtime video recoder and encoder for Linux
+ *
+ * Copyright (C) 2004 B. Stultiens
+ */
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __RTVIDEOREC_ENCODER_H
+#define __RTVIDEOREC_ENCODER_H
+
+#include "thread.h"
+
+#include "info.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+//#include <avformat.h>
+
+#include "miav.h"
+#include "util.h"
+#include "package.h"
+#include "frame.h"
+#include "queue.h"
+
+// FIXME: One size fits all...
+#define VIDEO_BUFFER_SIZE (1024*1024)
+
+
+/**
+ * This class contains code for sending the video stream and the snapshots
+ * over the network, to the MIaV server.
+ */
+class Encoder : public Thread {
+public:
+ Encoder(Info* ginfo,
+ const char *gip,
+ const int gport,
+ sem_t *gsem,
+ Queue<Frame> *gqueue,
+ pthread_mutex_t *gmutex,
+ volatile int *grunning);
+ ~Encoder();
+
+ void setCpr(char *newcpr);
+
+ void start();
+ void stop(n_savestate save);
+
+ void freeze();
+ void shoot();
+
+ void thread_main();
+
+ // AVFormatContext *fc;
+ sem_t *sem;
+ Queue<Frame> *queue;
+ pthread_mutex_t *mutex;
+ volatile int *running;
+
+private:
+ Info *info;
+
+ int port;
+ char ip[32];
+ char cpr[32];
+
+ bool frozen;
+
+ // volatile int record;
+
+ // volatile int shoot_request;
+ // int shoot_value;
+ // volatile int freeze_request;
+ // int freeze_value;
+
+ volatile bool savestate_sent;
+ volatile n_savestate savestate;
+
+ sem_t record_sem;
+ void encode();
+
+ Socket *s;
+ Network *n;
+};
+
+#endif
+
+#endif /*USE_GUI*/
diff --git a/client/historywidget.cc b/client/historywidget.cc
new file mode 100644
index 0000000..bdeb880
--- /dev/null
+++ b/client/historywidget.cc
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * historywidget.cc
+ *
+ * Wed Jul 27 14:00:37 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+#include "historywidget.h"
+
+#include "miav_config.h"
+
+HistoryWidget::HistoryWidget(QWidget *p) : QLabel(p)
+{
+ parent = p;
+ image = NULL;
+}
+
+HistoryWidget::~HistoryWidget()
+{
+ if(image) delete image;
+}
+
+void HistoryWidget::set_image(QImage *i)
+{
+ if(image) delete image;
+
+ image = new QImage(*i);
+
+ QImage resized = image->smoothScale(width(), height());
+ setPixmap(resized);
+}
+
+QImage * HistoryWidget::get_image()
+{
+ return image;
+}
+
+static HistoryWidget *fs = NULL;
+
+void HistoryWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if(!parent) { // We are a fullscreen window
+ destroy();
+ } else { // We are a nested window
+ // Delete old instances before going fullscreen.
+ if(fs) delete fs;
+
+ fs = new HistoryWidget(NULL);
+ fs->showFullScreen();
+ fs->setFixedWidth(config->readInt("pixel_width"));
+ fs->setFixedHeight(config->readInt("pixel_height"));
+ fs->set_image(image);
+ }
+}
+
+#endif/*USE_GUI*/
diff --git a/client/historywidget.h b/client/historywidget.h
new file mode 100644
index 0000000..d464d59
--- /dev/null
+++ b/client/historywidget.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * historywidget.h
+ *
+ * Wed Jul 27 14:00:37 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+#ifndef __MIAV_HISTORYWIDGET_H__
+#define __MIAV_HISTORYWIDGET_H__
+
+#include <qlabel.h>
+#include <qimage.h>
+
+class HistoryWidget : public QLabel {
+Q_OBJECT
+public:
+ HistoryWidget(QWidget *parent);
+ ~HistoryWidget();
+
+ void set_image(QImage *image);
+ QImage *get_image();
+
+ void mouseReleaseEvent(QMouseEvent *event);
+
+private:
+ QImage *image;
+ QWidget *parent;
+};
+
+#endif/*__MIAV_HISTORYWIDGET_H__*/
+#endif/*USE_GUI*/
diff --git a/client/info_gui.cc b/client/info_gui.cc
new file mode 100644
index 0000000..aa831b6
--- /dev/null
+++ b/client/info_gui.cc
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * info_gui.cc
+ *
+ * Tue May 3 09:34:59 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "info_gui.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <time.h>
+
+bool InfoEventHandler::eventFilter( QObject *o, QEvent *e )
+{
+ if ( e->type() == TYPE_SHOW_MESSAGEBOX ) {
+ // fprintf(stderr, "Custom event!\n"); fflush(stderr);
+ MessageBox *msgbox = ((ShowMessageEvent*)e)->messagebox();
+ msgbox->exec();
+ delete msgbox;
+ return TRUE; // eat event
+ } else {
+ // standard event processing
+ return FALSE;
+ }
+}
+
+InfoGui::InfoGui(QApplication *a, QWidget *p, MiavConfig *c): Info()
+{
+ this->config = c;
+ log_filename = *(this->config->readString("client_log_file"));
+
+ qapp = a;
+ parent = p;
+
+ pthread_mutex_init (&mutex, NULL);
+}
+
+InfoGui::~InfoGui()
+{
+ pthread_mutex_destroy(&mutex);
+}
+
+void InfoGui::setParent(QWidget *p)
+{
+ parent = p;
+}
+
+void InfoGui::showmsg(char *msg, char *title, msg_icon icon)
+{
+ pthread_mutex_lock(&mutex);
+ // Beginning of safezone
+
+ fprintf(stderr, "%s: %s\n", title, msg); fflush(stderr);
+
+ while( !parent ) {
+ struct timespec ts;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 200000000L; // 200ms
+ nanosleep(&ts, NULL);
+ }
+
+ MessageBox *msgbox = new MessageBox(parent,
+ title,
+ msg,
+ TYPE_OK,
+ icon);
+
+ ShowMessageEvent *event = new ShowMessageEvent( msgbox );
+
+ qapp->postEvent(parent, event);
+
+ // End of safezone
+ pthread_mutex_unlock(&mutex);
+}
+
+void InfoGui::error(char *fmt, ...)
+{
+ char buf[1024];
+
+ va_list argp;
+ va_start(argp, fmt);
+ vsprintf(buf, fmt, argp);
+ va_end(argp);
+
+ showmsg(buf, TXT_ERROR_TITLE, ICON_ERROR);
+
+ log("Error: %s", buf);
+}
+
+void InfoGui::warn(char *fmt, ...)
+{
+ char buf[1024];
+
+ va_list argp;
+ va_start(argp, fmt);
+ vsprintf(buf, fmt, argp);
+ va_end(argp);
+
+ showmsg(buf, TXT_WARNING_TITLE, ICON_WARNING);
+
+ log("Warning: %s", buf);
+}
+
+void InfoGui::info(char *fmt, ...)
+{
+ char buf[1024];
+
+ va_list argp;
+ va_start(argp, fmt);
+ vsprintf(buf, fmt, argp);
+ va_end(argp);
+
+ showmsg(buf, TXT_INFO_TITLE, ICON_INFO);
+
+ log("Info: %s", buf);
+}
+
+
+#endif/*USE_GUI*/
diff --git a/client/info_gui.h b/client/info_gui.h
new file mode 100644
index 0000000..a4f5135
--- /dev/null
+++ b/client/info_gui.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * info_gui.h
+ *
+ * Tue May 3 09:34:59 CEST 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifndef __MIAV_INFO_GUI_H__
+#define __MIAV_INFO_GUI_H__
+
+#ifdef USE_GUI
+
+#define TXT_ERROR_TITLE "Der er opstĺet en fejl!"
+#define TXT_WARNING_TITLE "Advarsel"
+#define TXT_INFO_TITLE "Information"
+
+#include "info.h"
+
+#include "miav_config.h"
+
+#include <qwidget.h>
+#include <qapplication.h>
+
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "messagebox.h"
+
+#define TYPE_SHOW_MESSAGEBOX 65432
+
+class ShowMessageEvent : public QCustomEvent {
+public:
+ ShowMessageEvent( MessageBox* msgbox )
+ : QCustomEvent( TYPE_SHOW_MESSAGEBOX ), m( msgbox ) {}
+ MessageBox *messagebox() const { return m; }
+private:
+ MessageBox *m;;
+};
+
+class InfoEventHandler : public QObject {
+protected:
+ bool eventFilter( QObject *o, QEvent *e );
+};
+
+
+class InfoGui: public Info {
+public:
+ InfoGui(QApplication *a, QWidget *p, MiavConfig *config);
+ ~InfoGui();
+
+ void error(char* fmt, ...);
+ void warn(char* fmt, ...);
+ void info(char* fmt, ...);
+
+ void setParent(QWidget *p);
+
+private:
+ void showmsg(char *msg, char *title, msg_icon icon);
+
+ QApplication *qapp;
+ QWidget *parent;
+};
+
+#endif/*__MIAV_INFO_GUI_H__*/
+
+#endif/*USE_GUI*/
diff --git a/client/mainwindow.cc b/client/mainwindow.cc
new file mode 100644
index 0000000..ce3d9bb
--- /dev/null
+++ b/client/mainwindow.cc
@@ -0,0 +1,575 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * mainwindow.cc
+ *
+ * Sat Aug 21 19:49:34 2004
+ * Copyright 2004 deva
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "mainwindow.h"
+
+#include <qpainter.h>
+#include <qpicture.h>
+
+#include <qpushbutton.h>
+#include <qfont.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+
+#include <qstatusbar.h>
+
+#include <math.h>
+
+//#include "mgui_alert.h"
+//#include "mgui_datasocket.h"
+
+#include "miav_config.h"
+
+#include <config.h>
+//"miav-grab.h"
+
+//#define WITH_DV
+MainWindow::MainWindow(QApplication *qApp, QWidget* parent, const char* name )
+ : QWidget( parent, name, WStyle_Customize | WStyle_NoBorder )
+{
+ info = new InfoGui(qApp, this, config);
+
+ info->log("Starting MIaV v. %s.", VERSION);
+
+ video_width = config->readInt("video_width");
+ video_height = config->readInt("video_height");
+
+ int resolution_w = config->readInt("pixel_width");
+ int resolution_h = config->readInt("pixel_height");
+
+ unit = ((float)resolution_w / config->readFloat("screensize")) / INCH_IN_CM;
+
+ printf("Unit: %f\n", unit);
+
+ move(0,0);
+ resize(resolution_w, resolution_h);
+
+ // Load icons
+ img_record = loadButtonIcon( PIXMAP_RECORD );
+ img_stop = loadButtonIcon( PIXMAP_STOP );
+ img_freeze = loadButtonIcon( PIXMAP_FREEZE );
+ img_unfreeze = loadButtonIcon( PIXMAP_UNFREEZE );
+ img_cpr = loadButtonIcon( PIXMAP_CPR );
+ img_clear = loadButtonIcon( PIXMAP_CLEAR );
+ img_snapshot = loadButtonIcon( PIXMAP_SNAPSHOT );
+ img_logo = loadButtonIcon( PIXMAP_LOGO_SMALL, 1 );
+ img_mute = loadButtonIcon( PIXMAP_MUTE );
+ img_unmute = loadButtonIcon( PIXMAP_UNMUTE );
+
+ img_dummy = loadImage( PIXMAP_DUMMY );
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(redraw_edge()));
+ rec_edge_counter = 0.0f;
+
+ // This must be defined before the gui i created (img_live uses it as parameter)
+ camera = new Camera(info);
+
+ createGui();
+ show();
+
+ camera->connect(config->readString("server_addr")->c_str(),
+ config->readInt("server_port"),
+ img_live->width(), img_live->height());
+
+ // Make sure this is created *after* the camera object!
+ taskbartimer = new QTimer(this);
+ connect(taskbartimer, SIGNAL(timeout()), SLOT(taskbar_update()));
+ taskbartimer->start(200);
+
+ recording = false;
+ frozen = false;
+ muted = false;
+
+ info->log("MIaV is ready.");
+
+ // Open the CPR Dialog
+ cpr_clicked();
+
+}
+
+MainWindow::~MainWindow()
+{
+ info->log("MIaV is shutting down.");
+
+ delete img_history;
+ delete camera;
+ delete btn_cpr;
+
+ info->log("MIaV is shut down.");
+}
+
+QImage *MainWindow::loadButtonIcon( char *name, int height )
+{
+
+ QImage scaled;
+ QImage *img;
+
+ img = new QImage();
+ img->load( name );
+
+ int h = (int)(height * unit);
+ int w = (int)((float)img->width() / (float)(img->height() / (float)h));
+
+ scaled = img->smoothScale(w, h);
+ delete img;
+ img = new QImage(scaled);
+
+ return img;
+}
+
+QImage *MainWindow::loadImage( char *name )
+{
+ QImage *img;
+
+ img = new QImage();
+ img->load( name );
+
+ return img;
+}
+
+void MainWindow::createGui()
+{
+ // Layout widgets
+
+ /* __________________________________________________
+ *(0) ___________________________ | ______________ |
+ * | | | | | | | | | |
+ * |(1) | | | | |(2) | |
+ * | | | | | | | | | |
+ * | | | | | | | | | |
+ * | | | | | | | |______________| |
+ * | | | | | | | | | |
+ * | | | | | | | | | |
+ * | | | | | | | | | |
+ * | |______|______|______|______| | | | |
+ * | | | | | | | |______________| |
+ * | |______|______|______|______| | | | |
+ * | | | | | | | | | |
+ * | |______|______|______|______| | | | |
+ * | | | | | | | | | |
+ * | |______|______|______|______| | |______________| |
+ * |_______________________________|__________________|
+ * |_______________________________|__________________|
+ */
+
+ QGridLayout *g0 = new QGridLayout(this, 2, 2, 0, -1);
+ QGridLayout *g1 = new QGridLayout(4, 4, -1);
+ g0->addLayout(g1, 0, 0);
+
+ QGroupBox *gb = new QGroupBox(this);
+ // gb->setRows(NUM_HISTORY);
+ gb->setColumns(1);
+ // gb->setTitle("fisk");
+ // QGridLayout *g2 = new QGridLayout(1, NUM_HISTORY, -1);
+ // QVBoxLayout *g2 = new QVBoxLayout(this);
+ // g0->addLayout(g2, 0, 1);
+
+ gb->setInsideMargin(HISTORY_LIST_MARGIN);
+ gb->setInsideSpacing(HISTORY_LIST_SPACING);
+ gb->setFlat(true);
+ g0->addWidget(gb, 0, 1);
+
+ int resolution_w = config->readInt("pixel_width");
+ int resolution_h = config->readInt("pixel_height");
+
+ int output_width = resolution_w - // this->width() -
+ (int)(BUTTON_WIDTH * unit) -
+ (gb->insideMargin() * 2) -
+ g1->margin() * 2 -
+ g0->margin() * 2;
+
+ int output_height = resolution_h - // this->height() -
+ (int)(3 * BUTTON_HEIGHT * unit) -
+ g1->margin() * 5 -
+ g0->margin() * 3;
+
+ img_recedge = new QLabel(this);
+ img_recedge->setBackgroundColor(QColor(160,160,160));
+ img_recedge->setFixedSize(output_width, output_height);
+
+ img_live = new VideoWidget(img_recedge, camera);
+ img_live->setFixedSize(output_width - 20, output_height - 20);
+ img_live->move(10,10);
+ g1->addMultiCellWidget ( img_recedge, 0, 0, 0, 3, Qt::AlignHCenter);
+ // QObject::connect( img_live, SIGNAL(clicked()), this, SLOT(live_clicked()) );
+
+ // CPR/NAME LABEL + CPR button
+ lbl_cpr = createLabel("", output_width - (int)(BUTTON_WIDTH * unit), BUTTON_HEIGHT);
+ g1->addMultiCellWidget ( lbl_cpr, 1, 1, 0, 2);
+
+ btn_cpr = createButton("");
+ btn_cpr->setFocus();
+ btn_cpr->setPixmap(*img_cpr);
+ QObject::connect( btn_cpr, SIGNAL(clicked()), this, SLOT(cpr_clicked()) );
+ // Will also be connected in the MGUI code
+ g1->addWidget(btn_cpr, 1, 3);
+
+ lbl_name = createLabel("", output_width, (int)(BUTTON_HEIGHT * 0.8f));
+ g1->addMultiCellWidget ( lbl_name, 2, 2, 0, 3);
+/*
+ btn_clear = createButton("");
+ btn_clear->setPixmap(*img_clear);
+ QObject::connect( btn_clear, SIGNAL(clicked()), this, SLOT(clear_clicked()) );
+ // Will also be connected in the MGUI code
+ g1->addWidget(btn_clear, 1, 2);
+*/
+ // Rec + Shot + Freeze buttons
+ btn_rec = createButton("");
+ btn_rec->setPixmap(*img_record);
+ QObject::connect( btn_rec, SIGNAL(clicked()), this, SLOT(rec_clicked()) );
+ g1->addWidget(btn_rec, 3, 0);
+
+ btn_shoot = createButton("");
+ btn_shoot->setPixmap(*img_snapshot);
+ QObject::connect( btn_shoot, SIGNAL(clicked()), this, SLOT(shoot_clicked()) );
+ g1->addWidget(btn_shoot, 3, 1);
+
+ btn_freeze = createButton("");
+ btn_freeze->setPixmap(*img_freeze);
+ QObject::connect( btn_freeze, SIGNAL(clicked()), this, SLOT(freeze_clicked()) );
+ g1->addWidget(btn_freeze, 3, 2);
+
+ btn_mute = createButton("");
+ btn_mute->setPixmap(*img_unmute);
+ QObject::connect( btn_mute, SIGNAL(clicked()), this, SLOT(mute_clicked()) );
+ g1->addWidget(btn_mute, 3, 3);
+
+ // History widgets
+ int w = (int)((float)BUTTON_WIDTH * unit);
+ int h = (int)(576.0f / (720.0f / ((float)BUTTON_WIDTH * unit)));
+
+ int window_height = config->readInt("pixel_height");
+ this->num_history = (window_height -
+ ((int)unit * BUTTON_HEIGHT + HISTORY_LIST_SPACING ) -
+ (2 * HISTORY_LIST_MARGIN)) / (h + HISTORY_LIST_SPACING);
+ img_history = new HistoryWidget*[this->num_history];
+
+ for(unsigned int i = 0; i < num_history; i++) {
+ img_history[i] = new HistoryWidget(gb);
+ img_history[i]->set_image(img_dummy);
+ img_history[i]->setFixedSize(w, h);
+ }
+
+ // Clear button
+ btn_clear = createButton("", gb);
+ btn_clear->setPixmap(*img_clear);
+ QObject::connect( btn_clear, SIGNAL(clicked()), this, SLOT(clear_clicked()) );
+
+ // Statusbar
+ status = new QStatusBar(this);
+ status->setSizeGripEnabled(FALSE);
+ // status->setFont(QFont( "Sans Serif", (int)(unit * height / 3), QFont::Normal ));
+ g0->addMultiCellWidget(status, 4, 4, 0, 1);
+
+ lbl_recordtime = createLabel("", BUTTON_WIDTH, 1);
+ lbl_recordtime->setFixedWidth((int)(BUTTON_WIDTH * unit) +
+ (gb->insideMargin() * 2) +
+ g1->margin() * 2 +
+ g0->margin() * 2);
+ status->addWidget(lbl_recordtime, 0, TRUE);
+
+ // About button
+ btn_about = new QPushButton("", this);
+ btn_about->setFixedHeight((int)unit);
+ btn_about->setPixmap(*img_logo);
+ QObject::connect( btn_about, SIGNAL(clicked()), this, SLOT(about_clicked()) );
+ status->addWidget(btn_about, 0, TRUE);
+
+ // Version label
+ lbl_version = createLabel("MIaV-Grab v" VERSION, BUTTON_WIDTH, 1);
+ lbl_version->setFixedWidth((int)(BUTTON_WIDTH * unit) +
+ (gb->insideMargin() * 2) +
+ g1->margin() * 2 +
+ g0->margin() * 2);
+ status->addWidget(lbl_version, 0, TRUE);
+
+ status->message( TXT_READY );
+}
+
+
+QPushButton *MainWindow::createButton(char *caption, int width, int height)
+{
+ return createButton(caption, this);//, width, height);
+}
+
+
+QPushButton *MainWindow::createButton(char *caption, QWidget *parent, int width, int height)
+{
+ QPushButton *btn = new QPushButton(caption, parent);
+ btn->setFont( QFont( "Sans Serif", (int)(unit * height / 2), QFont::Bold ) );
+ btn->setFixedHeight((int)(unit * height));
+ // btn->setFixedWidth((int)(unit * width));
+ return btn;
+}
+
+
+QLabel *MainWindow::createLabel(char *caption, int width, int height)
+{
+ QLabel *lbl = new QLabel(caption, this);
+ lbl->setFont( QFont( "Sans Serif",
+ //(height>1)?(int)(unit * height / 2):(int)(unit * height / 2),
+ (int)(unit * height / 2),
+ (height>1)?QFont::Bold:QFont::Normal ) );
+ lbl->setFixedHeight((int)(unit * height));
+ // lbl->setFixedWidth((int)(unit * width));
+ return lbl;
+}
+
+#include <sys/time.h>
+static struct timeval starttime;
+static int h = 0;
+static int m = 0;
+static int s = 0;
+static int watchdog = 0;
+
+void MainWindow::taskbar_update()
+{
+ struct timeval time;
+ watchdog++;
+
+ if(recording) {
+ if((watchdog % 300 == 0) || ((camera->getQueueLength() > 1000) && (watchdog % 50 == 0)))
+ info->log("Queue length: %d (active)", camera->getQueueLength());
+
+ gettimeofday(&time, NULL);
+
+ s = time.tv_sec - starttime.tv_sec;
+
+ h = s / (60 * 60);
+ s -= h * (60 * 60);
+ m = s / 60;
+ s -= m * 60;
+ } else {
+ if((camera->getQueueLength() > 0) && (watchdog % 300 == 0))
+ info->log("Queue length: %d (passive)", camera->getQueueLength());
+ gettimeofday(&starttime, NULL);
+ }
+
+ char msg[256];
+ int l = camera->getQueueLength();
+ sprintf(msg, TXT_TIME " %.02d:%.02d:%.02d " TXT_QUEUELENGTH " %d", h, m, s, l);
+ lbl_recordtime->setText(msg);
+}
+
+#define GREY 160
+#define SPEED 0.07f
+void MainWindow::redraw_edge()
+{
+ rec_edge_counter += SPEED;
+ float val = fabs(sin(rec_edge_counter));
+ img_recedge->setBackgroundColor(QColor((int) ((255 - GREY) * val + GREY),
+ (int) (GREY - (GREY * val)),
+ (int) (GREY - (GREY * val))));
+}
+
+void MainWindow::message(char *msg)
+{
+ status->message(msg);
+ info->log("Message: %s", msg);
+}
+
+void MainWindow::clear()
+{
+ info->log("Clearing screen.");
+
+
+ // History widgets
+ for(unsigned int i = 0; i < num_history; i++) {
+ img_history[i]->set_image(img_dummy);
+ }
+
+ lbl_name->setText("");
+ lbl_cpr->setText("");
+}
+
+#include "aboutwindow.h"
+void MainWindow::about_clicked()
+{
+ AboutWindow about;
+ about.exec();
+}
+
+void MainWindow::clear_clicked()
+{
+ if(MessageBox(this,
+ TXT_ASK_CLEAR_SCREEN_TITLE,
+ TXT_ASK_CLEAR_SCREEN,
+ TYPE_YES_NO,
+ ICON_QUESTION).exec() == MSG_YES) {
+ clear();
+ }
+}
+
+void MainWindow::cpr_clicked()
+{
+ char oldcpr[256];
+ char oldname[256];
+
+ // If recording, stop recording before changingcpr
+ if(recording) {
+ MessageBox(this,
+ TXT_STOP_RECORDING_TITLE,
+ TXT_STOP_RECORDING,
+ TYPE_OK,
+ ICON_WARNING).exec();
+ return;
+ }
+ info->log("Activated CPR chooser.");
+
+ // Save CPR and name, from the labels.
+ strcpy(oldname, lbl_name->text().ascii());
+ strcpy(oldcpr, lbl_cpr->text().ascii());
+
+ clear();
+
+ // Create and call the CPRQueryDialog.
+ CPRQueryDialog dlg(info, lbl_cpr, lbl_name, this, TXT_CPRDLG_TITLE, status);
+
+ if(dlg.exec() == 0) {
+ // Restore old CPR and name, in the labels.
+ lbl_name->setText(oldname);
+ lbl_cpr->setText(oldcpr);
+ info->log("Cancelled CPR chooser.");
+ } else {
+ // Change CPR camera.
+ info->log("New CPR %s (old %s).", (char*)lbl_cpr->text().ascii(), oldcpr);
+ strcpy(oldname, lbl_name->text().ascii());
+ strcpy(oldcpr, lbl_cpr->text().ascii());
+ clear();
+ lbl_name->setText(oldname);
+ lbl_cpr->setText(oldcpr);
+ camera->setCpr((char*)lbl_cpr->text().ascii(), (char*)lbl_name->text().ascii());
+ }
+}
+
+void MainWindow::rec_clicked()
+{
+ if(!recording) {
+ info->log("Start recording.");
+ recording = 1;
+ // Start flashing the edge
+ rec_edge_counter = 0.0f;
+ timer->start(100);
+ btn_rec->setPixmap(*img_stop);
+ camera->start();
+ } else {
+ switch(MessageBox(this,
+ TXT_ASK_SAVE_TITLE,
+ TXT_ASK_SAVE,
+ TYPE_YES_NO_MAYBE_CANCEL,
+ ICON_QUESTION).exec()) {
+ case MSG_YES:
+ info->log("Stop recording (Said yes to save).");
+ recording = 0;
+ camera->stop(SAVE);
+ timer->stop();
+ img_recedge->setBackgroundColor(QColor(160,160,160));
+ btn_rec->setPixmap(*img_record);
+ break;
+
+ case MSG_NO:
+ info->log("Stop recording (Said no to save).");
+ recording = 0;
+ camera->stop(DELETE);
+ timer->stop();
+ img_recedge->setBackgroundColor(QColor(160,160,160));
+ btn_rec->setPixmap(*img_record);
+ break;
+
+ case MSG_MAYBE:
+ info->log("Stop recording (Said maybe to save).");
+ recording = 0;
+ camera->stop(LATER);
+ timer->stop();
+ img_recedge->setBackgroundColor(QColor(160,160,160));
+ btn_rec->setPixmap(*img_record);
+ break;
+
+ case MSG_CANCEL:
+ info->log("Didn't stop recording (canceled).");
+ break;
+ }
+ }
+}
+
+void MainWindow::shoot_clicked()
+{
+ // unsigned char pixels[720*576*3];
+ info->log("Snapshot (%s).", frozen?"frozen":"unfrozen");
+
+ QImage screenshot(720, 576, 32);
+
+ camera->snapshot(screenshot.bits());
+
+ QImage *image;
+ for(int cnt = (num_history-1); cnt > 0; cnt--) {
+ image = img_history[cnt-1]->get_image();
+ img_history[cnt]->set_image(image);
+ }
+ img_history[0]->set_image(&screenshot);
+
+ if(frozen) {
+ camera->unfreeze();
+ btn_freeze->setPixmap(*img_freeze);
+ btn_freeze->setOn(false);
+ frozen = false;
+ }
+}
+
+void MainWindow::freeze_clicked()
+{
+ if(frozen) {
+ info->log("Unfreeze.");
+ camera->unfreeze();
+ btn_freeze->setPixmap(*img_freeze);
+ btn_freeze->setOn(false);
+ frozen = false;
+ } else {
+ info->log("Freeze.");
+ camera->freeze();
+ btn_freeze->setPixmap(*img_unfreeze);
+ btn_freeze->setOn(true);
+ frozen = true;
+ }
+}
+
+void MainWindow::mute_clicked()
+{
+ muted = !muted;
+ if(muted) btn_mute->setPixmap(*img_mute);
+ else btn_mute->setPixmap(*img_unmute);
+
+ camera->setMute(muted);
+}
+
+#endif /*USE_GUI*/
diff --git a/client/mainwindow.h b/client/mainwindow.h
new file mode 100644
index 0000000..2ac7d82
--- /dev/null
+++ b/client/mainwindow.h
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * mainwindow.h
+ *
+ * Sat Aug 21 19:50:13 2004
+ * Copyright 2004 deva
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __MAINWINDOW_H__
+#define __MAINWINDOW_H__
+
+#include <string>
+using namespace std;
+
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qstatusbar.h>
+#include <qtimer.h>
+#include <qpixmap.h>
+#include <qimage.h>
+
+#include "videowidget.h"
+#include "camera.h"
+#include "cprquerydialog.h"
+#include "historywidget.h"
+
+#include "info_gui.h"
+
+#define INCH_IN_CM 2.54f
+
+/**
+ * First some GUI specs
+ */
+//#define NUM_HISTORY 3 // moved to a genuine variable
+// Button sizes in cm (metric)
+#define BUTTON_WIDTH 7
+#define BUTTON_HEIGHT 2
+
+#define HISTORY_LIST_MARGIN 25
+#define HISTORY_LIST_SPACING 5
+
+/**
+ * Textstrings
+ */
+#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?"
+#define TXT_STOP_RECORDING_TITLE "Stop optagelsen"
+#define TXT_STOP_RECORDING "Optagelsen skal standses, inden et nyt cpr nummer kan indtastes.\n\
+Optagelsen standses ved tryk pĺ den rřde cirkel med gul streg over."
+#define TXT_TIME "Tid:"
+#define TXT_QUEUELENGTH "Buffer střrelse:"
+#define TXT_ASK_CLEAR_SCREEN_TITLE "Fjerne data fra skćrmen?"
+#define TXT_ASK_CLEAR_SCREEN "Er du sikker pĺ at du vil dataene fra skćrmen (billeder, CPR nummer og navn)?"
+
+/**
+ * Images
+ */
+#define PIXMAP_MUTE PIXMAPS"/mute.png"
+#define PIXMAP_UNMUTE PIXMAPS"/unmute.png"
+
+#define PIXMAP_RECORD PIXMAPS"/record.png"
+#define PIXMAP_STOP PIXMAPS"/stop.png"
+
+#define PIXMAP_FREEZE PIXMAPS"/freeze.png"
+#define PIXMAP_UNFREEZE PIXMAPS"/unfreeze.png"
+
+#define PIXMAP_CPR PIXMAPS"/cpr.png"
+#define PIXMAP_CLEAR PIXMAPS"/clear.png"
+
+#define PIXMAP_SNAPSHOT PIXMAPS"/snapshot.png"
+#define PIXMAP_DUMMY PIXMAPS"/dummy.png"
+#define PIXMAP_LOGO_SMALL PIXMAPS"/miav-logo.png"
+
+class MainWindow : public QWidget
+{
+ Q_OBJECT
+public:
+ MainWindow(QApplication *qApp, QWidget* parent = 0, const char* name = 0);
+ ~MainWindow();
+
+ void message(char* msg);
+
+public slots:
+ void cpr_clicked();
+ void clear_clicked();
+ void rec_clicked();
+ void shoot_clicked();
+ void freeze_clicked();
+ void redraw_edge();
+ void taskbar_update();
+ void about_clicked();
+ void mute_clicked();
+
+private:
+ unsigned int num_history;
+
+ void clear();
+
+ Info *info;
+
+ void createGui();
+
+ Camera *camera;
+ Info *cam_info;
+
+ // Image loading routines.
+ QImage *loadButtonIcon( char *name, int height = BUTTON_HEIGHT );
+ QImage *loadImage( char *name );
+
+ QImage *img_unfreeze;
+ QImage *img_freeze;
+ QImage *img_snapshot;
+ QImage *img_cpr;
+ QImage *img_clear;
+ QImage *img_record;
+ QImage *img_stop;
+ QImage *img_logo;
+ QImage *img_mute;
+ QImage *img_unmute;
+
+ QImage *img_dummy;
+
+ QLabel *lbl_version;
+ QLabel *lbl_cpr;
+ QLabel *lbl_name;
+ QLabel *lbl_recordtime;
+
+ QTimer *taskbartimer;
+
+ // Used for the check_for_error_once_per_2_seconds (very ugly)
+ QTimer *errtimer;
+
+ float rec_edge_counter;
+ QTimer *timer;
+ QLabel *img_recedge;
+ HistoryWidget **img_history;
+
+ QPushButton *btn_logo;
+ QPushButton *btn_clear;
+ QPushButton *btn_cpr;
+ QPushButton *btn_rec;
+ QPushButton *btn_shoot;
+ QPushButton *btn_freeze;
+ QPushButton *btn_mute;
+
+ QPushButton *btn_about;
+
+ QStatusBar *status;
+
+ VideoWidget *img_live;
+
+ bool recording;
+ bool frozen;
+ bool muted;
+
+ // Configuration values
+ float unit;
+ int video_width;
+ int video_height;
+
+ QPushButton *createButton(char *caption, int width = BUTTON_WIDTH, int height = BUTTON_HEIGHT);
+ QPushButton *createButton(char *caption, QWidget *parent, int width = BUTTON_WIDTH, int height = BUTTON_HEIGHT);
+ QLabel *createLabel(char *caption, int width, int height);
+};
+
+#endif
+
+#endif /*USE_GUI*/
diff --git a/client/messagebox.cc b/client/messagebox.cc
new file mode 100644
index 0000000..fd812eb
--- /dev/null
+++ b/client/messagebox.cc
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * messagebox.cc
+ *
+ * Fri Feb 25 20:23:19 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+#include "messagebox.h"
+#include "miav_config.h"
+
+// For button sizes!
+#include "mainwindow.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+/* If the cpr input by the user is not valid, this dialog
+ * ask the user what to do. Edit the number, use it as it is,
+ * or clear the number.
+ */
+
+MessageBox::MessageBox(QWidget* parent,
+ const char* name,
+ const char* text,
+ msg_type type,
+ msg_icon icon)
+ : QDialog(parent, name, TRUE)
+{
+ int resolution_w = config->readInt("pixel_width");
+ //int resolution_h = config->readInt("pixel_height");
+ unit = ((float)resolution_w / config->readFloat("screensize")) / INCH_IN_CM;
+
+
+ setCaption(name);
+ QFrame *topf = new QFrame(this);
+ topf->setFrameStyle(QFrame::Box | QFrame::Raised);
+ topf->setLineWidth(3);
+ QVBoxLayout *bl = new QVBoxLayout(this);
+ bl->addWidget(topf);
+
+ // Setup the icon
+ pix_icon = new QPixmap();
+ switch(icon) {
+ case ICON_NONE: // No icon is used
+ {
+ break;
+ }
+ case ICON_DEFAULT: // An icon matching the buttons is used
+ {
+ switch(type) {
+ case TYPE_OK:
+ pix_icon->load( PIXMAP_INFO );
+ break;
+ case TYPE_OK_CANCEL:
+ pix_icon->load( PIXMAP_WARNING );
+ break;
+ case TYPE_YES_NO:
+ case TYPE_YES_NO_MAYBE:
+ case TYPE_YES_NO_CANCEL:
+ case TYPE_YES_NO_MAYBE_CANCEL:
+ pix_icon->load( PIXMAP_QUESTION );
+ break;
+ }
+ break;
+ }
+ case ICON_INFO: // An info icon (matching the ok button)
+ {
+ pix_icon->load( PIXMAP_INFO );
+ break;
+ }
+ case ICON_WARNING: // An warning icon (matching the ok/cancel button)
+ {
+ pix_icon->load( PIXMAP_WARNING );
+ break;
+ }
+ case ICON_ERROR: // An critical error icon
+ {
+ pix_icon->load( PIXMAP_ERROR );
+ break;
+ }
+ case ICON_QUESTION:// An question icon (matching the yes/no and yes/no/cancel buttons)
+ {
+ pix_icon->load( PIXMAP_QUESTION );
+ break;
+ }
+ }
+ QLabel *lbl_icon = new QLabel(topf);
+ lbl_icon->setPixmap(*pix_icon);
+
+ QLabel *lbl_text = new QLabel(topf);
+ lbl_text->setText(text);
+ lbl_text->setFont( QFont( "Sans Serif",
+ //(height>1)?(int)(unit * height / 2):(int)(unit * height / 2),
+ (int)(unit * 0.7 * BUTTON_HEIGHT / 2),
+ QFont::Normal ) );
+ lbl_text->setFixedHeight((int)(unit * BUTTON_HEIGHT));
+ // lbl_text->setFont(QFont("Arial", 18));
+ QFrame *f = new QFrame(topf);
+
+ QVBoxLayout *blayout = new QVBoxLayout(topf, 20, 20);
+
+ blayout->addWidget(lbl_icon);
+ blayout->addWidget(lbl_text);
+ blayout->addWidget(f);
+
+ // Setup the buttons
+ switch(type) {
+ case TYPE_OK:
+ {
+ QPushButton *bok = createButton(f, TXT_OK );
+ QGridLayout *glayout = new QGridLayout(f, 1, 1, 20, 20);
+ glayout->addWidget(bok, 0, 0);
+ connect(bok, SIGNAL( clicked() ), SLOT(bok_clicked()));
+ break;
+ }
+ case TYPE_OK_CANCEL:
+ {
+ QPushButton *bok = createButton(f, TXT_OK );
+ QPushButton *bcancel = createButton(f, TXT_CANCEL );
+ QGridLayout *glayout = new QGridLayout(f, 1, 2, 20, 20);
+ glayout->addWidget(bcancel, 0, 1);
+ glayout->addWidget(bok, 0, 2);
+ connect(bcancel, SIGNAL( clicked() ), SLOT(bcancel_clicked()));
+ connect(bok, SIGNAL( clicked() ), SLOT(bok_clicked()));
+ break;
+ }
+ case TYPE_YES_NO:
+ {
+ QPushButton *bno = createButton(f, TXT_NO );
+ QPushButton *byes = createButton(f, TXT_YES );
+ QGridLayout *glayout = new QGridLayout(f, 1, 2, 20, 20);
+ glayout->addWidget(bno, 0, 0);
+ glayout->addWidget(byes, 0, 1);
+ connect(byes, SIGNAL( clicked() ), SLOT(byes_clicked()));
+ connect(bno, SIGNAL( clicked() ), SLOT(bno_clicked()));
+ break;
+ }
+ case TYPE_YES_NO_MAYBE:
+ {
+ QPushButton *bmaybe = createButton(f, TXT_MAYBE );
+ QPushButton *bno = createButton(f, TXT_NO );
+ QPushButton *byes = createButton(f, TXT_YES );
+ 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 *bcancel = createButton(f, TXT_CANCEL );
+ QPushButton *bno = createButton(f, TXT_NO );
+ QPushButton *byes = createButton(f, TXT_YES );
+ QGridLayout *glayout = new QGridLayout(f, 1, 3, 20, 20);
+ glayout->addWidget(bno, 0, 0);
+ glayout->addWidget(bcancel, 0, 1);
+ glayout->addWidget(byes, 0, 2);
+ connect(byes, SIGNAL( clicked() ), SLOT(byes_clicked()));
+ connect(bcancel, SIGNAL( clicked() ), SLOT(bcancel_clicked()));
+ connect(bno, SIGNAL( clicked() ), SLOT(bno_clicked()));
+ break;
+ }
+ case TYPE_YES_NO_MAYBE_CANCEL:
+ {
+ QPushButton *bmaybe = createButton(f, TXT_MAYBE );
+ QPushButton *bcancel = createButton(f, TXT_CANCEL );
+ QPushButton *bno = createButton(f, TXT_NO );
+ QPushButton *byes = createButton(f, TXT_YES );
+ 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;
+ }
+ }
+
+}
+
+MessageBox::~MessageBox()
+{
+ delete pix_icon;
+}
+
+QPushButton *MessageBox::createButton(QWidget *parent, const char *text)
+{
+ QPushButton *q = new QPushButton(parent);
+ q->setText(text);
+ q->setFont( QFont( "Sans Serif", (int)(unit * 0.7 * BUTTON_HEIGHT / 2 ), QFont::Normal ) );
+ q->setFixedSize((int)(BUTTON_WIDTH * unit), (int)(BUTTON_HEIGHT * unit));
+ return q;
+}
+
+void MessageBox::bok_clicked()
+{
+ done(MSG_OK);
+}
+
+void MessageBox::bcancel_clicked()
+{
+ done(MSG_CANCEL);
+}
+
+void MessageBox::byes_clicked()
+{
+ done(MSG_YES);
+}
+
+void MessageBox::bno_clicked()
+{
+ done(MSG_NO);
+}
+
+void MessageBox::bmaybe_clicked()
+{
+ done(MSG_MAYBE);
+}
+
+#endif/*USE_GUI*/
diff --git a/client/messagebox.h b/client/messagebox.h
new file mode 100644
index 0000000..30a8307
--- /dev/null
+++ b/client/messagebox.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * messagebox.h
+ *
+ * Fri Feb 25 20:23:19 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __MIAV_MESSAGEBOX_H__
+#define __MIAV_MESSAGEBOX_H__
+
+#include <qdialog.h>
+#include <qwidget.h>
+#include <qframe.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+
+typedef enum {
+ ICON_NONE, // No icon is used
+ ICON_DEFAULT, // An icon matching the buttons is used
+ ICON_INFO, // An info icon (matching the ok button)
+ ICON_WARNING, // An warning icon (matching the ok/cancel button)
+ ICON_ERROR, // An critical error icon
+ ICON_QUESTION // An question icon (matching the yes/no and yes/no/cancel buttons)
+} msg_icon;
+
+typedef enum {
+ MSG_YES,
+ MSG_NO,
+ MSG_CANCEL,
+ 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;
+
+
+/**
+ * Textstrings
+ */
+#define TXT_OK "Ok"
+#define TXT_CANCEL "Annullér"
+#define TXT_YES "Ja"
+#define TXT_NO "Nej"
+#define TXT_MAYBE "Mĺske"
+
+/**
+ * Images
+ */
+#define PIXMAP_INFO PIXMAPS"/info.png"
+#define PIXMAP_WARNING PIXMAPS"/warning.png"
+#define PIXMAP_QUESTION PIXMAPS"/question.png"
+#define PIXMAP_ERROR PIXMAPS"/error.png"
+
+
+class MessageBox : public QDialog
+{
+ Q_OBJECT
+public:
+ MessageBox(QWidget* parent = 0,
+ const char* name = "",
+ const char* text = "",
+ msg_type type = TYPE_OK,
+ msg_icon icon = ICON_DEFAULT);
+ ~MessageBox();
+
+public slots:
+ void bok_clicked();
+ void bcancel_clicked();
+ void byes_clicked();
+ void bno_clicked();
+ void bmaybe_clicked();
+
+private:
+ float unit;
+ QPixmap *pix_icon;
+ QPushButton *createButton(QWidget *parent, const char *text);
+};
+
+#endif/*__MIAV_MESSAGEBOX_H__*/
+
+#endif /*USE_GUI*/
diff --git a/client/miav_client.cc b/client/miav_client.cc
new file mode 100644
index 0000000..a8e9f7c
--- /dev/null
+++ b/client/miav_client.cc
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * miav.cc
+ *
+ * Sat Aug 21 17:32:24 2004
+ * Copyright 2004 deva
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+
+#include "miav_client.h"
+
+#include <QApplication>
+#include <stdio.h>
+
+#include "mainwindow.h"
+#include "miav_config.h"
+#include "info_gui.h"
+
+
+QApplication *miav_app;
+
+/**
+ * This function starts the MIaV gui.
+ */
+int main(int argc, char *argv[])
+ QApplication miav_grab( argc, argv );
+ miav_app = &miav_grab;
+
+ MiavConfig cfg(ETC"/miav.conf", NULL);
+ InfoGui info(&miav_grab, NULL, &cfg);
+ config = new MiavConfig(ETC"/miav.conf", &info);
+
+ InfoEventHandler *eventhandler = new InfoEventHandler( );
+ miav_grab.installEventFilter( eventhandler );
+
+ MainWindow mainwindow( &miav_grab );
+ miav_grab.setMainWidget( &mainwindow );
+
+ info.setParent(&mainwindow);
+ return miav_grab.exec();
+}
diff --git a/client/miav_client.h b/client/miav_client.h
new file mode 100644
index 0000000..ce7842a
--- /dev/null
+++ b/client/miav_client.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * miav.h
+ *
+ * Mon Nov 8 09:59:24 CET 2004
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifndef __LIBMIAV_H__
+#define __LIBMIAV_H__
+
+#include "util.h"
+
+#include "network.h"
+#include "socket.h"
+#include "queue.h"
+
+#ifdef USE_GUI
+#include <qapplication.h>
+extern QApplication *miav_app;
+#endif/*USE_GUI*/
+
+#endif/*__LIBMIAV_H__*/
diff --git a/client/player.cc b/client/player.cc
new file mode 100644
index 0000000..e57211d
--- /dev/null
+++ b/client/player.cc
@@ -0,0 +1,322 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * plsyer.cc
+ *
+ * Wed Nov 3 21:23:14 CET 2004
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * Originally from:
+ * RTVideoRec Realtime video recoder and encoder for Linux
+ *
+ * Copyright (C) 2004 B. Stultiens
+ * Copyright (C) 2004 Koen Otter and Glenn van der Meyden
+ */
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+#ifdef USE_GUI
+
+#include "player.h"
+
+// Use libdv
+#include <libdv/dv.h>
+#include <libdv/dv_types.h>
+
+#include <time.h>
+
+// For sleep
+#include <unistd.h>
+
+Player::Player(Info *ginfo,
+ int w, int h,
+ volatile int *grunning,
+ sem_t *gsem,
+ Queue<Frame> *gqueue,
+ pthread_mutex_t *gmutex)
+{
+ // No errors has ocurred... yet!
+ noErrors = true;
+
+ yuv_draw = new YUVDraw();
+
+ width = w;
+ height = h;
+
+ info = ginfo;
+
+ running = grunning;
+ sem = gsem;
+ queue = gqueue;
+ mutex = gmutex;
+
+ sem_init(&play_sem, 0, 1);
+
+ initSDL();
+
+ bypass = false;
+
+ // Do not show the text
+ showtext = false;
+ recording = false;
+ recording_prev = !recording;
+ cprchanged = false;
+
+ muted = false;
+ muted_prev = !muted;
+}
+
+Player::~Player()
+{
+ deinitSDL();
+ if(yuv_draw) delete yuv_draw;
+}
+
+void Player::reinitSDL()
+{
+ deinitSDL();
+ initSDL();
+}
+
+void Player::deinitSDL()
+{
+ SDL_FreeYUVOverlay(overlay);
+ SDL_Quit();
+}
+
+void Player::initSDL()
+{
+ if(SDL_Init(SDL_INIT_VIDEO) < 0) {
+ info->error("Unable to init SDL: %s.", SDL_GetError());
+ noErrors = false;
+ printf("failed!\n");
+ return;
+ }
+
+ screen = SDL_SetVideoMode(width,
+ height,
+ 0, // 0 bpp means 'use current display depth'
+ SDL_HWSURFACE |
+ SDL_ANYFORMAT |
+ SDL_HWACCEL );
+
+ if(!screen) {
+ info->error("Unable to set %dx%d video: %s.",
+ 720, 576, SDL_GetError());
+ noErrors = false;
+ printf("failed!\n");
+ return;
+ }
+
+ overlay = SDL_CreateYUVOverlay(720,
+ 576,
+ SDL_YUY2_OVERLAY, // Match for the libdv decoder output
+ screen);
+ if(!overlay) {
+ info->error("Unable to create SDL overlay: %s.", SDL_GetError());
+ noErrors = false;
+ printf("failed!\n");
+ return;
+ }
+
+ // Setup the displayarea.
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = width;
+ rect.h = height;
+
+ yuv_draw->setOverlay(overlay);
+}
+
+void Player::player()
+{
+ SDL_Event event;
+ Frame *frame;
+
+ int pitches[3];
+
+ if(!noErrors) return; // FIXME: Gracefully exit...
+
+ bool first = true;
+ dv_decoder_t *decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE);
+ decoder->quality = DV_QUALITY_BEST;
+
+ while(*running) {
+ // Wait for the semaphore to be free... then run
+ sem_wait(&play_sem);
+ sem_post(&play_sem);
+
+ if(bypass) continue;
+
+ if(!SDL_WaitEvent(&event)) break; // FIXME: Gracefully exit...
+
+ switch(event.type) {
+ case SDL_KEYDOWN:
+ switch(event.key.keysym.sym) {
+ case SDLK_q:
+ case SDLK_ESCAPE:
+ goto quitit;
+ default:
+ break;
+ }
+ break;
+
+ case SDL_USEREVENT:
+ frame = queue->pop();
+ if(!frame) break;
+
+ if(first) {
+ pitches[0] = overlay->pitches[0];
+ pitches[1] = overlay->pitches[1];
+ pitches[2] = overlay->pitches[2];
+
+ dv_parse_header(decoder, frame->data);
+ //dv_parse_packs(decoder, frame->data); // Not needed anyway!
+
+ decoder->system = e_dv_system_625_50; // PAL lines, PAL framerate
+ decoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v
+ decoder->std = e_dv_std_iec_61834;
+ decoder->num_dif_seqs = 12;
+ first = false;
+ }
+
+ if(SDL_LockYUVOverlay(overlay) == -1) info->error("SDL_LockYUVOverlay failed.");
+
+ // libdv img decode to yuv
+ dv_decode_full_frame(decoder,
+ frame->data,
+ e_dv_color_yuv,
+ overlay->pixels,
+ pitches);
+
+ // Set status text
+ // if(muted != muted_prev) {
+ yuv_draw->mute(muted);
+ // muted_prev = muted;
+ // }
+ if(recording != recording_prev) {
+ if(recording) yuv_draw->setTopText(TEXT_RECORDING);
+ else yuv_draw->setTopText(TEXT_STOPPED);
+ recording_prev = recording;
+ }
+
+ // Draw overlaytext (if enabled)
+ if(showtext) {
+ if(cprchanged) {
+ yuv_draw->setBottomText(cpr);
+ cprchanged = false;
+ }
+ yuv_draw->draw();
+ }
+
+ SDL_UnlockYUVOverlay(overlay);
+ SDL_DisplayYUVOverlay(overlay, &rect);
+ delete frame;
+ break;
+
+ case SDL_QUIT:
+ quitit:
+ *running = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if(decoder) dv_decoder_free(decoder);
+
+ struct timespec ts;
+
+ /* Remove any late buffer */
+ /* We don't care, the encoder finishes them all */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100000000L; // 100ms
+ nanosleep(&ts, NULL);
+
+ frame = queue->pop();
+ if(frame) delete frame;
+}
+
+void Player::thread_main()
+{
+ player();
+ fprintf(stderr, "Player thread stopped.\n"); fflush(stderr);
+}
+
+void Player::start()
+{
+ sem_post(&play_sem);
+}
+
+void Player::stop()
+{
+ sem_wait(&play_sem);
+}
+
+// FIXME: Worst case genario: the loop takes more than 1 second
+// to stop displaying => crash, due to deinitialization
+// of SDL, while calling it.!
+void Player::resize(int w, int h, bool s)
+{
+ // Tell loop to stop
+ bypass = true;
+
+ // Wait to ensure the current frame is done being displayed
+ sleep(1);
+
+ // Deinitialize SDL
+ deinitSDL();
+
+ // Set new size
+ width = w;
+ height = h;
+
+ // Initialize SDL
+ initSDL();
+
+ // Tell loop to go on.
+ bypass = false;
+
+ showtext = s;
+}
+
+void Player::setCpr(char *newcpr, char* name)
+{
+ sprintf(cpr, "ID: %s - %s", newcpr, name);
+ cprchanged = true;
+}
+
+void Player::startrecord()
+{
+ recording = true;
+}
+
+void Player::stoprecord()
+{
+ recording = false;
+}
+
+void Player::setMute(bool m)
+{
+ muted = m;
+}
+
+#endif /* USE_GUI */
diff --git a/client/player.h b/client/player.h
new file mode 100644
index 0000000..0f5ca51
--- /dev/null
+++ b/client/player.h
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * player.h
+ *
+ * Fri Feb 25 20:23:19 CET 2005
+ * Copyright 2005 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * Originally from:
+ * RTVideoRec Realtime video recoder and encoder for Linux
+ *
+ * Copyright (C) 2004 Bent Bisballe
+ *
+ */
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __RTVIDEOREC_PLAYER_H
+#define __RTVIDEOREC_PLAYER_H
+
+#include "info.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <SDL/SDL.h>
+//#include <avformat.h>
+
+#include "util.h"
+#include "queue.h"
+
+#include "thread.h"
+#include "frame.h"
+
+#include <qwidget.h>
+
+#include "yuv_draw.h"
+
+#define TEXT_RECORDING "Optager"
+#define TEXT_STOPPED "Stoppet"
+
+//#define DISPLAYWIDTH 720 // FIXME: These numbers suck!
+//#define DISPLAYHEIGHT 576
+
+/**
+ * This class contains the SDL code, for displaying the movie frames
+ * in the widget, using hardware overlay.
+ */
+class Player : public Thread {
+public:
+ Player(Info *ginfo,
+ int width, int height,
+ volatile int *grunning,
+ sem_t *gsem,
+ Queue<Frame> *gqueue,
+ pthread_mutex_t *gmutex);
+ ~Player();
+
+ // These functions are used to set the overlay text.
+ void setCpr(char *newcpr, char* name);
+ void startrecord();
+ void stoprecord();
+
+ // Start and stop runnning video (freeze/unfreeze)
+ void start();
+ void stop();
+
+ // Used to reinitialize the SDL output width a new size
+ void resize(int width, int height, bool showtext);
+
+ void thread_main();
+
+ void setMute(bool mute);
+
+private:
+
+ void initSDL();
+ void deinitSDL();
+ void reinitSDL();
+
+ // Output dimensions (overlay)
+ volatile int width;
+ volatile int height;
+
+ SDL_Rect rect;
+
+ // Set to true, whenever a resize is requested.
+ volatile bool bypass;
+
+ // Vars for the text overlay
+ volatile bool showtext;
+ volatile bool recording;
+ bool recording_prev;
+
+ volatile bool muted;
+ bool muted_prev;
+
+ volatile bool cprchanged;
+ char cpr[256];
+
+ Info *info;
+
+ void player();
+
+ // Used to verify if errors ha ocurred previously.
+ bool noErrors;
+
+ volatile int *running;
+ sem_t *sem;
+ Queue<Frame> *queue;
+ pthread_mutex_t *mutex;
+
+ sem_t play_sem;
+
+ SDL_Surface *screen;
+ SDL_Overlay *overlay;
+
+ YUVDraw *yuv_draw;
+};
+
+#endif/*__RTVIDEOREC_PLAYER_H*/
+
+#endif /* USE_GUI */
diff --git a/client/videowidget.cc b/client/videowidget.cc
new file mode 100644
index 0000000..61b5c8e
--- /dev/null
+++ b/client/videowidget.cc
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * videowidget.cc
+ *
+ * Fri Sep 3 14:36:37 2004
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <config.h>
+
+#ifdef USE_GUI
+
+#include "videowidget.h"
+
+#include "miav_config.h"
+
+VideoWidget::VideoWidget(QWidget *p, Camera *c, QWidget* old) : QWidget(p, "")
+{
+ camera = c;
+ parent = p;
+
+ oldWindow = old;
+
+ // A welltested hack to force SDL to draw in the QWidget
+ QString ids;
+ setenv("SDL_WINDOWID", ids.setNum(winId()), 1);
+}
+
+VideoWidget::~VideoWidget()
+{
+}
+
+QPixmap VideoWidget::getScreenshot()
+{
+ return QPixmap::grabWindow (winId());
+}
+
+static VideoWidget *fs = NULL;
+
+void VideoWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if(!parent) { // We are a fullscreen window
+ QString ids;
+ setenv("SDL_WINDOWID", ids.setNum(oldWindow->winId()), 1);
+ camera->resize(oldWindow->width(), oldWindow->height(), false);
+ destroy();
+ } else { // We are a nested window
+ // first delete old instance (if any)
+ if(fs) delete fs;
+ fs = new VideoWidget(NULL, camera, this);
+ fs->showFullScreen();
+ fs->setFixedWidth(config->readInt("pixel_width"));
+ fs->setFixedHeight(config->readInt("pixel_height"));
+ camera->resize(fs->width(), fs->height(), true);
+ }
+}
+
+#endif /* USE_GUI */
diff --git a/client/videowidget.h b/client/videowidget.h
new file mode 100644
index 0000000..b9ac9d6
--- /dev/null
+++ b/client/videowidget.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * videowidget.h
+ *
+ * Fri Sep 3 14:36:46 2004
+ * Copyright 2004 Bent Bisballe
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+
+#ifndef __VIDEOWIDGET_H__
+#define __VIDEOWIDGET_H__
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include "camera.h"
+
+class VideoWidget : public QWidget {
+Q_OBJECT
+public:
+ VideoWidget(QWidget *parent, Camera *camera, QWidget *old = NULL);
+ ~VideoWidget();
+ QPixmap getScreenshot();
+ void mouseReleaseEvent(QMouseEvent *event);
+
+private:
+ Camera *camera;
+
+ QWidget *parent;
+
+ // Reassign SDL to this when closing (if non-NULL)
+ QWidget *oldWindow;
+};
+
+#endif /* __VIDEOWIDGET_H__ */
+
+#endif /* USE_GUI */
diff --git a/client/yuv_draw.cc b/client/yuv_draw.cc
new file mode 100644
index 0000000..21e5c28
--- /dev/null
+++ b/client/yuv_draw.cc
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * yuv_draw.cc
+ *
+ * Thu Sep 22 12:35:28 CEST 2005
+ * Copyright 2005 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+#include "yuv_draw.h"
+
+// for miav_app
+#include "miav.h"
+
+#include <string.h>
+
+#define TEXT_MARGIN 10
+
+#include "mainwindow.h"
+static QImage *loadIcon( char *name, int height )
+{
+ QImage scaled;
+ QImage *img;
+
+ img = new QImage();
+ img->load( name );
+
+ int h = height;
+ int w = (int)((float)img->width() / (float)(img->height() / (float)h));
+
+ scaled = img->smoothScale(w, h);
+ delete img;
+ img = new QImage(scaled);
+
+ return img;
+}
+
+
+YUVDraw::YUVDraw()
+{
+ overlay = NULL;
+
+ // One line of text!
+ top_pixmap = new QPixmap(720 - TEXT_MARGIN, 20);
+ bottom_pixmap = new QPixmap(720 - TEXT_MARGIN, 20);
+
+ for(int x = 0; x < 720 - TEXT_MARGIN; x++) {
+ for(int y = 0; y < 20; y++) {
+ top_grey[x][y] = 255;
+ }
+ }
+
+ for(int x = 0; x < 720 - TEXT_MARGIN; x++) {
+ for(int y = 0; y < 20; y++) {
+ bottom_grey[x][y] = 255;
+ }
+ }
+
+ img_muted = loadIcon(PIXMAP_MUTE, ICON_HEIGHT);
+ img_unmuted = loadIcon(PIXMAP_UNMUTE, ICON_HEIGHT);
+}
+
+YUVDraw::~YUVDraw()
+{
+ delete top_pixmap;
+ delete bottom_pixmap;
+}
+
+void YUVDraw::setOverlay(SDL_Overlay* o)
+{
+ overlay = o;
+}
+
+void YUVDraw::addPixel(int x, int y, int val)
+{
+ if(overlay->w < x) return; // Out of range
+ if(overlay->h < y) return; // Out of range
+
+ Uint8 **pixels = overlay->pixels;
+ Uint16 *pitches = overlay->pitches;
+
+ Uint8* pixel = &pixels[0][(2 * x) + (y * pitches[0])];
+
+ if(val > 0) *pixel = (255<*pixel+val?255:*pixel+val);
+ else *pixel = (0>*pixel+val?0:*pixel+val);
+}
+
+
+void YUVDraw::setTopText(char* text)
+{
+ miav_app->lock();
+ top_pixmap->fill();
+
+ QPainter painter;
+ painter.begin(top_pixmap);
+ painter.setFont( QFont( "Arial", 12, QFont::Bold ) );
+ painter.setPen( Qt::black );
+ painter.drawText(64, 15, text);
+ painter.end();
+
+ QImage image = top_pixmap->convertToImage();
+
+ for(int x = 64; x < 720 - TEXT_MARGIN; x++) {
+ for(int y = 0; y < 20; y++) {
+ top_grey[x][y] = qGray(image.pixel(x, y));
+ }
+ }
+ miav_app->unlock();
+}
+
+void YUVDraw::setBottomText(char* text)
+{
+ miav_app->lock();
+ bottom_pixmap->fill();
+
+ QPainter painter;
+ painter.begin(bottom_pixmap);
+ painter.setFont( QFont( "Arial", 12, QFont::Bold ) );
+ painter.setPen( Qt::black );
+ painter.drawText(0, 15, text);
+ painter.end();
+
+ QImage image = bottom_pixmap->convertToImage();
+
+ for(int x = 0; x < 720 - TEXT_MARGIN; x++) {
+ for(int y = 0; y < 20; y++) {
+ bottom_grey[x][y] = qGray(image.pixel(x, y));
+ }
+ }
+ miav_app->unlock();
+}
+
+void YUVDraw::draw()
+{
+ for(int x = 0; x < 720 - TEXT_MARGIN; x++) {
+ for(int y = 0; y < 20; y++) {
+ if(top_grey[x][y] != 255) addPixel(x + TEXT_MARGIN, y + TEXT_MARGIN, 255 - top_grey[x][y]);
+ }
+ }
+
+ for(int x = 0; x < 720 - TEXT_MARGIN; x++) {
+ for(int y = 0; y < 20; y++) {
+ if(bottom_grey[x][y] != 255) addPixel(x + TEXT_MARGIN, (556 - TEXT_MARGIN)+ y, 255 - bottom_grey[x][y]);
+ }
+ }
+}
+
+void YUVDraw::mute(bool muted)
+{
+ int xoffset = 0;
+ int yoffset = 0;
+
+ QImage *img;
+ if(muted) img = img_muted;
+ else img = img_unmuted;
+
+ // Swicth the bool and draw an mute/unmute symbol
+ float alpha, color;
+
+ for(int x = 0; x < ICON_WIDTH; x++) {
+ for(int y = 0; y < ICON_HEIGHT; y++) {
+ alpha = ((float)qAlpha(img->pixel(x, y)) / 255.0);
+ color = (float)qGray(img->pixel(x, y)) * alpha;
+ addPixel(x + xoffset, y + yoffset, (unsigned char)color);
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+void YUVDraw::setText(int xoffset, int yoffset, char* text, int val)
+{
+ for(unsigned int i = 0; i < strlen(text); i++) {
+ for(int x = 0; x < FONT_WIDTH; x++) {
+ for(int y = 0; y < FONT_HEIGHT; y++) {
+ unsigned char col = palette[letter[(int)text[i]][y][x]];
+ if(col) col += val;
+ addPixel(i * FONT_WIDTH + x + xoffset, y + yoffset, col);
+ }
+ }
+ }
+}
+*/
+
+/*
+typedef struct{
+ Uint32 format;
+ int w, h;
+ int planes;
+ Uint16 *pitches;
+ Uint8 **pixels;
+ Uint32 hw_overlay:1;
+} SDL_Overlay;
+*/
+
+#endif/*USE_GUI*/
diff --git a/client/yuv_draw.h b/client/yuv_draw.h
new file mode 100644
index 0000000..62f7d02
--- /dev/null
+++ b/client/yuv_draw.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * yuv_draw.h
+ *
+ * Thu Sep 22 12:35:28 CEST 2005
+ * Copyright 2005 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of MIaV.
+ *
+ * MIaV is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MIaV is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIaV; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "config.h"
+#ifdef USE_GUI
+#ifndef __MIAV_YUV_DRAW_H__
+#define __MIAV_YUV_DRAW_H__
+
+#include <SDL/SDL.h>
+
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qpainter.h>
+
+#define ICON_HEIGHT 48
+#define ICON_WIDTH 48
+
+class YUVDraw {
+public:
+ YUVDraw();
+ ~YUVDraw();
+
+ void setOverlay(SDL_Overlay* overlay);
+
+ void addPixel(int x, int y, int val);
+
+ void setTopText(char* text);
+ void setBottomText(char* text);
+ void mute(bool muted);
+
+ void draw();
+
+private:
+ SDL_Overlay* overlay;
+
+ QPixmap *top_pixmap;
+ unsigned char top_grey[720][20];
+
+ QPixmap *bottom_pixmap;
+ unsigned char bottom_grey[720][20];
+
+ QImage *img_muted;
+ QImage *img_unmuted;
+};
+
+#endif/*__MIAV_YUV_DRAW_H__*/
+#endif/*USE_GUI*/