summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authordeva <deva>2006-03-04 14:53:17 +0000
committerdeva <deva>2006-03-04 14:53:17 +0000
commitf02095ee5ceb78f1781a9e250693b8866ca42181 (patch)
tree7953c6b5f004f31ee9b340d7cdff5e85890594fc /server
parent71c713dce2b5128862b293aa7fcc1d7ee89ffaf1 (diff)
*** empty log message ***
Diffstat (limited to 'server')
-rw-r--r--server/audio_encoder.cc218
-rw-r--r--server/audio_encoder.h60
-rw-r--r--server/config.h33
-rw-r--r--server/dvfile.cc60
-rw-r--r--server/dvfile.h51
-rw-r--r--server/img_encoder.cc196
-rw-r--r--server/img_encoder.h69
-rw-r--r--server/info_console.cc101
-rw-r--r--server/info_console.h53
-rw-r--r--server/iso11172-1.h161
-rw-r--r--server/iso11172-2.h73
-rw-r--r--server/iso11172-3.h85
-rw-r--r--server/libfame_wrapper.cc273
-rw-r--r--server/libfame_wrapper.h70
-rw-r--r--server/liblame_wrapper.cc293
-rw-r--r--server/liblame_wrapper.h71
-rw-r--r--server/libmplex_wrapper.cc485
-rw-r--r--server/libmplex_wrapper.h55
-rw-r--r--server/miav_daemon.cc108
-rw-r--r--server/miav_daemon.h42
-rw-r--r--server/miav_server.cc50
-rw-r--r--server/miav_server.h42
-rw-r--r--server/mov_encoder.cc293
-rw-r--r--server/mov_encoder.h83
-rw-r--r--server/mov_encoder_thread.cc158
-rw-r--r--server/mov_encoder_thread.h91
-rw-r--r--server/mov_encoder_writer.cc140
-rw-r--r--server/mov_encoder_writer.h73
-rw-r--r--server/multicast.cc178
-rw-r--r--server/multicast.h55
-rw-r--r--server/multicast_configuration.cc141
-rw-r--r--server/multicast_configuration.h56
-rw-r--r--server/multiplexer.cc495
-rw-r--r--server/multiplexer.h134
-rw-r--r--server/server.cc136
-rw-r--r--server/server.h37
-rw-r--r--server/server_status.cc77
-rw-r--r--server/server_status.h56
38 files changed, 4852 insertions, 0 deletions
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__*/