summaryrefslogtreecommitdiff
path: root/server/libmplex_wrapper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server/libmplex_wrapper.cc')
-rw-r--r--server/libmplex_wrapper.cc485
1 files changed, 485 insertions, 0 deletions
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*/