2
/*************************************************************************
4
* mplex - General-purpose MPEG-1/2 multiplexer.
5
* (C) 2000, 2001 Andrew Stevens <andrew.stevens@philips.com>
7
* Doxygen documentation and MPEG Z/Alpha multiplexing part by
8
* Gernot Ziegler <gz@lysator.liu.se>
9
* Constructed using mplex - MPEG-1/SYSTEMS multiplexer as starting point
10
* Copyright (C) 1994 1995 Christoph Moar
11
* Siemens ZFE ST SN 11 / T SN 6
13
* This program is free software; you can redistribute it and/or modify
14
* it under the terms of the GNU General Public License as published by
15
* the Free Software Foundation; either version 2 of the License, or
16
* (at your option) any later version. *
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this program; if not, write to the Free Software
25
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
*************************************************************************/
37
#include <sys/param.h>
41
#include "cpu_accel.h"
42
#include "mjpeg_types.h"
43
#include "mjpeg_logging.h"
44
#include "mpegconsts.h"
46
#include "interact.hpp"
48
#include "outputstrm.hpp"
49
#include "multiplexor.hpp"
55
/*************************************************************************
56
Command line wrapper. Basically, all the command line and file (actually
57
pipe and FIFO is what would be more normal) I/O specific sub-classes
59
Plus the top-level entry point. That's all!!
61
*************************************************************************/
64
#if !defined(HAVE_LROUND)
77
class FileOutputStream : public OutputStream
80
FileOutputStream( const char *filename_pat );
83
virtual off_t SegmentSize( );
84
virtual void NextSegment();
85
virtual void Write(uint8_t *data, unsigned int len);
89
char filename_pat[MAXPATHLEN];
90
char cur_filename[MAXPATHLEN];
96
FileOutputStream::FileOutputStream( const char *name_pat )
98
strncpy( filename_pat, name_pat, MAXPATHLEN );
99
snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num );
102
int FileOutputStream::Open()
104
strm = fopen( cur_filename, "wb" );
107
mjpeg_error_exit1( "Could not open for writing: %s", cur_filename );
113
void FileOutputStream::Close()
120
FileOutputStream::SegmentSize()
123
fstat(fileno(strm), &stb);
124
off_t written = stb.st_size;
129
FileOutputStream::NextSegment( )
131
auto_ptr<char> prev_filename_buf( new char[strlen(cur_filename)+1] );
132
char *prev_filename = prev_filename_buf.get();
135
strcpy( prev_filename, cur_filename );
136
snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num );
137
if( strcmp( prev_filename, cur_filename ) == 0 )
140
"Need to split output but there appears to be no %%d in the filename pattern %s", filename_pat );
142
strm = fopen( cur_filename, "wb" );
145
mjpeg_error_exit1( "Could not open for writing: %s", cur_filename );
150
FileOutputStream::Write( uint8_t *buf, unsigned int len )
152
if( fwrite( buf, 1, len, strm ) != len )
154
mjpeg_error_exit1( "Failed write: %s", cur_filename );
160
/********************************
162
* IFileBitStream - Input bit stream class for bit streams sourced
163
* from standard file I/O (this of course *includes* network sockets,
166
* OLAF: To hook into your PES reader/reconstructor you need to define
167
* a class like this one, where 'ReadStreamBytes' calls you code to
168
* generate the required number of bytes of ES data and transfer it
169
* to the specified buffer. The logical way to do this would be to
170
* inherit IBitStream as a base class of the top-level classes for the ES
173
********************************/
175
class IFileBitStream : public IBitStream
178
IFileBitStream( const char *bs_filename,
179
unsigned int buf_size = BUFFER_SIZE);
185
virtual size_t ReadStreamBytes( uint8_t *buf, size_t number )
187
return fread(buf,sizeof(uint8_t), number, fileh );
189
virtual bool EndOfStream() { return feof(fileh) != 0; }
195
IFileBitStream::IFileBitStream( const char *bs_filename,
196
unsigned int buf_size) :
199
if ((fileh = fopen(bs_filename, "rb")) == NULL)
201
mjpeg_error_exit1( "Unable to open file %s for reading.", bs_filename);
203
filename = strcpy( new char[strlen(bs_filename)+1], bs_filename );
204
streamname = filename;
206
SetBufSize(buf_size);
209
if (!ReadIntoBuffer())
213
mjpeg_error_exit1( "Unable to read from %s.", bs_filename);
220
Destructor: close the device containing the bit stream after a read
223
IFileBitStream::~IFileBitStream()
235
/*******************************
237
* Command line job class - sets up a Multiplex Job based on command
238
* line and File I/O...
240
******************************/
242
class CmdLineMultiplexJob : public MultiplexJob
245
CmdLineMultiplexJob( unsigned int argc, char *argv[]);
248
void InputStreamsFromCmdLine (unsigned int argc, char* argv[] );
249
void Usage(char *program_name);
250
bool ParseVideoOpt( const char *optarg );
251
bool ParseLpcmOpt( const char *optarg );
252
bool ParseWorkaroundOpt( const char *optarg );
253
bool ParseTimeOffset( const char *optarg );
256
static const char short_options[];
258
#if defined(HAVE_GETOPT_LONG)
259
static struct option long_options[];
264
const char CmdLineMultiplexJob::short_options[] =
265
"o:b:r:O:v:f:l:s:S:p:W:L:VMh";
266
#if defined(HAVE_GETOPT_LONG)
267
struct option CmdLineMultiplexJob::long_options[] =
269
{ "verbose", 1, 0, 'v' },
270
{ "format", 1, 0, 'f' },
271
{ "mux-bitrate", 1, 0, 'r' },
272
{ "video-buffer", 1, 0, 'b' },
273
{ "lpcm-params", 1, 0, 'L' },
274
{ "output", 1, 0, 'o' },
275
{ "sync-offset", 1, 0, 'O' },
276
{ "vbr", 1, 0, 'V' },
277
{ "system-headers", 1, 0, 'h' },
278
{ "split-segment", 0, 0, 'M' },
279
{ "max-segment-size", 1, 0, 'S' },
280
{ "mux-limit", 1, 0, 'l' },
281
{ "packets-per-pack", 1, 0, 'p' },
282
{ "sector-size", 1, 0, 's' },
283
{ "workarounds", 1, 0, 'W' },
284
{ "help", 0, 0, '?' },
290
CmdLineMultiplexJob::CmdLineMultiplexJob(unsigned int argc, char *argv[]) :
294
outfile_pattern = NULL;
296
#if defined(HAVE_GETOPT_LONG)
297
while( (n=getopt_long(argc,argv,short_options,long_options, NULL)) != -1 )
299
while( (n=getopt(argc,argv,short_options)) != -1 )
307
outfile_pattern = optarg;
310
verbose = atoi(optarg);
311
if( verbose < 0 || verbose > 2 )
320
always_system_headers = true;
324
if( ! ParseVideoOpt( optarg ) )
326
mjpeg_error( "Illegal video decoder buffer size(s): %s",
332
if( ! ParseLpcmOpt( optarg ) )
334
mjpeg_error( "Illegal LPCM option(s): %s", optarg );
340
data_rate = atoi(optarg);
343
/* Convert from kbit/sec (user spec) to 50B/sec units... */
344
data_rate = (( data_rate * 1000 / 8 + 49) / 50 ) * 50;
348
if( ! ParseTimeOffset(optarg) )
350
mjpeg_error( "Time offset units if specified must: ms|s|mpt" );
356
max_PTS = atoi(optarg);
362
packets_per_pack = atoi(optarg);
363
if( packets_per_pack < 1 || packets_per_pack > 100 )
369
mux_format = atoi(optarg);
370
if( mux_format < MPEG_FORMAT_MPEG1 || mux_format > MPEG_FORMAT_LAST
375
sector_size = atoi(optarg);
376
if( sector_size < 256 || sector_size > 16384 )
380
max_segment_size = atoi(optarg);
381
if( max_segment_size < 0 )
385
multifile_segment = true;
388
if( ! ParseWorkaroundOpt( optarg ) )
399
if (argc - optind < 1 || outfile_pattern == NULL)
403
(void)mjpeg_default_handler_verbosity(verbose);
404
mjpeg_info( "mplex version %s (%s %s)",VERSION,MPLEX_VER,MPLEX_DATE );
406
InputStreamsFromCmdLine( argc-(optind-1), argv+optind-1);
409
/*************************************************************************
410
Usage banner for the command line wrapper.
411
*************************************************************************/
414
void CmdLineMultiplexJob::Usage(char *str)
417
"mjpegtools mplex-2 version " VERSION " (" MPLEX_VER ")\n"
418
"Usage: %s [params] -o <output filename pattern> <input file>... \n"
419
" %%d in the output file name is by segment count\n"
420
" where possible params are:\n"
422
" Level of verbosity. 0 = quiet, 1 = normal 2 = verbose/debug\n"
424
" Set defaults for particular MPEG profiles\n"
425
" [0 = Generic MPEG1, 1 = VCD, 2 = user-rate VCD, 3 = Generic MPEG2,\n"
426
" 4 = SVCD, 5 = user-rate SVCD\n"
427
" 6 = VCD Stills, 7 = SVCD Stills, 8 = DVD with NAV sectors, 9 = DVD]\n"
428
"--mux-bitrate|-r num\n"
429
" Specify data rate of output stream in kbit/sec\n"
430
" (default 0=Compute from source streams)\n"
431
"--video-buffer|-b num [, num...] \n"
432
" Specifies decoder buffers size in kB. [ 20...2000]\n"
433
"--lpcm-params | -L samppersec:chan:bits [, samppersec:chan:bits]\n"
434
"--mux-limit|-l num\n"
435
" Multiplex only num seconds of material (default 0=multiplex all)\n"
436
"--sync-offset|-O num ms|s|mpt\n"
437
" Specify offset of timestamps (video-audio) in mSec\n"
438
"--sector-size|-s num\n"
439
" Specify sector size in bytes for generic formats [256..16384]\n"
441
" Multiplex variable bit-rate video\n"
442
"--packets-per-pack|-p num\n"
443
" Number of packets per pack generic formats [1..100]\n"
444
"--system-headers|-h\n"
445
" Create System header in every pack in generic formats\n"
446
"--max-segment-size|-S size\n"
447
" Maximum size of output file(s) in Mbyte (default: 0) (no limit)\n"
448
"--split-segment|-M\n"
449
" Simply split a sequence across files rather than building run-out/run-in\n"
450
"--workaround|-W workaround [, workaround ]\n"
452
" Print this lot out!\n", str);
457
bool CmdLineMultiplexJob::ParseLpcmOpt( const char *optarg )
459
char *endptr, *startptr;
460
unsigned int samples_sec;
461
unsigned int channels;
462
unsigned int bits_sample;
463
endptr = const_cast<char *>(optarg);
467
samples_sec = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
468
if( startptr == endptr || *endptr != ':' )
473
channels = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
474
if(startptr == endptr || *endptr != ':' )
478
bits_sample = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
479
if( startptr == endptr )
482
LpcmParams *params = LpcmParams::Checked( samples_sec,
487
lpcm_param.push_back(params);
490
} while( *endptr != '\0' );
495
bool CmdLineMultiplexJob::ParseWorkaroundOpt( const char *optarg )
497
char *endptr, *startptr;
498
endptr = const_cast<char *>(optarg);
499
struct { const char *longname; char shortname; bool *flag; } flag_table[] =
505
// Find start of next flag...
506
while( isspace(*endptr) || *endptr == ',' )
508
if( *endptr == '\0' )
511
// Find end of current flag...
512
while( *endptr != ' ' && *endptr != ',' && *endptr != '\0' )
515
size_t len = endptr - startptr;
518
while( flag_table[flag].longname != 0 )
520
if( (len == 1 && *startptr == flag_table[flag].shortname ) ||
521
strncmp( startptr, flag_table[flag].longname, len ) == 0 )
523
*flag_table[flag].flag = true;
529
if( flag_table[flag].longname == 0 )
531
std::string message( "Illegal work-around option: not one of " );
536
message += flag_table[flag].longname;
538
message += flag_table[flag].shortname;
540
if( flag_table[flag].longname != 0 )
543
while( flag_table[flag].longname != 0 );
544
mjpeg_error( message.c_str() );
552
bool CmdLineMultiplexJob::ParseVideoOpt( const char *optarg )
554
char *endptr, *startptr;
555
unsigned int buffer_size;
556
endptr = const_cast<char *>(optarg);
560
buffer_size = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
561
if( startptr == endptr )
564
VideoParams *params = VideoParams::Checked( buffer_size );
567
video_param.push_back(params);
571
while( *endptr != '\0' );
575
bool CmdLineMultiplexJob::ParseTimeOffset(const char *optarg)
578
double persecond=1000.0;
583
while(isspace(*e)) e++;
584
if(!strcmp(e,"ms")) persecond=1000.0;
585
else if(!strcmp(e,"s")) persecond=1.0;
586
else if(!strcmp(e,"mpt")) persecond=90000.0;
590
video_offset = lround(f*CLOCKS/(persecond));
591
if( video_offset < 0 )
593
audio_offset = - video_offset;
599
void CmdLineMultiplexJob::InputStreamsFromCmdLine(unsigned int argc, char* argv[] )
601
vector<IBitStream *> inputs;
603
for( i = 1; i < argc; ++i )
605
inputs.push_back( new IFileBitStream( argv[i] ) );
607
SetupInputStreams( inputs );
611
int main (int argc, char* argv[])
613
CmdLineMultiplexJob job(argc,argv);
614
FileOutputStream output( job.outfile_pattern );
615
Multiplexor mux(job, output);