diff options
Diffstat (limited to 'server/libmplex_wrapper.cc')
-rw-r--r-- | server/libmplex_wrapper.cc | 485 |
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*/ |