|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
|
Packit |
a38265 |
Organisation (CSIRO) Australia
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
a38265 |
modification, are permitted provided that the following conditions
|
|
Packit |
a38265 |
are met:
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions of source code must retain the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions in binary form must reproduce the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
a38265 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Neither the name of CSIRO Australia nor the names of its
|
|
Packit |
a38265 |
contributors may be used to endorse or promote products derived from
|
|
Packit |
a38265 |
this software without specific prior written permission.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
a38265 |
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
a38265 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
a38265 |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
|
|
Packit |
a38265 |
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
a38265 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
a38265 |
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
a38265 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
a38265 |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
a38265 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
a38265 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "config.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <stdio.h>
|
|
Packit |
a38265 |
#include <stdlib.h>
|
|
Packit |
a38265 |
#include <string.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifndef WIN32
|
|
Packit |
a38265 |
#include <strings.h>
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <getopt.h>
|
|
Packit |
a38265 |
#include <errno.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef HAVE_INTTYPES_H
|
|
Packit |
a38265 |
# include <inttypes.h>
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
# define PRId64 "I64d"
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz/oggz.h"
|
|
Packit |
a38265 |
#include "oggz_tools.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* #define DEBUG */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef WIN32
|
|
Packit |
a38265 |
#define strcasecmp _stricmp
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
OggzReadPacket read_packet;
|
|
Packit |
a38265 |
int clipcount;
|
|
Packit |
a38265 |
int pktssincekey;
|
|
Packit |
a38265 |
int granuleshift;
|
|
Packit |
a38265 |
int keyframes;
|
|
Packit |
a38265 |
int cmml;
|
|
Packit |
a38265 |
int html;
|
|
Packit |
a38265 |
} OSData;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static char * progname;
|
|
Packit |
a38265 |
static FILE * outfile = NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define HTML_HEAD "<html>\n<head>\n<title>OGGZ_SCAN OUTPUT</title>\n</head>\n\n<body>\nOGGZ_SCAN OUTPUT for %s\n\n"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define HTML_END " \n</body>\n</html>"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define HTML_CLIP "Clip No %i\tat t=%lf. \n\n"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#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"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define CMML_END "</cmml>"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define CMML_CLIP "<clip id=\"clip-%i\" start=\"%lf\">\n<desc>Enter description.</desc>\n</clip>\n\n"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
usage (char * progname)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
printf ("Usage: %s [options] filename\n", progname);
|
|
Packit |
a38265 |
printf ("Scan an Ogg file and output characteristic landmarks.\n");
|
|
Packit |
a38265 |
printf ("\nOutput options\n");
|
|
Packit |
a38265 |
printf (" -o filename, --output filename\n");
|
|
Packit |
a38265 |
printf (" Specify output filename\n");
|
|
Packit |
a38265 |
printf (" -f format, --format format\n");
|
|
Packit |
a38265 |
printf (" Specify output format. Supported formats are plain,\n");
|
|
Packit |
a38265 |
printf (" cmml, and html. (Default: plain)\n");
|
|
Packit |
a38265 |
printf ("\nFeature options\n");
|
|
Packit |
a38265 |
printf (" -k, --keyframe Display timestamps of unforced theora keyframes\n");
|
|
Packit |
a38265 |
printf ("\nMiscellaneous options\n");
|
|
Packit |
a38265 |
printf (" -h, --help Display this help and exit\n");
|
|
Packit |
a38265 |
printf (" -v, --version Output version information and exit\n");
|
|
Packit |
a38265 |
printf ("\n");
|
|
Packit |
a38265 |
printf ("Please report bugs to <ogg-dev@xiph.org>\n");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
filter_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OSData * osdata = (OSData *) user_data;
|
|
Packit |
a38265 |
const char * ident;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* set scanning callback for keyframe calculation on theora pages only */
|
|
Packit |
a38265 |
if (osdata->keyframes && ogg_page_bos ((ogg_page *)og)) {
|
|
Packit |
a38265 |
ident = ot_page_identify (oggz, og, NULL);
|
|
Packit |
a38265 |
if (ident && (strcasecmp ("theora", ident) == 0)) {
|
|
Packit |
a38265 |
oggz_set_read_callback (oggz, serialno, osdata->read_packet, osdata);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return OGGZ_CONTINUE;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
read_packet (OGGZ * oggz, oggz_packet * zp, long serialno, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OSData * osdata = (OSData *) user_data;
|
|
Packit |
a38265 |
ogg_packet * op = &zp->op;
|
|
Packit |
a38265 |
double time_offset;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* calculate granuleshift for theora track */
|
|
Packit |
a38265 |
if (osdata->granuleshift == 0) {
|
|
Packit |
a38265 |
osdata->granuleshift = 1 << oggz_get_granuleshift (oggz, serialno);
|
|
Packit |
a38265 |
osdata->granuleshift--;
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf(outfile, "Granuleshift = %d\n", osdata->granuleshift);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* don't do anything on bos page */
|
|
Packit |
a38265 |
if (op->b_o_s) {
|
|
Packit |
a38265 |
return OGGZ_CONTINUE;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* calculate the keyframes if requested */
|
|
Packit |
a38265 |
if (osdata->keyframes) {
|
|
Packit |
a38265 |
/* increase number of packets seen since the last intra frame */
|
|
Packit |
a38265 |
osdata->pktssincekey++;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* does the current packet contain a keyframe? */
|
|
Packit |
a38265 |
if(!(op->packet[0] & 0x80) /* data packet */ &&
|
|
Packit |
a38265 |
!(op->packet[0] & 0x40) /* intra frame */ ) {
|
|
Packit |
a38265 |
ogg_int64_t units;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf(outfile, "Keyframe found: packetno=%" PRId64
|
|
Packit |
a38265 |
"\t pktssincekey=%d\n", op->packetno, osdata->pktssincekey);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* if the keyframe is on the granuleshift position, ignore it */
|
|
Packit |
a38265 |
if (osdata->pktssincekey >= osdata->granuleshift) {
|
|
Packit |
a38265 |
osdata->pktssincekey=0;
|
|
Packit |
a38265 |
return OGGZ_CONTINUE;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
osdata->pktssincekey=0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* new shot boundary found: calculate time */
|
|
Packit |
a38265 |
units = oggz_tell_units (oggz);
|
|
Packit |
a38265 |
if (units == -1) {
|
|
Packit |
a38265 |
time_offset = oggz_tell(oggz);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
time_offset = (double)units / 1000.0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* output in requested format */
|
|
Packit |
a38265 |
if (osdata->html) {
|
|
Packit |
a38265 |
fprintf(outfile, HTML_CLIP, osdata->clipcount, time_offset);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
if (osdata->cmml) {
|
|
Packit |
a38265 |
fprintf(outfile, CMML_CLIP, osdata->clipcount, time_offset);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
osdata->clipcount++;
|
|
Packit |
a38265 |
if (!osdata->html && !osdata->cmml) {
|
|
Packit |
a38265 |
ot_fprint_time (outfile, time_offset);
|
|
Packit |
a38265 |
fputc ('\n', outfile);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (outfile, "%ld bytes pktno=%" PRId64 "\n", op->bytes, op->packetno);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return OGGZ_CONTINUE;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
main (int argc, char ** argv)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int show_version = 0;
|
|
Packit |
a38265 |
int show_help = 0;
|
|
Packit |
a38265 |
int output_cmml = 0;
|
|
Packit |
a38265 |
int output_html = 0;
|
|
Packit |
a38265 |
int scan_keyframes = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
OSData * osdata = NULL;
|
|
Packit |
a38265 |
OGGZ * oggz;
|
|
Packit |
a38265 |
char * infilename = NULL, * outfilename = NULL;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
char * optstring = "f:khvo:";
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
static struct option long_options[] = {
|
|
Packit |
a38265 |
{"output", required_argument, 0, 'o'},
|
|
Packit |
a38265 |
{"format", required_argument, 0, 'f'},
|
|
Packit |
a38265 |
{"keyframe", no_argument, 0, 'k'},
|
|
Packit |
a38265 |
{"help", no_argument, 0, 'h'},
|
|
Packit |
a38265 |
{"version", no_argument, 0, 'v'},
|
|
Packit |
a38265 |
{0,0,0,0}
|
|
Packit |
a38265 |
};
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
progname = argv[0];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (argc < 2) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
return (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!strncmp (argv[1], "-?", 2)) {
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
ot_print_options (long_options, optstring);
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
ot_print_short_options (optstring);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
exit (0);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
while (1) {
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
i = getopt_long(argc, argv, optstring, long_options, NULL);
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
i = getopt (argc, argv, optstring);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
if (i == -1) break;
|
|
Packit |
a38265 |
if (i == ':') {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
switch (i) {
|
|
Packit |
a38265 |
case 'f': /* format */
|
|
Packit |
a38265 |
if (!strcmp (optarg, "cmml")) {
|
|
Packit |
a38265 |
output_cmml = 1;
|
|
Packit |
a38265 |
output_html = 0;
|
|
Packit |
a38265 |
} else if (!strcmp (optarg, "html")) {
|
|
Packit |
a38265 |
output_cmml = 0;
|
|
Packit |
a38265 |
output_html = 1;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
output_cmml = 0;
|
|
Packit |
a38265 |
output_html = 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'w': /* html */
|
|
Packit |
a38265 |
output_html = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'k': /* keyframe */
|
|
Packit |
a38265 |
scan_keyframes = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'h': /* help */
|
|
Packit |
a38265 |
show_help = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'v': /* version */
|
|
Packit |
a38265 |
show_version = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'o': /* output */
|
|
Packit |
a38265 |
outfilename = optarg;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
default:
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (show_version) {
|
|
Packit |
a38265 |
printf ("%s version " VERSION "\n", progname);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (show_help) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (show_version || show_help) {
|
|
Packit |
a38265 |
goto exit_ok;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (optind >= argc) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
infilename = argv[optind++];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (outfilename == NULL) {
|
|
Packit |
a38265 |
outfile = stdout;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
outfile = fopen (outfilename, "wb");
|
|
Packit |
a38265 |
if (outfile == NULL) {
|
|
Packit |
a38265 |
fprintf (stderr, "%s: unable to open output file %s\n",
|
|
Packit |
a38265 |
progname, outfilename);
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
errno = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (strcmp (infilename, "-") == 0) {
|
|
Packit |
a38265 |
oggz = oggz_open_stdio (stdin, OGGZ_READ|OGGZ_AUTO);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
oggz = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) {
|
|
Packit |
a38265 |
if (errno == 0) {
|
|
Packit |
a38265 |
fprintf (stderr, "%s: %s: error opening input file\n",
|
|
Packit |
a38265 |
progname, infilename);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
fprintf (stderr, "%s: %s: %s\n",
|
|
Packit |
a38265 |
progname, infilename, strerror (errno));
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* init osdata */
|
|
Packit |
a38265 |
osdata = malloc (sizeof (OSData));
|
|
Packit |
a38265 |
if (osdata == NULL) {
|
|
Packit |
a38265 |
fprintf (stderr, "%s: Out of memory\n", progname);
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
memset (osdata, 0, sizeof (OSData));
|
|
Packit |
a38265 |
osdata->read_packet = read_packet;
|
|
Packit |
a38265 |
if (scan_keyframes) osdata->keyframes = 1;
|
|
Packit |
a38265 |
if (output_cmml) osdata->cmml = 1;
|
|
Packit |
a38265 |
if (output_html) osdata->html = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* set up the right filters on the tracks */
|
|
Packit |
a38265 |
oggz_set_read_page (oggz, -1, filter_page, osdata);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* correct output format */
|
|
Packit |
a38265 |
if (output_html) {
|
|
Packit |
a38265 |
fprintf(outfile, HTML_HEAD, infilename);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
if (output_cmml) {
|
|
Packit |
a38265 |
fprintf(outfile, CMML_HEAD, infilename, infilename);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_run_set_blocksize (oggz, 1024*1024);
|
|
Packit |
a38265 |
oggz_run (oggz);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* finish output */
|
|
Packit |
a38265 |
if (output_html) {
|
|
Packit |
a38265 |
fprintf(outfile, HTML_END);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
if (output_cmml) {
|
|
Packit |
a38265 |
fprintf(outfile, CMML_END);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_close (oggz);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_ok:
|
|
Packit |
a38265 |
free(osdata);
|
|
Packit |
a38265 |
exit(0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_err:
|
|
Packit |
a38265 |
free(osdata);
|
|
Packit |
a38265 |
exit(1);
|
|
Packit |
a38265 |
}
|