2
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
3
Organisation (CSIRO) Australia
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions
9
- Redistributions of source code must retain the above copyright
10
notice, this list of conditions and the following disclaimer.
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.
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.
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.
42
#ifdef HAVE_INTTYPES_H
43
# include <inttypes.h>
45
# define PRId64 "I64d"
48
#include <oggz/oggz.h>
49
#include "oggz_tools.h"
54
OggzReadPacket read_packet;
63
static char * progname;
64
static FILE * outfile = NULL;
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"
68
#define HTML_END "<hr/>\n</body>\n</html>"
70
#define HTML_CLIP "<p>Clip No %i\tat t=%lf.</p>\n\n"
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"
75
#define CMML_END "</cmml>"
77
#define CMML_CLIP "<clip id=\"clip-%i\" start=\"%lf\">\n<desc>Enter description.</desc>\n</clip>\n\n"
80
usage (char * progname)
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");
96
printf ("Please report bugs to <ogg-dev@xiph.org>\n");
100
filter_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
102
OSData * osdata = (OSData *) user_data;
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);
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 */
119
# define PRI_off_t "q"
121
# define PRI_off_t "l"
125
read_packet (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
127
OSData * osdata = (OSData *) user_data;
130
/* calculate granuleshift for theora track */
131
if (osdata->granuleshift == 0) {
132
osdata->granuleshift = 1 << oggz_get_granuleshift (oggz, serialno);
133
osdata->granuleshift--;
135
fprintf(outfile, "Granuleshift = %d\n", osdata->granuleshift);
139
/* don't do anything on bos page */
144
/* calculate the keyframes if requested */
145
if (osdata->keyframes) {
146
/* increase number of packets seen since the last intra frame */
147
osdata->pktssincekey++;
149
/* does the current packet contain a keyframe? */
150
if(!(op->packet[0] & 0x80) /* data packet */ &&
151
!(op->packet[0] & 0x40) /* intra frame */ ) {
155
fprintf(outfile, "Keyframe found: packetno=%" PRId64
156
"\t pktssincekey=%d\n", op->packetno, osdata->pktssincekey);
159
/* if the keyframe is on the granuleshift position, ignore it */
160
if (osdata->pktssincekey >= osdata->granuleshift) {
161
osdata->pktssincekey=0;
164
osdata->pktssincekey=0;
166
/* new shot boundary found: calculate time */
167
units = oggz_tell_units (oggz);
169
time_offset = oggz_tell(oggz);
171
time_offset = (double)units / 1000.0;
174
/* output in requested format */
176
fprintf(outfile, HTML_CLIP, osdata->clipcount, time_offset);
179
fprintf(outfile, CMML_CLIP, osdata->clipcount, time_offset);
182
if (!osdata->html && !osdata->cmml) {
183
ot_fprint_time (outfile, time_offset);
184
fputc ('\n', outfile);
190
fprintf (outfile, "%ld bytes pktno=%" PRId64 "\n", op->bytes, op->packetno);
197
main (int argc, char ** argv)
199
int show_version = 0;
203
int scan_keyframes = 0;
205
OSData * osdata = NULL;
207
char * infilename = NULL, * outfilename = NULL;
219
char * optstring = "f:khvo:";
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'},
231
i = getopt_long(argc, argv, optstring, long_options, NULL);
233
i = getopt (argc, argv, optstring);
242
case 'f': /* format */
243
if (!strcmp (optarg, "cmml")) {
246
} else if (!strcmp (optarg, "html")) {
257
case 'k': /* keyframe */
263
case 'v': /* version */
266
case 'o': /* output */
267
outfilename = optarg;
275
printf ("%s version " VERSION "\n", progname);
282
if (show_version || show_help) {
286
if (optind >= argc) {
291
infilename = argv[optind++];
293
if (outfilename == NULL) {
296
outfile = fopen (outfilename, "wb");
297
if (outfile == NULL) {
298
fprintf (stderr, "%s: unable to open output file %s\n",
299
progname, outfilename);
306
if (strcmp (infilename, "-") == 0) {
307
oggz = oggz_open_stdio (stdin, OGGZ_READ|OGGZ_AUTO);
309
oggz = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO);
314
fprintf (stderr, "%s: %s: error opening input file\n",
315
progname, infilename);
317
fprintf (stderr, "%s: %s: %s\n",
318
progname, infilename, strerror (errno));
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;
331
/* set up the right filters on the tracks */
332
oggz_set_read_page (oggz, -1, filter_page, osdata);
334
/* correct output format */
336
fprintf(outfile, HTML_HEAD, infilename);
339
fprintf(outfile, CMML_HEAD, infilename, infilename);
342
while ((n = oggz_read (oggz, 1024)) > 0);
346
fprintf(outfile, HTML_END);
349
fprintf(outfile, CMML_END);