diff options
Diffstat (limited to 'client')
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*/ |