/************************************************************************* * @mainpage * mplex - General-purpose MPEG-1/2 multiplexer. * (C) 2000, 2001 Andrew Stevens * * Doxygen documentation and MPEG Z/Alpha multiplexing part by * Gernot Ziegler * Constructed using mplex - MPEG-1/SYSTEMS multiplexer as starting point * Copyright (C) 1994 1995 Christoph Moar * Siemens ZFE ST SN 11 / T SN 6 * * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. *************************************************************************/ /* * Modifications to work with streamdvd by Reinhardt Wolf */ #include "config.h" #include #include #ifdef HAVE_GETOPT_H #include #endif #include #include #include #ifndef _WIN32 #include #endif #include #include #include "cpu_accel.h" #include "mjpeg_types.h" #include "mjpeg_logging.h" #include "mpegconsts.h" #include "interact.hpp" #include "bits.hpp" #include "outputstrm.hpp" #include "multiplexor.hpp" #include using std::auto_ptr; extern int read_from_buffer ( unsigned char, unsigned char *, int, int ); /************************************************************************* 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 = ceil(x); return(l); } }; #endif class FileOutputStream : public OutputStream { public: FileOutputStream( const char *filename_pat ); //FileOutputStream(); 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]; }; FileOutputStream::FileOutputStream( const char *name_pat ) //FileOutputStream::FileOutputStream( ) { strncpy( filename_pat, name_pat, MAXPATHLEN ); snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num ); } int FileOutputStream::Open() { strm = fopen( cur_filename, "wb" ); if( strm == NULL ) { mjpeg_error_exit1( "Could not open for writing: %s", cur_filename ); } return 0; } void FileOutputStream::Close() { fclose(strm); } off_t FileOutputStream::SegmentSize() { struct stat stb; fstat(fileno(strm), &stb); off_t written = stb.st_size; return written; return (1); } void FileOutputStream::NextSegment( ) { auto_ptr 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 FileOutputStream::Write( uint8_t *buf, unsigned int len ) { // if( fwrite( buf, 1, len, strm ) != len ) // { // mjpeg_error_exit1( "Failed write: %s", cur_filename ); // } write(STDOUT_FILENO, buf, len); } /******************************** * * IFileBitStream - 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 IFileBitStream : public IBitStream { public: //IFileBitStream( const char *bs_filename, unsigned int buf_size = BUFFER_SIZE); IFileBitStream( unsigned char stream_id, unsigned int buf_size = BUFFER_SIZE); ~IFileBitStream(); virtual bool GetStreamID() { return (mystream); }; private: //FILE *fileh == 0; char filename[64]; int is_eof; unsigned char mystream; virtual size_t ReadStreamBytes( uint8_t *buf, size_t number ) { //return fread(buf,sizeof(uint8_t), number, fileh ); int was_read = read_from_buffer( mystream, buf, number, 1 ); is_eof = number - was_read; return ( was_read ); } //virtual bool EndOfStream() { return feof(fileh) != 0; } virtual bool EndOfStream() { return (is_eof != 0); }; }; //IFileBitStream::IFileBitStream( const char *bs_filename, unsigned int buf_size) : IBitStream() IFileBitStream::IFileBitStream( unsigned char stream_id, 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 ); if( (stream_id >= 0xA0) && (stream_id <= 0xAF) ) { sprintf(filename, "%s-0x%x.%s", "unnamed", stream_id, "lpcm"); } else if( (stream_id >= 0xC0) && (stream_id <= 0xCF) ) { sprintf(filename, "%s-0x%x.%s", "unnamed", stream_id, "mpa"); } else if( (stream_id >= 0x80) && (stream_id <= 0x87) ) { sprintf(filename, "%s-0x%x.%s", "unnamed", stream_id, "ac3"); } else if( (stream_id >= 0x88) && (stream_id <= 0x8F) ) { sprintf(filename, "%s-0x%x.%s", "unnamed", stream_id, "dts"); } else if( (stream_id >= 0xE0) && (stream_id <= 0xEF) ) { sprintf(filename, "%s-0x%x.%s", "unnamed", stream_id, "m2v"); } else { sprintf(filename, "%s-0x%x", "unnamed", stream_id); } streamname = filename; is_eof = 0; mystream = stream_id; SetBufSize(buf_size); eobs = false; byteidx = 0; if (!ReadIntoBuffer()) { if (buffered==0) { //mjpeg_error_exit1( "Unable to read from %s.", bs_filename); mjpeg_error_exit1( "Unable to read from %x.", stream_id); } } } /** Destructor: close the device containing the bit stream after a read process */ IFileBitStream::~IFileBitStream() { // 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( int stream_count, int stream_list[], int av_delay); private: void InputStreamsFromCmdLine ( int stream_count, int stream_list[] ); }; CmdLineMultiplexJob::CmdLineMultiplexJob( int stream_count, int stream_list[], int av_delay ) : MultiplexJob() { //outfile_pattern = NULL; outfile_pattern = "/tmp/mplextmp"; verbose = 1; mux_format = MPEG_FORMAT_DVD_NAV; //video_offset = lround(av_delay*CLOCKS/(1000.0)); video_offset = av_delay * (90*300); audio_offset = 0; if( video_offset < 0 ) { audio_offset = - video_offset; video_offset = 0; } //fprintf(stderr, "Coding with V_off: %d, A_off: %d\n", video_offset, audio_offset); (void)mjpeg_default_handler_verbosity(verbose); mjpeg_info( "mplex version %s (%s %s)",VERSION,MPLEX_VER,MPLEX_DATE ); InputStreamsFromCmdLine( stream_count, stream_list ); } void CmdLineMultiplexJob::InputStreamsFromCmdLine(int stream_count, int stream_list[] ) { vector inputs; int i; for( i = 0; i < stream_count; ++i ) { inputs.push_back( new IFileBitStream( stream_list[i] ) ); } SetupInputStreams( inputs ); } int run_mplex( int stream_count, int *stream_list, int av_delay ) { CmdLineMultiplexJob job( stream_count, stream_list, av_delay ); FileOutputStream output( job.outfile_pattern ); //FileOutputStream output(); Multiplexor mux(job, output); mux.Multiplex(); return(1); }