diff options
| author | deva <deva> | 2005-10-30 14:26:05 +0000 | 
|---|---|---|
| committer | deva <deva> | 2005-10-30 14:26:05 +0000 | 
| commit | f66b7824aba0ffda17cb6a475763dbd2be28c008 (patch) | |
| tree | 9dc01bb3c6c8d5212a065d65c7c5072152f43aad /src | |
| parent | 971d1fdf8599dccdc604ed9374373af16af8354f (diff) | |
OCVS: ----------------------------------------------------------------------
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/libmplex_wrapper.cc | 637 | ||||
| -rw-r--r-- | src/libmplex_wrapper.h | 39 | 
3 files changed, 678 insertions, 0 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index 6a72a0d..3ccf9d2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,7 @@ miav_SOURCES = $(shell  if [ $QT_CXXFLAGS ] ; then ../tools/MocList cc; fi ) \  	jpeg_mem_dest.cc \  	libfame_wrapper.cc \  	liblame_wrapper.cc \ +	libmplex_wrapper.cc \  	mainwindow.cc \  	messagebox.cc \  	miav.cc \ @@ -80,6 +81,7 @@ EXTRA_DIST = \  	jpeg_mem_dest.h \  	libfame_wrapper.h \  	liblame_wrapper.h \ +	libmplex_wrapper.h \  	mainwindow.h \  	messagebox.h \  	miav.h \ diff --git a/src/libmplex_wrapper.cc b/src/libmplex_wrapper.cc new file mode 100644 index 0000000..9b37c02 --- /dev/null +++ b/src/libmplex_wrapper.cc @@ -0,0 +1,637 @@ +/* -*- 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 <stdio.h> +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif +#include <string> +#include <memory> +#include <sys/stat.h> +#ifndef _WIN32 +#include <sys/param.h> +#endif +#include <ctype.h> +#include <math.h> +//#include <cpu_accel.h> +#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> + + +using std::auto_ptr; + + +/************************************************************************* + Command line wrapper.  Basically, all the command line and file (actually + pipe and FIFO is what would be more normal) I/O specific sub-classes + + Plus the top-level entry point.  That's all!! + +*************************************************************************/ + + +#if	!defined(HAVE_LROUND) +extern "C" { +long +lround(double x) +{ +	long l = (long)ceil(x); +	return(l); +} +}; +#endif + + + +class FrameOutputStream : public OutputStream +{ +public: +    FrameOutputStream( const char *filename_pat ); +    virtual int  Open( ); +    virtual void Close(); +    virtual off_t SegmentSize( ); +    virtual void NextSegment(); +    virtual void Write(uint8_t *data, unsigned int len); + +private: +    FILE *strm; +    char filename_pat[MAXPATHLEN]; +    char cur_filename[MAXPATHLEN]; + +}; + + + +FrameOutputStream::FrameOutputStream( const char *name_pat )  +{ +	strncpy( filename_pat, name_pat, MAXPATHLEN ); +	snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num ); +} +       +int FrameOutputStream::Open() +{ +	strm = fopen( cur_filename, "wb" ); +	if( strm == NULL ) +	{ +		mjpeg_error_exit1( "Could not open for writing: %s", cur_filename ); +	} + +	return 0; +} + +void FrameOutputStream::Close() +{  +    fclose(strm); +} + + +off_t +FrameOutputStream::SegmentSize() +{ +	struct stat stb; +    fstat(fileno(strm), &stb); +	off_t written = stb.st_size; +    return written; +} + +void  +FrameOutputStream::NextSegment( ) +{ +    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 ) +{ +    if( fwrite( buf, 1, len, strm ) != len ) +    { +        mjpeg_error_exit1( "Failed write: %s", cur_filename ); +    } +} + + + +/******************************** + * + * FrameInputStream - Input bit stream class for bit streams sourced + * from standard file I/O (this of course *includes* network sockets, + * fifo's, et al). + * + * OLAF: To hook into your PES reader/reconstructor you need to define + * a class like this one, where 'ReadStreamBytes' calls you code to + * generate the required number of bytes of ES data and transfer it  + * to the specified buffer.  The logical way to do this would be to + * inherit IBitStream as a base class of the top-level classes for the ES + * reconstructors. + * + ********************************/ + +class FrameInputStream : public IBitStream +{ +public: + 	FrameInputStream( const char *bs_filename,  +					unsigned int buf_size = BUFFER_SIZE); +	~FrameInputStream(); + +private: +	FILE *fileh; +	char *filename; +	virtual size_t ReadStreamBytes( uint8_t *buf, size_t number )  +		{ +			return fread(buf,sizeof(uint8_t), number, fileh );  +		} +	virtual bool EndOfStream() { return feof(fileh) != 0; } +	 +}; + + + +FrameInputStream::FrameInputStream( const char *bs_filename, +                                unsigned int buf_size) : +    IBitStream() +{ +	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); +		} +	} +} + + +/** +   Destructor: close the device containing the bit stream after a read +   process +*/ +FrameInputStream::~FrameInputStream() +{ +	if (fileh) +	{ +		fclose(fileh); +		delete filename; +	} +	fileh = 0; +    Release(); +} + + +/******************************* + * + * Command line job class - sets up a Multiplex Job based on command + * line and File I/O... + * + ******************************/ + +class CmdLineMultiplexJob : public MultiplexJob +{ +public: +	CmdLineMultiplexJob( unsigned int argc, char *argv[]); + +private: +	void InputStreamsFromCmdLine (unsigned int argc, char* argv[] ); +	void Usage(char *program_name); +	bool ParseVideoOpt( const char *optarg ); +	bool ParseLpcmOpt( const char *optarg ); +	bool ParseWorkaroundOpt( const char *optarg ); +	bool ParseTimeOffset( const char *optarg ); +	 + +	static const char short_options[]; + +#if defined(HAVE_GETOPT_LONG) +	static struct option long_options[]; +#endif + +}; + +const char CmdLineMultiplexJob::short_options[] = +    "o:b:r:O:v:f:l:s:S:p:W:L:VMh"; +#if defined(HAVE_GETOPT_LONG) +struct option CmdLineMultiplexJob::long_options[] =  +{ +	{ "verbose",           1, 0, 'v' }, +	{ "format",            1, 0, 'f' }, +	{ "mux-bitrate",       1, 0, 'r' }, +	{ "video-buffer",      1, 0, 'b' }, +	{ "lpcm-params",       1, 0, 'L' }, +	{ "output",            1, 0, 'o' }, +	{ "sync-offset",    	1, 0, 'O' }, +	{ "vbr",      	        1, 0, 'V' }, +	{ "system-headers",    1, 0, 'h' }, +	{ "ignore-seqend-markers",     0, 0, 'M' }, +	{ "max-segment-size",  1, 0, 'S' }, +	{ "mux-limit",   	    1, 0, 'l' }, +	{ "packets-per-pack",  1, 0, 'p' }, +	{ "sector-size",       1, 0, 's' }, +	{ "workarounds", 1, 0, 'W' }, +	{ "help",              0, 0, '?' }, +	{ 0,                   0, 0, 0   } +}; +#endif + + +CmdLineMultiplexJob::CmdLineMultiplexJob(unsigned int argc, char *argv[]) : +	MultiplexJob() +{ +    int n; +    outfile_pattern = NULL; + +#if defined(HAVE_GETOPT_LONG) +	while( (n=getopt_long(argc,argv,short_options,long_options, NULL)) != -1 ) +#else +    while( (n=getopt(argc,argv,short_options)) != -1 ) +#endif +	{ +		switch(n) +		{ +        case 0 : +            break; +		case 'o' : +			outfile_pattern = optarg; +			break; +		case 'v' : +			verbose = atoi(optarg); +			if( verbose < 0 || verbose > 2 ) +				Usage(argv[0]); +			break; + +		case 'V' : +			VBR = true; +			break; +	   +		case 'h' : +			always_system_headers = true; +			break; + +		case 'b' : +            if( ! ParseVideoOpt( optarg ) ) +            { +                mjpeg_error( "Illegal video decoder buffer size(s): %s",  +                             optarg ); +                Usage(argv[0]); +            } +            break; +        case 'L': +            if( ! ParseLpcmOpt( optarg ) ) +            { +                mjpeg_error( "Illegal LPCM option(s): %s", optarg ); +                Usage(argv[0]); +            } +            break; + +		case 'r': +			data_rate = atoi(optarg); +			if( data_rate < 0 ) +				Usage(argv[0]); +			/* Convert from kbit/sec (user spec) to 50B/sec units... */ +			data_rate = (( data_rate * 1000 / 8 + 49) / 50 ) * 50; +			break; + +		case 'O': +			if( ! ParseTimeOffset(optarg) ) +			{ +				mjpeg_error( "Time offset units if specified must: ms|s|mpt" ); +				Usage(argv[0]); +			} +			break; +           +		case 'l' :  + 			max_PTS = atoi(optarg); +			if( max_PTS < 1  ) +				Usage(argv[0]); +			break; +		 +		case 'p' :  +			packets_per_pack = atoi(optarg); +			if( packets_per_pack < 1 || packets_per_pack > 100  ) +				Usage(argv[0]); +			break; +		 +	   +		case 'f' : +			mux_format = atoi(optarg); +			if( mux_format < MPEG_FORMAT_MPEG1 || mux_format > MPEG_FORMAT_LAST +                ) +				Usage(argv[0]); +			break; +		case 's' : +			sector_size = atoi(optarg); +			if( sector_size < 256 || sector_size > 16384 ) +				Usage(argv[0]); +			break; +		case 'S' : +			max_segment_size = atoi(optarg); +			if( max_segment_size < 0  ) +				Usage(argv[0]); +			break; +		case 'M' : +			multifile_segment = true; +			break; +        case 'W' : +            if( ! ParseWorkaroundOpt( optarg ) ) +            { +                Usage(argv[0]); +            } +            break; +		case '?' : +		default : +			Usage(argv[0]); +			break; +		} +	} +	if (argc - optind < 1 || outfile_pattern == NULL) +    {	 +		Usage(argv[0]); +    } +	(void)mjpeg_default_handler_verbosity(verbose); +	mjpeg_info( "mplex version %s (%s %s)",VERSION,MPLEX_VER,MPLEX_DATE ); + +    InputStreamsFromCmdLine( argc-(optind-1), argv+optind-1); +} + +/************************************************************************* + Usage banner for the command line wrapper. +*************************************************************************/ + +     +void CmdLineMultiplexJob::Usage(char *str) +{ +    fprintf( stderr, +	"mjpegtools mplex-2 version " VERSION " (" MPLEX_VER ")\n" +	"Usage: %s [params] -o <output filename pattern> <input file>... \n" +	"         %%d in the output file name is by segment count\n" +	"  where possible params are:\n" +	"--verbose|-v num\n" +    "  Level of verbosity. 0 = quiet, 1 = normal 2 = verbose/debug\n" +	"--format|-f fmt\n" +    "  Set defaults for particular MPEG profiles\n" +	"  [0 = Generic MPEG1, 1 = VCD, 2 = user-rate VCD, 3 = Generic MPEG2,\n" +    "   4 = SVCD, 5 = user-rate SVCD\n" +	"   6 = VCD Stills, 7 = SVCD Stills, 8 = DVD with NAV sectors, 9 = DVD]\n" +    "--mux-bitrate|-r num\n" +    "  Specify data rate of output stream in kbit/sec\n" +	"    (default 0=Compute from source streams)\n" +	"--video-buffer|-b num [, num...] \n" +    "  Specifies decoder buffers size in kB.  [ 20...2000]\n" +    "--lpcm-params | -L samppersec:chan:bits [, samppersec:chan:bits]\n" +	"--mux-limit|-l num\n" +    "  Multiplex only num seconds of material (default 0=multiplex all)\n" +	"--sync-offset|-O num ms|s|mpt\n" +    "  Specify offset of timestamps (video-audio) in mSec\n" +	"--sector-size|-s num\n" +    "  Specify sector size in bytes for generic formats [256..16384]\n" +    "--vbr|-V\n" +    "  Multiplex variable bit-rate video\n" +	"--packets-per-pack|-p num\n" +    "  Number of packets per pack generic formats [1..100]\n" +	"--system-headers|-h\n" +    "  Create System header in every pack in generic formats\n" +	"--max-segment-size|-S size\n" +    "  Maximum size of output file(s) in Mbyte (default: 0) (no limit)\n" +	"--ignore-seqend-markers|-M\n" +    "  Don't switch to a new output file if a  sequence end marker\n" +	"  is encountered ithe input video.\n" +    "--workaround|-W workaround [, workaround ]\n" +	"--help|-?\n" +    "  Print this lot out!\n", str); +	exit (1); +} + + +bool CmdLineMultiplexJob::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 CmdLineMultiplexJob::ParseWorkaroundOpt( const char *optarg ) +{ +    char *endptr, *startptr; +    endptr = const_cast<char *>(optarg); +    struct { const char *longname; char shortname; bool *flag; } flag_table[] = +        { +            { 0, '\0', 0 } +        }; +    for(;;) +    { +        // Find start of next flag... +        while( isspace(*endptr) || *endptr == ',' ) +            ++endptr; +        if( *endptr == '\0' ) +            break; +        startptr = endptr; +        // Find end of current flag... +        while( *endptr != ' ' && *endptr != ',' && *endptr != '\0' ) +            ++endptr; +             +        size_t len = endptr - startptr; + +        int flag = 0; +        while( flag_table[flag].longname != 0 ) +        { +            if( (len == 1 && *startptr == flag_table[flag].shortname ) || +                strncmp( startptr, flag_table[flag].longname, len ) == 0 ) +            { +                *flag_table[flag].flag = true; +                break; +            } +            ++flag; +        } + +        if( flag_table[flag].longname == 0 ) +        { +            std::string message( "Illegal work-around option: not one of " ); +            flag = 0; +            char sep[] = ","; +            do +            { +                message += flag_table[flag].longname; +                message += sep; +                message += flag_table[flag].shortname; +                ++flag; +                if( flag_table[flag].longname != 0 ) +                    message += sep; +            } +            while( flag_table[flag].longname != 0 ); +            mjpeg_error( message.c_str() ); +            return false; +        } + +    }  +    return true; +} + +bool CmdLineMultiplexJob::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; +} + +bool CmdLineMultiplexJob::ParseTimeOffset(const char *optarg) +{ +    double f; +    double persecond=1000.0; +    char *e; + +    f=strtod(optarg,&e); +    if( *e ) { +        while(isspace(*e)) e++; +        if(!strcmp(e,"ms")) persecond=1000.0; +        else if(!strcmp(e,"s")) persecond=1.0; +        else if(!strcmp(e,"mpt")) persecond=90000.0; +		else +			return false; +    } +    video_offset = static_cast<int>(f*CLOCKS/(persecond)); +	if( video_offset < 0 ) +	{ +		audio_offset = - video_offset; +		video_offset = 0; +	} +	return true; +} + +void CmdLineMultiplexJob::InputStreamsFromCmdLine(unsigned int argc, char* argv[] ) +{ +	vector<IBitStream *> inputs; +    unsigned int i; +	for( i = 1; i < argc; ++i ) +    { +		inputs.push_back( new FrameInputStream( argv[i] ) ); +	} +	SetupInputStreams( inputs ); +} + +LibMPlexWrapper::LibMPlexWrapper() +{ +} + +LibMPlexWrapper::~LibMPlexWrapper() +{ +} + +void LibMPlexWrapper::multiplex() +{ +	CmdLineMultiplexJob job(0, NULL); +	FrameOutputStream output( job.outfile_pattern ); +	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*/ +			 diff --git a/src/libmplex_wrapper.h b/src/libmplex_wrapper.h new file mode 100644 index 0000000..0246314 --- /dev/null +++ b/src/libmplex_wrapper.h @@ -0,0 +1,39 @@ +/* -*- 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__ + +class LibMPlexWrapper { +public: +	LibMPlexWrapper(); +	~LibMPlexWrapper(); + +  void multiplex(); +}; + +#endif/*__MIAV_LIBMPLEX_WRAPPER_H__*/ | 
