~ubuntu-branches/ubuntu/karmic/liboggz/karmic

« back to all changes in this revision

Viewing changes to src/tools/oggz-scan.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Waugh
  • Date: 2006-02-07 13:31:07 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060207133107-bxwb7faeao1v7jrr
Tags: 0.9.3-0ubuntu1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright (C) 2003 Commonwealth Scientific and Industrial Research
 
3
   Organisation (CSIRO) Australia
 
4
 
 
5
   Redistribution and use in source and binary forms, with or without
 
6
   modification, are permitted provided that the following conditions
 
7
   are met:
 
8
 
 
9
   - Redistributions of source code must retain the above copyright
 
10
   notice, this list of conditions and the following disclaimer.
 
11
 
 
12
   - Redistributions in binary form must reproduce the above copyright
 
13
   notice, this list of conditions and the following disclaimer in the
 
14
   documentation and/or other materials provided with the distribution.
 
15
 
 
16
   - Neither the name of CSIRO Australia nor the names of its
 
17
   contributors may be used to endorse or promote products derived from
 
18
   this software without specific prior written permission.
 
19
 
 
20
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
21
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
22
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
23
   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
 
24
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
25
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
26
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
27
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
28
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
29
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
30
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
31
*/
 
32
 
 
33
#include "config.h"
 
34
 
 
35
#include <stdio.h>
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
 
 
39
#include <getopt.h>
 
40
#include <errno.h>
 
41
 
 
42
#ifdef HAVE_INTTYPES_H
 
43
#  include <inttypes.h>
 
44
#else
 
45
#  define PRId64 "I64d"
 
46
#endif
 
47
 
 
48
#include <oggz/oggz.h>
 
49
#include "oggz_tools.h"
 
50
 
 
51
/* #define DEBUG */
 
52
 
 
53
typedef struct {
 
54
  OggzReadPacket read_packet;
 
55
  int clipcount;
 
56
  int pktssincekey;
 
57
  int granuleshift;
 
58
  int keyframes;
 
59
  int cmml;
 
60
  int html;
 
61
} OSData;
 
62
 
 
63
static char * progname;
 
64
static FILE * outfile = NULL;
 
65
 
 
66
#define HTML_HEAD "<html>\n<head>\n<title>OGGZ_SCAN OUTPUT</title>\n</head>\n\n<body>\n<h1>OGGZ_SCAN OUTPUT for %s</h1>\n\n"
 
67
 
 
68
#define HTML_END "<hr/>\n</body>\n</html>"
 
69
 
 
70
#define HTML_CLIP "<p>Clip No %i\tat t=%lf.</p>\n\n"
 
71
 
 
72
 
 
73
#define CMML_HEAD "<cmml>\n<stream>\n<import src=\"%s\"/>\n</stream>\n\n<head>\n<title>OGGZ_SCAN OUTPUT for %s</title>\n</head>\n\n"
 
74
 
 
75
#define CMML_END "</cmml>"
 
76
 
 
77
#define CMML_CLIP "<clip id=\"clip-%i\" start=\"%lf\">\n<desc>Enter description.</desc>\n</clip>\n\n"
 
78
 
 
79
static void
 
80
usage (char * progname)
 
81
{
 
82
  printf ("Usage: %s [options] filename\n", progname);
 
83
  printf ("Scan an Ogg file and output characteristic landmarks.\n");
 
84
  printf ("\nOutput options\n");
 
85
  printf ("  -o filename, --output filename\n");
 
86
  printf ("                         Specify output filename\n");
 
87
  printf ("  -f format, --format format\n");
 
88
  printf ("                         Specify output format. Supported formats are plain,\n");
 
89
  printf ("                         cmml, and html. (Default: plain)\n");
 
90
  printf ("\nFeature options\n");
 
91
  printf ("  -k, --keyframe         Display timestamps of unforced theora keyframes\n");
 
92
  printf ("\nMiscellaneous options\n");
 
93
  printf ("  -h, --help             Display this help and exit\n");
 
94
  printf ("  -v, --version          Output version information and exit\n");
 
95
  printf ("\n");
 
96
  printf ("Please report bugs to <ogg-dev@xiph.org>\n");
 
97
}
 
98
 
 
99
static int
 
100
filter_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
 
101
{
 
102
  OSData * osdata = (OSData *) user_data;
 
103
  const char * ident;
 
104
 
 
105
  /* set scanning callback for keyframe calculation on theora pages only */
 
106
  if (osdata->keyframes && ogg_page_bos ((ogg_page *)og)) {
 
107
    ident = ot_page_identify (og, NULL);
 
108
    if (strcasecmp ("theora", ident) == 0) {
 
109
       oggz_set_read_callback (oggz, serialno, osdata->read_packet, osdata);
 
110
    }
 
111
  }
 
112
 
 
113
  return 0;
 
114
}
 
115
 
 
116
/* FIXME: on Mac OS X, off_t is 64-bits.  Obviously we want a nicer
 
117
 * way to do it than this, but a quick fix is a good fix */
 
118
#ifdef __APPLE__
 
119
#  define PRI_off_t "q"
 
120
#else
 
121
#  define PRI_off_t "l"
 
122
#endif
 
123
 
 
124
static int
 
125
read_packet (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
 
126
{
 
127
  OSData * osdata = (OSData *) user_data;
 
128
  double time_offset;
 
129
 
 
130
  /* calculate granuleshift for theora track */
 
131
  if (osdata->granuleshift == 0) {
 
132
    osdata->granuleshift = 1 << oggz_get_granuleshift (oggz, serialno);
 
133
    osdata->granuleshift--;
 
134
#ifdef DEBUG
 
135
    fprintf(outfile, "Granuleshift = %d\n", osdata->granuleshift);
 
136
#endif
 
137
  }
 
138
 
 
139
  /* don't do anything on bos page */
 
140
  if (op->b_o_s) {
 
141
    return 0;
 
142
  }
 
143
 
 
144
  /* calculate the keyframes if requested */
 
145
  if (osdata->keyframes) {
 
146
    /* increase number of packets seen since the last intra frame */
 
147
    osdata->pktssincekey++;
 
148
 
 
149
    /* does the current packet contain a keyframe? */
 
150
    if(!(op->packet[0] & 0x80) /* data packet */ &&
 
151
       !(op->packet[0] & 0x40) /* intra frame */ ) {
 
152
      ogg_int64_t units;
 
153
 
 
154
#ifdef DEBUG
 
155
      fprintf(outfile, "Keyframe found: packetno=%" PRId64 
 
156
              "\t pktssincekey=%d\n", op->packetno, osdata->pktssincekey);
 
157
#endif
 
158
 
 
159
      /* if the keyframe is on the granuleshift position, ignore it */
 
160
      if (osdata->pktssincekey >= osdata->granuleshift) {
 
161
        osdata->pktssincekey=0;
 
162
        return 0;
 
163
      }
 
164
      osdata->pktssincekey=0;
 
165
 
 
166
      /* new shot boundary found: calculate time */
 
167
      units = oggz_tell_units (oggz);
 
168
      if (units == -1) {
 
169
        time_offset = oggz_tell(oggz);
 
170
      } else {
 
171
        time_offset = (double)units / 1000.0;
 
172
      }
 
173
 
 
174
      /* output in requested format */
 
175
      if (osdata->html) {
 
176
        fprintf(outfile, HTML_CLIP, osdata->clipcount, time_offset);
 
177
      }
 
178
      if (osdata->cmml) {
 
179
        fprintf(outfile, CMML_CLIP, osdata->clipcount, time_offset);
 
180
      }
 
181
      osdata->clipcount++;
 
182
      if (!osdata->html && !osdata->cmml) {
 
183
        ot_fprint_time (outfile, time_offset);
 
184
        fputc ('\n', outfile);
 
185
      }
 
186
    }
 
187
  }
 
188
 
 
189
#ifdef DEBUG
 
190
  fprintf (outfile, "%ld bytes pktno=%" PRId64 "\n", op->bytes, op->packetno);
 
191
#endif
 
192
 
 
193
  return 0;
 
194
}
 
195
 
 
196
int
 
197
main (int argc, char ** argv)
 
198
{
 
199
  int show_version = 0;
 
200
  int show_help = 0;
 
201
  int output_cmml = 0;
 
202
  int output_html = 0;
 
203
  int scan_keyframes = 0;
 
204
 
 
205
  OSData * osdata = NULL;
 
206
  OGGZ * oggz;
 
207
  char * infilename = NULL, * outfilename = NULL;
 
208
  int i;
 
209
  long n;
 
210
 
 
211
  progname = argv[0];
 
212
 
 
213
  if (argc < 2) {
 
214
    usage (progname);
 
215
    return (1);
 
216
  }
 
217
 
 
218
  while (1) {
 
219
    char * optstring = "f:khvo:";
 
220
 
 
221
#ifdef HAVE_GETOPT_LONG
 
222
    static struct option long_options[] = {
 
223
      {"output",   required_argument, 0, 'o'},
 
224
      {"format",   required_argument, 0, 'f'},
 
225
      {"keyframe", no_argument, 0, 'k'},
 
226
      {"help",     no_argument, 0, 'h'},
 
227
      {"version",  no_argument, 0, 'v'},
 
228
      {0,0,0,0}
 
229
    };
 
230
 
 
231
    i = getopt_long(argc, argv, optstring, long_options, NULL);
 
232
#else
 
233
    i = getopt (argc, argv, optstring);
 
234
#endif
 
235
    if (i == -1) break;
 
236
    if (i == ':') {
 
237
      usage (progname);
 
238
      goto exit_err;
 
239
    }
 
240
 
 
241
    switch (i) {
 
242
    case 'f': /* format */
 
243
      if (!strcmp (optarg, "cmml")) {
 
244
        output_cmml = 1;
 
245
        output_html = 0;
 
246
      } else if (!strcmp (optarg, "html")) {
 
247
        output_cmml = 0;
 
248
        output_html = 1;
 
249
      } else {
 
250
        output_cmml = 0;
 
251
        output_html = 0;
 
252
      }
 
253
      break;
 
254
    case 'w': /* html */
 
255
      output_html = 1;
 
256
      break;
 
257
    case 'k': /* keyframe */
 
258
      scan_keyframes = 1;
 
259
      break;
 
260
    case 'h': /* help */
 
261
      show_help = 1;
 
262
      break;
 
263
    case 'v': /* version */
 
264
      show_version = 1;
 
265
      break;
 
266
    case 'o': /* output */
 
267
      outfilename = optarg;
 
268
      break;
 
269
    default:
 
270
      break;
 
271
    }
 
272
  }
 
273
 
 
274
  if (show_version) {
 
275
    printf ("%s version " VERSION "\n", progname);
 
276
  }
 
277
 
 
278
  if (show_help) {
 
279
    usage (progname);
 
280
  }
 
281
 
 
282
  if (show_version || show_help) {
 
283
    goto exit_ok;
 
284
  }
 
285
 
 
286
  if (optind >= argc) {
 
287
    usage (progname);
 
288
    goto exit_err;
 
289
  }
 
290
 
 
291
  infilename = argv[optind++];
 
292
 
 
293
  if (outfilename == NULL) {
 
294
    outfile = stdout;
 
295
  } else {
 
296
    outfile = fopen (outfilename, "wb");
 
297
    if (outfile == NULL) {
 
298
      fprintf (stderr, "%s: unable to open output file %s\n",
 
299
               progname, outfilename);
 
300
      goto exit_err;
 
301
    }
 
302
  }
 
303
 
 
304
  errno = 0;
 
305
 
 
306
  if (strcmp (infilename, "-") == 0) {
 
307
    oggz = oggz_open_stdio (stdin, OGGZ_READ|OGGZ_AUTO);
 
308
  } else {
 
309
    oggz = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO);
 
310
  }
 
311
 
 
312
  if (oggz == NULL) {
 
313
    if (errno == 0) {
 
314
      fprintf (stderr, "%s: %s: error opening input file\n",
 
315
              progname, infilename);
 
316
    } else {
 
317
      fprintf (stderr, "%s: %s: %s\n",
 
318
               progname, infilename, strerror (errno));
 
319
    }
 
320
    goto exit_err;
 
321
  }
 
322
 
 
323
  /* init osdata */
 
324
  osdata = malloc (sizeof (OSData));
 
325
  memset (osdata, 0, sizeof (OSData));
 
326
  osdata->read_packet = read_packet;
 
327
  if (scan_keyframes) osdata->keyframes = 1;
 
328
  if (output_cmml)    osdata->cmml = 1;
 
329
  if (output_html)    osdata->html = 1;
 
330
 
 
331
  /* set up the right filters on the tracks */
 
332
  oggz_set_read_page (oggz, -1, filter_page, osdata);
 
333
 
 
334
  /* correct output format */
 
335
  if (output_html) {
 
336
    fprintf(outfile, HTML_HEAD, infilename);
 
337
  }
 
338
  if (output_cmml) {
 
339
    fprintf(outfile, CMML_HEAD, infilename, infilename);
 
340
  }
 
341
 
 
342
  while ((n = oggz_read (oggz, 1024)) > 0);
 
343
 
 
344
  /* finish output */
 
345
  if (output_html) {
 
346
    fprintf(outfile, HTML_END);
 
347
  }
 
348
  if (output_cmml) {
 
349
    fprintf(outfile, CMML_END);
 
350
  }
 
351
 
 
352
  oggz_close (oggz);
 
353
 
 
354
exit_ok:
 
355
  free(osdata);
 
356
  exit(0);
 
357
 
 
358
exit_err:
 
359
  free(osdata);
 
360
  exit(1);
 
361
}