diff options
| author | deva <deva> | 2006-03-04 14:53:17 +0000 | 
|---|---|---|
| committer | deva <deva> | 2006-03-04 14:53:17 +0000 | 
| commit | f02095ee5ceb78f1781a9e250693b8866ca42181 (patch) | |
| tree | 7953c6b5f004f31ee9b340d7cdff5e85890594fc | |
| parent | 71c713dce2b5128862b293aa7fcc1d7ee89ffaf1 (diff) | |
*** empty log message ***
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__*/ | 
