~eternity/eternity/0.1

« back to all changes in this revision

Viewing changes to eternity-mpeg2/src/eternity-mpeg2.c

  • Committer: Garry Parker
  • Date: 2007-07-30 15:27:53 UTC
  • Revision ID: parker13@gmail.com-20070730152753-3stm6v1oh36ssy2p
Initial checkin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * eternity-mpeg2.c
 
3
 * Copyright (C) 2007      Garry Parker <parker13@gmail.com>
 
4
 *
 
5
 * Based on mpeg2dec_onroot.c (electricsheep):
 
6
 * Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
 
7
 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
 
8
 *
 
9
 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
 
10
 * See http://libmpeg2.sourceforge.net/ for updates.
 
11
 *
 
12
 * mpeg2dec is free software; you can redistribute it and/or modify
 
13
 * it under the terms of the GNU General Public License as published by
 
14
 * the Free Software Foundation; either version 2 of the License, or
 
15
 * (at your option) any later version.
 
16
 *
 
17
 * mpeg2dec is distributed in the hope that it will be useful,
 
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 * GNU General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU General Public License
 
23
 * along with this program; if not, write to the Free Software
 
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
25
 */
 
26
#define _GNU_SOURCE  /* for strcasestr */
 
27
 
 
28
#include "config.h"
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <unistd.h>
 
33
#include <string.h>
 
34
#include <errno.h>
 
35
#include <getopt.h>
 
36
#ifdef HAVE_SYS_TIME_H
 
37
#include <sys/time.h>
 
38
#include <signal.h>
 
39
#endif
 
40
#include <inttypes.h>
 
41
 
 
42
#include <sys/types.h>
 
43
#include <dirent.h>
 
44
 
 
45
#include "video_out.h"
 
46
#include "mpeg2.h"
 
47
#include "mm_accel.h"
 
48
 
 
49
#define BUFFER_SIZE 4096
 
50
#define MINFPS         1
 
51
#define MAXFPS       100
 
52
#define DEFFPS        23
 
53
#define MINLOOP        1
 
54
#define MAXLOOP      100
 
55
#define DEFLOOP        1
 
56
#define MAX_CLIPS    512
 
57
 
 
58
int window_id  = -3;  /* virtual root */
 
59
int quiet      = 1;
 
60
int target_fps = DEFFPS;
 
61
int numloops   = DEFLOOP;
 
62
 
 
63
typedef struct
 
64
{
 
65
  char fname[FILENAME_MAX];
 
66
  int  nloops;
 
67
  int  fps;
 
68
} CFG;
 
69
CFG cfg[MAX_CLIPS];
 
70
int numclips=0;
 
71
 
 
72
 
 
73
static uint8_t buffer[BUFFER_SIZE];
 
74
static FILE * in_file;
 
75
static int demux_track = 0;
 
76
static int demux_pid = 0;
 
77
static int disable_accel = 0;
 
78
static mpeg2dec_t mpeg2dec;
 
79
static vo_open_t * output_open = NULL;
 
80
static char filename[FILENAME_MAX];
 
81
 
 
82
 
 
83
#ifdef HAVE_SYS_TIME_H
 
84
static void print_fps (int final);
 
85
 
 
86
static RETSIGTYPE signal_handler (int sig)
 
87
{
 
88
  print_fps (1);
 
89
  signal (sig, SIG_DFL);
 
90
  raise (sig);
 
91
}
 
92
 
 
93
static void print_fps (int final) 
 
94
{
 
95
  static uint32_t frame_counter = 0;
 
96
  static struct timeval tv_beg, tv_start, tv_rate;
 
97
  static int total_elapsed;
 
98
  static int last_count = 0;
 
99
  struct timeval tv_end;
 
100
  int fps, tfps, frames, elapsed;
 
101
 
 
102
  gettimeofday (&tv_end, NULL);
 
103
 
 
104
  if (!frame_counter) {
 
105
  tv_rate = tv_start = tv_beg = tv_end;
 
106
  signal (SIGINT, signal_handler);
 
107
  }
 
108
 
 
109
  elapsed = (tv_end.tv_sec - tv_beg.tv_sec) * 100 +
 
110
  (tv_end.tv_usec - tv_beg.tv_usec) / 10000;
 
111
  total_elapsed = (tv_end.tv_sec - tv_start.tv_sec) * 100 +
 
112
  (tv_end.tv_usec - tv_start.tv_usec) / 10000;
 
113
 
 
114
  if (final) {
 
115
  if (total_elapsed) 
 
116
    tfps = frame_counter * 10000 / total_elapsed;
 
117
  else
 
118
    tfps = 0;
 
119
 
 
120
  if (!quiet)
 
121
  fprintf (stderr,"\n%d frames decoded in %d.%02d "
 
122
     "seconds (%d.%02d fps)\n", frame_counter,
 
123
     total_elapsed / 100, total_elapsed % 100,
 
124
     tfps / 100, tfps % 100);
 
125
 
 
126
  return;
 
127
  }
 
128
 
 
129
  frame_counter++;
 
130
 
 
131
  if (elapsed < 50)  /* only display every 0.50 seconds */
 
132
  return;
 
133
 
 
134
  tv_beg = tv_end;
 
135
  frames = frame_counter - last_count;
 
136
 
 
137
  fps = frames * 10000 / elapsed;      /* 100x */
 
138
  tfps = frame_counter * 10000 / total_elapsed;  /* 100x */
 
139
 
 
140
  if (!quiet)
 
141
    fprintf (stderr, "%d frames in %d.%02d sec (%d.%02d fps), "
 
142
       "%d last %d.%02d sec (%d.%02d fps)\n", frame_counter,
 
143
       total_elapsed / 100, total_elapsed % 100,
 
144
       tfps / 100, tfps % 100, frames, elapsed / 100, elapsed % 100,
 
145
       fps / 100, fps % 100);
 
146
 
 
147
  last_count = frame_counter;
 
148
 
 
149
}
 
150
#else /* !HAVE_SYS_TIME_H */
 
151
static void print_fps (int final)
 
152
{
 
153
}
 
154
#endif
 
155
 
 
156
static void print_usage (char ** argv)
 
157
{
 
158
  int i;
 
159
  vo_driver_t * drivers;
 
160
 
 
161
  fprintf (stderr,
 
162
     "usage: %s [-l <numloops>] [-o <mode>] [-s [<track>]] [-t <pid>] [-c] "
 
163
     "[-w <id>] [-f <fps>] <file>\n"
 
164
     "\t-l\tnumber of times to loop each mpeg, \n"
 
165
     "\t-s\tuse program stream demultiplexer, "
 
166
     "track 0-15 or 0xe0-0xef\n"
 
167
     "\t-t\tuse transport stream demultiplexer, pid 0x10-0x1ffe\n"
 
168
     "\t-c\tuse c implementation, disables all accelerations\n"
 
169
     "\t-w\twindow id\n"
 
170
     "\t-f\ttarget frame rate\n"
 
171
     "\t-o\tvideo output mode\n", argv[0]);
 
172
 
 
173
  drivers = vo_drivers ();
 
174
  for (i = 0; drivers[i].name; i++)
 
175
  fprintf (stderr, "\t\t\t%s\n", drivers[i].name);
 
176
 
 
177
  exit (1);
 
178
}
 
179
 
 
180
static void handle_args (int argc, char ** argv)
 
181
{
 
182
  int c;
 
183
  vo_driver_t * drivers;
 
184
  int i;
 
185
  char * s;
 
186
 
 
187
  drivers = vo_drivers ();
 
188
  while ((c = getopt (argc, argv, "l:s::t:co:w:f:")) != -1)
 
189
  switch (c) {
 
190
  case 'o':
 
191
    for (i = 0; drivers[i].name != NULL; i++)
 
192
      if (strcmp(drivers[i].name, optarg) == 0)
 
193
          output_open = drivers[i].open;
 
194
 
 
195
      if (output_open == NULL)
 
196
      {
 
197
        fprintf(stderr, "Invalid video driver: %s\n", optarg);
 
198
        print_usage(argv);
 
199
      }
 
200
    break;
 
201
 
 
202
  case 's':
 
203
    demux_track = 0xe0;
 
204
    if (optarg != NULL)
 
205
    {
 
206
      demux_track = strtol (optarg, &s, 16);
 
207
      if (demux_track < 0xe0) demux_track += 0xe0;
 
208
 
 
209
      if ((demux_track < 0xe0) || (demux_track > 0xef) || (*s))
 
210
      {
 
211
        fprintf (stderr, "Invalid track number: %s\n", optarg);
 
212
        print_usage (argv);
 
213
      }
 
214
    }
 
215
    break;
 
216
 
 
217
  case 't':
 
218
    demux_pid = strtol (optarg, &s, 16);
 
219
    if ((demux_pid < 0x10) || (demux_pid > 0x1ffe) || (*s))
 
220
    {
 
221
      fprintf (stderr, "Invalid pid: %s\n", optarg);
 
222
      print_usage (argv);
 
223
    }
 
224
    break;
 
225
 
 
226
  case 'c':
 
227
    disable_accel = 1;
 
228
    break;
 
229
 
 
230
  case 'w':
 
231
  window_id = strtol (optarg, &s, 0);
 
232
  break;
 
233
 
 
234
  case 'f':
 
235
    target_fps = strtol (optarg, &s, 10);
 
236
    if (0 >= target_fps)
 
237
    {
 
238
      fprintf(stderr, "target frame rate must be positive, not %d.\n", target_fps);
 
239
      print_usage(argv);
 
240
    }
 
241
    break;
 
242
 
 
243
  case 'l':
 
244
    numloops = strtol(optarg, &s, 10);
 
245
    if (numloops <= 0)
 
246
    {
 
247
      fprintf(stderr, "number of loops be >= 0\n");
 
248
      print_usage(argv);
 
249
    }
 
250
    break;
 
251
 
 
252
  default:
 
253
    print_usage (argv);
 
254
  }
 
255
 
 
256
  /* -o not specified, use a default driver */
 
257
  if (output_open == NULL)
 
258
  output_open = drivers[0].open;
 
259
 
 
260
#if 0
 
261
  if (optind < argc) {
 
262
  in_file = fopen (argv[optind], "rb");
 
263
  if (!in_file) {
 
264
    fprintf (stderr, "%s - couldnt open file %s\n", strerror (errno), argv[optind]);
 
265
    exit (1);
 
266
  }
 
267
  } else
 
268
  in_file = stdin;
 
269
#endif
 
270
  if (optind < argc)
 
271
    strcpy(filename, argv[optind]);
 
272
  else
 
273
  {
 
274
    fprintf (stderr, "Must specify a file or directory to play\n");
 
275
    exit (1);
 
276
  }
 
277
}
 
278
 
 
279
static void decode_mpeg2 (uint8_t * buf, uint8_t * end)
 
280
{
 
281
  int num_frames;
 
282
 
 
283
  num_frames = mpeg2_decode_data (&mpeg2dec, buf, end);
 
284
  while (num_frames--)
 
285
  print_fps (0);
 
286
}
 
287
 
 
288
#define DEMUX_PAYLOAD_START 1
 
289
static int demux (uint8_t * buf, uint8_t * end, int flags)
 
290
{
 
291
  static int mpeg1_skip_table[16] = {
 
292
  0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 
293
  };
 
294
 
 
295
  /*
 
296
   * the demuxer keeps some state between calls:
 
297
   * if "state" = DEMUX_HEADER, then "head_buf" contains the first
 
298
   *     "bytes" bytes from some header.
 
299
   * if "state" == DEMUX_DATA, then we need to copy "bytes" bytes
 
300
   *     of ES data before the next header.
 
301
   * if "state" == DEMUX_SKIP, then we need to skip "bytes" bytes
 
302
   *     of data before the next header.
 
303
   *
 
304
   * NEEDBYTES makes sure we have the requested number of bytes for a
 
305
   * header. If we dont, it copies what we have into head_buf and returns,
 
306
   * so that when we come back with more data we finish decoding this header.
 
307
   *
 
308
   * DONEBYTES updates "buf" to point after the header we just parsed.
 
309
   */
 
310
 
 
311
#define DEMUX_HEADER 0
 
312
#define DEMUX_DATA 1
 
313
#define DEMUX_SKIP 2
 
314
  static int state = DEMUX_SKIP;
 
315
  static int state_bytes = 0;
 
316
  static uint8_t head_buf[264];
 
317
 
 
318
  uint8_t * header;
 
319
  int bytes;
 
320
  int len;
 
321
 
 
322
#define NEEDBYTES(x)            \
 
323
  do {              \
 
324
  int missing;            \
 
325
              \
 
326
  missing = (x) - bytes;          \
 
327
  if (missing > 0) {          \
 
328
    if (header == head_buf) {        \
 
329
  if (missing <= end - buf) {      \
 
330
      memcpy (header + bytes, buf, missing);  \
 
331
      buf += missing;        \
 
332
      bytes = (x);        \
 
333
  } else {          \
 
334
      memcpy (header + bytes, buf, end - buf);  \
 
335
      state_bytes = bytes + end - buf;    \
 
336
      return 0;          \
 
337
  }            \
 
338
    } else {            \
 
339
  memcpy (head_buf, header, bytes);    \
 
340
  state = DEMUX_HEADER;        \
 
341
  state_bytes = bytes;        \
 
342
  return 0;          \
 
343
    }              \
 
344
  }              \
 
345
  } while (0)
 
346
 
 
347
#define DONEBYTES(x)    \
 
348
  do {      \
 
349
  if (header != head_buf)  \
 
350
    buf = header + (x);  \
 
351
  } while (0)
 
352
 
 
353
  if (flags & DEMUX_PAYLOAD_START)
 
354
  goto payload_start;
 
355
  switch (state) {
 
356
  case DEMUX_HEADER:
 
357
  if (state_bytes > 0) {
 
358
    header = head_buf;
 
359
    bytes = state_bytes;
 
360
    goto continue_header;
 
361
  }
 
362
  break;
 
363
  case DEMUX_DATA:
 
364
  if (demux_pid || (state_bytes > end - buf)) {
 
365
    decode_mpeg2 (buf, end);
 
366
    state_bytes -= end - buf;
 
367
    return 0;
 
368
  }
 
369
  decode_mpeg2 (buf, buf + state_bytes);
 
370
  buf += state_bytes;
 
371
  break;
 
372
  case DEMUX_SKIP:
 
373
  if (demux_pid || (state_bytes > end - buf)) {
 
374
    state_bytes -= end - buf;
 
375
    return 0;
 
376
  }
 
377
  buf += state_bytes;
 
378
  break;
 
379
  }
 
380
 
 
381
  while (1) {
 
382
  if (demux_pid) {
 
383
    state = DEMUX_SKIP;
 
384
    return 0;
 
385
  }
 
386
  payload_start:
 
387
  header = buf;
 
388
  bytes = end - buf;
 
389
  continue_header:
 
390
  NEEDBYTES (4);
 
391
  if (header[0] || header[1] || (header[2] != 1)) {
 
392
    if (demux_pid) {
 
393
  state = DEMUX_SKIP;
 
394
  return 0;
 
395
    } else if (header != head_buf) {
 
396
  buf++;
 
397
  goto payload_start;
 
398
    } else {
 
399
  header[0] = header[1];
 
400
  header[1] = header[2];
 
401
  header[2] = header[3];
 
402
  bytes = 3;
 
403
  goto continue_header;
 
404
    }
 
405
  }
 
406
  if (demux_pid) {
 
407
    if ((header[3] >= 0xe0) && (header[3] <= 0xef))
 
408
  goto pes;
 
409
    fprintf (stderr, "bad stream id %x\n", header[3]);
 
410
    exit (1);
 
411
  }
 
412
  switch (header[3]) {
 
413
  case 0xb9:  /* program end code */
 
414
    /* DONEBYTES (4); */
 
415
    /* break;         */
 
416
    return 1;
 
417
  case 0xba:  /* pack header */
 
418
    NEEDBYTES (12);
 
419
    if ((header[4] & 0xc0) == 0x40) {  /* mpeg2 */
 
420
  NEEDBYTES (14);
 
421
  len = 14 + (header[13] & 7);
 
422
  NEEDBYTES (len);
 
423
  DONEBYTES (len);
 
424
  /* header points to the mpeg2 pack header */
 
425
    } else if ((header[4] & 0xf0) == 0x20) {  /* mpeg1 */
 
426
  DONEBYTES (12);
 
427
  /* header points to the mpeg1 pack header */
 
428
    } else {
 
429
  fprintf (stderr, "weird pack header\n");
 
430
  exit (1);
 
431
    }
 
432
    break;
 
433
  default:
 
434
    if (header[3] == demux_track) {
 
435
    pes:
 
436
  NEEDBYTES (7);
 
437
  if ((header[6] & 0xc0) == 0x80) {  /* mpeg2 */
 
438
      NEEDBYTES (9);
 
439
      len = 9 + header[8];
 
440
      NEEDBYTES (len);
 
441
      /* header points to the mpeg2 pes header */
 
442
      if (header[7] & 0x80) {
 
443
    uint32_t pts;
 
444
 
 
445
    pts = (((buf[9] >> 1) << 30) |
 
446
           (buf[10] << 22) | ((buf[11] >> 1) << 15) |
 
447
           (buf[12] << 7) | (buf[13] >> 1));
 
448
    mpeg2_pts (&mpeg2dec, pts);
 
449
      }
 
450
  } else {  /* mpeg1 */
 
451
      int len_skip;
 
452
      uint8_t * ptsbuf;
 
453
 
 
454
      len = 7;
 
455
      while (header[len - 1] == 0xff) {
 
456
    len++;
 
457
    NEEDBYTES (len);
 
458
    if (len == 23) {
 
459
        fprintf (stderr, "too much stuffing\n");
 
460
        break;
 
461
    }
 
462
      }
 
463
      if ((header[len - 1] & 0xc0) == 0x40) {
 
464
    len += 2;
 
465
    NEEDBYTES (len);
 
466
      }
 
467
      len_skip = len;
 
468
      len += mpeg1_skip_table[header[len - 1] >> 4];
 
469
      NEEDBYTES (len);
 
470
      /* header points to the mpeg1 pes header */
 
471
      ptsbuf = header + len_skip;
 
472
      if (ptsbuf[-1] & 0x20) {
 
473
    uint32_t pts;
 
474
 
 
475
    pts = (((ptsbuf[-1] >> 1) << 30) |
 
476
           (ptsbuf[0] << 22) | ((ptsbuf[1] >> 1) << 15) |
 
477
           (ptsbuf[2] << 7) | (ptsbuf[3] >> 1));
 
478
    mpeg2_pts (&mpeg2dec, pts);
 
479
      }
 
480
  }
 
481
  DONEBYTES (len);
 
482
  bytes = 6 + (header[4] << 8) + header[5] - len;
 
483
  if (demux_pid || (bytes > end - buf)) {
 
484
      decode_mpeg2 (buf, end);
 
485
      state = DEMUX_DATA;
 
486
      state_bytes = bytes - (end - buf);
 
487
      return 0;
 
488
  } else if (bytes > 0) {
 
489
      decode_mpeg2 (buf, buf + bytes);
 
490
      buf += bytes;
 
491
  }
 
492
    } else if (header[3] < 0xb9) {
 
493
  fprintf (stderr,
 
494
     "looks like a video stream, not system stream\n");
 
495
  exit (1);
 
496
    } else {
 
497
  NEEDBYTES (6);
 
498
  DONEBYTES (6);
 
499
  bytes = (header[4] << 8) + header[5];
 
500
  if (bytes > end - buf) {
 
501
      state = DEMUX_SKIP;
 
502
      state_bytes = bytes - (end - buf);
 
503
      return 0;
 
504
  }
 
505
  buf += bytes;
 
506
    }
 
507
  }
 
508
  }
 
509
}
 
510
 
 
511
static void ps_loop (void)
 
512
{
 
513
  uint8_t * end;
 
514
 
 
515
  do {
 
516
  end = buffer + fread (buffer, 1, BUFFER_SIZE, in_file);
 
517
  if (demux (buffer, end, 0))
 
518
    break;  /* hit program_end_code */
 
519
  } while (end == buffer + BUFFER_SIZE);
 
520
}
 
521
 
 
522
static void ts_loop (void)
 
523
{
 
524
#define PACKETS (BUFFER_SIZE / 188)
 
525
  uint8_t * buf;
 
526
  uint8_t * data;
 
527
  uint8_t * end;
 
528
  int packets;
 
529
  int i;
 
530
  int pid;
 
531
 
 
532
  do {
 
533
    packets = fread (buffer, 188, PACKETS, in_file);
 
534
    for (i = 0; i < packets; i++) {
 
535
      buf = buffer + i * 188;
 
536
      end = buf + 188;
 
537
      if (buf[0] != 0x47) {
 
538
        fprintf (stderr, "bad sync byte\n");
 
539
        exit (1);
 
540
      }
 
541
      pid = ((buf[1] << 8) + buf[2]) & 0x1fff;
 
542
      if (pid != demux_pid)
 
543
        continue;
 
544
      data = buf + 4;
 
545
      if (buf[3] & 0x20) {  /* buf contains an adaptation field */
 
546
        data = buf + 5 + buf[4];
 
547
      if (data > end)
 
548
        continue;
 
549
      }
 
550
      if (buf[3] & 0x10)
 
551
        demux (data, end, (buf[1] & 0x40) ? DEMUX_PAYLOAD_START : 0);
 
552
    }
 
553
  } while (packets == PACKETS);
 
554
}
 
555
 
 
556
static void es_loop()
 
557
{
 
558
  uint8_t *end;
 
559
 
 
560
  do
 
561
  {
 
562
    end = buffer + fread (buffer, 1, BUFFER_SIZE, in_file);
 
563
    decode_mpeg2 (buffer, end);
 
564
  } while (end == buffer + BUFFER_SIZE);
 
565
}
 
566
 
 
567
static void play_file(char *fname, int nloops, int fps)
 
568
{
 
569
  int i;
 
570
 
 
571
  target_fps=fps;  /* global used by video_out_x11.c  */
 
572
 
 
573
  for (i=0; i<nloops; i++)
 
574
  {
 
575
    in_file = fopen(fname, "rb");
 
576
    if (!in_file)
 
577
    {
 
578
      fprintf(stderr, "%s - couldn't open file %s\n", strerror(errno), fname);
 
579
      return;
 
580
    }
 
581
 
 
582
/*  printf("Playing '%s' %d %d\n", fname, nloops, fps);*/
 
583
 
 
584
    if (demux_pid)
 
585
      ts_loop();
 
586
    else if (demux_track)
 
587
      ps_loop();
 
588
    else
 
589
      es_loop();
 
590
 
 
591
    fclose(in_file);
 
592
  }
 
593
}
 
594
 
 
595
void parse_config(char *fname)
 
596
{
 
597
  FILE *rc;
 
598
  char buf[1024];
 
599
  char *f;
 
600
  int fn, nloops, fps;
 
601
  char name[FILENAME_MAX];
 
602
 
 
603
  rc = fopen(fname, "r");
 
604
  if (!rc)
 
605
  {
 
606
    fprintf(stderr, "%s - couldn't open file %s\n", strerror(errno), fname);
 
607
    exit (1);
 
608
  }
 
609
 
 
610
  while (fgets(buf, sizeof buf, rc))
 
611
  {
 
612
    fn=1;
 
613
    f=strtok(buf, " ");
 
614
          while (f != NULL)
 
615
          {
 
616
      switch(fn)
 
617
      {
 
618
        case 1: strcpy(name, f); break;
 
619
        case 2: nloops = atoi(f); break;
 
620
        case 3: fps = atoi(f);    break;
 
621
      }
 
622
      fn++;
 
623
                  f=strtok(NULL, " ");
 
624
    }
 
625
 
 
626
    if (name[0]!='\0' && name[0]!='#')
 
627
    {
 
628
      strcpy(cfg[numclips].fname, name);
 
629
 
 
630
      cfg[numclips].nloops = (nloops >= MINLOOP && nloops <= MAXLOOP) ? nloops : DEFLOOP;
 
631
      cfg[numclips].fps    = (fps >= MINFPS && fps <= MAXFPS)         ? fps    : DEFFPS;
 
632
 
 
633
      printf("CFG[%i]: %s %d %d \n",
 
634
        numclips, cfg[numclips].fname, cfg[numclips].nloops, cfg[numclips].fps);
 
635
      numclips++;
 
636
    }
 
637
  }
 
638
  fclose (rc);
 
639
}
 
640
 
 
641
static void play_files()
 
642
{
 
643
  int i;
 
644
 
 
645
  while(1)
 
646
  {
 
647
    for (i=0; i<numclips; i++)
 
648
      play_file(cfg[i].fname, cfg[i].nloops, cfg[i].fps);
 
649
  }
 
650
}
 
651
 
 
652
/* "filename" can be a single .mpg file or a directory containing 
 
653
 * multiple files.
 
654
 */
 
655
static void process_dir(char *dname)
 
656
{
 
657
  DIR *dp;
 
658
  struct dirent *fp;
 
659
  char fullpath[FILENAME_MAX];
 
660
 
 
661
  /* Continually loop through the directory and play each
 
662
   * .mpg file the requested number of times
 
663
   */
 
664
  while(1)
 
665
  {
 
666
    if ((dp=opendir(dname))==NULL)
 
667
    {
 
668
      /* Assume it's a file and play it */
 
669
      play_file(dname, numloops, target_fps);
 
670
      continue;
 
671
    }
 
672
 
 
673
    /* Parse the directory */
 
674
    while ((fp=readdir(dp)) != NULL)
 
675
    {
 
676
      if (strcasestr(fp->d_name, ".mpg") != NULL)
 
677
      {
 
678
        sprintf(fullpath, "%s/%s", dname, fp->d_name);
 
679
        play_file(fullpath, numloops, target_fps);
 
680
      }
 
681
    }
 
682
    closedir(dp);
 
683
  }
 
684
}
 
685
 
 
686
 
 
687
int main (int argc, char ** argv)
 
688
{
 
689
  vo_instance_t * output;
 
690
  uint32_t accel;
 
691
 
 
692
  if (!quiet) fprintf (stderr, PACKAGE"-"VERSION
 
693
     " - by Michel Lespinasse <walken@zoy.org> and Aaron Holtzman\n");
 
694
  handle_args (argc, argv);
 
695
 
 
696
  accel = disable_accel ? 0 : (mm_accel () | MM_ACCEL_MLIB);
 
697
 
 
698
  vo_accel (accel);
 
699
  output = vo_open (output_open);
 
700
  if (output == NULL) {
 
701
    fprintf (stderr, "Cannot open output\n");
 
702
    return 1;
 
703
  }
 
704
  mpeg2_init (&mpeg2dec, accel, output);
 
705
 
 
706
 
 
707
  /* Check if we've been passed a config file */
 
708
  if (strcasestr(filename, ".cfg") != NULL)
 
709
  {
 
710
    /* The config file tells us what to play and the settings for each file */
 
711
    parse_config(filename);
 
712
    play_files();
 
713
  }
 
714
  else
 
715
  {
 
716
    /* Process the directory or file using default values */
 
717
    process_dir(filename);
 
718
  }
 
719
 
 
720
  mpeg2_close (&mpeg2dec);
 
721
  vo_close (output);
 
722
  print_fps (1);
 
723
  return 0;
 
724
}