diff options
112 files changed, 13412 insertions, 54 deletions
@@ -1,25 +0,0 @@ -/* .in. Generated from configure.in by autoheader. */ - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Version number of package */ -#undef VERSION - -/* Defined if on Win32 platform */ -#undef WIN32 diff --git a/acinclude.m4 b/acinclude.m4 index d5ef61f..b48ee93 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1,4 +1,4 @@ -###############################################################################################################333 +################################################################################################## # Check for Qt compiler flags, linker flags, and binary packages AC_DEFUN([gw_CHECK_QT], [ @@ -9,9 +9,9 @@ AC_MSG_CHECKING([QTDIR]) AC_ARG_WITH([qtdir], [ --with-qtdir=DIR Qt installation directory [default=$QTDIR]], QTDIR=$withval) # Check that QTDIR is defined or that --with-qtdir given if test x"$QTDIR" = x ; then - QT_SEARCH="/usr/lib/qt31 /usr/local/qt31 /usr/lib/qt3 /usr/local/qt3 /usr/lib/qt2 /usr/local/qt2 /usr/lib/qt /usr/local/qt" + QT_SEARCH="/usr/lib/qt4 /usr/local/qt4 /usr/lib/qt /usr/local/qt" for i in $QT_SEARCH; do - if test -f $i/include/qglobal.h -a x$QTDIR = x; then QTDIR=$i; fi + if test -f $i/include/QtCore/QObject -a x$QTDIR = x; then QTDIR=$i; fi done fi if test x"$QTDIR" = x ; then @@ -27,13 +27,10 @@ QTDIR=`echo $QTDIR | perl -p -e 's/\\\\/\\//g'` # Figure out which version of Qt we are using AC_MSG_CHECKING([Qt version]) -QT_VER=`grep 'define.*QT_VERSION_STR\W' $QTDIR/include/qglobal.h | perl -p -e 's/\D//g'` +QT_VER=`grep 'define.*QT_VERSION_STR\W' $QTDIR/include/QtCore/qglobal.h | perl -p -e 's/\D//g'` case "${QT_VER}" in - 2*) - QT_MAJOR="2" - ;; - 3*) - QT_MAJOR="3" + 4*) + QT_MAJOR="4" ;; *) AC_MSG_ERROR([*** Don't know how to handle this Qt major version]) @@ -41,26 +38,43 @@ case "${QT_VER}" in esac AC_MSG_RESULT([$QT_VER ($QT_MAJOR)]) -# Check that moc is in path -AC_CHECK_PROG(MOC, moc, moc) -if test x$MOC = x ; then - AC_MSG_ERROR([*** moc must be in path]) -fi - -# uic is the Qt user interface compiler -AC_CHECK_PROG(UIC, uic, uic) -if test x$UIC = x ; then - AC_MSG_ERROR([*** uic must be in path]) +if test x"$QTDIR" = x ; then + # Check that moc is in path + AC_CHECK_PROG(MOC, $QTDIR/bin/moc, $QTDIR/bin/moc) + if test x$MOC = x ; then + AC_MSG_ERROR([*** moc must be in path]) + fi + + # uic is the Qt user interface compiler + AC_CHECK_PROG(UIC, $QTDIR/bin/uic, $QTDIR/bin/uic) + if test x$UIC = x ; then + AC_MSG_ERROR([*** uic must be in path]) + fi + + # qembed is the Qt data embedding utility. + # It is located in $QTDIR/tools/qembed, and must be compiled and installed + # manually, we'll let it slide if it isn't present + AC_CHECK_PROG(QEMBED, qembed, qembed) +else + # Check that moc is in path + MOC=$QTDIR/bin/moc + + # uic is the Qt user interface compiler + UIC=$QTDIR/bin/uic + + # qembed is the Qt data embedding utility. + # It is located in $QTDIR/tools/qembed, and must be compiled and installed + # manually, we'll let it slide if it isn't present + QEMBED=$QTDIR/bin/qembed + + AC_SUBST(MOC) + AC_SUBST(UIC) + AC_SUBST(QEMBED) fi -# qembed is the Qt data embedding utility. -# It is located in $QTDIR/tools/qembed, and must be compiled and installed -# manually, we'll let it slide if it isn't present -AC_CHECK_PROG(QEMBED, qembed, qembed) - # Calculate Qt include path -QT_CXXFLAGS="-I$QTDIR/include" +QT_CXXFLAGS="-I$QTDIR/include -I$QTDIR/include/Qt -I$QTDIR/include/Qt3Support -I$QTDIR/include/QtCore -I$QTDIR/include/QtDesigner -I$QTDIR/include/QtGui -I$QTDIR/include/QtNetwork -I$QTDIR/include/QtOpenGL -I$QTDIR/include/QtSql -I$QTDIR/include/QtXml" QT_IS_EMBEDDED="no" # On unix, figure out if we're doing a static or dynamic link @@ -137,7 +151,7 @@ case "${host}" in *linux*) QT_LIBS="$QT_LIB" if test $QT_IS_STATIC = yes && test $QT_IS_EMBEDDED = no; then - QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE -ldl -ljpeg" + QT_LIBS="$QT_LIBS -L$x_libraries -lQtCore -lQtGui -lXext -lX11 -lm -lSM -lICE -ldl -ljpeg" fi ;; 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*/ diff --git a/configure.in b/configure.in index 2d5721a..ec5bd62 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ # Filename: configure.in -AC_INIT(src/miav.cc) -AM_INIT_AUTOMAKE( miav, 0.3.2 ) +AC_INIT(client/miav_client.cc) +AM_INIT_AUTOMAKE( miav, 0.4.0 ) AC_PROG_CXX @@ -126,7 +126,9 @@ AC_SUBST(LDFLAGS) AC_OUTPUT( Makefile - src/Makefile + lib/Makefile + client/Makefile + server/Makefile tools/Makefile etc/Makefile pixmaps/Makefile diff --git a/lib/aa_socket.cc b/lib/aa_socket.cc new file mode 100644 index 0000000..28ecead --- /dev/null +++ b/lib/aa_socket.cc @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +#include "aa_socket.h" + +//#include <string.h> + +#include <iostream> +using namespace std; + +#include <unistd.h> +//#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <errno.h> + +#include <netinet/in.h> +#if defined(linux) +#include <endian.h> +#else +#include <sys/endian.h> +#endif /*defined(linux)*/ + +// for gethostbyname +#include <netdb.h> + +// These functions are wrappers, to preserve my nice method naming! +inline int _socket(int a,int b,int c){return socket(a,b,c);} +inline int _connect(int a,const struct sockaddr *b,socklen_t c){return connect(a,b,c);} +inline int _listen(int a,int b){return listen(a,b);} +inline int _send(int a,char *b,unsigned int c, int d){return send(a,b,c,d);} + + +AASocket::AASocket() +{ +} + +AASocket::~AASocket() +{ + int err = close(socket); // close server + if(err == -1) throw Network_error("close", strerror(errno)); +} + +void AASocket::connect(char *host, unsigned short port) +{ + // create socket + socket = _socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + // PF_INET: ipv4, PF_INET6: ipv6 + // tcp: IPPROTO_TCP + // upd: IPPROTO_UDP + + if (socket == -1) throw Network_error("socket", strerror(errno)); + + socketaddr.sin_family = AF_INET; // Use "internet protocol" IP + socketaddr.sin_port = htons(port); // connect to that port + socketaddr.sin_addr.s_addr = INADDR_ANY; + // INADDR_ANY puts your IP address automatically + + + + struct hostent *hp = gethostbyname(host); + // memcpy(&socketaddr.sin_addr.s_addr, *(hp->h_addr_list),sizeof(struct in_addr)); + memcpy(&(socketaddr.sin_addr),*(hp->h_addr_list),sizeof(struct in_addr)); + + // FIXME: gethostbyname() + // socketaddr.sin_addr.s_addr = inet_addr(host); + //inet_aton (ip, &socketaddr.sin_addr); + + int err = _connect(socket, (struct sockaddr*)&socketaddr, sizeof(socketaddr)); + if(err == -1) throw Network_error("connect", strerror(errno)); +} + +void AASocket::listen(unsigned short port) +{ + int err; + + bind_socket = _socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if(bind_socket == -1) throw Network_error("tmp socket", strerror(errno)); + + int optval = 1; + err = setsockopt(bind_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + if(err == -1) throw Network_error("setsockopt", strerror(errno)); + + socketaddr.sin_family = AF_INET; // Use "internet protocol" IP + socketaddr.sin_port = htons(port); // connect to that port + socketaddr.sin_addr.s_addr = INADDR_ANY; + // INADDR_ANY puts your IP address automatically + + // bind socket to address specified by "sa" parameter + err = bind(bind_socket, (struct sockaddr*)&socketaddr, sizeof(socketaddr)); + if(err == -1) throw Network_error("bind", strerror(errno)); + + err = _listen(bind_socket, 5); + if(err == -1) throw Network_error("listen", strerror(errno)); + + int csalen = sizeof(socketaddr); + socket = accept(bind_socket, + (struct sockaddr*)&socketaddr, + (socklen_t*)&csalen); + if(socket == -1) throw Network_error("accept", strerror(errno)); + + err = close(bind_socket); // We don't need this anymore + bind_socket = -1; + if(err == -1) throw Network_error("tmp close", strerror(errno)); +} + + +void AASocket::force_close() +{ + if(bind_socket != -1) close(bind_socket); // This should break the accept call +} + + +void AASocket::send(char* buf, unsigned int size) +{ + //unsigned int newsize = size + sizeof(unsigned int); + // char *newbuf = new char[newsize]; + + unsigned int nsize = htonl(size); + int n = _send(socket, (char*)&nsize, sizeof(unsigned int), MSG_WAITALL); + if(n == -1) throw Network_error("send", strerror(errno)); + + n = _send(socket, buf, size, MSG_WAITALL); + if(n == -1) throw Network_error("send", strerror(errno)); +} + + +int AASocket::receive(char* buf, unsigned int size) +{ + unsigned int insize; + + int n = recv(socket, &insize, sizeof(unsigned int), MSG_WAITALL); + if(n == -1) throw Network_error("recv", strerror(errno)); + + insize = ntohl(insize); + if(insize > size) { + char err_buf[256]; + sprintf(err_buf, "Buffer is too small. Should be %d is %d." , insize, size); + throw Network_error("receive", err_buf); + } + + n = recv(socket, buf, insize, MSG_WAITALL); + if(n == -1) throw Network_error("recv", strerror(errno)); + + return n; +} + + +void AASocket::send_string(string str) +{ + this->send((char*)str.c_str(), str.length()); +} + + +string AASocket::receive_string() +{ + char buf[1024]; + memset(buf, 0, sizeof(buf)); + + receive(buf, sizeof(buf)); + + return string(buf); +} + + + +#ifdef TEST_SOCKET + +/** + * Test application for AASocket + * It should print the following to stdout: + * A: Hello, how are you? + * B: Fine thanks. + * A: What about you? + * B: I'm fine too. + */ + +#include <sys/types.h> +#include <unistd.h> + +#include <string> +#include <iostream> + +int main() +{ + char buf[1024]; + memset(buf, 0, sizeof(buf)); + int f = fork(); + switch(f) { + case -1: // Fork error + perror("Fork failed!"); + return 1; + + case 0: // Forked child + { + try { + AASocket out; + + sleep(1); // Make sure the other end is listening + + // Test connect + out.connect("127.0.0.1", 6666); + + // Test raw communication send + sprintf(buf, "Hello how are you?"); + out.send(buf, sizeof(buf)); + + // Test raw communication receive + out.receive(buf, sizeof(buf)); + std::cout << "B: " << buf << std::endl; + + // Test string receive + std::string q = out.receive_string(); + std::cout << "B: " << q << std::endl; + + // Test string send + out.send_string(std::string("I'm fine too.")); + return 0; + } catch(Network_error e) { + std::cerr << "Out: " << e.error << std::endl; + } + } + default: // Parent + { + try { + AASocket in; + + // Test listen + in.listen(6666); + + // Test raw communication receive + in.receive(buf, sizeof(buf)); + std::cout << "A: " << buf << std::endl; + + // Test raw communication send + sprintf(buf, "Fine thanks."); + in.send(buf, sizeof(buf)); + + // Test string send + in.send_string(std::string("What about you?")); + + // Test string receive + std::string a = in.receive_string(); + std::cout << "A: " << a << std::endl; + return 0; + } catch(Network_error e) { + std::cerr << "In: " << e.error << std::endl; + } + } + } + return 0; +} +#endif/*TEST_SOCKET*/ diff --git a/lib/aa_socket.h b/lib/aa_socket.h new file mode 100644 index 0000000..0d02723 --- /dev/null +++ b/lib/aa_socket.h @@ -0,0 +1,42 @@ +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#include <string> + +#include <netinet/in.h> +//#include <sys/socket.h> + + +/** + * Exceptions + */ +struct Network_error { + Network_error(char *event, char *err) { + error = std::string(err) + " - in " + std::string(event); + } + std::string error; +}; + +class AASocket { +public: + AASocket(); + ~AASocket(); + + void listen(unsigned short port); + void connect(char *ip, unsigned short port); + + void send(char* buf, unsigned int buf_size); + int receive(char* buf, unsigned int buf_size); + + void send_string(std::string buf); + std::string receive_string(); + + void force_close(); + +private: + struct sockaddr_in socketaddr; + int socket; + int bind_socket; // Tmp socket for listen. +}; + +#endif/*__SOCKET_H__*/ diff --git a/lib/config.h b/lib/config.h new file mode 100644 index 0000000..e7101c9 --- /dev/null +++ b/lib/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/lib/daemon.cc b/lib/daemon.cc new file mode 100644 index 0000000..6e46bd5 --- /dev/null +++ b/lib/daemon.cc @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * daemon.cc + * + * Thu Jun 9 10:27:59 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "daemon.h" + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> + +// For getgrent and getgrent +#include <sys/types.h> +#include <grp.h> +#include <pwd.h> + +// For strcmp +#include <string.h> + +Daemon::Daemon() +{} + +Daemon::~Daemon() +{} + +int Daemon::run(const char *user, const char* group) +{ + int f; + int fd; + + // Fetch user id + int uid = -1; + struct passwd *p = getpwent(); + while(p) { + if(strcmp(p->pw_name, user) == 0) uid = p->pw_uid; + p = getpwent(); + } + if(uid == -1) { + fprintf(stderr, "Could not find user \"%s\" in /etc/passwd file.\n", user); + } + + // Fetch group id + int gid = -1; + struct group *g = getgrent(); + while(g) { + if(strcmp(g->gr_name, group) == 0) gid = g->gr_gid; + g = getgrent(); + } + if(gid == -1) { + fprintf(stderr, "Could not find group \"%s\" in /etc/group file.\n", group); + } + + chdir("/"); + umask(0); + + f = fork(); + switch(f) { + case -1: // Fork error + perror("Fork in daemon.cc"); + return 1; + + case 0: // Forked child + // Switch to given group + if(setgid(gid) != 0) { + fprintf(stderr, "Failed to change to group \"%s\" (gid: %d), quitting.\n", group, gid); + perror(""); + fprintf(stderr, "Runnning daemon as current group\n"); + } + + // Switch to given user + if(setuid(uid) != 0) { + fprintf(stderr, "Failed to change to user \"%s\" (uid: %d), quitting.\n", user, uid); + perror(""); + fprintf(stderr, "Runnning daemon as current user\n"); + } + + // Redirect stdin, stdout and stderr to /dev/null + fd = open("/dev/null", O_NOCTTY | O_RDWR, 0666); + + dup2(0, fd); + dup2(1, fd); + dup2(2, fd); + + setsid(); + + signal (SIGTERM, SIG_IGN); + signal (SIGINT, SIG_IGN); + signal (SIGHUP, SIG_IGN); + + return daemon_main(); + + default: // Parent + // exit(0); + return 0; + } +} diff --git a/lib/daemon.h b/lib/daemon.h new file mode 100644 index 0000000..1bd663e --- /dev/null +++ b/lib/daemon.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * daemon.h + * + * Thu Jun 9 10:27:59 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DAEMON_H__ +#define __DAEMON_H__ + +#include <sys/types.h> + +class Daemon { +public: + Daemon(); + virtual ~Daemon(); + + /** + * Use NOBODY_GROUP and NOBODY_USER if no privileges are needed to run. + */ + int run(const char* user, const char* group); + +private: + virtual int daemon_main() = 0; +}; + +#endif/*__DAEMON_H__*/ diff --git a/lib/file.cc b/lib/file.cc new file mode 100644 index 0000000..3a59334 --- /dev/null +++ b/lib/file.cc @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * file.cc + * + * Thu Jun 9 15:31:38 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 "file.h" + +#include "miav_config.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include <errno.h> + +// For ntoh* +#include <netinet/in.h> + +#include <stdlib.h> + +File::File(char *fn, char* ext, Info *i) +{ + char path[256]; + + info = i; + + savestate = SAVE; + + filename = new char[strlen(fn) + 1]; + extension = new char[strlen(ext) + 1]; + + strcpy(filename, fn); + strcpy(extension, ext); + + num = 0; + seqnum = 0; + fd = -1; + + int pos = (int)strrchr(filename, '/'); + memset(path, 0, sizeof(path)); + + if(pos) { // pos is NULL, a file will be created in the current dir (Which is bad) + pos -= (int)filename; // Make pos relative to the beginning of the string + strncpy(path, filename, pos); + createPath(path); + } + + Open(); +} + +File::~File() +{ + close(fd); + + info->info("This session contains the following files..."); + for(unsigned int cnt = 0; cnt < filelist.size(); cnt ++) { + info->info("[%s]", filelist[cnt].c_str()); + } + + std::string *trash = config->readString("server_trash"); + std::string *later = config->readString("server_later"); + + switch(savestate) { + case NO_CHANGE: + info->warn("File had no savestate!"); + break; + + case SAVE: + info->info("Files in this session is to be saved."); + break; + + case DELETE: + info->info("Files in this session is to be deleted (moved to trash)."); + Move((char*)trash->c_str()); + break; + + case LATER: + info->info("Files in this session is stored for later decisson."); + Move((char*)later->c_str()); + break; + } + + delete filename; + delete extension; +} + +int File::Move(char *destination) +{ + char newfile[256]; + char filename[256]; + + createPath(destination); + for(unsigned int cnt = 0; cnt < filelist.size(); cnt ++) { + // TODO: Check is the file exists... if not make som noise! + + + // TODO: Move file filelist[cnt] to the destination folder. + strcpy(filename, (char*)filelist[cnt].c_str()); + sprintf(newfile, "%s%s", destination, strrchr(filename, '/')); + if(rename((char*)filelist[cnt].c_str(), newfile) == -1) + info->error("Error moving file %s to %s:", + (char*)filelist[cnt].c_str(), + newfile, + strerror(errno)); + } + return 0; +} + +int File::Open() +{ + char fname[256]; + + if(fd != -1) { + close(fd); + fd = -1; + } + + while(fd == -1) { + if(seqnum) { + // A sequence number > 0 + sprintf(fname, "%s%.3d-%d.%s", filename, num, seqnum, extension); + } else { + // A sequence number of 0 + sprintf(fname, "%s%.3d.%s", filename, num, extension); + } + fd = open(fname, O_CREAT | O_WRONLY | O_ASYNC | O_EXCL, //| O_LARGEFILE + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if(fd == -1) num ++; + + // If more than 100 files are created in one day, something is terribly wrong! + if(num > 100) { + info->error("Something is wrong with the path [%s]!", fname); + exit(1); + } + + } + + std::string filename_string(fname); + filelist.push_back(filename_string); + + seqnum ++; + + info->info("Output file: %s", fname); + + return 0; +} + +int File::Write(void* data, int size) +{ + int w; + + w = write(fd, data, size); + + if(w != size) { + info->info("Wrapping file."); + Open(); + w = write(fd, data, size); + if(w != size) { + info->error("Out of diskspace!"); + return -1; + } + } + + return w; +} + +int File::createPath(char* path) +{ + // struct stat stats; + char *subpath; + + subpath = (char*)calloc(strlen(path) + 1, 1); + + strcpy(subpath, path); + + subpath[strrchr(subpath, '/') - subpath] = '\0'; + + if(strlen(subpath) > 0) createPath(subpath); + + info->info("Checking and/or generating directory: %s", path); + + // stat(path, &stats); + //if(!S_ISDIR(stats.st_mode) && S_ISREG(stats.st_mode)) + mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH); + // TODO: Check for creation errors! + + free(subpath); + + return 0; +} + +void File::setSaveState(n_savestate s) +{ + savestate = s; + info->info("SETTING SAVESTATE TO: %d", savestate); +} + +#ifdef __TEST_FILE +#include "info_simple.h" + +int main(int argc, char *argv[]) { + if(argc < 3) { + fprintf(stderr, "usage:\n\ttest_file [filename] [extension]\n"); + return 1; + } + + + InfoSimple info; + File file(argv[1], argv[2], &info); + + unsigned int val = 0x01234567; + file.Write(val); + +} + +#endif/* __TEST_FILE*/ diff --git a/lib/file.h b/lib/file.h new file mode 100644 index 0000000..04947df --- /dev/null +++ b/lib/file.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * file.h + * + * Thu Jun 9 15:31:38 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_FILE_H__ +#define __MIAV_FILE_H__ + +#include "info.h" +#include <stdio.h> + +#include <vector> +#include <string> + +#include <string.h> + +// For savestate_n +#include "package.h" + +class File { +public: + File(char *filename, char* ext, Info* info); + ~File(); + + int Write(void* data, int size); + /* + int Write(char* data, int size); + + int Write(unsigned long long int val); + int Write(long long int val); + int Write(long int val); + int Write(unsigned long int val); + int Write(int val); + int Write(unsigned int val); + int Write(short int val); + int Write(unsigned short int val); + */ + + void setSaveState(n_savestate savestate); + +private: + volatile n_savestate savestate; + Info* info; + + std::vector<std::string> filelist; + + int Open(); + + int Move(char *destination); + + int fd; + + int num; + int seqnum; + + char* filename; + char* extension; + + int createPath(char* path); +}; + +#endif/*__MIAV_FILE_H__*/ diff --git a/lib/frame.cc b/lib/frame.cc new file mode 100644 index 0000000..a274d89 --- /dev/null +++ b/lib/frame.cc @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * frame.cc + * + * Mon Nov 15 19:45:07 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> +#include "frame.h" + +#include "debug.h" + +#include <memory.h> +#include <stdlib.h> + +Frame::Frame(unsigned char *d, int sz) +{ + if(sz) data = new unsigned char[sz]; + if(sz && d) memcpy(data, d, sz); + size = sz; + number = 0; + memset(timecode, 0, sizeof(timecode)); + + endOfFrameStream = false; +} + +Frame::~Frame() +{ + delete data; + data = NULL; + size = 0; +} + diff --git a/lib/frame.h b/lib/frame.h new file mode 100644 index 0000000..988f460 --- /dev/null +++ b/lib/frame.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * frame.h + * + * Mon Nov 15 19:45:07 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 __FRAME_H__ +#define __FRAME_H__ + +// Definition of vector +#include <vector> + +class Frame { +public: + Frame(unsigned char *d, int sz); + ~Frame(); + + unsigned char *data; + unsigned int size; + + unsigned int number; + + unsigned int bitrate; + + bool mute; + + bool shoot; + int freeze; // 1 is freeze, -1 is unfreeze + bool record; + char timecode[12]; + + bool endOfFrameStream; +}; + +typedef std::vector< Frame* > FrameVector; + +#endif/*__FRAME_H__*/ diff --git a/lib/frame_stream.h b/lib/frame_stream.h new file mode 100644 index 0000000..bc0b9a2 --- /dev/null +++ b/lib/frame_stream.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * frame_stream.h + * + * Thu Jul 28 17:15:27 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_FRAME_STREAM_H__ +#define __MIAV_FRAME_STREAM_H__ + +class frame_stream { +public: + frame_stream() {} + virtual ~frame_stream() {} + + virtual unsigned char *readFrame() = 0; +}; + + +#endif/*__MIAV_FRAME_STREAM_H__*/ + diff --git a/lib/info.cc b/lib/info.cc new file mode 100644 index 0000000..701a705 --- /dev/null +++ b/lib/info.cc @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info.cc + * + * Mon Jun 13 22:16:18 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 "info.h" + +#include <time.h> + +Info::Info() { + pthread_mutex_init (&mutex, NULL); +} + +void Info::log(char *fmt, ...) +{ + // const time_t t; + FILE *fp; + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + fp = fopen(log_filename.c_str(), "a"); + if(!fp) { + fprintf(stderr, "Log file %s could not be opened in writemode.\n", log_filename.c_str()); + return; + } + + va_list argp; + va_start(argp, fmt); + vsprintf(buf, fmt, argp); + va_end(argp); + + time_t t = time(NULL); + char sdate[32]; + memset(sdate, 0, sizeof(sdate)); + strftime(sdate, sizeof(sdate), "%d %b %H:%M:%S", localtime(&t)); + + fprintf(fp, "%s miav[%d] %s\n", sdate, getpid(), buf); + // fprintf(stderr, "%s miav[%d] %s\n", sdate, getpid(), buf); + + fclose(fp); + + // End of safezone + pthread_mutex_unlock(&mutex); +} diff --git a/lib/info.h b/lib/info.h new file mode 100644 index 0000000..d533051 --- /dev/null +++ b/lib/info.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info.h + * + * Tue May 3 09:04:04 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_H__ +#define __MIAV_INFO_H__ + +#include "miav_config.h" +// Cyclic include :( +class MiavConfig; + +#include <time.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdarg.h> +#include <pthread.h> +#include <semaphore.h> +#include <string> +using namespace std; + +class Info { +public: + Info(); + virtual ~Info() {} + + virtual void error(char* fmt, ...) = 0; + virtual void warn(char* fmt, ...) = 0; + virtual void info(char* fmt, ...) = 0; + void log(char* fmt, ...); + +protected: + MiavConfig *config; + + pthread_mutex_t mutex; + string log_filename; +}; + +#endif/*__MIAV_INFO_H__*/ diff --git a/lib/info_simple.cc b/lib/info_simple.cc new file mode 100644 index 0000000..a3db393 --- /dev/null +++ b/lib/info_simple.cc @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info_simple.cc + * + * Tue Sep 20 17:00:25 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" +#include "info_simple.h" + +#include <stdio.h> +#include <stdarg.h> + +InfoSimple::InfoSimple(): Info() +{ +} + +InfoSimple::~InfoSimple() +{ + pthread_mutex_destroy(&mutex); +} + +void InfoSimple::error(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + fprintf(stderr, "Error: %s\n", buf); +} + +void InfoSimple::warn(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + fprintf(stderr, "Warning: %s\n", buf); +} + +void InfoSimple::info(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + fprintf(stderr, "Info: %s\n", buf); +} diff --git a/lib/info_simple.h b/lib/info_simple.h new file mode 100644 index 0000000..302a371 --- /dev/null +++ b/lib/info_simple.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info_simple.h + * + * Tue Sep 20 17:00:25 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" +#ifndef __MIAV_INFO_SIMPLE_H__ +#define __MIAV_INFO_SIMPLE_H__ + +#include "info.h" + +class InfoSimple: public Info { +public: + InfoSimple(); + ~InfoSimple(); + + void error(char* fmt, ...); + void warn(char* fmt, ...); + void info(char* fmt, ...); + +private: +}; + +#endif/*__MIAV_INFO_SIMPLE_H__*/ diff --git a/lib/jpeg_mem_dest.cc b/lib/jpeg_mem_dest.cc new file mode 100644 index 0000000..439c9a8 --- /dev/null +++ b/lib/jpeg_mem_dest.cc @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * jpeg_mem_dest.cc + * + * Thu Jul 28 16:40:08 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 "jpeg_mem_dest.h" + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently ?? size */ + +/* Expanded data destination object for stdio output */ +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + JOCTET * outbuff; /* target buffer */ + size_t * size; +} mem_destination_mgr; + +typedef mem_destination_mgr * mem_dest_ptr; + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ +void init_destination (j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + + *dest->size = 0; + dest->pub.next_output_byte = dest->outbuff; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ +void term_destination (j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + dest->outbuff+=datacount; + *dest->size+=datacount; + } +} + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ +boolean empty_output_buffer (j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + + dest->outbuff+=OUTPUT_BUF_SIZE; + *dest->size+=OUTPUT_BUF_SIZE; + + dest->pub.next_output_byte = dest->outbuff; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +/* + * Prepare for output to a memory buffer. + . The caller must have already allocated the buffer, and is responsible + * for closing it after finishing compression. + */ +void jpeg_mem_dest (j_compress_ptr cinfo, char * outbuff, size_t * size) +{ + mem_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(mem_destination_mgr)); + } + + dest = (mem_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outbuff = (JOCTET *)outbuff; + dest->size = (size_t *)size; +} diff --git a/lib/jpeg_mem_dest.h b/lib/jpeg_mem_dest.h new file mode 100644 index 0000000..b1ff103 --- /dev/null +++ b/lib/jpeg_mem_dest.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * jpeg_mem_dest.h + * + * Thu Jul 28 16:40:08 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_JPEG_MEM_DEST_H__ +#define __MIAV_JPEG_MEM_DEST_H__ + +#include <stdio.h> + +extern "C" { +#include <jpeglib.h> +} + +void jpeg_mem_dest (j_compress_ptr cinfo, char * outbuff, size_t * size); + +#endif/*__MIAV_JPEG_MEM_DEST_H__*/ diff --git a/lib/miav_config.cc b/lib/miav_config.cc new file mode 100644 index 0000000..adfa5c5 --- /dev/null +++ b/lib/miav_config.cc @@ -0,0 +1,492 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav_config.cc + * + * Sat Feb 19 14:13: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> +#include "miav_config.h" + +MiavConfig *config; + +MiavConfig::MiavConfig(char *file, Info *i) +{ + info = i; + configs = NULL; + + filename = string(file); + + // Read config file + FILE* fp = fopen(file, "r"); + + if(!fp) { + if(info) info->error("Error reading configuration file %s\n", file); + else fprintf(stderr, "Error reading configuration file %s\n", file); + return; + } + fseek(fp, 0, SEEK_END); + int fsz = ftell(fp) + 1; + fseek(fp, 0, SEEK_SET); + + char *raw = (char*)calloc(fsz, 1); + fread(raw, 1, fsz, fp); + + fclose(fp); + + configs = parse(raw); + + free(raw); +} + +MiavConfig::~MiavConfig() +{ + _cfg *die = NULL; + _cfg *cfg = configs; + + while(cfg) { + if(die) free(die); + die = cfg; + cfg = cfg->next; + } + if(die) free(die); +} + +/** + * Prints a reasonable error message when a parse error occurres. + */ +void MiavConfig::parseError(char* msg, _cfg* cfg) +{ + if(info) info->error("Error parsing file %s at line %d:\n\t%s\n\t%s\n", + filename.c_str(), + cfg->line, + cfg->orig, + msg); + else fprintf(stderr, "Error parsing file %s at line %d:\n\t%s\n\t%s\n", + filename.c_str(), + cfg->line, + cfg->orig, + msg); +} + +_cfg* MiavConfig::readLines(char* raw) +{ + int line = 1; + + _cfg *first = (_cfg*)calloc(1, sizeof(_cfg)); + _cfg *current = first; + _cfg *next = NULL; + + char *nl = strchr(raw, '\n'); + + while(nl != NULL) { + int len = nl - raw; + + current->line = line; + + current->orig = (char*) calloc(len + 1, 1); + strncpy(current->orig, raw, len); + + // Find next newline + raw = nl+1; + nl = strchr(raw, '\n'); + + line++; + + // Add _cfg + if(nl != NULL) { + next = (_cfg*)calloc(1, sizeof(_cfg)); + current->next = next; + current = next; + } else { + current->next = NULL; + } + } + + return first; +} + +_cfg* MiavConfig::parseLines(_cfg *cfg) +{ + if(cfg == NULL) return NULL; + + char *l = cfg->left = (char*)calloc(1, strlen(cfg->orig)); + char *r = cfg->right = (char*)calloc(1, strlen(cfg->orig)); + + char *p = cfg->orig; + + // Skip leftmost whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + // Empty line, with whitespaces + if(p == cfg->orig + strlen(cfg->orig)) { + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Parse left side + while(p < cfg->orig + strlen(cfg->orig) && !strchr("\t ", *p)) { + if(strchr("#", *p)) { + if(l != cfg->left) parseError("Incomplete line.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + if(strchr("=", *p)) break; + + if(strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_", *p)) { + *l = *p; + l++; + } else { + char buf[256]; + sprintf(buf, "Invalid left hand side character at [%s].", p); + parseError(buf, cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + p++; + } + + // Skip whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + if(*p != '=') { + parseError("Expected '='.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + p++; // Get past the '=' + + // Skip whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + // Parse right hand side + int instring = 0; + while(p < cfg->orig + strlen(cfg->orig) && !(strchr("\t ", *p) && instring != 1)) { + if(*p == '\"') instring++; + if(instring > 2) { + parseError("Too many '\"'.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + if(instring == 1) { + // Accept all chars + *r= *p; + r++; + } else { + // Accept only those chars valid for the data types. + if(strchr("truefalseyesnoTRUEFALSEYESNO1234567890\",.-", *p)) { + if(*p == ',') *r= '.'; + *r = *p; + r++; + } else if(!strchr("\n", *p)) { + char buf[256]; + sprintf(buf, "Invalid right hand side character at [%s].", p); + parseError(buf, cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + if(*p == '#') break; + } + + p++; + } + + // Skip whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + // Detect if whitespace ocurred inside righthand value. + if(p != cfg->orig + strlen(cfg->orig)) { + parseError("Invalid use of whitespace.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for instring (string not ended) + if(instring == 1) { + parseError("String not closed.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for empty line + if(l == cfg->left && r == cfg->right) { + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for empty left side. + if(l == cfg->left) { + parseError("Empty left side.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for empty right side. + if(r == cfg->right) { + parseError("Empty right side.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + cfg->next = parseLines(cfg->next); + return cfg; +} + + +_cfg *MiavConfig::createSemantics(_cfg *cfg) { + if(cfg == NULL) return NULL; + + cfg->type = CONFIG_UNKNOWN; + + // Boolean - true + if(strcasecmp(cfg->right, "yes") == 0 || + strcasecmp(cfg->right, "true") == 0) { + cfg->type = CONFIG_BOOL; + cfg->boolval = true; + } + + // Boolean - false + if(strcasecmp(cfg->right, "no") == 0 || + strcasecmp(cfg->right, "false") == 0) { + cfg->type = CONFIG_BOOL; + cfg->boolval = false; + } + + // String + if(cfg->right[0] == '\"') { + cfg->type = CONFIG_STRING; + cfg->right[strlen(cfg->right) - 1] = '\0'; + cfg->stringval = new string(cfg->right + 1); + + } + + // Number + bool number = true; + char *p = cfg->right; + while(p < cfg->right + strlen(cfg->right)) { + if(!strchr("01234567890.-", *p)) number = false; + p++; + } + + // Integer + if(number && strstr(cfg->right, ".") == NULL ) { + cfg->type = CONFIG_INT; + cfg->intval = atoi(cfg->right); + } + + // Float + if(number && strstr(cfg->right, ".") != NULL) { + cfg->type = CONFIG_FLOAT; + cfg->floatval = atof(cfg->right); + } + + if(cfg->type == CONFIG_UNKNOWN) { + parseError("Unknown type (see 'man miav.conf' for valid right hand sides).", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return createSemantics(next); + } + + // Create name + cfg->name = new string(cfg->left); + + cfg->next = createSemantics(cfg->next); + return cfg; +} + + +_cfg* MiavConfig::parse(char* raw) +{ + _cfg *first = readLines(raw); + first = parseLines(first); + + first = createSemantics(first); + + /* + _cfg* cfg = first; + while(cfg) { + printf("Node:\n"); + printf("\tLine: [%d]\n", cfg->line); + printf("\tOrig: [%s]\n", cfg->orig); + printf("\tLeft: [%s]\n", cfg->left); + printf("\tRight: [%s]\n", cfg->right); + + switch(cfg->type) { + case CONFIG_INT: + printf("\tInt value: %d\n", cfg->intval); + break; + case CONFIG_BOOL: + printf("\tBool value: %d\n", cfg->boolval); + break; + case CONFIG_FLOAT: + printf("\tFloat value: %f\n", cfg->floatval); + break; + case CONFIG_STRING: + printf("\tString value: %s\n", cfg->stringval->c_str()); + break; + case CONFIG_UNKNOWN: + printf("\tUnknown type: %s\n", cfg->right); + break; + } + + cfg= cfg->next; + } + */ + return first; +} + +int MiavConfig::readInt(char *node) +{ + _cfg* n = findNode(node); + if(n) { + if(n->type == CONFIG_INT) return n->intval; + parseError("Expected integer.", n); + } + return 0; +} + +bool MiavConfig::readBool(char *node) +{ + _cfg* n = findNode(node); + if(n) { + if(n->type == CONFIG_BOOL) return n->boolval; + if(n->type == CONFIG_INT) return (n->intval != 0); + parseError("Expected boolean.", n); + } + return false; +} + +string *MiavConfig::readString(char *node) +{ + _cfg* n = findNode(node); + if(n) { + if(n->type == CONFIG_STRING) return n->stringval; + parseError("Expected string.", n); + } + return &emptyString; +} + +float MiavConfig::readFloat(char *node) +{ + _cfg* n = findNode(node); + if(n) { + if(n->type == CONFIG_FLOAT) return n->floatval; + if(n->type == CONFIG_INT) return (float)n->intval; + parseError("Expected float.", n); + } + return 0.0f; +} + +_cfg *MiavConfig::findNode(char* node) +{ + _cfg *cfg = configs; + + while(cfg) { + if(!strcmp(node, cfg->name->c_str())) return cfg; + cfg = cfg->next; + } + if(info) info->error("Missing line in configuration file: \"%s\"!\n", node); + else fprintf(stderr, "Missing line in configuration file: \"%s\"!\n", node); + + return NULL; +} + +#ifdef __TEST_MIAV_CONFIG + +int main(int argc, char *argv[]) { + if(argc < 2) { + fprintf(stderr, "usage:\n\tmiav_config [filename]\n"); + return 1; + } + + MiavConfig cfg(argv[1]); + printf("Server user: [%s]\n", cfg.readString("server_user")->c_str()); + printf("Resolution: [%f]\n", cfg.readFloat("screensize")); + printf("Resolution (as int): [%d]\n", cfg.readInt("screensize")); + printf("Width: [%d]\n", cfg.readInt("pixel_width")); + printf("Width (as float): [%f]\n", cfg.readFloat("pixel_width")); + printf("Frame quality: [%d]\n", cfg.readInt("frame_quality")); + printf("Skip frames: [%d]\n", cfg.readBool("player_skip_frames")); + printf("Skip frames (as int): [%d]\n", cfg.readInt("player_skip_frames")); + printf("Frame quality (as bool): [%d]\n", cfg.readBool("frame_quality")); + +} + +#endif/* __TEST_MIAV_CONFIG*/ diff --git a/lib/miav_config.h b/lib/miav_config.h new file mode 100644 index 0000000..a8658f1 --- /dev/null +++ b/lib/miav_config.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav_config.h + * + * Sat Feb 19 14:13: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" +#ifndef __MIAV_MIAV_CONFIG_H__ +#define __MIAV_MIAV_CONFIG_H__ + +#include <string> +using namespace std; + +#include "info.h" +// Cyclic include :( +class Info; + +typedef enum { + CONFIG_UNKNOWN, + CONFIG_INT, + CONFIG_BOOL, + CONFIG_FLOAT, + CONFIG_STRING +} ConfigType; + + +typedef struct __cfg { + // For parsing + char* orig; + int line; + char* left; + char* right; + + // For traversal + string *name; + ConfigType type; + int intval; + bool boolval; + float floatval; + string *stringval; + + struct __cfg* next; +} _cfg; + +class MiavConfig { +public: + MiavConfig(char *file, Info *info = NULL); + ~MiavConfig(); + + int readInt(char *node); + bool readBool(char *node); + string *readString(char *node); + float readFloat(char *node); + +protected: + Info *info; + string filename; + + _cfg *createSemantics(_cfg *cfg); + _cfg* readLines(char* raw); + _cfg* parseLines(_cfg *cfg); + _cfg *parse(char* raw); + string emptyString; + + +#if 0 + _cfg *addConfig(_cfg *parent, char* conf); + char *strip(char* conf); +#endif + + void parseError(char* msg, _cfg *cfg); + _cfg *findNode(char* node); + _cfg *configs; +}; + +extern MiavConfig *config; + +#endif/*__MIAV_MIAV_CONFIG_H__*/ diff --git a/lib/mutex.cc b/lib/mutex.cc new file mode 100644 index 0000000..483d71a --- /dev/null +++ b/lib/mutex.cc @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mutex.cc + * + * Sat Oct 8 17:44:09 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" +#include "mutex.h" + +Mutex::Mutex() +{ + pthread_mutex_init (&mutex, NULL); +} + +Mutex::~Mutex() +{ + pthread_mutex_destroy(&mutex); +} + +void Mutex::lock() +{ + pthread_mutex_lock( &mutex ); +} + +void Mutex::unlock() +{ + pthread_mutex_unlock( &mutex ); +} diff --git a/lib/mutex.h b/lib/mutex.h new file mode 100644 index 0000000..0b1f4e7 --- /dev/null +++ b/lib/mutex.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mutex.h + * + * Sat Oct 8 17:44:09 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" +#ifndef __MIAV_MUTEX_H__ +#define __MIAV_MUTEX_H__ + +#include <pthread.h> + +class Mutex { +public: + Mutex(); + ~Mutex(); + + void lock(); + void unlock(); + +private: + pthread_mutex_t mutex; +}; + +#endif/*__MIAV_MUTEX_H__*/ diff --git a/lib/network.cc b/lib/network.cc new file mode 100644 index 0000000..799bc98 --- /dev/null +++ b/lib/network.cc @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * network.cc + * + * Wed Nov 3 21:23:14 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> +#include "network.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> + +Network::Network(Socket *gs, Info *ginfo) +{ + info = ginfo; + s = gs; +} + +Network::~Network() +{ +} + +int Network::write(void *buf, int size) +{ + if(!s->isConnected()) { + // info->error("Write attempted to a socket not connected!"); + return -1; + } + int n = send(s->ssocket, buf, size, MSG_WAITALL); + + if(n == -1) { + info->error("An error occurred!"); + } + + return n; +} + +int Network::read(void *buf, int size) +{ + if(!s->isConnected()) { + // info->error("Read attempted from a socket not connected!"); + return -1; + } + int n = recv(s->ssocket, buf, size, MSG_WAITALL); + + if(n == -1) { + info->error("An error occurred!"); + } + + return n; +} + +/* +struct msghdr { + void *msg_name // Optional address. + socklen_t msg_namelen // Size of address. + struct iovec *msg_iov // Scatter/gather array. + int msg_iovlen // Members in msg_iov. + void *msg_control // Ancillary data; see below. + socklen_t msg_controllen // Ancillary data buffer len. + int msg_flags // Flags on received message. +}; +*/ + +int Network::sendPackage(n_header *h, void* buf, int bufsz) +{ + struct msghdr msg; + struct iovec iovecs[2]; + + if(!s->isConnected()) { + // info->error("Write attempted to a socket not connected!"); + return -1; + } + + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = iovecs; + msg.msg_iovlen = 2; + + msg.msg_iov[0].iov_base = h; + msg.msg_iov[0].iov_len = sizeof(*h); + + msg.msg_iov[1].iov_base = buf; + msg.msg_iov[1].iov_len = bufsz; + + int n = sendmsg(s->ssocket, &msg, 0); + if(n < 0) { + info->error("A network error ocurred during sendPackage!"); + return -1; + } + + return n; +} + +int Network::recvPackage(n_header *h, void* buf, int bufsz) +{ + struct msghdr msg; + struct iovec iovecs[2]; + + if(!s->isConnected()) { + // info->error("Read attempted to a socket not connected!"); + return -1; + } + + memset(&msg, 0, sizeof(msg)); + + iovecs[0].iov_base = h; + iovecs[0].iov_len = sizeof(*h); + + iovecs[1].iov_base = buf; + iovecs[1].iov_len = bufsz; + + msg.msg_iov = iovecs; + msg.msg_iovlen = 2; + + int n = recvmsg(s->ssocket, &msg, MSG_WAITALL); + + if(n < 0) { + info->error("A network error ocurred during recvPackage!"); + return -1; + } + + if(msg.msg_iovlen != 2) { + info->error("Wrong package format!"); + return -1; + } + return n; +} + diff --git a/lib/network.h b/lib/network.h new file mode 100644 index 0000000..f64310e --- /dev/null +++ b/lib/network.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * network.h + * + * Wed Nov 3 21:23:14 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 __MIAVLIB_NETWORK_H__ +#define __MIAVLIB_NETWORK_H__ + +#include "socket.h" +#include "package.h" +#include "info.h" + +class Network { +public: + Network(Socket *gs, Info* ginfo); + ~Network(); + + // Raw communication + int write(void *buf, int size); + int read(void *buf, int size); + + // Package communication + int sendPackage(n_header *h, void* buf, int bufsz); + int recvPackage(n_header *h, void* buf, int bufsz); + +private: + Info *info; + Socket *s; +}; + +#endif/*__NETWORK_H__*/ + + diff --git a/lib/package.h b/lib/package.h new file mode 100644 index 0000000..a16557a --- /dev/null +++ b/lib/package.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * package.h + * + * Tue Nov 9 10:57:20 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 __MIAVLIB_PACKAGE_H__ +#define __MIAVLIB_PACKAGE_H__ + +typedef enum { + NO_CHANGE = 0, + SAVE, + DELETE, + LATER +} n_savestate; + +typedef enum { + DATA_HEADER = 0x0001, + INFO_HEADER = 0x0002 +} n_header_type; + +typedef struct { + n_header_type header_type; + union { + struct { + char cpr[32]; // Can hold wierd cpr numbers as well (not only danish) + bool record; + bool freeze; + bool snapshot; + n_savestate savestate; + bool mute; + } h_data; + struct { + int fisk; + } h_info; + } header; +} n_header; + + +#endif/*__PACKAGE_H__*/ + + diff --git a/lib/queue.h b/lib/queue.h new file mode 100644 index 0000000..3cb6fbc --- /dev/null +++ b/lib/queue.h @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * queue.h + * + * Tue Nov 9 10:57:20 CET 2004 + * Copyright 2004 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" +#ifndef __RTVIDEOREC_QUEUE_H +#define __RTVIDEOREC_QUEUE_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +//#include <avformat.h> +//#include <avcodec.h> + +#include "thread.h" +#include "util.h" + +typedef struct __buf_t { + struct __buf_t *next; + struct __buf_t *prev; + void *data; +} buf_t; + + +template<typename T> +class Queue { +public: + Queue(int glimit = 0); + ~Queue(); + + void push(T *t); + T *pop(); + T *peek(); + + void lock(); + void unlock(); + + int length(); + +private: + volatile bool locked; + int limit; + buf_t *head; + buf_t *tail; + int count; + pthread_mutex_t mutex; + T *_pop(); +}; + +/** + * Initialize queue + */ +template<typename T> +Queue<T>::Queue(int glimit) +{ + locked = false; + pthread_mutex_init (&mutex, NULL); + limit = glimit; + count = 0; + head = NULL; + tail = NULL; +} + +/** + * Clean up queue. + */ +template<typename T> +Queue<T>::~Queue() +{ + if(count != 0) { + fprintf(stderr, "Queue not empty (%d)\n", count); + while(T *t = _pop()) delete t; + } + pthread_mutex_destroy(&mutex); +} + +/** + * Push element on queue. + */ +template<typename T> +void Queue<T>::push(T *t) +{ + if(locked) { + delete t; + return; + } + + pthread_mutex_lock(&mutex); + + buf_t *b = (buf_t*)xmalloc(sizeof(*b)); + b->data = (void*)t; + + assert(b != NULL); + + if(limit && count > 0) { + T* tmp = (T*)_pop(); + delete tmp; + } + + if(!head) { + head = tail = b; + b->next = b->prev = NULL; + count = 1; + pthread_mutex_unlock(&mutex); + return; + } + + b->next = tail; + b->prev = NULL; + if(tail) + tail->prev = b; + tail = b; + count++; + + pthread_mutex_unlock(&mutex); +} + +/** + * Pop element from queue. + * If queue is empty, NULL is returned. + */ +template<typename T> +T *Queue<T>::pop() +{ + pthread_mutex_lock(&mutex); + T *d = _pop(); + pthread_mutex_unlock(&mutex); + return d; +} + +/** + * Pop helper method + * If queue is empty, NULL is returned. + */ +template<typename T> +T *Queue<T>::_pop() +{ + T *d; + buf_t *b; + + assert(count >= 0); + + if(count == 0) { + return NULL; + } + + b = head; + if(b->prev) + b->prev->next = NULL; + head = b->prev; + if(b == tail) + tail = NULL; + count--; + + d = (T*)b->data; + free(b); + + return d; +} + +/** + * Peek foremost element in queue + * If queue is empty, NULL is returned. + */ +template<typename T> +T *Queue<T>::peek() +{ + // pthread_mutex_lock(&mutex); + T *d; + + // assert(count >= 0); + + if(count == 0) { + return NULL; + } + + d = (T*)head->data; + // pthread_mutex_unlock(&mutex); + return d; +} + +/** + * Print current length of queue + */ +template<typename T> +int Queue<T>::length() +{ + int length; + pthread_mutex_lock(&mutex); + length = count; + pthread_mutex_unlock(&mutex); + return length; +} + +/** + * Lock the queue (all elements pushed from this point will be deleted.) + */ +template<typename T> +void Queue<T>::lock() +{ + fprintf(stderr, "Lock this motherfucker..."); fflush(stderr); + locked = true; + fprintf(stderr, "done\n"); fflush(stderr); +} + +/** + * Unlock the queue. + */ +template<typename T> +void Queue<T>::unlock() +{ + fprintf(stderr, "Unlock this motherfucker..."); fflush(stderr); + locked = false; + fprintf(stderr, "done\n"); fflush(stderr); +} + +#endif + diff --git a/lib/semaphore.cc b/lib/semaphore.cc new file mode 100644 index 0000000..147bd24 --- /dev/null +++ b/lib/semaphore.cc @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * semaphore.cc + * + * Sat Oct 8 17:44:13 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" +#include "semaphore.h" + +Semaphore::Semaphore() +{ + sem_init(&semaphore, 0, 0); +} + +Semaphore::~Semaphore() +{ + sem_destroy(&semaphore); +} + +void Semaphore::post() +{ + sem_post(&semaphore); +} + +void Semaphore::wait() +{ + sem_wait(&semaphore); +} diff --git a/lib/semaphore.h b/lib/semaphore.h new file mode 100644 index 0000000..85f4c09 --- /dev/null +++ b/lib/semaphore.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * semaphore.h + * + * Sat Oct 8 17:44:13 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" +#ifndef __MIAV_SEMAPHORE_H__ +#define __MIAV_SEMAPHORE_H__ + +#include </usr/include/semaphore.h> + +class Semaphore { +public: + Semaphore(); + ~Semaphore(); + + void post(); + void wait(); + +private: + sem_t semaphore; +}; + +#endif/*__MIAV_SEMAPHORE_H__*/ diff --git a/lib/socket.cc b/lib/socket.cc new file mode 100644 index 0000000..2ae88dc --- /dev/null +++ b/lib/socket.cc @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * socket.cc + * + * Mon Nov 8 10:49:33 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> + +#include "socket.h" + +#include <errno.h> + +Socket::Socket(Info *ginfo) +{ + info = ginfo; + connected = false; + err = 0; +} + +Socket::Socket(u_short port, Info *ginfo) +{ + info = ginfo; + connected = false; + err = 0; + + // create socket + ssocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + // PF_INET: ipv4, PF_INET6: ipv6 + // tcp: IPPROTO_TCP + // upd: IPPROTO_UDP + + if (ssocket < 0) { + err = 1; + info->error("Socket: socket() failed!"); + } + + socketaddr.sin_family = AF_INET; // Use "internet protocol" IP + socketaddr.sin_port = htons(port); // connect to that port + socketaddr.sin_addr.s_addr = INADDR_ANY; + // INADDR_ANY puts your IP address automatically +} + + +Socket::~Socket() +{ + // if(err) perror("Socket: No socket to kill"); + // printf("Socket: I'm melting...[%d]\n", ssocket); + if(ssocket >= 0) close(ssocket); // close server socket +} + + +Socket Socket::slisten() +{ + Socket s = Socket(info); + + if(err) { + //info->error("Socket: No socket present!"); + return s; + } + if(!connected) { + // bind socket to address specified by "sa" parameter + err = bind(ssocket, (struct sockaddr*)&socketaddr, sizeof(socketaddr)); + + if (err) { + info->error("Socket: bind() failed! %s", strerror(errno)); + return s; + } + + // start listen for connection - kernel will accept connection + // requests (max 5 in queue) + err = listen(ssocket, 5); + if(err) { + info->error("Socket: listen() failed! %s", strerror(errno)); + return s; + } + } + + // accept new connection and get its connection descriptor + int csalen = sizeof(s.socketaddr); + + s.ssocket = accept(ssocket, + (struct sockaddr*)&s.socketaddr, + (socklen_t*)&csalen); + + if (s.ssocket < 0) { + s.connected = false; + err = 1; + info->error("Socket: accept() failed! %s", strerror(errno)); + return s; + } + + connected = true; + s.connected = true; + return s; +} + + +int Socket::sconnect(char *ip) +{ + if(err) { + connected = false; + info->error("Socket: No socket present!"); + return err; + } + + // FIXME: gethostbyname() + socketaddr.sin_addr.s_addr = inet_addr(ip); + //inet_aton (ip, &socketaddr.sin_addr); + + err = connect(ssocket, (struct sockaddr*)&socketaddr, sizeof(socketaddr)); + if (err) { + connected = false; + info->error("Socket: connect() failed! %s", strerror(errno)); + return err; + } + // fprintf(stderr, "Socket connected\n"); + connected = true; + return 0; +} + + +bool Socket::isConnected() +{ + return connected; +} + +bool Socket::hasError() +{ + return err != 0; +} diff --git a/lib/socket.h b/lib/socket.h new file mode 100644 index 0000000..df2a133 --- /dev/null +++ b/lib/socket.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * socket.h + * + * Mon Nov 8 10:49:33 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 __MIAVLIB_SOCKET_H__ +#define __MIAVLIB_SOCKET_H__ + +#include <stdio.h> +#include <string.h> + +#include <unistd.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include "info.h" + +class Socket { +public: + Socket(Info *ginfo); + Socket(u_short port, Info *ginfo); + ~Socket(); + Socket slisten(); + int sconnect(char *ip); + bool isConnected(); + bool hasError(); + + struct sockaddr_in socketaddr; + int ssocket; + bool connected; + +private: + Info *info; + int err; +}; + +#endif/*__SOCKET_H__*/ diff --git a/lib/thread.cc b/lib/thread.cc new file mode 100644 index 0000000..147cf00 --- /dev/null +++ b/lib/thread.cc @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * thread.cc + * + * Sun Oct 31 12:12:20 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> + +#include "thread.h" +#include <stdio.h> + +static void* thread_run(void *data) { + Thread *t = (Thread*)data; + t->thread_main(); + return NULL; +} + +Thread::Thread() +{ +} + +Thread::~Thread() +{ +} + +void Thread::run() +{ + pthread_attr_init(&attr); + + pthread_create(&tid, &attr, thread_run, this); +} + +void Thread::wait_stop() +{ + pthread_join(tid, NULL); +} diff --git a/lib/thread.h b/lib/thread.h new file mode 100644 index 0000000..3d58d74 --- /dev/null +++ b/lib/thread.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * thread.h + * + * Sun Oct 31 12:12:20 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 __THREAD_H__ +#define __THREAD_H__ + +#include <pthread.h> +#include <semaphore.h> + +class Thread { +public: + Thread(); + virtual ~Thread(); + + void run(); + void wait_stop(); + + virtual void thread_main() = 0; + +private: + pthread_attr_t attr; + pthread_t tid; +}; + +#endif/*__THREAD_H__*/ diff --git a/lib/threadsafe_queue.cc b/lib/threadsafe_queue.cc new file mode 100644 index 0000000..89f2d6a --- /dev/null +++ b/lib/threadsafe_queue.cc @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * threadsafe_queue.cc + * + * Tue Sep 27 14:43:45 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" +#include "threadsafe_queue.h" +/* +template <typename T> +ThreadSafeQueue<T>::ThreadSafeQueue() +{ + pthread_mutex_init (&mutex, NULL); + sem_init(&semaphore, 0, 0); +} + +template <typename T> +ThreadSafeQueue<T>::~ThreadSafeQueue() +{ + pthread_mutex_destroy(&mutex); + sem_destroy(&semaphore); +} + +*/ diff --git a/lib/threadsafe_queue.h b/lib/threadsafe_queue.h new file mode 100644 index 0000000..b6d5725 --- /dev/null +++ b/lib/threadsafe_queue.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * threadsafe_queue.h + * + * Tue Sep 27 14:01:01 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" +#ifndef __MIAV_THREADSAFE_QUEUE_H__ +#define __MIAV_THREADSAFE_QUEUE_H__ + +#include "mutex.h" +#include "semaphore.h" + +template <typename T> +class ThreadSafeQueue { +public: + ThreadSafeQueue() { + // pthread_mutex_init (&mutex, NULL); + // sem_init(&semaphore, 0, 0); + } + + virtual ~ThreadSafeQueue() { + // pthread_mutex_destroy(&mutex); + //sem_destroy(&semaphore); + } + + virtual void push(T t) = 0; + virtual T pop() = 0; + virtual int size() = 0; + +protected: + // pthread_mutex_t mutex; + Mutex mutex; + //sem_t semaphore; + Semaphore semaphore; +}; + +#endif/*__MIAV_THREADSAFE_QUEUE_H__*/ diff --git a/lib/threadsafe_queue_fifo.cc b/lib/threadsafe_queue_fifo.cc new file mode 100644 index 0000000..6dbcb67 --- /dev/null +++ b/lib/threadsafe_queue_fifo.cc @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * threadsafe_queue_fifo.cc + * + * Tue Sep 27 14:01:10 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" +#include "threadsafe_queue_fifo.h" + +ThreadSafeQueueFIFO::ThreadSafeQueueFIFO() +{ +} + +ThreadSafeQueueFIFO::~ThreadSafeQueueFIFO() +{ +} + +void ThreadSafeQueueFIFO::push(FrameVector *framevector) +{ + mutex.lock(); + queue.push(framevector); + mutex.unlock(); + + semaphore.post(); +} + +FrameVector *ThreadSafeQueueFIFO::pop() +{ + semaphore.wait(); + + FrameVector *framevector; + + mutex.lock(); + framevector = queue.front(); + queue.pop(); + mutex.unlock(); + + return framevector; +} + +int ThreadSafeQueueFIFO::size() +{ + int sz; + + mutex.lock(); + sz = queue.size(); + mutex.unlock(); + + return sz; +} diff --git a/lib/threadsafe_queue_fifo.h b/lib/threadsafe_queue_fifo.h new file mode 100644 index 0000000..ee3ac3b --- /dev/null +++ b/lib/threadsafe_queue_fifo.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * threadsafe_queue_fifo.h + * + * Tue Sep 27 14:01:10 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" +#ifndef __MIAV_THREADSAFE_QUEUE_FIFO_H__ +#define __MIAV_THREADSAFE_QUEUE_FIFO_H__ + +#include "threadsafe_queue.h" + +#include "frame.h" + +#include <queue> + +class ThreadSafeQueueFIFO: public ThreadSafeQueue<FrameVector*> { +public: + ThreadSafeQueueFIFO(); + ~ThreadSafeQueueFIFO(); + + void push(FrameVector* framevector); + FrameVector* pop(); + int size(); + +private: + std::queue<FrameVector*> queue; +}; + +#endif/*__MIAV_THREADSAFE_QUEUE_FIFO_H__*/ diff --git a/lib/threadsafe_queue_priority.cc b/lib/threadsafe_queue_priority.cc new file mode 100644 index 0000000..df7ae8c --- /dev/null +++ b/lib/threadsafe_queue_priority.cc @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * threadsafe_queue_priority.cc + * + * Tue Sep 27 14:01:24 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" +#include "threadsafe_queue_priority.h" + +#include "util.h" + +ThreadSafeQueuePriority::ThreadSafeQueuePriority(Info* i, unsigned int number) + // : ThreadSafeQueue< Frame* >() +{ + info = i; + framenumber = number; +} + +ThreadSafeQueuePriority::~ThreadSafeQueuePriority() +{ +} + +void ThreadSafeQueuePriority::push(Frame *frame) +{ + // Lock mutex + // pthread_mutex_lock( &mutex ); + mutex.lock(); + queue.push(frame); + // pthread_mutex_unlock( &mutex ); + mutex.unlock(); + // Unlock mutex + + // sem_post(&semaphore); + semaphore.post(); +} + +Frame *ThreadSafeQueuePriority::pop() +{ + semaphore.wait(); + // sem_wait(&semaphore); + + Frame *tmpframe = NULL; + Frame *frame = NULL; + + while( frame == NULL ) { + // Lock mutex + // pthread_mutex_lock( &mutex ); + mutex.lock(); + + tmpframe = queue.top(); + + if(tmpframe && tmpframe->number == framenumber ) { + queue.pop(); + frame = tmpframe; + framenumber++; + } + + // pthread_mutex_unlock( &mutex ); + mutex.unlock(); + // Unlock mutex + + if(frame == NULL) sleep_0_2_frame(); + } + + return frame; +} + +int ThreadSafeQueuePriority::size() +{ + int sz; + + // Lock mutex + // pthread_mutex_lock( &mutex ); + mutex.lock(); + sz = queue.size(); + // pthread_mutex_unlock( &mutex ); + mutex.unlock(); + // Unlock mutex + + return sz; +} diff --git a/lib/threadsafe_queue_priority.h b/lib/threadsafe_queue_priority.h new file mode 100644 index 0000000..8d3cdf1 --- /dev/null +++ b/lib/threadsafe_queue_priority.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * threadsafe_queue_priority.h + * + * Tue Sep 27 14:01:24 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" +#ifndef __MIAV_THREADSAFE_QUEUE_PRIORITY_H__ +#define __MIAV_THREADSAFE_QUEUE_PRIORITY_H__ + +#include "threadsafe_queue.h" + +#include "frame.h" + +#include <queue> +#include <functional> + +#include "info.h" + +// Method for use, when comparing Frames in priority queue. +template <typename T> +struct priority : std::binary_function<T, T, bool> { + bool operator() (const T& a, const T& b) const { + return ((Frame*)a)->number > ((Frame*)b)->number; + } +}; + +class ThreadSafeQueuePriority: public ThreadSafeQueue< Frame* > { +public: + ThreadSafeQueuePriority(Info *info, unsigned int framenumber = 0); + ~ThreadSafeQueuePriority(); + + void push(Frame *frame); + Frame *pop(); + int size(); + +private: + Info* info; + + unsigned int framenumber; + std::priority_queue< Frame*, std::vector<Frame*>, priority<Frame*> > queue; +}; + +#endif/*__MIAV_THREADSAFE_QUEUE_PRIORITY_H__*/ diff --git a/lib/util.cc b/lib/util.cc new file mode 100644 index 0000000..11f1402 --- /dev/null +++ b/lib/util.cc @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * util.cc + * + * Sun Oct 31 12:12:20 CET 2004 + * Copyright 2004 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> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +// For nanosleep +#include <time.h> + +#include "util.h" + +void *xmalloc(size_t s) +{ + void *p; + assert(s > 0); + + p = malloc(s); + if(!p) { + fprintf(stderr, "Out of memory in xmalloc\n"); + exit(1); + } + memset(p, 0, s); + return p; +} + +void *xrealloc(void *b, size_t s) +{ + void *p; + assert(s > 0); + + if(!b) return xmalloc(s); + + p = realloc(b, s); + if(!p) { + fprintf(stderr, "Out of memory in xrealloc\n"); + exit(1); + } + return p; +} + +void sleep_1_frame() +{ + // Sleep 1/25th of a second + + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = 1000000000L / 25L; // 1000ms / 25 + nanosleep(&ts, NULL); +} + +void sleep_0_2_frame() +{ + // Sleep 1/25th of a second + + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = 8000000L;//1000000000L / 25L * 0.2; // 1000ms / 25 + nanosleep(&ts, NULL); +} diff --git a/lib/util.h b/lib/util.h new file mode 100644 index 0000000..ef21e06 --- /dev/null +++ b/lib/util.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * util.h + * + * Mon Nov 8 10:49:33 CET 2004 + * Copyright 2004 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" +#ifndef __RTVIDEOREC_UTIL_H +#define __RTVIDEOREC_UTIL_H + +#include <stdio.h> +//#include <stdlib.h> + +//#ifdef __cplusplus +//extern "C" { +//#endif + +void *xmalloc(size_t s); +void *xrealloc(void *b, size_t s); + +void sleep_1_frame(); +void sleep_0_2_frame(); +//#ifdef __cplusplus +//} +//#endif + +#endif diff --git a/server/audio_encoder.cc b/server/audio_encoder.cc new file mode 100644 index 0000000..6e412c3 --- /dev/null +++ b/server/audio_encoder.cc @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * audio_encoder.cc + * + * Sat Sep 17 18:38:45 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" +#include "audio_encoder.h" +#include "util.h" + +#include "liblame_wrapper.h" + +AudioEncoder::AudioEncoder(ThreadSafeQueuePriority *audio_input_queue, + ThreadSafeQueuePriority *audio_output_queue, + Info *i) +{ + info = i; + info->info("AudioEncoder"); + + running = true; + + input_queue = audio_input_queue; + output_queue = audio_output_queue; +} + +AudioEncoder::~AudioEncoder() +{ +} + +void AudioEncoder::thread_main() +{ + info->info("AudioEncoder::run"); + + // Run with slightly lower priority than MovEncoderWriter + nice(1); + + Frame *in_frame = NULL; + Frame *out_frame = NULL; + + LibLAMEWrapper lame(info); + + while(running) { + in_frame = input_queue->pop(); + + if(in_frame == NULL) info->error("AudioEncoder: in_frame == NULL!"); + + // Check for end of stream + if(in_frame->endOfFrameStream == true) { + info->info("endOfFrameStream in AudioEncoder"); + running = false; + out_frame = lame.close(); + } else { + // Encode audio + out_frame = lame.encode(in_frame); + } + out_frame->number = in_frame->number; + out_frame->endOfFrameStream = in_frame->endOfFrameStream; + + delete in_frame; + in_frame = NULL; + + output_queue->push(out_frame); + } + + info->info("AudioEncoder::stop"); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* + +void AudioEncoder::thread_main() +{ + info->info("AudioEncoder::run"); + +#ifndef NEW_QUEUE + unsigned int queuesize = 0; + Frame *tmpframe; +#endif + + // Run with slightly lower priority than MovEncoderWriter + nice(2); + + Frame *in_frame = NULL; + Frame *out_frame = NULL; + + LibLAMEWrapper lame(info); + + while(running) { + info->info("fisk"); +#ifdef NEW_QUEUE + in_frame = input_queue->pop(); +#else + sem_wait(input_sem); + + // If no frame is in the buffer, get one from the queue + while( in_frame == NULL ) { + + // sem_wait(input_sem); + + // Lock output mutex + pthread_mutex_lock( input_mutex ); + tmpframe = inputqueue->top(); + + if(tmpframe && tmpframe->number == frame_number) { + inputqueue->pop(); + queuesize = inputqueue->size(); + in_frame = tmpframe; + frame_number++; + } + + pthread_mutex_unlock( input_mutex ); + // Unlock output mutex + + sleep_0_2_frame(); + } +#endif + + // Check for end of stream + if(in_frame->endOfFrameStream == true) { + info->info("endOfFrameStream in AudioEncoder"); + running = false; + out_frame = lame.close(); + } else { + // Encode audio + out_frame = lame.encode(in_frame); + } + out_frame->number = in_frame->number; + out_frame->endOfFrameStream = in_frame->endOfFrameStream; + + delete in_frame; + in_frame = NULL; + +#ifdef NEW_QUEUE + output_queue->push(out_frame); +#else + // Lock output mutex + pthread_mutex_lock(output_mutex); + outputqueue->push(out_frame); + pthread_mutex_unlock(output_mutex); + // Unlock output mutex + + // Kick multiplexer (audio) + sem_post(output_sem); +#endif + } + +#ifndef NEW_QUEUE + // Kick multiplexer (audio) + sem_post(output_sem); +#endif + + info->info("AudioEncoder::stop"); +} +*/ diff --git a/server/audio_encoder.h b/server/audio_encoder.h new file mode 100644 index 0000000..9d86178 --- /dev/null +++ b/server/audio_encoder.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * audio_encoder.h + * + * Sat Sep 17 18:38:45 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" +#ifndef __MIAV_AUDIO_ENCODER_H__ +#define __MIAV_AUDIO_ENCODER_H__ + +#include "frame.h" +#include "util.h" + +#include "thread.h" +#include <pthread.h> + +#include "info.h" + +#include "threadsafe_queue_priority.h" + +class AudioEncoder : public Thread { +public: + AudioEncoder(ThreadSafeQueuePriority *audio_input_queue, + ThreadSafeQueuePriority *audio_output_queue, + Info *info); + ~AudioEncoder(); + + void thread_main(); + + volatile bool running; + +private: + Info *info; + + ThreadSafeQueuePriority *input_queue; + ThreadSafeQueuePriority *output_queue; +}; + + +#endif/*__MIAV_AUDIO_ENCODER_H__*/ diff --git a/server/config.h b/server/config.h new file mode 100644 index 0000000..e7101c9 --- /dev/null +++ b/server/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/server/dvfile.cc b/server/dvfile.cc new file mode 100644 index 0000000..7d83255 --- /dev/null +++ b/server/dvfile.cc @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * dvfile.cc + * + * Thu Jul 28 17:30:48 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 "dvfile.h" + +#include "dv.h" +#include "util.h" + +dvfile::dvfile(Info* i) +{ + info = i; + fp = fopen(TEST_MOVIE, "r"); + if(!fp) info->error("Couldn't open %s for reading.", TEST_MOVIE); +} + +dvfile::~dvfile() +{ + fclose(fp); +} + +unsigned char *dvfile::readFrame() +{ + unsigned char *frame = new unsigned char[DVPACKAGE_SIZE]; + + sleep_1_frame(); + + if(fp) { + while(fread(frame, DVPACKAGE_SIZE, 1, fp) == 0) { + fseek(fp, 0L, SEEK_SET); + } + } else { + memset(frame, 0, sizeof(frame)); + } + + return frame; +} diff --git a/server/dvfile.h b/server/dvfile.h new file mode 100644 index 0000000..dc91a14 --- /dev/null +++ b/server/dvfile.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * dvfile.h + * + * Thu Jul 28 17:30:48 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_DVFILE_H__ +#define __MIAV_DVFILE_H__ + +#include "frame_stream.h" + +#include <stdio.h> + +#include "info.h" + +#define TEST_MOVIE PIXMAPS"/dummy.dv" + +class dvfile : public frame_stream { +public: + dvfile(Info* info); + ~dvfile(); + + unsigned char *readFrame(); + +private: + Info* info; + FILE* fp; +}; + +#endif/*__MIAV_DVFILE_H__*/ diff --git a/server/img_encoder.cc b/server/img_encoder.cc new file mode 100644 index 0000000..9282dc0 --- /dev/null +++ b/server/img_encoder.cc @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * img_encoder.cc + * + * Mon Nov 15 19:45:07 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 "img_encoder.h" +#include <stdio.h> + +#include "debug.h" + +extern "C" { +#include <jpeglib.h> +} + +#include "jpeg_mem_dest.h" + +// Use libdv +#include <libdv/dv.h> +#include <libdv/dv_types.h> + +ImgEncoder::ImgEncoder(const char* cpr, Info *i) +{ + info = i; + + // Create path and filename + char fname[256]; + string *server_root; + char birthmonth[3]; + char date[32]; + char encrypted_cpr[32]; + + // Get server root + server_root = config->readString("server_image_root"); + + // Copy the bytes representing the birth month from the cpr + // [dd][mm][yy]-[nn][nn] + strncpy(birthmonth, &cpr[2], 2); + birthmonth[2] = 0; + + // Create date (today) in [yyyy][mm][dd] + struct tm *ltime; + time_t t = time(NULL); + ltime = localtime(&t); + sprintf(date, "%.4d%.2d%.2d", + ltime->tm_year + 1900, + ltime->tm_mon, + ltime->tm_mday); + + // Create 'encrypted' cpr, reverse numbers, skip month, and subtract from 9 + // [d1][d2][m1][m2][y1][y2]-[n1][n2][n3][n4] + // => + // [9-n4][9-n3][9-n2][9-n1][9-y2][9-y1][9-d2][9-d1] + memset(encrypted_cpr, 0, sizeof(encrypted_cpr)); + int p = strlen(cpr) - 1; + int cnt = 0; + while(p) { + encrypted_cpr[cnt] = cpr[p]; + p--; + if(p == 2) p--; + if(cpr[p] == '-' || p == 3) p--; + cnt++; + } + + sprintf(fname, "%s/%s/%s/%s-%s-", server_root->c_str(), birthmonth, encrypted_cpr, cpr, date); + + file = new File(fname, "jpg", info); +} + + +ImgEncoder::~ImgEncoder() +{ + delete file; +} + + +void ImgEncoder::encode(Frame *dvframe, int quality) +{ + unsigned char rgb[720*576*4]; + + getRGB(dvframe, rgb); + writeJPEGFile(quality, rgb, 720, 576); +} + + +void ImgEncoder::writeJPEGFile(int quality, unsigned char *rgb, int image_width, int image_height) +{ + JSAMPLE *image_buffer = (JSAMPLE*)rgb; + + size_t buffersize = (image_width * image_height * 3) + JPEG_HEADER_PAD; + char *jpeg_output_buffer = new char [buffersize]; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] + int row_stride; // physical row width in image buffer + + // Allocate and initialize JPEG compression object + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + // Specify data destination (see jpeg_mem_dest) + jpeg_mem_dest(&cinfo, jpeg_output_buffer, &buffersize); + + // Set compression parameters + cinfo.image_width = image_width; // image width and height, in pixels + cinfo.image_height = image_height; + cinfo.input_components = 3; // # of color components per pixel + cinfo.in_color_space = JCS_RGB; // colorspace of input image + + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, quality, TRUE); // limit to baseline-JPEG values + + // Start compressor + jpeg_start_compress(&cinfo, TRUE); + + // While (scan lines remain to be written) + row_stride = image_width * 3; // JSAMPLEs per row in image_buffer + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + // Finish compression + jpeg_finish_compress(&cinfo); + + // Release JPEG compression object + jpeg_destroy_compress(&cinfo); + + info->info("JPEG buffersize: %d", buffersize); + file->Write(jpeg_output_buffer, buffersize); + delete jpeg_output_buffer; +} + +void ImgEncoder::getRGB(Frame *frame, unsigned char *rgb) +{ + unsigned char *pixels[3]; + int pitches[3]; + + pixels[ 0 ] = rgb; + pixels[ 1 ] = NULL; + pixels[ 2 ] = NULL; + + pitches[ 0 ] = 720 * 3; + 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_rgb, + pixels, + pitches); + + dv_decoder_free(decoder); +} diff --git a/server/img_encoder.h b/server/img_encoder.h new file mode 100644 index 0000000..9745a8f --- /dev/null +++ b/server/img_encoder.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * img_encoder.h + * + * Mon Nov 15 19:45:07 CET 2004 + * Copyright 2004 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" +#ifndef __RTVIDEOREC_IMGENCODER_H +#define __RTVIDEOREC_IMGENCODER_H + +#include <stdio.h> + +#include "frame.h" +#include "util.h" + +//#include <stdlib.h> +//#include <string.h> + +#include "info.h" +#include "file.h" + +#define VIDEO_BUFFER_SIZE (1024*1024) // FIXME: One size fits all... +#define JPEG_HEADER_PAD 500 + +class ImgEncoder { +public: + ImgEncoder(const char* cpr, Info *info); + ~ImgEncoder(); + void encode(Frame *frame, int quality); + void writeJPEGFile(int quality, + unsigned char *image_buffer, // Points to large array of R,G,B-order data + int image_width, // Number of columns in image + int image_height); // Number of rows in image + +private: + File *file; + Info *info; + void getRGB(Frame *frame, unsigned char *rgb); +}; + +#endif /*__RTVIDEOREC_IMGENCODER_H*/ + diff --git a/server/info_console.cc b/server/info_console.cc new file mode 100644 index 0000000..ce406fb --- /dev/null +++ b/server/info_console.cc @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info_console.cc + * + * Tue May 3 09:35:03 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 "info_console.h" + +#include "miav_config.h" + +#include <stdio.h> +#include <stdarg.h> + +InfoConsole::InfoConsole(MiavConfig *c): Info() +{ + this->config = c; + log_filename = *(this->config->readString("server_log_file")); +} + +InfoConsole::~InfoConsole() +{ + pthread_mutex_destroy(&mutex); +} + +void InfoConsole::error(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + // fprintf(stderr, "Error: ["); vfprintf(stderr, fmt, argp); fprintf(stderr, "]\n"); fflush(stderr); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + log("Error: %s", buf); +} + +void InfoConsole::warn(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + // fprintf(stderr, "Warning: ["); vfprintf(stderr, fmt, argp); fprintf(stderr, "]\n"); fflush(stderr); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + log("Warning: %s", buf); +} + +void InfoConsole::info(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + // fprintf(stderr, "Info: ["); vfprintf(stderr, fmt, argp); fprintf(stderr, "]\n"); fflush(stderr); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + log("Info: %s", buf); +} diff --git a/server/info_console.h b/server/info_console.h new file mode 100644 index 0000000..2adcad6 --- /dev/null +++ b/server/info_console.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info_console.h + * + * Tue May 3 09:35:03 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_CONSOLE_H__ +#define __MIAV_INFO_CONSOLE_H__ + +#include "info.h" + +#include "miav_config.h" + +#include <pthread.h> +#include <semaphore.h> + +#include <string> +using namespace std; + +class InfoConsole: public Info { +public: + InfoConsole(MiavConfig *config); + ~InfoConsole(); + + void error(char* fmt, ...); + void warn(char* fmt, ...); + void info(char* fmt, ...); + +private: +}; + +#endif/*__MIAV_INFO_CONSOLE_H__*/ diff --git a/server/iso11172-1.h b/server/iso11172-1.h new file mode 100644 index 0000000..ee8f408 --- /dev/null +++ b/server/iso11172-1.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * iso11172-1.h + * + * Wed Aug 31 13:48:30 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. + */ + +/* + * This file contains symbols used to create an ISO11172-1 compatible multiplexed + * MPEG stream. + */ + +#include "config.h" +#ifndef __MIAV_ISO11172_1_H__ +#define __MIAV_ISO11172_1_H__ + +#define CLOCK_90KHZ 90000 + +namespace ISO11172_1 { + //////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////// + // 64 bits (8 bytes) + typedef struct { + unsigned long long int marker_bit3:1; + unsigned long long int system_clock_reference3:15; + unsigned long long int marker_bit2:1; + unsigned long long int system_clock_reference2:15; + unsigned long long int marker_bit1:1; + unsigned long long int system_clock_reference1:3; + unsigned long long int padding:4; + unsigned long long int stuffing_byte:8; + unsigned long long int packet_length:16; + } packet_header; + + typedef struct { + unsigned long long int marker_bit5:1; + unsigned long long int mux_rate:22; + unsigned long long int marker_bit4:1; + unsigned long long int marker_bit3:1; + unsigned long long int system_clock_reference3:15; + unsigned long long int marker_bit2:1; + unsigned long long int system_clock_reference2:15; + unsigned long long int marker_bit1:1; + unsigned long long int system_clock_reference1:3; + unsigned long long int padding:4; + } pack_header; + + typedef struct { + unsigned long long int reserved_byte:8; + unsigned long long int video_bound:5; + unsigned long long int marker_bit3:1; + unsigned long long int system_video_clock_flag:1; + unsigned long long int system_audio_clock_flag:1; + unsigned long long int CSPS_flag:1; + unsigned long long int fixed_flag:1; + unsigned long long int audio_bound:6; + unsigned long long int marker_bit2:1; + unsigned long long int rate_bound:22; + unsigned long long int marker_bit1:1; + unsigned long long int header_length:16; + } system_header; + + typedef struct { + unsigned long int STD_buffer_size_bound:13; + unsigned long int STD_buffer_bound_scale:1; + unsigned long int market_bits:2; + unsigned long int stream_id:8; + } stream_description; + + //////////////////////////////////////////////////// + // Constants + //////////////////////////////////////////////////// + const char pack_start_code[] = "\x00\x00\x01\xBA"; + const char system_header_start_code[] = "\x00\x00\x01\xBB"; + const char packet_start_code_prefix[] = "\x00\x00\x01"; + const char stream_id_video1[] = "\xE3"; + const char stream_id_video2[] = "\xE4"; + const char stream_id_video3[] = "\xE5"; + const char stream_id_video4[] = "\xE6"; + const char stream_id_video5[] = "\xE7"; + const char stream_id_video6[] = "\xE8"; + const char stream_id_video7[] = "\xE9"; + const char stream_id_video8[] = "\xEA"; + const char stream_id_audio1[] = "\xC0"; + const char stream_id_audio2[] = "\xC1"; + const char stream_id_audio3[] = "\xC2"; + const char stream_id_audio4[] = "\xC3"; + const char stream_id_audio5[] = "\xC4"; + const char stream_id_audio6[] = "\xC5"; + const char stream_id_audio7[] = "\xC6"; + const char stream_id_audio8[] = "\xC7"; + const char stream_id_padding[] = "\xBE"; + const char end_code[] = "\x00\x00\x01\xB9"; + + //////////////////////////////////////////////////// + // Methods + //////////////////////////////////////////////////// + /** + * SCR stands for System Clock Reference + */ + inline unsigned int SCR(unsigned int previous_SCR, + unsigned int pack_header_size, + unsigned int packets_per_pack, + unsigned int packet_data_size, + unsigned int Rmux) + { + // To prevent a crash when doing division. + if(Rmux == 0) Rmux = 1; + return previous_SCR + (unsigned int)((double)(pack_header_size + + (packets_per_pack * packet_data_size)) * + (double)CLOCK_90KHZ / (double)Rmux); + } + + /** + * Calculates Rmux according to subclause A.5.4 + * mux stands for multiplexing and R for Rate, + * so Rmux is the rate of the multiplexing. + */ + inline unsigned int Rmux(unsigned int video_data_rate, + unsigned int audio_data_rate, + unsigned int packet_header_size, + unsigned int pack_header_size, + unsigned int packets_per_pack, + unsigned int packet_data_size) + { + // To prevent a crash when doing division. + if(packets_per_pack == 0) packets_per_pack = 1; + if(packet_data_size == 0) packet_data_size = 1; + + return (unsigned int)( + ((double)video_data_rate + (double)audio_data_rate) * + (1.0 + ((double)packet_header_size + (double)pack_header_size / (double)packets_per_pack) + / (double)packet_data_size) + ); + } + + +}; + +#endif/*__MIAV_ISO11172_1_H__*/ diff --git a/server/iso11172-2.h b/server/iso11172-2.h new file mode 100644 index 0000000..f2e2fa3 --- /dev/null +++ b/server/iso11172-2.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * iso11172-2.h + * + * Tue Sep 6 13:31:04 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" +#ifndef __MIAV_ISO11172_2_H__ +#define __MIAV_ISO11172_2_H__ + +namespace ISO11172_2 { + //////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////// + typedef struct { + unsigned long int picture_rate:4; + unsigned long int pel_aspect_ratio:4; + unsigned long int vertical_size:12; + unsigned long int horizontal_size:12; + } sequence_header_1; + + typedef struct { + unsigned long int load_non_intra_quantizer_flag:1; + unsigned long int load_intra_quantizer_flag:1; + unsigned long int constrained_parameter_flag:1; + unsigned long int vbv_buffer_size:10; + unsigned long int marker_bit:1; + unsigned long int bitrate:18; + } sequence_header_2; + + //////////////////////////////////////////////////// + // Constants + //////////////////////////////////////////////////// + const char picture_start_code[] = "\x00\x00\x01\x00"; + const char slice_start_code_prefix[] ="\x00\x00\x01"; + // const char _code = "\x00\x00\x01\xB0"; //Reserved + // const char _code = "\x00\x00\x01\xB1"; //Reserved + const char user_data_start_code[] = "\x00\x00\x01\xB2"; + const char sequence_header_code[] = "\x00\x00\x01\xB3"; + const char sequence_error_code[] = "\x00\x00\x01\xB4"; + const char sequence_start_code[] = "\x00\x00\x01\xB5"; + // const char _code = "\x00\x00\x01\xB6"; //Reserved + const char sequence_end_code[] = "\x00\x00\x01\xB7"; + const char group_start_code[] = "\x00\x00\x01\xB8"; + const char system_start_code_prefix[] = "\x00\x00\x01"; + + //////////////////////////////////////////////////// + // Methods + //////////////////////////////////////////////////// + +}; + +#endif/*__MIAV_ISO11172_2_H__*/ diff --git a/server/iso11172-3.h b/server/iso11172-3.h new file mode 100644 index 0000000..d3eda79 --- /dev/null +++ b/server/iso11172-3.h @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * iso11172-3.h + * + * Tue Sep 6 13:10:48 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" +#ifndef __MIAV_ISO11172_3_H__ +#define __MIAV_ISO11172_3_H__ + +namespace ISO11172_3 { + //////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////// + typedef struct { + unsigned long int emphasis:2; + unsigned long int original_home:1; + unsigned long int copyright:1; + unsigned long int mode_extension:2; + unsigned long int mode:2; + unsigned long int private_bit:1; + unsigned long int padding_bit:1; + unsigned long int sampling_frequency:2; + unsigned long int bitrate_index:4; + unsigned long int protection_bit:1; + unsigned long int layer:2; + unsigned long int ID:1; + unsigned long int syncword:12; + } header; + + //////////////////////////////////////////////////// + // Constants + //////////////////////////////////////////////////// + + typedef enum { + ID_RESERVED = 0, + ID_MPEG = 1 + } IDs; + + typedef enum { + LAYER_RESERVED = 0x00, + LAYER_III = 0x01, + LAYER_II = 0x10, + LAYER_I = 0x11 + } layers; + + typedef enum { + CRC_ON = 0, + CRC_OFF = 1 + } crcs; + + typedef enum { + MODE_STEREO = 0x00, + MODE_JOINT_STEREO = 0x01, + MODE_DUAL_CHANNEL = 0x10, + MODE_SINGLE_CHANNEL = 0x11, + } modes; + + //////////////////////////////////////////////////// + // Methods + //////////////////////////////////////////////////// + +}; + +#endif/*__MIAV_ISO11172_3_H__*/ diff --git a/server/libfame_wrapper.cc b/server/libfame_wrapper.cc new file mode 100644 index 0000000..a663df6 --- /dev/null +++ b/server/libfame_wrapper.cc @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * libfame_wrapper.cc + * + * Sat Jul 2 11:11:31 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 "libfame_wrapper.h" + +#include <errno.h> + +#include "miav_config.h" +#include "frame.h" + +LibFAMEWrapper::LibFAMEWrapper(Info *i) +{ + info = i; + + // FIXME: Hmmm... should this be detected somewhere?! + int w = 720; + int h = 576; + + // Initialize yuv structure. + yuv.w = w; + yuv.h = h; + yuv.p = w; + yuv.y = new unsigned char [w*h * 2]; + yuv.u = new unsigned char [w*h];// [w*h/4] + yuv.v = new unsigned char [w*h];// [w*h/4] + + calc_bitrate = 0; + frame_number = 0; + + ////////////LIBDV STUFF/////////////// + + dvdecoder = NULL; // Initialize in encode method + + /////////LIBFAME STUFF/////////// + + // Allocate the output buffer. +// fame_buffer = new unsigned char [FAME_BUFFER_SIZE]; + + // Open a new session of the fame library. + // (If initialization was successful, it returns a non-null context which + // can then be used for subsequent library calls.) + fame_context = fame_open(); + if(!fame_context) { + info->error("Unable to open FAME context, due to the following error: %s", strerror(errno)); + return; + } + + /* + typedef struct _fame_parameters_ { + int width; // width of the video sequence + int height; // height of the video sequence + char const *coding; // coding sequence + int quality; // video quality + int slices_per_frame; // number of slices per frame + unsigned int frames_per_sequence; // number of frames per sequence + int frame_rate_num; // numerator of frames per second + int frame_rate_den; // denominator of frames per second + unsigned int shape_quality; // binary shape quality + unsigned int search_range; // motion estimation search range + unsigned char verbose; // verbosity + } fame_parameters_t; + */ + // width and height specify the size of each frames of the video sequence. + // Both must be multiple of 16. width and height must be less than 4096x4096 + fame_par.width = 720; + fame_par.height = 576; + + // coding is a string of I, P or B characters representing the sequence of + // frames the encoder must produce. I frames are intra-coded frames (similar + // to JPEG), whereas P and B frames are motion compressed, respectively + // predicted from past reference (I or P) frame, or bidirectionally predicted + // from past and future reference frame. + fame_par.coding = config->readString("frame_sequence")->c_str(); + + // quality is a percentage, which controls compression versus quality. + fame_par.quality = config->readInt("video_quality"); + + // Bitrate + fame_par.bitrate = config->readInt("video_bitrate") * 1000; // video bitrate in bytes pr second (0=VBR) + + // slices_per_frame is the number of frame slices per frame. More slices provide + // better error recovery. There must be at least one slice per frame, and at most + // height / 16 + fame_par.slices_per_frame = 1;//fame_par.height / 16; + + // frames_per_sequence is the maximum number of frames contained in a video + // sequence. + fame_par.frames_per_sequence = 0xffffffff; // Unlimited length + + // frame_rate_num/frame_rate_den specify the number of frames per second for + // playback. + fame_par.frame_rate_num = 25; // 25 / 1 fps = 25 fps + fame_par.frame_rate_den = 1; + + // shape_quality is percentage determing the average binary shape accuracy in + // video with arbitrary shape. + fame_par.shape_quality = 100; // Original shape + + // search_range specifies the motion estimation search range in pixel unit. + // Small search ranges work best with slow motion videos, whereas larger search + // ranges are rather for fast motion videos. + fame_par.search_range = 0; // Adaptive search range + + // verbose when set to 1 outputs information on copyright, modules used and + // current frame on standard error. + fame_par.verbose = 0; + + static const char profilename[] = "MIaV\0"; + fame_par.profile = profilename; // profile name + fame_par.total_frames = 0; // total number of frames + + if(strcmp(config->readString("encoding_codec")->c_str(), "mpeg4") == 0) { + + info->info("Using mpeg4 compression."); + fame_object_t *object; + + object = fame_get_object(fame_context, "profile/mpeg4/simple"); + if(object) fame_register(fame_context, "profile", object); + + } else if(strcmp(config->readString("encoding_codec")->c_str(), "mpeg1") == 0) { + + info->info("Using mpeg1 compression."); + fame_object_t *object; + + object = fame_get_object(fame_context, "profile/mpeg1"); + if(object) fame_register(fame_context, "profile", object); + + } else if(strcmp(config->readString("encoding_codec")->c_str(), "mpeg1") == 0) { + } else { + info->info("Using default (mpeg1) compression."); + } + + fame_init(fame_context, &fame_par, fame_buffer, FAME_BUFFER_SIZE); +} + +LibFAMEWrapper::~LibFAMEWrapper() +{ + delete [] yuv.y; + delete [] yuv.u; + delete [] yuv.v; +} + +Frame *LibFAMEWrapper::encode(Frame *dvframe) +{ + // if(!f) return; // The file was not opened. + + // Decode DV Frame to YUV422 + int w = 720; + int h = 576; + + unsigned char *pixels[3]; + int pitches[3]; + + if(!dvdecoder) { + dvdecoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); + dvdecoder->quality = DV_QUALITY_BEST; + + dv_parse_header(dvdecoder, dvframe->data); + //dv_parse_packs(decoder, frame->data); // Not needed anyway! + + dvdecoder->system = e_dv_system_625_50; // PAL lines, PAL framerate + dvdecoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v + dvdecoder->std = e_dv_std_iec_61834; + dvdecoder->num_dif_seqs = 12; + } + + pixels[ 0 ] = picture; // We use this as the output buffer + pitches[ 0 ] = w * 2; + + dv_decode_full_frame(dvdecoder, + dvframe->data, + e_dv_color_yuv, + pixels, + pitches); + + // Convert YUV422 to YUV420p + int w2 = w / 2; + uint8_t *y = yuv.y; + uint8_t *cb = yuv.u; + uint8_t *cr = yuv.v; + uint8_t *p = picture; + + for ( int i = 0; i < h; i += 2 ) { + // process two scanlines (one from each field, interleaved) + for ( int j = 0; j < w2; j++ ) { + // packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] + *( y++ ) = *( p++ ); + *( cb++ ) = *( p++ ); + *( y++ ) = *( p++ ); + *( cr++ ) = *( p++ ); + } + + // process next two scanlines (one from each field, interleaved) + for ( int j = 0; j < w2; j++ ) { + // skip every second line for U and V + *( y++ ) = *( p++ ); + p++; + *( y++ ) = *( p++ ); + p++; + } + } + + // Allocate a new frame for the output + Frame *output = new Frame(NULL, FAME_BUFFER_SIZE); + + // Init frame params + dv_get_timestamp(dvdecoder, output->timecode); // Set timecode + output->size = 0; // Init size (incremented as we read) + unsigned char* pt = output->data; // Set pointer to start of data buffer + + // Encode YUV frame and write it to disk. + fame_start_frame(fame_context, &yuv, 0); + int written; + + while((written = fame_encode_slice(fame_context))) { + memcpy(pt, fame_buffer, written); + pt += written; + output->size += written; + } + + // fame_frame_statistics_t stats; + + // fame_end_frame(fame_context, &stats); + /* + info->info("frame_number: %d, coding: %c, target_bits: %d, actual_bits: %d, spatial_activity: %d, quant_scale: %f", + stats.frame_number, + stats.coding, + stats.target_bits, + stats.actual_bits, + stats.spatial_activity, + stats.quant_scale); + */ + /* + fame_frame_statistics_t_ { + unsigned int frame_number; + char coding; + signed int target_bits; + unsigned int actual_bits; + unsigned int spatial_activity; + float quant_scale; + } + */ + frame_number++; + calc_bitrate += output->size; //stats.actual_bits; + output->bitrate = (unsigned int)((double)calc_bitrate / (double)frame_number) * 25; + + return output; +} + diff --git a/server/libfame_wrapper.h b/server/libfame_wrapper.h new file mode 100644 index 0000000..bf9e7b9 --- /dev/null +++ b/server/libfame_wrapper.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * libfame_wrapper.h + * + * Sat Jul 2 11:11:31 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_LIBFAME_WRAPPER_H__ +#define __MIAV_LIBFAME_WRAPPER_H__ + +// Use libfame +#include <fame.h> + +// Use libdv +#include <libdv/dv.h> +#include <libdv/dv_types.h> + +#include "frame.h" +#include "info.h" + +// size specifies the length of the buffer. +#define FAME_BUFFER_SIZE (1024*1024) // FIXME: One size fits all... + +class LibFAMEWrapper { +public: + LibFAMEWrapper(Info *info); + ~LibFAMEWrapper(); + + Frame *encode(Frame *dvframe); + +private: + unsigned long long calc_bitrate; + unsigned int frame_number; + + Info* info; + + // libFAME encoder + // unsigned char *fame_buffer; + fame_parameters_t fame_par; + fame_context_t *fame_context; + fame_yuv_t yuv; + unsigned char fame_buffer[FAME_BUFFER_SIZE]; + + // libdv decoder + dv_decoder_t *dvdecoder; + + unsigned char picture[FAME_BUFFER_SIZE]; +}; + +#endif/*__MIAV_LIBFAME_WRAPPER_H__*/ diff --git a/server/liblame_wrapper.cc b/server/liblame_wrapper.cc new file mode 100644 index 0000000..5603d6f --- /dev/null +++ b/server/liblame_wrapper.cc @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * liblame_wrapper.cc + * + * Sat Jul 2 11:11: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 "liblame_wrapper.h" +#include "miav_config.h" + +LibLAMEWrapper::LibLAMEWrapper(Info *i) +{ + info = i; + + // Init library. + if( (gfp = lame_init()) == NULL) { + info->error("LAME initialization failed (due to malloc failure!)"); + return; + } + + lame_set_in_samplerate(gfp, INPUT_SAMPLE_RATE); + lame_set_out_samplerate(gfp, OUTPUT_SAMPLE_RATE); + + lame_set_num_channels(gfp, CHANNELS); + // lame_set_num_samples(gfp, 1152); + // lame_set_num_samples(gfp, SAMPLES); + // lame_set_num_samples(gfp, 0); + + lame_set_quality(gfp, config->readInt("mp3_quality")); + lame_set_mode(gfp, STEREO); + lame_set_brate(gfp, config->readInt("mp3_bitrate")); + + lame_set_strict_ISO(gfp, 1); + + // 1 = write a Xing VBR header frame. + lame_set_bWriteVbrTag(gfp, 0); + + // Types of VBR. default = vbr_off = CBR + // lame_set_VBR(gfp, vbr_rh); + + // VBR quality level. 0=highest 9=lowest + // lame_set_VBR_q(gfp, 6); + + lame_set_copyright(gfp, 0); // is there a copyright on the encoded data? + lame_set_original(gfp, 1); // is the encoded data on the original media? + lame_set_error_protection(gfp, 0);// add 2 byte CRC protection to each frame? + lame_set_padding_type(gfp, PAD_NO); // PAD_NO, PAD_ALL, PAD_ADJUST, PAD_MAX_INDICATOR + // 0 = do not pad frames + // 1 = always pad frames + // 2 = adjust padding to satisfy bit rate + lame_set_extension(gfp, 0); // private extension bit + + + if (lame_init_params(gfp) < 0) { + info->error("LAME parameter initialization failed."); + return; + } + + audio_buffer[0] = new int16_t[AUDIO_BUFFER_SIZE]; + audio_buffer[1] = new int16_t[AUDIO_BUFFER_SIZE]; + + // And now for the dv decoder! + decoder = NULL; + + calc_bitrate = 0; + frame_number = 0; +} + +LibLAMEWrapper::~LibLAMEWrapper() +{ + delete audio_buffer[0]; + delete audio_buffer[1]; +} + +Frame *LibLAMEWrapper::close(Frame *oldframe) +{ + Frame *frame; + unsigned int offset = 0; + + frame = new Frame(NULL, (int)(1.25 * SAMPLES + 7200) * 2); // Big enough to hold two frames + + if(oldframe) { + offset = oldframe->size; + frame->number = oldframe->number; + memcpy(frame->data, oldframe->data, oldframe->size); + delete oldframe; + } + + int flush; + + flush = lame_encode_finish(gfp, frame->data + offset, 7200); + + frame->size = offset + flush; + + calc_bitrate += flush; + frame->bitrate = (unsigned int)((double)calc_bitrate / (double)(frame_number)) * 25; + + return frame; +} + +#include <math.h> +static unsigned int sin_cnt = 0; +Frame *LibLAMEWrapper::encode(Frame *dvframe) +{ + if(dvframe->mute) { + // Overwrite audiobuffer with dummy data + double volume = 1000; // Min:= 0 - Max := 32000 + double frequency = 440; // in Hz + + for(int cnt = 0; cnt < SAMPLES; cnt++) { + sin_cnt++; + double sin_val = (((double)sin_cnt / (double)OUTPUT_SAMPLE_RATE) * (double)M_PI) * frequency; + audio_buffer[0][cnt] = audio_buffer[1][cnt] = (short int)(sin(sin_val) * volume); + } + + // memset(audio_buffer[0], 0, sizeof(audio_buffer[0])); + // memset(audio_buffer[1], 0, sizeof(audio_buffer[1])); + } else { + // Decode audio from dv frame + if(!decoder) { + decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); + decoder->quality = DV_QUALITY_BEST; + + dv_parse_header(decoder, dvframe->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; + } + // Decode audio using libdv + dv_decode_full_audio( decoder, dvframe->data, audio_buffer ); + } + + /** + * input pcm data, output (maybe) mp3 frames. + * This routine handles all buffering, resampling and filtering for you. + * + * The required mp3buf_size can be computed from num_samples, + * samplerate and encoding rate, but here is a worst case estimate: + * + * return code number of bytes output in mp3buffer. can be 0 + * if return code = -1: mp3buffer was too small + * + * mp3buf_size in bytes = 1.25*num_samples + 7200 + * + * I think a tighter bound could be: (mt, March 2000) + * MPEG1: + * num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512 + * MPEG2: + * num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256 + * + * but test first if you use that! + * + * set mp3buf_size = 0 and LAME will not check if mp3buf_size is + * large enough. + * + * NOTE: + * if gfp->num_channels=2, but gfp->mode = 3 (mono), the L & R channels + * will be averaged into the L channel before encoding only the L channel + * This will overwrite the data in buffer_l[] and buffer_r[]. + * + */ + Frame* audio_frame = new Frame(NULL, (int)(1.25 * SAMPLES + 7200)); + + const short int *buffer_l = audio_buffer[0]; // PCM data for left channel + const short int *buffer_r = audio_buffer[1]; // PCM data for right channel + const int nsamples = SAMPLES; // number of samples per channel + unsigned char* mp3buf = audio_frame->data; // pointer to encoded MP3 stream + const int mp3buf_size = audio_frame->size; // number of valid octets in this + + int val; + val = lame_encode_buffer(gfp, buffer_l, buffer_r, nsamples, mp3buf, mp3buf_size); + // val = lame_encode_mp3_frame(gfp, buffer_l, buffer_r, mp3buf, mp3buf_size); + + // info->info("Framenr: %d", lame_get_frameNum(gfp)); + + if(val < 0) { + switch(val) { + case -1: // mp3buf was too small + info->error("Lame encoding failed, mp3buf was too small."); + break; + case -2: // malloc() problem + info->error("Lame encoding failed, due to malloc() problem."); + break; + case -3: // lame_init_params() not called + info->error("Lame encoding failed, lame_init_params() not called."); + break; + case -4: // psycho acoustic problems + info->error("Lame encoding failed, due to psycho acoustic problems."); + break; + default: + info->error("Lame encoding failed, due to unknown error."); + break; + } + } + + /** + * OPTIONAL: + * lame_encode_flush_nogap will flush the internal mp3 buffers and pad + * the last frame with ancillary data so it is a complete mp3 frame. + * + * 'mp3buf' should be at least 7200 bytes long + * to hold all possible emitted data. + * + * After a call to this routine, the outputed mp3 data is complete, but + * you may continue to encode new PCM samples and write future mp3 data + * to a different file. The two mp3 files will play back with no gaps + * if they are concatenated together. + * + * This routine will NOT write id3v1 tags into the bitstream. + * + * return code = number of bytes output to mp3buf. Can be 0 + */ + + int flush_sz = 0; + + /* + flush_sz = lame_encode_flush_nogap(gfp, // global context handle + mp3buf + val, // pointer to encoded MP3 stream + mp3buf_size - val); // number of valid octets in this stream + */ + + // info->info("VAL: %d - FLUSH_SZ: %d - TOTAL: %d", val, flush_sz, (val + flush_sz)); + + audio_frame->size = val + flush_sz; + + /* + + int bitrate_kbps[14]; + // lame_bitrate_kbps(gfp, bitrate_kbps); + lame_bitrate_hist(gfp, bitrate_kbps); + // 32 40 48 56 64 80 96 112 128 160 192 224 256 320 + info->info("%d %d %d %d %d %d %d %d %d %d %d %d %d %d", + bitrate_kbps[0], + bitrate_kbps[1], + bitrate_kbps[2], + bitrate_kbps[3], + bitrate_kbps[4], + bitrate_kbps[5], + bitrate_kbps[6], + bitrate_kbps[7], + bitrate_kbps[8], + bitrate_kbps[9], + bitrate_kbps[10], + bitrate_kbps[11], + bitrate_kbps[12], + bitrate_kbps[13]); + */ + // while(frame_number != lame_get_frameNum(gfp)) { + + calc_bitrate += audio_frame->size;//lame_get_framesize(gfp); + frame_number ++;//= 1;//lame_get_frameNum(gfp); + + // info->info("lame_get_frameNum(gfp) %d ?= frame_number %d", lame_get_frameNum(gfp), frame_number); + // } + + // Bits pr. second + // 25 * 7 frames pr.second (it seems!) + audio_frame->bitrate = (unsigned int)((double)calc_bitrate / (double)(frame_number)) * 25; + /* + info->info("Audio size: %d, bitrate: %.4f", + audio_frame->bitrate, + (float)(config->readInt("mp3_bitrate") * 1000)/(float)(audio_frame->bitrate)); + */ + + /* + FILE* fp = fopen("/tmp/audiotest.mp3", "a"); + fwrite(audio_frame->data, audio_frame->size, 1, fp); + fclose(fp); + */ + return audio_frame; +} diff --git a/server/liblame_wrapper.h b/server/liblame_wrapper.h new file mode 100644 index 0000000..43518c8 --- /dev/null +++ b/server/liblame_wrapper.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * liblame_wrapper.h + * + * Sat Jul 2 11:11: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_LIBLAME_WRAPPER_H__ +#define __MIAV_LIBLAME_WRAPPER_H__ + +// Use libdv +#include <libdv/dv.h> +#include <libdv/dv_types.h> + +// Use liblame +#include <lame/lame.h> + +#include "frame.h" +#include "info.h" + +#define AUDIO_BUFFER_SIZE DV_AUDIO_MAX_SAMPLES + +#define CHANNELS 2 +#define INPUT_SAMPLE_RATE 48000 +#define OUTPUT_SAMPLE_RATE 48000 +#define SAMPLES OUTPUT_SAMPLE_RATE / 25 + +class LibLAMEWrapper { +public: + LibLAMEWrapper(Info *info); + ~LibLAMEWrapper(); + + Frame *encode(Frame *dvframe); + + Frame *close(Frame *dvframe = NULL); + +private: + unsigned long long calc_bitrate; + int frame_number; + + Info *info; + + // LAME stuff + lame_global_flags *gfp; + + // libdv stuff + dv_decoder_t *decoder; + int16_t *audio_buffer[2]; +}; + +#endif/*__MIAV_LIBLAME_WRAPPER_H__*/ diff --git a/server/libmplex_wrapper.cc b/server/libmplex_wrapper.cc new file mode 100644 index 0000000..4164ffe --- /dev/null +++ b/server/libmplex_wrapper.cc @@ -0,0 +1,485 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * libmplex_wrapper.cc + * + * Sun Oct 30 12:28:47 CET 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" +#include "libmplex_wrapper.h" +#include "miav_config.h" + +#ifdef WITH_LIBMPLEX + +#include <mjpeg_types.h> +#include <mjpeg_logging.h> +#include <mpegconsts.h> + +#include <mplex/interact.hpp> +#include <mplex/bits.hpp> +#include <mplex/outputstrm.hpp> +#include <mplex/multiplexor.hpp> + +/** + * FrameOutputStream - Wraps the File object + */ +class FrameOutputStream : public OutputStream +{ +public: + FrameOutputStream( Info *info, File *outputfile ); + int Open( ); + void Close(); + off_t SegmentSize( ); + void NextSegment(); + void Write(uint8_t *data, unsigned int len); + +private: + Info *info; + off_t written; + File *file; +}; + + + +FrameOutputStream::FrameOutputStream( Info *info, File *outputfile ) +{ + this->info = info; + file = outputfile; + written = 0; + info->info("FrameOutputStream - constructor"); +} + +int FrameOutputStream::Open() +{ + // info->info("FrameOutputStream::Open"); + // Nothing to do here! + return 0; +} + +void FrameOutputStream::Close() +{ + // info->info("FrameOutputStream::Close"); + // Nothing to do here! +} + + +off_t FrameOutputStream::SegmentSize() +{ + // info->info("FrameOutputStream::SegmentSize - return: %d", written); + return written; + + /* + struct stat stb; + fstat(fileno(strm), &stb); + off_t written = stb.st_size; + return written; + */ +} + +void FrameOutputStream::NextSegment( ) +{ + // info->info("FrameOutputStream::NextSegment"); + // Nothing to do here! + /* + auto_ptr<char> prev_filename_buf( new char[strlen(cur_filename)+1] ); + char *prev_filename = prev_filename_buf.get(); + fclose(strm); + ++segment_num; + strcpy( prev_filename, cur_filename ); + snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num ); + if( strcmp( prev_filename, cur_filename ) == 0 ) { + mjpeg_error_exit1("Need to split output but there appears to be no %%d in the filename pattern %s", + filename_pat ); + } + strm = fopen( cur_filename, "wb" ); + if( strm == NULL ) { + mjpeg_error_exit1( "Could not open for writing: %s", cur_filename ); + } + */ +} + +void FrameOutputStream::Write( uint8_t *buf, unsigned int len ) +{ + unsigned int write; + write = file->Write(buf, len); + written += write; + // info->info("FrameOutputStream::Write - len: %d", len); +} + +/** + * FrameInputStream - Wraps the ThreadSafeQueuePriority objects, containing + * the prosessed frames from libfame and liblame. + */ +class FrameInputStream : public IBitStream +{ +public: + FrameInputStream( Info *info, ThreadSafeQueuePriority *queue ); + ~FrameInputStream(); + +private: + Frame *getFrame(); + size_t ReadStreamBytes( uint8_t *buf, size_t size ); + bool EndOfStream(); + + Info *info; + ThreadSafeQueuePriority *queue; + bool seen_eof; + Frame *frame; + unsigned int read; +}; + +FrameInputStream::FrameInputStream( Info *info, ThreadSafeQueuePriority *queue ) : + IBitStream() +{ + this->info = info; + this->queue = queue; + seen_eof = false; + frame = NULL; + read = 0; + streamname = "MIaV Stream\0"; + + // info->info("FrameInputStream - constructor", seen_eof); + + /* + if ((fileh = fopen(bs_filename, "rb")) == NULL) + { + mjpeg_error_exit1( "Unable to open file %s for reading.", bs_filename); + } + filename = strcpy( new char[strlen(bs_filename)+1], bs_filename ); + streamname = filename; + + SetBufSize(buf_size); + eobs = false; + byteidx = 0; + if (!ReadIntoBuffer()) + { + if (buffered==0) + { + mjpeg_error_exit1( "Unable to read from %s.", bs_filename); + } + } + */ + SetBufSize(BUFFER_SIZE); + // SetBufSize(buf_size); + eobs = false; + byteidx = 0; + if (!ReadIntoBuffer()) { + if (buffered==0) { + info->error( "Unable to read from %s.", streamname); + } + } + + // info->info("FrameInputStream - leaving constructor", seen_eof); +} + + +/** + Destructor: close the device containing the bit stream after a read + process +*/ +FrameInputStream::~FrameInputStream() +{ + // info->info("FrameInputStream - destructor", seen_eof); + // Nothing to do here! + /* + if (fileh) + { + fclose(fileh); + delete filename; + } + fileh = 0; + */ + Release(); // Hmmm.. wonder what this 'Release()' does!? +} + +Frame *FrameInputStream::getFrame() +{ + read = 0; + return queue->pop(); +} + +bool FrameInputStream::EndOfStream() +{ + // info->info("FrameInputStream::EndOfStream - return: %d", seen_eof); + return seen_eof; +} + +size_t FrameInputStream::ReadStreamBytes( uint8_t *buf, size_t size ) +{ + // info->info("FrameInputStream::ReadStreamBytes - size: %d", size); + unsigned int copied = 0; + + while( copied < size ) { + + // If we read the entire frame, prepare to get a new one + if(frame && read == frame->size) { + delete frame; + frame = NULL; + } + + // If no frame is in the buffer, get one from the queue + if(frame == NULL) frame = getFrame(); + + // check for end of stream + if( frame->endOfFrameStream == true) { + seen_eof = true; + return copied; + } + + // If a frame exists in the buffer copy it to the output buffer + // (No frame ocurres when *running is set to false) + if( frame ) { + unsigned int doread = (size - copied) < (frame->size - read) ? + size - copied : (frame->size - read); + + //info->info("Requested: %d. Read: %d. Doread: %d. In buffer %d", size, (*read), doread, (*frame)->size); + + memcpy(buf + copied, frame->data + read, doread); + read += doread; + copied += doread; + } + } + + return copied; +} + +/******************************* + * + * Command line job class - sets up a Multiplex Job based on command + * line and File I/O... + * + ******************************/ + +class MIaVMultiplexJob : public MultiplexJob +{ +public: + MIaVMultiplexJob(Info *info, + ThreadSafeQueuePriority *video_queue, + ThreadSafeQueuePriority *audio_queue); + +private: + bool ParseVideoOpt( const char *optarg ); + bool ParseLpcmOpt( const char *optarg ); +}; + +MIaVMultiplexJob::MIaVMultiplexJob(Info *info, + ThreadSafeQueuePriority *video_queue, + ThreadSafeQueuePriority *audio_queue) : + MultiplexJob() +{ + // this->info = info; + // info->info("MIaVMultiplexJob - constructor"); + outfile_pattern = "/tmp/aaargh.mpg"; // Output file... or something + + verbose = 0; // Level of verbosity. 0 = quiet, 1 = normal 2 = verbose/debug + + VBR = config->readInt("video_bitrate") == 0; // Multiplex variable bit-rate video + + always_system_headers = true; // Create System header in every pack in generic formats + + // Specifies decoder buffers size in kB. [ 20...2000] + if( ! ParseVideoOpt( "500" ) ) + info->error( "Illegal video decoder buffer size(s): %s", "500" ); + + // --lpcm-params | -L samppersec:chan:bits [, samppersec:chan:bits] + // if( ! ParseLpcmOpt( "48000:2:16" ) ) info->error( "Illegal LPCM option(s): %s", "48000:2:16" ); + + data_rate = 0; //Specify data rate of output stream in kbit/sec (default 0=Compute from source streams) + // Convert from kbit/sec (user spec) to 50B/sec units... + data_rate = (( data_rate * 1000 / 8 + 49) / 50 ) * 50; + + audio_offset = 0; //Specify offset of timestamps (video-audio) in mSec + video_offset = 0; //Specify offset of timestamps (video-audio) in mSec + + max_PTS = 0; // Multiplex only num seconds of material (default 0=multiplex all) + + packets_per_pack = 5; //Number of packets per pack generic formats [1..100] + + mux_format = 3; // Set defaults for particular MPEG profiles: + // 0 = Generic MPEG1 + // 1 = VCD + // 2 = user-rate VCD + // 3 = Generic MPEG2 + // 4 = SVCD + // 5 = user-rate SVCD + // 6 = VCD Stills + // 7 = SVCD Stills + // 8 = DVD with NAV sectors + // 9 = DVD + + sector_size = 2042; // Specify sector size in bytes for generic formats [256..16384] + + //max_segment_size = 0; // Maximum size of output file(s) in Mbyte (default: 0) (no limit) + + multifile_segment = true; // Don't switch to a new output file if a sequence end marker + // is encountered ithe input video + + (void)mjpeg_default_handler_verbosity(verbose); + info->info( "mplex version %s (%s %s)", VERSION,MPLEX_VER, MPLEX_DATE ); + + // Connect streams + vector<IBitStream *> inputs; + if(video_queue) inputs.push_back( new FrameInputStream( info, video_queue ) ); + if(audio_queue) inputs.push_back( new FrameInputStream( info, audio_queue ) ); + SetupInputStreams( inputs ); +} + +/************************************************************************* + Usage banner for the command line wrapper. +*************************************************************************/ +/* + mjpegtools mplex-2 version VERSION ( MPLEX_VER ) + Usage: %s [params] -o <output filename pattern> <input file>... + %%d in the output file name is by segment count + where possible params are: + --verbose|-v num + Level of verbosity. 0 = quiet, 1 = normal 2 = verbose/debug + --format|-f fmt + Set defaults for particular MPEG profiles + [0 = Generic MPEG1, 1 = VCD, 2 = user-rate VCD, 3 = Generic MPEG2, + 4 = SVCD, 5 = user-rate SVCD + 6 = VCD Stills, 7 = SVCD Stills, 8 = DVD with NAV sectors, 9 = DVD] + --mux-bitrate|-r num + Specify data rate of output stream in kbit/sec + (default 0=Compute from source streams) + --video-buffer|-b num [, num...] + Specifies decoder buffers size in kB. [ 20...2000] + --lpcm-params | -L samppersec:chan:bits [, samppersec:chan:bits] + --mux-limit|-l num + Multiplex only num seconds of material (default 0=multiplex all) + --sync-offset|-O num ms|s|mpt + Specify offset of timestamps (video-audio) in mSec + --sector-size|-s num + Specify sector size in bytes for generic formats [256..16384] + --vbr|-V + Multiplex variable bit-rate video + --packets-per-pack|-p num + Number of packets per pack generic formats [1..100] + --system-headers|-h + Create System header in every pack in generic formats + --max-segment-size|-S size + Maximum size of output file(s) in Mbyte (default: 0) (no limit) + --ignore-seqend-markers|-M + Don't switch to a new output file if a sequence end marker + is encountered ithe input video. + --workaround|-W workaround [, workaround ] + --help|-? + Print this lot out! +*/ + + +bool MIaVMultiplexJob::ParseLpcmOpt( const char *optarg ) +{ + char *endptr, *startptr; + unsigned int samples_sec; + unsigned int channels; + unsigned int bits_sample; + endptr = const_cast<char *>(optarg); + do { + startptr = endptr; + samples_sec = static_cast<unsigned int>(strtol(startptr, &endptr, 10)); + if( startptr == endptr || *endptr != ':' ) + return false; + + startptr = endptr+1; + channels = static_cast<unsigned int>(strtol(startptr, &endptr, 10)); + if(startptr == endptr || *endptr != ':' ) + return false; + + startptr = endptr+1; + bits_sample = static_cast<unsigned int>(strtol(startptr, &endptr, 10)); + if( startptr == endptr ) + return false; + + LpcmParams *params = LpcmParams::Checked( samples_sec, + channels, + bits_sample ); + if( params == 0 ) + return false; + lpcm_param.push_back(params); + if( *endptr == ',' ) + ++endptr; + } while( *endptr != '\0' ); + return true; +} + +bool MIaVMultiplexJob::ParseVideoOpt( const char *optarg ) +{ + char *endptr, *startptr; + unsigned int buffer_size; + endptr = const_cast<char *>(optarg); + do + { + startptr = endptr; + buffer_size = static_cast<unsigned int>(strtol(startptr, &endptr, 10)); + if( startptr == endptr ) + return false; + + VideoParams *params = VideoParams::Checked( buffer_size ); + if( params == 0 ) + return false; + video_param.push_back(params); + if( *endptr == ',' ) + ++endptr; + } + while( *endptr != '\0' ); + return true; +} + +LibMPlexWrapper::LibMPlexWrapper(Info *info, + File *outputfile, + ThreadSafeQueuePriority *video_queue, + ThreadSafeQueuePriority *audio_queue) +{ + this->info = info; + this->outputfile = outputfile; + this->video_queue = video_queue; + this->audio_queue = audio_queue; +} + +LibMPlexWrapper::~LibMPlexWrapper() +{ +} + + +void LibMPlexWrapper::multiplex() +{ + // info->info("MPLEX!"); + // sleep(10); + // info->info("The road goes ever on and on..."); + MIaVMultiplexJob job(info, video_queue, audio_queue); + FrameOutputStream output( info, outputfile ); + Multiplexor mux(job, output); + mux.Multiplex(); +} + + +#ifdef LIBMPLEX_WRAPPER_TEST +int main (int argc, char* argv[]) +{ + LibMPlexWrapper mplex; + mplex.multiplex(); + return 0; +} +#endif/*LIBMPLEX_WRAPPER_TEST*/ + +#endif/*WITH_LIBMPLEX*/ diff --git a/server/libmplex_wrapper.h b/server/libmplex_wrapper.h new file mode 100644 index 0000000..1be71a1 --- /dev/null +++ b/server/libmplex_wrapper.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * libmplex_wrapper.h + * + * Sun Oct 30 12:28:47 CET 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" +#ifndef __MIAV_LIBMPLEX_WRAPPER_H__ +#define __MIAV_LIBMPLEX_WRAPPER_H__ + +#ifdef WITH_LIBMPLEX + +#include "info.h" +#include "file.h" +#include "threadsafe_queue_priority.h" + +class LibMPlexWrapper { +public: + LibMPlexWrapper(Info *info, + File *outputfile, + ThreadSafeQueuePriority *video_queue, + ThreadSafeQueuePriority *audio_queue); + ~LibMPlexWrapper(); + + void multiplex(); + +private: + Info *info; + File *outputfile; + ThreadSafeQueuePriority *video_queue; + ThreadSafeQueuePriority *audio_queue; +}; +#endif/*WITH_LIBMPLEX*/ + +#endif/*__MIAV_LIBMPLEX_WRAPPER_H__*/ diff --git a/server/miav_daemon.cc b/server/miav_daemon.cc new file mode 100644 index 0000000..500e92a --- /dev/null +++ b/server/miav_daemon.cc @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav_daemon.cc + * + * Thu Jun 9 11:14:19 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 "miav_daemon.h" + +#include "info_console.h" +#include "miav_config.h" + +#include "server.h" +#include "socket.h" + +#include <signal.h> +#include <errno.h> + +MiavDaemon::MiavDaemon() +{} + +MiavDaemon::~MiavDaemon() +{} + +int MiavDaemon::daemon_main() +{ + MiavConfig cfg(ETC"/miav.conf", NULL); + InfoConsole info(&cfg); + config = new MiavConfig(ETC"/miav.conf", &info); + + int port = config->readInt("server_port"); + pid_t childpid; // variable to store the child's pid + + signal(SIGCLD, SIG_IGN); // Ved SIGCHILD til IGNORE maa wait/waitpid ikke kaldes + // (ellers kommer der kernel-brok) + + info.info("Starting MIaV server v. %s", VERSION); + info.info("Listening on port %d", port); + Socket *socket = new Socket(port, &info); + + if(socket->hasError()) { + info.error("Listening socket has errors, quitting."); + delete socket; + return 1; + } + + while(1) { + Socket *csocket = new Socket(socket->slisten()); + + if(socket->hasError()) { + info.error("Server socket has errors, quitting."); + delete csocket; + break; + } + + if(csocket->hasError()) { + info.error("Child socket has errors, quitting."); + delete csocket; + break; + } + + if(!csocket->isConnected()) { + info.error("Child socket is not connected, quitting."); + delete csocket; + break; + } + + childpid = fork(); + + switch(childpid) { + case -1: // fork() returns -1 on failure + info.log("Fork error: %s", strerror(errno)); + exit(1); + case 0: // fork() returns 0 to the child process + delete socket; // Close listen socket. + newConnection(csocket, &info); + delete csocket; // Close communication socket. + exit(0); + + default: // fork() returns new pid to the parent process + break; + } + } + + delete socket; + return 0; +} + diff --git a/server/miav_daemon.h b/server/miav_daemon.h new file mode 100644 index 0000000..6ab469e --- /dev/null +++ b/server/miav_daemon.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav_daemon.h + * + * Thu Jun 9 11:14:19 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_MIAV_DAEMON_H__ +#define __MIAV_MIAV_DAEMON_H__ + +#include "daemon.h" + +class MiavDaemon: public Daemon { +public: + MiavDaemon(); + ~MiavDaemon(); + +private: + int daemon_main(); +}; + +#endif/*__MIAV_MIAV_DAEMON_H__*/ diff --git a/server/miav_server.cc b/server/miav_server.cc new file mode 100644 index 0000000..88a0d2a --- /dev/null +++ b/server/miav_server.cc @@ -0,0 +1,50 @@ +/* -*- 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_server.h" +#include "miav_daemon.h" +#include "miav_config.h" + +#include "info_console.h" + +#include <stdio.h> + +/** + * This function starts the MIaV server. + */ +int main(int argc, char *argv[]) +{ + MiavDaemon daemon; + + MiavConfig cfg(ETC"/miav.conf", NULL); + + string *user = cfg.readString("server_user"); + string *group = cfg.readString("server_group"); + + return daemon.run(user->c_str(), group->c_str()); +} diff --git a/server/miav_server.h b/server/miav_server.h new file mode 100644 index 0000000..ce7842a --- /dev/null +++ b/server/miav_server.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/server/mov_encoder.cc b/server/mov_encoder.cc new file mode 100644 index 0000000..6ac5876 --- /dev/null +++ b/server/mov_encoder.cc @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder.cc + * + * Sat Feb 19 14:13:19 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 "mov_encoder.h" + +#include <errno.h> + +// For nice +#include <unistd.h> + +#include "miav_config.h" + +#include "debug.h" +#include "libfame_wrapper.h" + +MovEncoder::MovEncoder(volatile bool *r, sem_t *r_sem, + ThreadSafeQueueFIFO *in, + ThreadSafeQueuePriority *video_out, + ThreadSafeQueuePriority *audio_out, + Info *i) +{ + info = i; + info->info("MovEncoder"); + + running = r; + + // Queues + inputqueue = in; + video_output_queue = video_out; + audio_output_queue = audio_out; + + read_sem = r_sem; +} + +MovEncoder::~MovEncoder() +{ + info->info("~MovEncoder"); +} + + +// this runs in a thread +void MovEncoder::thread_main() +{ + info->info("MovEncoder::run"); + + // Run with slightly lower priority than MovEncoderWriter AND AudioEncoder + nice(2); + + FrameVector *item; + Frame *in_frame; + Frame *out_v_frame; + Frame *out_a_frame; + + LibFAMEWrapper fame(info); + + // Process until running == false and the queue is empty + while(*running) { + + item = inputqueue->pop(); + + if(item) { + for(unsigned int cnt = 0; cnt < item->size(); cnt++) { + in_frame = item->at(cnt); + + // Check for end of stream + if(in_frame->endOfFrameStream == true) { + info->info("endOfFrameStream in MovEncoder"); + + // Signal to stop running + *running = false; + + // Kick them sleepy ones so they get the message. + int threads = config->readInt("encoding_threads") - 1; // -1 cause we only need the others! + for(int cnt = 0; cnt < threads; cnt++) { + inputqueue->push(NULL); + } + } + + // Encode video + out_v_frame = fame.encode(in_frame); + out_v_frame->number = in_frame->number; + out_v_frame->endOfFrameStream = in_frame->endOfFrameStream; + + // Create audio frame + out_a_frame = in_frame; + + video_output_queue->push(out_v_frame); + audio_output_queue->push(out_a_frame); + } + + delete item; + + item = NULL; + + // Kick reader + sem_post(read_sem); + } + } + + info->info("MovEncoder::stop"); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* + +// this runs in a thread +void MovEncoder::thread_main() +{ + info->info("MovEncoder::run"); + // static volatile int test = 0; +#ifndef NEW_QUEUE + int v_outsize = 0; + int a_outsize = 0; +#endif + int insize = 0; + + // Run with slightly lower priority than MovEncoderWriter AND AudioEncoder + nice(3); + + FrameVector *item; + Frame *in_frame; + Frame *out_v_frame; + Frame *out_a_frame; + + LibFAMEWrapper fame(info); + + // Process until running == false and the queue is empty + while(*running) { + sem_wait(input_sem); + + // Lock inout mutex + pthread_mutex_lock(input_mutex); + item = inputqueue->front(); + inputqueue->pop(); + insize = inputqueue->size(); + pthread_mutex_unlock(input_mutex); + // Unlock input mutex + + if(item) { + for(unsigned int cnt = 0; cnt < item->size(); cnt++) { + in_frame = item->at(cnt); + + // Check for end of stream + if(in_frame->endOfFrameStream == true) { + info->info("endOfFrameStream in MovEncoder"); + + // Signal to stop running + *running = false; + + // Kick them sleepy ones so they get the message. + int threads = config->readInt("encoding_threads"); + for(int cnt = 0; cnt < threads; cnt++) sem_post(input_sem); + } + // Encode video + out_v_frame = fame.encode(in_frame); + out_v_frame->number = in_frame->number; + out_v_frame->endOfFrameStream = in_frame->endOfFrameStream; + + // Create audio frame + out_a_frame = in_frame; + +#ifdef NEW_QUEUE + video_output_queue->push(out_v_frame); + audio_output_queue->push(out_a_frame); +#else + // Lock output mutex + pthread_mutex_lock(video_output_mutex); + video_outputqueue->push(out_v_frame); + v_outsize = video_outputqueue->size(); + pthread_mutex_unlock(video_output_mutex); + // Unlock output mutex + + // Kick multiplexer (video) + sem_post(video_output_sem); + + // Lock output mutex + pthread_mutex_lock(audio_output_mutex); + audio_outputqueue->push(out_a_frame); + a_outsize = audio_outputqueue->size(); + pthread_mutex_unlock(audio_output_mutex); + // Unlock output mutex + + // Kick audio encoder + sem_post(audio_output_sem); +#endif + } + + delete item; + item = NULL; + + // Kick reader + sem_post(read_sem); + } + } + + //info->info("Input pool size: %d, video output pool size: %d, audio output pool size: %d", + // insize, v_outsize, a_outsize); + + +#ifndef NEW_QUEUE + // Kick audio encoder + sem_post(audio_output_sem); + + // Kick multiplexer (video) + sem_post(video_output_sem); +#endif + + info->info("MovEncoder::stop"); +} +*/ diff --git a/server/mov_encoder.h b/server/mov_encoder.h new file mode 100644 index 0000000..8910f4b --- /dev/null +++ b/server/mov_encoder.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder.h + * + * Sat Feb 19 14:13:19 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 program 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. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "config.h" +#ifndef __RTVIDEOREC_ENCODER_H +#define __RTVIDEOREC_ENCODER_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <vector> +using namespace std; + +#include "frame.h" +#include "util.h" + +#include "thread.h" +#include <pthread.h> + +#include "info.h" + +#include "threadsafe_queue_priority.h" +#include "threadsafe_queue_fifo.h" + +class MovEncoder : public Thread { +public: + MovEncoder(volatile bool *r, sem_t *r_sem, + ThreadSafeQueueFIFO *in, + ThreadSafeQueuePriority *video_out, + ThreadSafeQueuePriority *audio_out, + Info *info); + ~MovEncoder(); + + void thread_main(); + + volatile bool *running; + +private: + Info *info; + + // Input queue + ThreadSafeQueueFIFO *inputqueue; + + // Output queues + ThreadSafeQueuePriority *video_output_queue; + ThreadSafeQueuePriority *audio_output_queue; + + // Reader (mov_encoder_thread.cc) semaphore + sem_t *read_sem; + +}; + +#endif + diff --git a/server/mov_encoder_thread.cc b/server/mov_encoder_thread.cc new file mode 100644 index 0000000..2ff013d --- /dev/null +++ b/server/mov_encoder_thread.cc @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder_thread.cc + * + * Tue May 17 16:00:01 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 "mov_encoder_thread.h" +#include <errno.h> +#include "miav_config.h" + +MovEncoderThread::MovEncoderThread(const char *clientip, const char *cpr, Info *i) +{ + info = i; + info->info("MovEncoderThread"); + + // Queue + inputqueue = new ThreadSafeQueueFIFO(); + + // Initialize read semaphore + sem_init(&read_sem, 0, 0); + + video_output_queue = new ThreadSafeQueuePriority(info); + audio_input_queue = new ThreadSafeQueuePriority(info); + audio_output_queue = new ThreadSafeQueuePriority(info); + + info->info("video_output_queue: 0x%x", video_output_queue); + info->info("audio_input_queue: 0x%x", audio_input_queue); + info->info("audio_output_queue: 0x%x", audio_output_queue); + + block = new FrameVector(); + + num_frames_in_block = config->readString("frame_sequence")->length(); + + info->info("Frame sequence length %d", num_frames_in_block); + + threads = config->readInt("encoding_threads"); + + movencodersrunning = true; + + for(int cnt = 0; cnt < threads; cnt++) sem_post(&read_sem); + + // Create the video encoders + for(int cnt = 0; cnt < threads; cnt++) { + MovEncoder *movenc = new MovEncoder(&movencodersrunning, &read_sem, + inputqueue, + video_output_queue, + audio_input_queue, + info); + movenc->run(); + encs.push_back(movenc); + } + + // Create the audio encoder + audioenc = new AudioEncoder(audio_input_queue, + audio_output_queue, + info); + audioenc->run(); + + // Create the multiplexer + writer = new MovEncoderWriter(clientip, cpr, + video_output_queue, + audio_output_queue, + info); + writer->run(); + + frame_number = 0; +} + +//#include <unistd.h> +MovEncoderThread::~MovEncoderThread() +{ + info->info("~MovEncoderThread"); + + // First we destroy the movie encoders + for(int cnt = 0; cnt < threads; cnt++) { + encs[cnt]->wait_stop(); // Wait for it to stop + delete encs[cnt]; // Delete it + } + info->info("Deleted the movie encoders"); + + + // Then we destroy the audio encoder + audioenc->wait_stop(); // Wait for it to stop. + delete audioenc; // delete the audio encoder + info->info("Deleted the audio encoder"); + + + // Finally we destroy the writer. + writer->wait_stop(); // Wait for it to stop. + delete writer; // delete the writer (end thereby close the file) + info->info("Deleted the writer"); + + + // Destroy the semaphore. + sem_destroy(&read_sem); + + info->info("~MovEncoderThread::done"); +} + +static int output = 0; +void MovEncoderThread::encode(Frame* frame) +{ + if(output % 250 == 0) // 25 * 24 + info->info("inputqueue: %d\tvideo_outputqueue: %d\taudio_inputqueue: %d\taudio_outputqueue: %d.", + inputqueue->size(), + video_output_queue->size(), + audio_input_queue->size(), + audio_output_queue->size()); + output++; + + if(frame == NULL) { + info->info("MovEncoderThread::encode - NULL frame detected."); + // Terminate + return; + } + + frame->number = frame_number; + block->push_back(frame); + + // Switch frame + if(block->size() == num_frames_in_block || frame->endOfFrameStream == true) { + // Wait until a free encoder. + sem_wait(&read_sem); + + inputqueue->push(block); + + // Start new block + block = new FrameVector; + } + + frame_number ++; +} + +void MovEncoderThread::setSaveState(n_savestate savestate) +{ + writer->setSaveState(savestate); +} diff --git a/server/mov_encoder_thread.h b/server/mov_encoder_thread.h new file mode 100644 index 0000000..feea8e2 --- /dev/null +++ b/server/mov_encoder_thread.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder_thread.h + * + * Tue May 17 16:00:01 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_MOV_ENCODER_THREAD_H__ +#define __MIAV_MOV_ENCODER_THREAD_H__ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <vector> +using namespace std; + +#include "frame.h" + +#include "threadsafe_queue_priority.h" +#include "threadsafe_queue_fifo.h" + +#include "mov_encoder.h" +#include "audio_encoder.h" +#include "mov_encoder_writer.h" + +#include "info.h" + +// For savestate_n +#include "package.h" + +class MovEncoderThread { +public: + MovEncoderThread(const char *clientip, const char *cpr, Info *info); + ~MovEncoderThread(); + + void encode(Frame* frame); + + void setSaveState(n_savestate savestate); + +private: + Info *info; + + // FrameVectorQueue *inputqueue; + ThreadSafeQueueFIFO *inputqueue; + FrameVector *block; + + //thread stuff + sem_t read_sem; + + ThreadSafeQueuePriority *video_output_queue; + ThreadSafeQueuePriority *audio_input_queue; + ThreadSafeQueuePriority *audio_output_queue; + + volatile bool movencodersrunning; + + // Used for encoder switching + unsigned int frame_number; + + unsigned int num_frames_in_block; + + MovEncoderWriter *writer; + AudioEncoder* audioenc; + + int threads; + vector<MovEncoder*> encs; + // vector<pthread_t*> tids; +}; + +#endif/*__MIAV_MOV_ENCODER_THREAD_H__*/ diff --git a/server/mov_encoder_writer.cc b/server/mov_encoder_writer.cc new file mode 100644 index 0000000..1773527 --- /dev/null +++ b/server/mov_encoder_writer.cc @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder_writer.cc + * + * Sun May 22 12:51:36 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 "mov_encoder_writer.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <pthread.h> +#include <semaphore.h> + +#include <errno.h> + +#include <string> +using namespace std; + +#include "miav_config.h" + +#include <time.h> + +#include "multiplexer.h" +#include "libmplex_wrapper.h" + +#include "multicast_configuration.h" + +MovEncoderWriter::MovEncoderWriter(const char *clientip, const char* cpr, + ThreadSafeQueuePriority *video_q, + ThreadSafeQueuePriority *audio_q, + Info *i) +{ + info = i; + info->info("MovEncoderWriter"); + + // Create path and filename + char fname[256]; + string *server_root; + char birthmonth[3]; + char date[32]; + + // Get server root + server_root = config->readString("server_movie_root"); + + // Copy the bytes representing the birth month from the cpr + // [dd][mm][yy]-[nn][nn] + strncpy(birthmonth, &cpr[2], 2); + birthmonth[2] = 0; + + // Create date (today) in [yyyy][mm][dd] + struct tm *ltime; + time_t t = time(NULL); + ltime = localtime(&t); + sprintf(date, "%.4d%.2d%.2d", + ltime->tm_year + 1900, + ltime->tm_mon + 1, // Ranging from 0 to 11 + ltime->tm_mday); + + sprintf(fname, "%s/%s/%s/%s-%s-", server_root->c_str(), birthmonth, cpr, cpr, date); + + file = new File(fname, "mpg", info); + + MulticastConfiguration mcconfig(info, ETC"/multicast.conf"); + + mcastconf_t mcclientconf = mcconfig.getConf((char*)clientip); + + info->info("Client: %s - Enabled: %s - Addr: %s - Port: %d - WithAudio: %s", + mcclientconf.client.c_str(), + mcclientconf.enabled?"Yes\0":"No\0", + mcclientconf.addr.c_str(), + mcclientconf.port, + mcclientconf.with_audio?"Yes\0":"No\0"); + + + multicast = NULL; + if(mcclientconf.enabled) multicast = new Multicast(info, + mcclientconf); + + video_queue = video_q; + audio_queue = audio_q; + + running = true; +} + +MovEncoderWriter::~MovEncoderWriter() +{ + info->info("~MovEncoderWriter"); + delete file; + if(multicast) delete multicast; +} + +void MovEncoderWriter::thread_main() +{ + info->info("MovEncoderWriter::run"); + +#ifdef WITH_LIBMPLEX + LibMPlexWrapper mplex(info, + file, + video_queue, + audio_queue); + mplex.multiplex(); +#else/*WITH_LIBMPLEX*/ + Multiplexer multiplexer(file, multicast, + info, &running, + video_queue, + audio_queue); + multiplexer.multiplex(); +#endif/*WITH_LIBMPLEX*/ + + info->info("MovEncoderWriter::stop"); +} + +void MovEncoderWriter::setSaveState(n_savestate savestate) +{ + file->setSaveState(savestate); +} diff --git a/server/mov_encoder_writer.h b/server/mov_encoder_writer.h new file mode 100644 index 0000000..ba9ff16 --- /dev/null +++ b/server/mov_encoder_writer.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder_writer.h + * + * Sun May 22 12:51:35 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_MOV_ENCODER_WRITER_H__ +#define __MIAV_MOV_ENCODER_WRITER_H__ + +#include "frame.h" +#include "thread.h" +#include "file.h" +#include "multicast.h" +#include "info.h" + +#include "threadsafe_queue_priority.h" + +#include <string> +using namespace std; + +// For n_savestate +#include "package.h" + +#define AUDIO_FRAME(x) x->number%2==1 +#define VIDEO_FRAME(x) x->number%2==0 + +class MovEncoderWriter : public Thread { +public: + MovEncoderWriter(const char *clientip, const char* cpr, + ThreadSafeQueuePriority *video_queue, + ThreadSafeQueuePriority *audio_queue, + Info *info); + ~MovEncoderWriter(); + + void thread_main(); + + void setSaveState(n_savestate savestate); + + volatile bool running; + +private: + Info *info; + + File *file; + Multicast *multicast; + + ThreadSafeQueuePriority *video_queue; + ThreadSafeQueuePriority *audio_queue; +}; + + +#endif/*__MIAV_MOV_ENCODER_WRITER_H__*/ diff --git a/server/multicast.cc b/server/multicast.cc new file mode 100644 index 0000000..0072c19 --- /dev/null +++ b/server/multicast.cc @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multicast.cc + * + * Mon Sep 26 12:25:22 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" +#include "multicast.h" + +#include "multicast_configuration.h" + +#include "miav_config.h" + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/param.h> +#include <arpa/inet.h> +#include <sys/types.h> + +// For IP_MTU +//#include <linux/in.h> +//#ifndef IP_MTU +//#define IP_MTU 14 +//#endif + +#include <errno.h> + +Multicast::Multicast(Info *i, mcastconf_t &mcclientconf) +{ + info = i; + udp_buffer = NULL; + + multicast_audio = mcclientconf.with_audio; + + // Open connection socket + if(!UDPOpen(mcclientconf.addr.c_str(), mcclientconf.port)) + info->error("Error creating socket %s:%d", + mcclientconf.addr.c_str(), + mcclientconf.port); + + int mtu = config->readInt("udp_packet_size"); + + // Create buffer with the size of MTU + // socklen_t mtu_sz; + // if(getsockopt(sock, SOL_IP, IP_MTU, &mtu, &mtu_sz) != -1) { + + udp_buffer_size = mtu - 28; + if(udp_buffer_size < 1) udp_buffer_size = 1; + udp_buffer = new char[udp_buffer_size]; + udp_buffer_pointer = udp_buffer; + info->info("UDP packet buffer size %db", udp_buffer_size); + + //} else { + // info->error("Error getting MTU size from socket: %s", strerror(errno)); + // return; + //} +} + +Multicast::~Multicast() +{ + if(udp_buffer) delete udp_buffer; +} + +int Multicast::Write(void* buf, int size) +{ + if(!udp_buffer) return 0; // no buffer to write in... better break out! + + // info->info("To send: %d", size); + + char *p = (char*)buf; + int left = udp_buffer_size - (udp_buffer_pointer - udp_buffer); + + while(size) { + int to_copy = size > left ? left : size; + + memcpy(udp_buffer_pointer, p, to_copy); + + left-=to_copy; + udp_buffer_pointer += to_copy; + + p+=to_copy; + size-=to_copy; + + // info->info("Copied %d - %d to go", to_copy, size); + + if(left == 0) { + // info->info("Sending full packet"); + write(sock, udp_buffer, udp_buffer_size); + left = udp_buffer_size; + udp_buffer_pointer = udp_buffer; + } + } + return size; +} + +bool Multicast::is_address_multicast(unsigned long address) +{ + if((address & 255) >= 224 && (address & 255) <= 239) { + info->info("Address is multicast."); + return true; + } + info->info("Address is NOT multicast."); + return false; +} + +/* + * open UDP socket + */ +bool Multicast::UDPOpen(const char *address, int port) +{ + int enable = 1L; + struct sockaddr_in stAddr; + struct sockaddr_in stLclAddr; + struct hostent * host; + // int sock; + + stAddr.sin_family = AF_INET; + stAddr.sin_port = htons(port); + if((host = gethostbyname(address)) == NULL) return false; + stAddr.sin_addr = *((struct in_addr *) host->h_addr_list[0]); + + // Create a UDP socket + if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return false; + + // Allow multiple instance of the client to share the same address and port + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(unsigned long int)) < 0) + return false; + + // If the address is multicast, register to the multicast group + if(is_address_multicast(stAddr.sin_addr.s_addr)) { + struct ip_mreq stMreq; + + // Bind the socket to port + stLclAddr.sin_family = AF_INET; + stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); + stLclAddr.sin_port = stAddr.sin_port; + if(bind(sock, (struct sockaddr*) & stLclAddr, sizeof(stLclAddr)) < 0) return false; + + // Register to a multicast address + stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr; + stMreq.imr_interface.s_addr = INADDR_ANY; + if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) & stMreq, sizeof(stMreq)) < 0) + return false; + } else { + // Bind the socket to port + stLclAddr.sin_family = AF_INET; + stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); + stLclAddr.sin_port = htons(0); + if(bind(sock, (struct sockaddr*) & stLclAddr, sizeof(stLclAddr)) < 0) + return false; + } + + connect(sock, (struct sockaddr*) & stAddr, sizeof(stAddr)); + + return true; +} diff --git a/server/multicast.h b/server/multicast.h new file mode 100644 index 0000000..08df3e1 --- /dev/null +++ b/server/multicast.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multicast.h + * + * Mon Sep 26 12:25:22 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" +#ifndef __MIAV_MULTICAST_H__ +#define __MIAV_MULTICAST_H__ + +#include "multicast_configuration.h" +#include "info.h" + +class Multicast { +public: + Multicast(Info *i, mcastconf_t &mcclientconf); + ~Multicast(); + + int Write(void* buf, int size); + + bool multicast_audio; + +private: + Info *info; + + bool is_address_multicast(unsigned long address); + bool UDPOpen(const char *address, int port); + int sock; + + int udp_buffer_size; + char *udp_buffer; + char *udp_buffer_pointer; +}; + +#endif/*__MIAV_MULTICAST_H__*/ diff --git a/server/multicast_configuration.cc b/server/multicast_configuration.cc new file mode 100644 index 0000000..969faca --- /dev/null +++ b/server/multicast_configuration.cc @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multicast_configuration.cc + * + * Wed Oct 12 10:12:11 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" +#include "multicast_configuration.h" + +MulticastConfiguration::MulticastConfiguration(Info *info, char *file) + : MiavConfig(file, info) +{ + mcastconf_t conf; + + // Create the default values. + global_conf.addr = "224.0.0.1"; + global_conf.port = 1234; + global_conf.enabled = false; + global_conf.with_audio = false; + + bool global = true; + + _cfg *cfg = configs; + + // Build the client list + while(cfg) { + if(strcmp(cfg->name->c_str(), "client") == 0) { + if(!global) confs.push_back(conf); + + // Reset the configuration to the defaults + conf.client = *(cfg->stringval); + conf.addr = global_conf.addr; + conf.port = global_conf.port; + conf.enabled = global_conf.enabled; + conf.with_audio = global_conf.with_audio; + + global = false; + } + if(strcmp(cfg->name->c_str(), "address") == 0) { + if(global) global_conf.addr = *(cfg->stringval); + else conf.addr = *(cfg->stringval); + } + if(strcmp(cfg->name->c_str(), "port") == 0) { + if(global) global_conf.port = cfg->intval; + else conf.port = cfg->intval; + } + if(strcmp(cfg->name->c_str(), "enabled") == 0) { + if(global) global_conf.enabled = cfg->boolval; + else conf.enabled = cfg->boolval; + } + if(strcmp(cfg->name->c_str(), "with_audio") == 0) { + if(global) global_conf.with_audio = cfg->boolval; + else conf.with_audio = cfg->boolval; + } + cfg = cfg->next; + } + if(!global) confs.push_back(conf); + + // Show the configuration in the log file . + info->info("Global - Enabled: %s - Addr: %s - Port: %d - WithAudio: %s", + global_conf.enabled?"Yes\0":"No\0", + global_conf.addr.c_str(), + global_conf.port, + global_conf.with_audio?"Yes\0":"No\0"); + + for(unsigned int cnt = 0; cnt < confs.size(); cnt++) { + info->info("Client: %s - Enabled: %s - Addr: %s - Port: %d - WithAudio: %s", + confs[cnt].client.c_str(), + confs[cnt].enabled?"Yes\0":"No\0", + confs[cnt].addr.c_str(), + confs[cnt].port, + confs[cnt].with_audio?"Yes\0":"No\0"); + } + + info->info("Chosing:"); +} + +MulticastConfiguration::~MulticastConfiguration() +{ +} + +mcastconf_t &MulticastConfiguration::getConf(char *client) +{ + for(unsigned int cnt = 0; cnt < confs.size(); cnt++) { + if(strcmp(confs[cnt].client.c_str(), client) == 0) + return confs[cnt]; + } + + return global_conf; +} + +#ifdef __TEST_MULTICAST_CONFIGURATION +#include "info_simple.h" + +int main(int argc, char *argv[]) { + if(argc < 2) { + fprintf(stderr, "usage:\n\t%s [filename]\n", argv[0]); + return 1; + } + + InfoSimple info; + MulticastConfiguration conf(&info, argv[1]); + + mcastconf_t mcconf = conf.getConf("192.168.0.11"); + + info.warn("Client: %s - Enabled: %s - Addr: %s - Port: %d", + mcconf.client.c_str(), + mcconf.enabled?"Yes\0":"No\0", + mcconf.addr.c_str(), + mcconf.port); + + mcconf = conf.getConf("192.168.0.0"); + + info.warn("Client: %s - Enabled: %s - Addr: %s - Port: %d", + mcconf.client.c_str(), + mcconf.enabled?"Yes\0":"No\0", + mcconf.addr.c_str(), + mcconf.port); +} + +#endif/* __TEST_MULTICAST_CONFIGURATION*/ diff --git a/server/multicast_configuration.h b/server/multicast_configuration.h new file mode 100644 index 0000000..3fa7ef1 --- /dev/null +++ b/server/multicast_configuration.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multicast_configuration.h + * + * Wed Oct 12 10:12:11 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" +#ifndef __MIAV_MULTICAST_CONFIGURATION_H__ +#define __MIAV_MULTICAST_CONFIGURATION_H__ + +#include "miav_config.h" + +#include <vector> +#include <string> + +typedef struct { + std::string client; + std::string addr; + bool enabled; + int port; + bool with_audio; +} mcastconf_t; + +class MulticastConfiguration : private MiavConfig { +public: + MulticastConfiguration(Info *info, char *file); + ~MulticastConfiguration(); + + mcastconf_t &getConf(char *client); + +private: + std::vector<mcastconf_t> confs; + mcastconf_t global_conf; +}; + +#endif/*__MIAV_MULTICAST_CONFIGURATION_H__*/ diff --git a/server/multiplexer.cc b/server/multiplexer.cc new file mode 100644 index 0000000..7a8b095 --- /dev/null +++ b/server/multiplexer.cc @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multiplexer.cc + * + * Wed Aug 31 13:05:18 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" +#include "multiplexer.h" + +#include <netinet/in.h> +#include <math.h> + +#include "util.h" + +#define SIZEOF(x) (sizeof(x)-1) + +#define MASK3 0x7 +#define MASK15 0x7FFF +#define TIMECODE32_30(x) ((x >> 30) & MASK3 ) +#define TIMECODE29_15(x) ((x >> 15) & MASK15) +#define TIMECODE14_0(x) ((x >> 0) & MASK15) + +// Audio index lists +/* +static unsigned int frequency_index[4] = {44100, 48000, 32000, 0}; +//static unsigned int slots [4] = {12, 144, 0, 0}; +//static unsigned int slot_index [4] = {144, 144, 144, 0}; +//static unsigned int sample_index [4] = {384, 1152, 0, 0}; +static unsigned int bitrate_index [4][16] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0}, // Reserved + {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, // Layer III + {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, // Layer II + {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0} // Layer I +}; +static char layer_index[4][12] = { "Reserved", "Layer III", "Layer II", "Layer I" }; +static char mode_index[4][32] = { "Stereo", "Joint Stereo", "Dual Channel", "Single Channel"}; +static char protection_index[2][32] = { "CRC check enabled", "CRC check disabled" }; +*/ +//static unsigned short int syncword = 0xFFF; + +// Video index lists +/* +#define FORBIDDEN -1.0 +#define RESERVED -2.0 +static double picture_rate_index[16] = { + FORBIDDEN, 23.976, 24.0, 25.0, 29.97, 30.0, 50.0, 59.94, 60, + RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED +}; +*/ +Multiplexer::Multiplexer(File *f, Multicast *m, Info *i, volatile bool *r, + ThreadSafeQueuePriority *video_q, + ThreadSafeQueuePriority *audio_q) +{ + running = r; + file = f; + multicast = m; + info = i; + + frame[TYPE_VIDEO] = NULL; + written[TYPE_VIDEO] = 0.0; + + frame[TYPE_AUDIO] = NULL; + written[TYPE_AUDIO] = 0.0; + + write_audio_packet = 0; + write_system_header = 0; + + audio_header_read = false; + + queue[TYPE_VIDEO] = video_q; + queue[TYPE_AUDIO] = audio_q; + + SCR = 3904;//0x40010003LL;//0x1E80; + +} + +Multiplexer::~Multiplexer() +{ +} + +int Multiplexer::Write(void* data, int size) +{ + int ret; + + if(multicast && multicast->multicast_audio == true) multicast->Write(data, size); + ret = file->Write(data, size); + + return ret; +} + +int Multiplexer::Write(char* data, int size) +{ + return Write((void*)data, size); +} + +int Multiplexer::Write(unsigned long long int val) +{ + int res; + int written = 0; + unsigned long int *h_u = (unsigned long int *)&val; + unsigned long int *h_l = (unsigned long int *)(((char*)&val) + sizeof(unsigned long int)); + + *h_u = htonl(*h_u); + *h_l = htonl(*h_l); + + if((res = Write((void*)h_l, sizeof(*h_l))) < 0) { + return res; + } + written += res; + + if((res = Write((void*)h_u, sizeof(*h_u))) < 0) { + return res; + } + written += res; + + return written; +} + +int Multiplexer::Write(long long int val) +{ + int res; + int written = 0; + unsigned long int *h_u = (unsigned long int *)&val; + unsigned long int *h_l = (unsigned long int *)(((char*)&val) + sizeof(unsigned long int)); + + *h_u = htonl(*h_u); + *h_l = htonl(*h_l); + + if((res = Write((void*)h_l, sizeof(*h_l))) < 0) { + return res; + } + written += res; + + if((res = Write((void*)h_u, sizeof(*h_u))) < 0) { + return res; + } + written += res; + + return written; +} + +int Multiplexer::Write(long int val) +{ + val = htonl(val); + + return Write((char*)&val, sizeof(val)); +} + +int Multiplexer::Write(unsigned long int val) +{ + val = htonl(val); + + return Write((char*)&val, sizeof(val)); +} + +int Multiplexer::Write(int val) +{ + val = htonl(val); + + return Write((char*)&val, sizeof(val)); +} + +int Multiplexer::Write(unsigned int val) +{ + val = htonl(val); + + return Write((char*)&val, sizeof(val)); +} + +int Multiplexer::Write(short int val) +{ + val = htons(val); + + return Write((char*)&val, sizeof(val)); +} + +int Multiplexer::Write(unsigned short int val) +{ + val = htons(val); + + return Write((char*)&val, sizeof(val)); +} + +Frame *Multiplexer::getFrame(StreamType type) +{ + // info->info("Get %s Frame", type==TYPE_AUDIO?"Audio\0":"Video\0"); + + read[type] = 0; + + Frame *frame = queue[type]->pop(); + + // If we multicast without audio, we better write the raw video stream. + if(type == TYPE_VIDEO && multicast && multicast->multicast_audio == false) + multicast->Write(frame->data, frame->size); + + return frame; +} + +int Multiplexer::read_stream(char *buf, unsigned int size, StreamType type) +{ + unsigned int copied = 0; + + while( copied < size ) { + + // If we read the entire frame, prepare to get a new one + if(frame[type] && read[type] == frame[type]->size) { + delete frame[type]; + frame[type] = NULL; + } + + // If no frame is in the buffer, get one from the queue + if(frame[type] == NULL) frame[type] = getFrame(type); + + // check for end of stream + if( frame[type]->endOfFrameStream == true) { + info->info("endOfFrameStream in Multiplexer %s-stream.", type==TYPE_VIDEO?"video\0":"audio\0"); + return copied; + } + + // If a frame exists in the buffer copy it to the output buffer + // (No frame ocurres when *running is set to false) + if( frame[type] ) { + unsigned int doread = (size - copied) < (frame[type]->size - read[type]) ? + size - copied : (frame[type]->size - read[type]); + + //info->info("Requested: %d. Read: %d. Doread: %d. In buffer %d", size, (*read), doread, (*frame)->size); + + memcpy(buf + copied, frame[type]->data + read[type], doread); + read[type] += doread; + copied += doread; + } + } + + return copied; +} + +bool Multiplexer::packet(StreamType type) +{ + char buf[PACKET_SIZE]; + + // Write data + // info->info("\t\t[%sPacket]", type==TYPE_AUDIO?"Audio\0":"Video\0"); + + unsigned short int framesize = read_stream(buf, PACKET_SIZE, type); + + Write((void*)ISO11172_1::packet_start_code_prefix, SIZEOF(ISO11172_1::packet_start_code_prefix)); + switch(type) { + case TYPE_VIDEO: + Write((void*)ISO11172_1::stream_id_video1, SIZEOF(ISO11172_1::stream_id_video1)); + break; + case TYPE_AUDIO: + Write((void*)ISO11172_1::stream_id_audio1, SIZEOF(ISO11172_1::stream_id_audio1)); + break; + } + + ISO11172_1::packet_header header; + header.marker_bit1 = header.marker_bit2 = header.marker_bit3 = 1; + header.padding = 0x2; // Must be 2 + header.stuffing_byte = 0xFF; + header.packet_length = framesize + sizeof(ISO11172_1::packet_header) - sizeof(short); + header.system_clock_reference1 = TIMECODE32_30(SCR); + header.system_clock_reference2 = TIMECODE29_15(SCR); + header.system_clock_reference3 = TIMECODE14_0(SCR); + Write(*((unsigned long long int*)&header)); + + Write(buf, framesize); + + if(framesize != PACKET_SIZE) return false; + + written[type] += (double)PACKET_SIZE / (double)frame[type]->size;//bitrate; + + return true; +} + +/** + * Create and write a packet + */ +bool Multiplexer::packet() +{ + //info->info("\t\tWritten[A]: %f, Written[V]: %f", written[TYPE_AUDIO], written[TYPE_VIDEO]); + + StreamType type; + /* + // New switching mechanism + if(written[TYPE_AUDIO] < written[TYPE_VIDEO]) { + type = TYPE_AUDIO; + } else { + type = TYPE_VIDEO; + } + */ + + // Newer switching mechanism + if(queue[TYPE_AUDIO]->size() > queue[TYPE_VIDEO]->size()) { + type = TYPE_AUDIO; + } else { + type = TYPE_VIDEO; + } + + + if(!packet(type)) { + // Flush the other stream too... + if(type == TYPE_AUDIO) type = TYPE_VIDEO; + else type = TYPE_AUDIO; + while(packet(type)); + return false; + } + return true; + + /* + // Count this up here, we want audio packets in packet 4, 9, ... NOT 0, 3, ... + + write_audio_packet++; + if(write_audio_packet % AUDIO_PACKET_FREQUENCY == 0) { + packet(TYPE_AUDIO); + } else { + packet(TYPE_VIDEO); + } + */ +} + +/** + * Create and write the system header + */ +void Multiplexer::system_header() +{ + // info->info("\t\t[System Header]"); + + // system_header_start_code (32 bits) + Write((void*)ISO11172_1::system_header_start_code, SIZEOF(ISO11172_1::system_header_start_code)); + + ISO11172_1::system_header header; + + header.marker_bit1 = header.marker_bit2 = header.marker_bit3 = 1; + + header.header_length = 8 - 2 + (NUM_TYPES * 3); + // (sizeof(header) - sizeof(header.header_length)) + + // NUM_TYPES * sizeof(ISO11172_1::stream_description); + header.rate_bound = 3521; // FIXME: Taken from the example! + header.audio_bound = 1; // Only 1 audio stream + header.fixed_flag = 1; // Fixed bitrate (0 indicates vbr) + header.CSPS_flag = 1; // Standarts compliant? (yes: see lame_set_strict_ISO in liblame_wrapper.cc) + header.system_audio_clock_flag = 1; // FIXME: What excactly is this?? + header.system_video_clock_flag = 1; // FIXME: What excactly is this?? + header.video_bound = 1; // Only 1 video stream + header.reserved_byte = 0xFF; // Must be 0xFF + Write(*((unsigned long long int*)&header)); + + ISO11172_1::stream_description audio_stream_description; + audio_stream_description.stream_id = 0xC0; + audio_stream_description.market_bits = 0x3; + audio_stream_description.STD_buffer_bound_scale = 0; // Must be 0 for audio streams + audio_stream_description.STD_buffer_size_bound = 32; // Buffer must be 32 * 128 bytes + Write(*((unsigned long int*)&audio_stream_description)); + + ISO11172_1::stream_description video_stream_description; + video_stream_description.stream_id = 0xE3; + video_stream_description.market_bits = 0x3; + video_stream_description.STD_buffer_bound_scale = 1; // Must be 1 for video streams + video_stream_description.STD_buffer_size_bound = 46; // Buffer must be 32 * 1024 bytes + Write(*((unsigned long int*)&video_stream_description)); +} + +/** + * Create and write a pack + */ +bool Multiplexer::pack() +{ + // info->info("\t[Pack"); + + Write((void*)ISO11172_1::pack_start_code, SIZEOF(ISO11172_1::pack_start_code)); + + ISO11172_1::pack_header header; + // Set marker bits to 1 + header.marker_bit1 = + header.marker_bit2 = + header.marker_bit3 = + header.marker_bit4 = + header.marker_bit5 = 1; + + header.padding = 0x2; + + unsigned int video_data_rate; + unsigned int audio_data_rate; + + if(frame[TYPE_AUDIO]) audio_data_rate = frame[TYPE_AUDIO]->bitrate; + else audio_data_rate = 112000; + + if(frame[TYPE_VIDEO]) video_data_rate = frame[TYPE_VIDEO]->bitrate; + else video_data_rate = 1100000; + + unsigned int Rmux = ISO11172_1::Rmux(video_data_rate, + audio_data_rate, + 20, // packet_header_size, + 12, // pack_header_size, + PACKETS_PER_PACK, // packets_per_pack, + PACKET_SIZE);// packet_data_size) + + header.mux_rate = Rmux; + //0x1B82; + + SCR = ISO11172_1::SCR(SCR, + 12, //pack_header_size, + PACKETS_PER_PACK, //packets_per_pack, + PACKET_SIZE, //packet_data_size, + Rmux); + + // SCR = 0x40010003LL; + + header.system_clock_reference1 = TIMECODE32_30(SCR); + header.system_clock_reference2 = TIMECODE29_15(SCR); + header.system_clock_reference3 = TIMECODE14_0(SCR); + /* + info->info("timecode All: %lld, 1: %lld, 2: %lld, 3: %lld", + SCR, + (unsigned long long int)header.system_clock_reference1, + (unsigned long long int)header.system_clock_reference2, + (unsigned long long int)header.system_clock_reference3 + ); + */ + Write(*((unsigned long long int*)&header)); + + if(write_system_header % SYSTEM_HEADER_FREQUENCY == 0) system_header(); + // Count this up here, we want a system header in pack 0, 5, ... NOT 4, 9, ... + write_system_header++; + + for(int cnt = 0; cnt < PACKETS_PER_PACK; cnt++) + if(!packet()) return false; + + // info->info("\t]"); + + return true; +} + +/** + * + */ +void Multiplexer::iso11172_stream() +{ + // info->info("[iso11172_stream"); + + while(pack()); + + // info->info("]"); + // info->info("[iso11172_end_code]"); + Write((void*)ISO11172_1::end_code, SIZEOF(ISO11172_1::end_code)); + + /* + info->info("false && false = %d", false && false); + info->info("true && false = %d", true && false); + info->info("true && true = %d", true && true); + */ +} + +//#define BYPASS TYPE_VIDEO +//#define BYPASS TYPE_AUDIO +void Multiplexer::multiplex() +{ +#ifdef BYPASS + + int frmsz; + char buf[1024]; + do { + frmsz = read_stream(buf, sizeof(buf), BYPASS); + info->info("Wrote %d bytes", frmsz); + Write(buf, frmsz); + } while(frmsz == sizeof(buf)); + return; + +#else/*BYPASS*/ + + iso11172_stream(); + +#endif/*BYPASS*/ +} diff --git a/server/multiplexer.h b/server/multiplexer.h new file mode 100644 index 0000000..9959009 --- /dev/null +++ b/server/multiplexer.h @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multiplexer.h + * + * Wed Aug 31 13:05:18 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" +#ifndef __MIAV_MULTIPLEXER_H__ +#define __MIAV_MULTIPLEXER_H__ + +#include "iso11172-1.h" +#include "iso11172-2.h" +#include "iso11172-3.h" + +#include "file.h" +#include "multicast.h" +#include "info.h" +#include "frame.h" + +#include "threadsafe_queue_priority.h" + +/** + * Multiplexer configuration + */ +// How many packets should we put in one pack +#define PACKETS_PER_PACK 3 + +// How many packets bewteen audio packs +#define AUDIO_PACKET_FREQUENCY 10 + +// How many packs bewteen system headers +#define SYSTEM_HEADER_FREQUENCY 5 + +// Size of video or audio data pr. packet +#define PACKET_SIZE 2028 + +/** + * Other stuff + */ +// The number of streamtypes. +#define NUM_TYPES 2 + +// Enum of the streamtypes. +typedef enum { + TYPE_VIDEO, + TYPE_AUDIO +} StreamType; + + +class Multiplexer { +public: + Multiplexer(File *file, Multicast *m, Info *info, volatile bool *running, + ThreadSafeQueuePriority *video_queue, + ThreadSafeQueuePriority *audio_queue); + ~Multiplexer(); + + void multiplex(); + +private: + int Write(void* data, int size); + int Write(char* data, int size); + int Write(unsigned long long int val); + int Write(long long int val); + int Write(long int val); + int Write(unsigned long int val); + int Write(int val); + int Write(unsigned int val); + int Write(short int val); + int Write(unsigned short int val); + + unsigned long long int SCR; + + double written[NUM_TYPES]; + + void iso11172_stream(); + bool pack(); + void system_header(); + bool packet(); + bool packet(StreamType type); + /* + void audio_packet(); + void video_packet(); + + void audio_data(ISO11172_3::header *header); + void audio_data_layer_I(ISO11172_3::header *header); + void audio_data_layer_II(ISO11172_3::header *header); + void audio_data_layer_III(ISO11172_3::header *header); + + void video_data(ISO11172_2::sequence_header_1 *header1, + ISO11172_2::sequence_header_2 *header2); + */ + // Frequency variables + unsigned int write_system_header; + unsigned int write_audio_packet; + + Frame *getFrame(StreamType type); + int read_stream(char *buf, unsigned int size, StreamType type); + + Frame *frame[NUM_TYPES]; + unsigned int frame_number[NUM_TYPES]; + unsigned int read[NUM_TYPES]; + + File *file; + Multicast *multicast; + Info *info; + volatile bool *running; + + // Audio Header + bool audio_header_read; + + ThreadSafeQueuePriority *queue[NUM_TYPES]; +}; + +#endif/*__MIAV_MULTIPLEXER_H__*/ diff --git a/server/server.cc b/server/server.cc new file mode 100644 index 0000000..34aac7b --- /dev/null +++ b/server/server.cc @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * server.cc + * + * Mon Nov 8 11:35:01 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 "server.h" +#include "miav.h" + +#include <stdio.h> +#include <stdlib.h> + +// For mkdir +#include <sys/stat.h> +#include <sys/types.h> + +// For unlink +#include <unistd.h> + +// For errno +#include <errno.h> + +// For inet_ntoa +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "miav_config.h" + +#include "mov_encoder_thread.h" +#include "img_encoder.h" + +#include "server_status.h" + +#include "dv.h" + +void newConnection(Socket *socket, Info *info) +{ + char cpr[256]; + char clientip[64]; + bool hasCpr = false; + ServerStatus status(info); + + n_savestate savestate = LATER; + n_header h; + Frame *frame; + Frame *freeze_frame = NULL; + MovEncoderThread *enc = NULL; + + frame = new Frame(NULL, DVPACKAGE_SIZE); + + info->info("CONNECTION OPENED"); + info->info("New connection (%s)", inet_ntoa(socket->socketaddr.sin_addr)); + + sprintf(clientip, "%s", inet_ntoa(socket->socketaddr.sin_addr)); + + Network network = Network(socket, info); + while(int ret = network.recvPackage(&h, frame->data, frame->size)) { + status.checkPoint(); + + if(ret == -1) { + info->error("A network error ocurred, terminating session"); + break; + } + + frame->mute = h.header.h_data.mute; + + if(!hasCpr) { + sprintf(cpr, h.header.h_data.cpr); + hasCpr = true; + } + + if(h.header.h_data.snapshot) { + if(freeze_frame) { + ImgEncoder(cpr, info).encode(freeze_frame, 100); + delete freeze_frame; + freeze_frame = NULL; + } else { + ImgEncoder(cpr, info).encode(frame, 100); + } + } + + if(h.header.h_data.savestate != NO_CHANGE) { + savestate = h.header.h_data.savestate; + info->info("GOT SAVESTATE FROM NETWORK: %d", savestate ); + } + + if(h.header.h_data.freeze) { + if(freeze_frame) delete freeze_frame; + // copy the frame into another temporary one. + freeze_frame = new Frame(frame->data, frame->size); + } + + // This one must be last! + if(h.header.h_data.record) { + // if(!enc) enc = newMovEncoder(cpr); + if(!enc) enc = new MovEncoderThread(clientip, cpr, info); + enc->encode(frame); + } + + frame = new Frame(NULL, DVPACKAGE_SIZE); + } + + info->info("Closing connection..."); + + // No encoder exists, if this is a pure snapshot (image) connection. + if(enc) { + enc->setSaveState(savestate); + // Send end of stream frame. + frame->endOfFrameStream = true; + enc->encode(frame); + delete enc; + } + + info->info("CONNECTION CLOSED"); +} diff --git a/server/server.h b/server/server.h new file mode 100644 index 0000000..7126a75 --- /dev/null +++ b/server/server.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * server.h + * + * Mon Nov 8 11:35:01 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. + */ +#ifndef __SERVER_H__ +#define __SERVER_H__ + +#include "socket.h" + +#include "info.h" + +void newConnection(Socket *s, Info* info); + + +#endif/*__SERVER_H__*/ diff --git a/server/server_status.cc b/server/server_status.cc new file mode 100644 index 0000000..7f4714e --- /dev/null +++ b/server/server_status.cc @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * server_status.cc + * + * Fri Apr 29 13:58:26 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 "server_status.h" + +#include <stdio.h> + +ServerStatus::ServerStatus(Info *i) +{ + info = i; + + gettimeofday(&oldtime, NULL); + + for(int cnt = 0; cnt < BUFFERSIZE; cnt++) { + frametime[cnt] = 41660; + } + + gettimeofday(&time, NULL); + + interval = 0; +} + +ServerStatus::~ServerStatus() +{ +} + +void ServerStatus::checkPoint() +{ + for(int cnt = BUFFERSIZE - 1; cnt > 0; cnt--) { + frametime[cnt] = frametime[cnt-1]; + } + frametime[0] = (1000000 * time.tv_sec + time.tv_usec) - (1000000 * oldtime.tv_sec + oldtime.tv_usec); + + oldtime.tv_sec = time.tv_sec; + oldtime.tv_usec = time.tv_usec; + + gettimeofday(&time, NULL); + + interval += frametime[0]; + if(interval > UPD) { + interval = 0; + double total = 0.0; + for(int cnt = 0; cnt < BUFFERSIZE; cnt++) { + total += (double)frametime[cnt]; + } + info->info("Status - fps: %f", 1000000.0 / (total / (double)BUFFERSIZE)); + } + +} + +/* +date(1), gettimeofday(2), ctime(3), ftime(3) +*/ diff --git a/server/server_status.h b/server/server_status.h new file mode 100644 index 0000000..5a7cb6c --- /dev/null +++ b/server/server_status.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * server_status.h + * + * Fri Apr 29 13:58:26 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_SERVER_STATUS_H__ +#define __MIAV_SERVER_STATUS_H__ + +#include "info.h" + +#include <sys/time.h> + +// How many steps to do avarage calculation over. +#define BUFFERSIZE 100 + +// Interval in us (microseconds) +#define UPD 60 * 1000 * 1000 // 1 minute + +class ServerStatus { +public: + ServerStatus(Info *info); + ~ServerStatus(); + + void checkPoint(); + +private: + long long interval; + Info *info; + unsigned int frametime[BUFFERSIZE]; + struct timeval time; + struct timeval oldtime; +}; + +#endif/*__MIAV_SERVER_STATUS_H__*/ |