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