~ubuntu-branches/ubuntu/feisty/avidemux/feisty

« back to all changes in this revision

Viewing changes to avidemux/ADM_mplex/main_example.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2005-05-25 13:02:29 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20050525130229-jw94cav0yhmg7vjw
Tags: 1:2.0.40-0.0
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*************************************************************************
 
3
* @mainpage
 
4
*  mplex - General-purpose MPEG-1/2 multiplexer.
 
5
* (C) 2000, 2001 Andrew Stevens <andrew.stevens@philips.com>
 
6
 
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
 
12
*
 
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.                                   *
 
17
*
 
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. 
 
22
*
 
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
*************************************************************************/
 
27
 
 
28
#include <config.h>
 
29
#include <stdio.h>
 
30
#ifdef HAVE_GETOPT_H
 
31
#include <getopt.h>
 
32
#endif
 
33
#include <string>
 
34
#include <memory>
 
35
#include <sys/stat.h>
 
36
#ifndef _WIN32
 
37
#include <sys/param.h>
 
38
#endif
 
39
#include <ctype.h>
 
40
#include <math.h>
 
41
#include "cpu_accel.h"
 
42
#include "mjpeg_types.h"
 
43
#include "mjpeg_logging.h"
 
44
#include "mpegconsts.h"
 
45
 
 
46
#include "interact.hpp"
 
47
#include "bits.hpp"
 
48
#include "outputstrm.hpp"
 
49
#include "multiplexor.hpp"
 
50
 
 
51
 
 
52
using std::auto_ptr;
 
53
 
 
54
 
 
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
 
58
 
 
59
 Plus the top-level entry point.  That's all!!
 
60
 
 
61
*************************************************************************/
 
62
 
 
63
 
 
64
#if     !defined(HAVE_LROUND)
 
65
extern "C" {
 
66
long
 
67
lround(double x)
 
68
{
 
69
        long l = ceil(x);
 
70
        return(l);
 
71
}
 
72
};
 
73
#endif
 
74
 
 
75
 
 
76
 
 
77
class FileOutputStream : public OutputStream
 
78
{
 
79
public:
 
80
    FileOutputStream( const char *filename_pat );
 
81
    virtual int  Open( );
 
82
    virtual void Close();
 
83
    virtual off_t SegmentSize( );
 
84
    virtual void NextSegment();
 
85
    virtual void Write(uint8_t *data, unsigned int len);
 
86
 
 
87
private:
 
88
    FILE *strm;
 
89
    char filename_pat[MAXPATHLEN];
 
90
    char cur_filename[MAXPATHLEN];
 
91
 
 
92
};
 
93
 
 
94
 
 
95
 
 
96
FileOutputStream::FileOutputStream( const char *name_pat ) 
 
97
{
 
98
        strncpy( filename_pat, name_pat, MAXPATHLEN );
 
99
        snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num );
 
100
}
 
101
      
 
102
int FileOutputStream::Open()
 
103
{
 
104
        strm = fopen( cur_filename, "wb" );
 
105
        if( strm == NULL )
 
106
        {
 
107
                mjpeg_error_exit1( "Could not open for writing: %s", cur_filename );
 
108
        }
 
109
 
 
110
        return 0;
 
111
}
 
112
 
 
113
void FileOutputStream::Close()
 
114
 
115
    fclose(strm);
 
116
}
 
117
 
 
118
 
 
119
off_t
 
120
FileOutputStream::SegmentSize()
 
121
{
 
122
        struct stat stb;
 
123
    fstat(fileno(strm), &stb);
 
124
        off_t written = stb.st_size;
 
125
    return written;
 
126
}
 
127
 
 
128
void 
 
129
FileOutputStream::NextSegment( )
 
130
{
 
131
    auto_ptr<char> prev_filename_buf( new char[strlen(cur_filename)+1] );
 
132
    char *prev_filename = prev_filename_buf.get();
 
133
        fclose(strm);
 
134
        ++segment_num;
 
135
    strcpy( prev_filename, cur_filename );
 
136
        snprintf( cur_filename, MAXPATHLEN, filename_pat, segment_num );
 
137
        if( strcmp( prev_filename, cur_filename ) == 0 )
 
138
        {
 
139
                mjpeg_error_exit1( 
 
140
                        "Need to split output but there appears to be no %%d in the filename pattern %s", filename_pat );
 
141
        }
 
142
        strm = fopen( cur_filename, "wb" );
 
143
        if( strm == NULL )
 
144
        {
 
145
                mjpeg_error_exit1( "Could not open for writing: %s", cur_filename );
 
146
        }
 
147
}
 
148
 
 
149
void
 
150
FileOutputStream::Write( uint8_t *buf, unsigned int len )
 
151
{
 
152
    if( fwrite( buf, 1, len, strm ) != len )
 
153
    {
 
154
        mjpeg_error_exit1( "Failed write: %s", cur_filename );
 
155
    }
 
156
}
 
157
 
 
158
 
 
159
 
 
160
/********************************
 
161
 *
 
162
 * IFileBitStream - Input bit stream class for bit streams sourced
 
163
 * from standard file I/O (this of course *includes* network sockets,
 
164
 * fifo's, et al).
 
165
 *
 
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
 
171
 * reconstructors.
 
172
 *
 
173
 ********************************/
 
174
 
 
175
class IFileBitStream : public IBitStream
 
176
{
 
177
public:
 
178
        IFileBitStream( const char *bs_filename, 
 
179
                                        unsigned int buf_size = BUFFER_SIZE);
 
180
        ~IFileBitStream();
 
181
 
 
182
private:
 
183
        FILE *fileh;
 
184
        char *filename;
 
185
        virtual size_t ReadStreamBytes( uint8_t *buf, size_t number ) 
 
186
                {
 
187
                        return fread(buf,sizeof(uint8_t), number, fileh ); 
 
188
                }
 
189
        virtual bool EndOfStream() { return feof(fileh) != 0; }
 
190
        
 
191
};
 
192
 
 
193
 
 
194
 
 
195
IFileBitStream::IFileBitStream( const char *bs_filename,
 
196
                                unsigned int buf_size) :
 
197
    IBitStream()
 
198
{
 
199
        if ((fileh = fopen(bs_filename, "rb")) == NULL)
 
200
        {
 
201
                mjpeg_error_exit1( "Unable to open file %s for reading.", bs_filename);
 
202
        }
 
203
        filename = strcpy( new char[strlen(bs_filename)+1], bs_filename );
 
204
    streamname = filename;
 
205
 
 
206
    SetBufSize(buf_size);
 
207
        eobs = false;
 
208
    byteidx = 0;
 
209
        if (!ReadIntoBuffer())
 
210
        {
 
211
                if (buffered==0)
 
212
                {
 
213
                        mjpeg_error_exit1( "Unable to read from %s.", bs_filename);
 
214
                }
 
215
        }
 
216
}
 
217
 
 
218
 
 
219
/**
 
220
   Destructor: close the device containing the bit stream after a read
 
221
   process
 
222
*/
 
223
IFileBitStream::~IFileBitStream()
 
224
{
 
225
        if (fileh)
 
226
        {
 
227
                fclose(fileh);
 
228
                delete filename;
 
229
        }
 
230
        fileh = 0;
 
231
    Release();
 
232
}
 
233
 
 
234
 
 
235
/*******************************
 
236
 *
 
237
 * Command line job class - sets up a Multiplex Job based on command
 
238
 * line and File I/O...
 
239
 *
 
240
 ******************************/
 
241
 
 
242
class CmdLineMultiplexJob : public MultiplexJob
 
243
{
 
244
public:
 
245
        CmdLineMultiplexJob( unsigned int argc, char *argv[]);
 
246
 
 
247
private:
 
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 );
 
254
        
 
255
 
 
256
        static const char short_options[];
 
257
 
 
258
#if defined(HAVE_GETOPT_LONG)
 
259
        static struct option long_options[];
 
260
#endif
 
261
 
 
262
};
 
263
 
 
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[] = 
 
268
{
 
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, '?' },
 
285
        { 0,                   0, 0, 0   }
 
286
};
 
287
#endif
 
288
 
 
289
 
 
290
CmdLineMultiplexJob::CmdLineMultiplexJob(unsigned int argc, char *argv[]) :
 
291
        MultiplexJob()
 
292
{
 
293
    int n;
 
294
    outfile_pattern = NULL;
 
295
 
 
296
#if defined(HAVE_GETOPT_LONG)
 
297
        while( (n=getopt_long(argc,argv,short_options,long_options, NULL)) != -1 )
 
298
#else
 
299
    while( (n=getopt(argc,argv,short_options)) != -1 )
 
300
#endif
 
301
        {
 
302
                switch(n)
 
303
                {
 
304
        case 0 :
 
305
            break;
 
306
                case 'o' :
 
307
                        outfile_pattern = optarg;
 
308
                        break;
 
309
                case 'v' :
 
310
                        verbose = atoi(optarg);
 
311
                        if( verbose < 0 || verbose > 2 )
 
312
                                Usage(argv[0]);
 
313
                        break;
 
314
 
 
315
                case 'V' :
 
316
                        VBR = true;
 
317
                        break;
 
318
          
 
319
                case 'h' :
 
320
                        always_system_headers = true;
 
321
                        break;
 
322
 
 
323
                case 'b' :
 
324
            if( ! ParseVideoOpt( optarg ) )
 
325
            {
 
326
                mjpeg_error( "Illegal video decoder buffer size(s): %s", 
 
327
                             optarg );
 
328
                Usage(argv[0]);
 
329
            }
 
330
            break;
 
331
        case 'L':
 
332
            if( ! ParseLpcmOpt( optarg ) )
 
333
            {
 
334
                mjpeg_error( "Illegal LPCM option(s): %s", optarg );
 
335
                Usage(argv[0]);
 
336
            }
 
337
            break;
 
338
 
 
339
                case 'r':
 
340
                        data_rate = atoi(optarg);
 
341
                        if( data_rate < 0 )
 
342
                                Usage(argv[0]);
 
343
                        /* Convert from kbit/sec (user spec) to 50B/sec units... */
 
344
                        data_rate = (( data_rate * 1000 / 8 + 49) / 50 ) * 50;
 
345
                        break;
 
346
 
 
347
                case 'O':
 
348
                        if( ! ParseTimeOffset(optarg) )
 
349
                        {
 
350
                                mjpeg_error( "Time offset units if specified must: ms|s|mpt" );
 
351
                                Usage(argv[0]);
 
352
                        }
 
353
                        break;
 
354
          
 
355
                case 'l' : 
 
356
                        max_PTS = atoi(optarg);
 
357
                        if( max_PTS < 1  )
 
358
                                Usage(argv[0]);
 
359
                        break;
 
360
                
 
361
                case 'p' : 
 
362
                        packets_per_pack = atoi(optarg);
 
363
                        if( packets_per_pack < 1 || packets_per_pack > 100  )
 
364
                                Usage(argv[0]);
 
365
                        break;
 
366
                
 
367
          
 
368
                case 'f' :
 
369
                        mux_format = atoi(optarg);
 
370
                        if( mux_format < MPEG_FORMAT_MPEG1 || mux_format > MPEG_FORMAT_LAST
 
371
                )
 
372
                                Usage(argv[0]);
 
373
                        break;
 
374
                case 's' :
 
375
                        sector_size = atoi(optarg);
 
376
                        if( sector_size < 256 || sector_size > 16384 )
 
377
                                Usage(argv[0]);
 
378
                        break;
 
379
                case 'S' :
 
380
                        max_segment_size = atoi(optarg);
 
381
                        if( max_segment_size < 0  )
 
382
                                Usage(argv[0]);
 
383
                        break;
 
384
                case 'M' :
 
385
                        multifile_segment = true;
 
386
                        break;
 
387
        case 'W' :
 
388
            if( ! ParseWorkaroundOpt( optarg ) )
 
389
            {
 
390
                Usage(argv[0]);
 
391
            }
 
392
            break;
 
393
                case '?' :
 
394
                default :
 
395
                        Usage(argv[0]);
 
396
                        break;
 
397
                }
 
398
        }
 
399
        if (argc - optind < 1 || outfile_pattern == NULL)
 
400
    {   
 
401
                Usage(argv[0]);
 
402
    }
 
403
        (void)mjpeg_default_handler_verbosity(verbose);
 
404
        mjpeg_info( "mplex version %s (%s %s)",VERSION,MPLEX_VER,MPLEX_DATE );
 
405
 
 
406
    InputStreamsFromCmdLine( argc-(optind-1), argv+optind-1);
 
407
}
 
408
 
 
409
/*************************************************************************
 
410
 Usage banner for the command line wrapper.
 
411
*************************************************************************/
 
412
 
 
413
    
 
414
void CmdLineMultiplexJob::Usage(char *str)
 
415
{
 
416
    fprintf( stderr,
 
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"
 
421
        "--verbose|-v num\n"
 
422
    "  Level of verbosity. 0 = quiet, 1 = normal 2 = verbose/debug\n"
 
423
        "--format|-f fmt\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"
 
440
    "--vbr|-V\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"
 
451
        "--help|-?\n"
 
452
    "  Print this lot out!\n", str);
 
453
        exit (1);
 
454
}
 
455
 
 
456
 
 
457
bool CmdLineMultiplexJob::ParseLpcmOpt( const char *optarg )
 
458
{
 
459
    char *endptr, *startptr;
 
460
    unsigned int samples_sec;
 
461
    unsigned int channels;
 
462
    unsigned int bits_sample;
 
463
    endptr = const_cast<char *>(optarg);
 
464
    do 
 
465
    {
 
466
        startptr = endptr;
 
467
        samples_sec = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
 
468
        if( startptr == endptr || *endptr != ':' )
 
469
            return false;
 
470
 
 
471
 
 
472
        startptr = endptr+1;
 
473
        channels = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
 
474
        if(startptr == endptr || *endptr != ':' )
 
475
            return false;
 
476
 
 
477
        startptr = endptr+1;
 
478
        bits_sample = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
 
479
        if( startptr == endptr )
 
480
            return false;
 
481
 
 
482
        LpcmParams *params = LpcmParams::Checked( samples_sec,
 
483
                                                  channels,
 
484
                                                  bits_sample );
 
485
        if( params == 0 )
 
486
            return false;
 
487
        lpcm_param.push_back(params);
 
488
        if( *endptr == ',' )
 
489
            ++endptr;
 
490
    } while( *endptr != '\0' );
 
491
    return true;
 
492
}
 
493
 
 
494
 
 
495
bool CmdLineMultiplexJob::ParseWorkaroundOpt( const char *optarg )
 
496
{
 
497
    char *endptr, *startptr;
 
498
    endptr = const_cast<char *>(optarg);
 
499
    struct { const char *longname; char shortname; bool *flag; } flag_table[] =
 
500
        {
 
501
            { 0, '\0', 0 }
 
502
        };
 
503
    for(;;)
 
504
    {
 
505
        // Find start of next flag...
 
506
        while( isspace(*endptr) || *endptr == ',' )
 
507
            ++endptr;
 
508
        if( *endptr == '\0' )
 
509
            break;
 
510
        startptr = endptr;
 
511
        // Find end of current flag...
 
512
        while( *endptr != ' ' && *endptr != ',' && *endptr != '\0' )
 
513
            ++endptr;
 
514
            
 
515
        size_t len = endptr - startptr;
 
516
 
 
517
        int flag = 0;
 
518
        while( flag_table[flag].longname != 0 )
 
519
        {
 
520
            if( (len == 1 && *startptr == flag_table[flag].shortname ) ||
 
521
                strncmp( startptr, flag_table[flag].longname, len ) == 0 )
 
522
            {
 
523
                *flag_table[flag].flag = true;
 
524
                break;
 
525
            }
 
526
            ++flag;
 
527
        }
 
528
 
 
529
        if( flag_table[flag].longname == 0 )
 
530
        {
 
531
            std::string message( "Illegal work-around option: not one of " );
 
532
            flag = 0;
 
533
            char sep[] = ",";
 
534
            do
 
535
            {
 
536
                message += flag_table[flag].longname;
 
537
                message += sep;
 
538
                message += flag_table[flag].shortname;
 
539
                ++flag;
 
540
                if( flag_table[flag].longname != 0 )
 
541
                    message += sep;
 
542
            }
 
543
            while( flag_table[flag].longname != 0 );
 
544
            mjpeg_error( message.c_str() );
 
545
            return false;
 
546
        }
 
547
 
 
548
    } 
 
549
    return true;
 
550
}
 
551
 
 
552
bool CmdLineMultiplexJob::ParseVideoOpt( const char *optarg )
 
553
{
 
554
    char *endptr, *startptr;
 
555
    unsigned int buffer_size;
 
556
    endptr = const_cast<char *>(optarg);
 
557
    do 
 
558
    {
 
559
        startptr = endptr;
 
560
        buffer_size = static_cast<unsigned int>(strtol(startptr, &endptr, 10));
 
561
        if( startptr == endptr )
 
562
            return false;
 
563
 
 
564
        VideoParams *params = VideoParams::Checked( buffer_size );
 
565
        if( params == 0 )
 
566
            return false;
 
567
        video_param.push_back(params);
 
568
        if( *endptr == ',' )
 
569
            ++endptr;
 
570
    } 
 
571
    while( *endptr != '\0' );
 
572
    return true;
 
573
}
 
574
 
 
575
bool CmdLineMultiplexJob::ParseTimeOffset(const char *optarg)
 
576
{
 
577
    double f;
 
578
    double persecond=1000.0;
 
579
    char *e;
 
580
 
 
581
    f=strtod(optarg,&e);
 
582
    if( e ) {
 
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;
 
587
                else
 
588
                        return false;
 
589
    }
 
590
    video_offset = lround(f*CLOCKS/(persecond));
 
591
        if( video_offset < 0 )
 
592
        {
 
593
                audio_offset = - video_offset;
 
594
                video_offset = 0;
 
595
        }
 
596
        return true;
 
597
}
 
598
 
 
599
void CmdLineMultiplexJob::InputStreamsFromCmdLine(unsigned int argc, char* argv[] )
 
600
{
 
601
        vector<IBitStream *> inputs;
 
602
    unsigned int i;
 
603
        for( i = 1; i < argc; ++i )
 
604
    {
 
605
                inputs.push_back( new IFileBitStream( argv[i] ) );
 
606
        }
 
607
        SetupInputStreams( inputs );
 
608
}
 
609
 
 
610
 
 
611
int main (int argc, char* argv[])
 
612
{
 
613
        CmdLineMultiplexJob job(argc,argv);
 
614
        FileOutputStream output( job.outfile_pattern );
 
615
        Multiplexor mux(job, output);
 
616
        mux.Multiplex();
 
617
 
 
618
    return (0); 
 
619
}
 
620
 
 
621