|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
Copyright (C) 2008 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 <stdio.h>
|
|
Packit |
a38265 |
#include <stdlib.h>
|
|
Packit |
a38265 |
#include <string.h>
|
|
Packit |
a38265 |
#include <limits.h> /* LONG_MAX */
|
|
Packit |
a38265 |
#include <math.h>
|
|
Packit |
a38265 |
#include <ctype.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <getopt.h>
|
|
Packit |
a38265 |
#include <errno.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <oggz/oggz.h>
|
|
Packit |
a38265 |
#include "oggz_tools.h"
|
|
Packit |
a38265 |
#include "mimetypes.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 |
#define READ_BLOCKSIZE 16384
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int show_all = 0;
|
|
Packit |
a38265 |
static int show_as_mime = 0;
|
|
Packit |
a38265 |
static int show_one_per_line = 0;
|
|
Packit |
a38265 |
static int displayed_once = 0;
|
|
Packit |
a38265 |
static int many_files = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Assumes UNKNOWN is last - fair assumption I think */
|
|
Packit |
a38265 |
static int codecs_count[OGGZ_CONTENT_UNKNOWN+1] = {0};
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
usage (const char * progname)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
printf ("Usage: %s [options] filename ...\n", progname);
|
|
Packit |
a38265 |
printf ("List codecs in one or more Ogg files and their bitstreams. The default\n");
|
|
Packit |
a38265 |
printf ("comma-separated output is designed for use in an HTML5 <video> codecs\n");
|
|
Packit |
a38265 |
printf ("attribute.\n");
|
|
Packit |
a38265 |
printf ("\nDisplay options\n");
|
|
Packit |
a38265 |
printf (" -a, --all Display codec names multiple times if present in\n");
|
|
Packit |
a38265 |
printf (" multiple tracks.\n");
|
|
Packit |
a38265 |
printf (" -m, --mime Display MIME types rather than codec names\n");
|
|
Packit |
a38265 |
printf (" -1, --one-per-line Display one entry per line\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 |
#define SEP "------------------------------------------------------------"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct _OI_Info OI_Info;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Let's get functional */
|
|
Packit |
a38265 |
typedef void (*OI_TrackFunc) (OI_Info * info, long serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
struct _OI_Info {
|
|
Packit |
a38265 |
OGGZ * oggz;
|
|
Packit |
a38265 |
OggzTable * tracks;
|
|
Packit |
a38265 |
};
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
oggz_info_apply (OI_TrackFunc func, OI_Info * info)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
long serialno;
|
|
Packit |
a38265 |
int n, i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
n = oggz_table_size (info->tracks);
|
|
Packit |
a38265 |
for (i = 0; i < n; i++) {
|
|
Packit |
a38265 |
oggz_table_nth (info->tracks, i, &serialno);
|
|
Packit |
a38265 |
func (info, serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
print_codec_name (OI_Info * info, long serialno)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OggzStreamContent content = oggz_stream_get_content(info->oggz, serialno);
|
|
Packit |
a38265 |
if (!codecs_count[content]++ || show_all) {
|
|
Packit |
a38265 |
if (displayed_once && !show_one_per_line) {
|
|
Packit |
a38265 |
printf(", ");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
if (show_as_mime) {
|
|
Packit |
a38265 |
const char *mime_type = NULL;
|
|
Packit |
a38265 |
if (content < OGGZ_CONTENT_UNKNOWN)
|
|
Packit |
a38265 |
mime_type = mime_type_names[content];
|
|
Packit |
a38265 |
if (!mime_type) mime_type = "application/octet-stream";
|
|
Packit |
a38265 |
printf("%s%s", mime_type, show_one_per_line?"\n":"");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
else {
|
|
Packit |
a38265 |
const char *codec_name = oggz_content_type (content), *ptr;
|
|
Packit |
a38265 |
if (!codec_name) codec_name = "unknown";
|
|
Packit |
a38265 |
for (ptr = codec_name; *ptr; ++ptr) putchar(tolower(*ptr));
|
|
Packit |
a38265 |
if (show_one_per_line) putchar('\n');
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
displayed_once = 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
ensure_newline (void)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
if (many_files) {
|
|
Packit |
a38265 |
putchar ('\n');
|
|
Packit |
a38265 |
} else if (!show_one_per_line) {
|
|
Packit |
a38265 |
/* For single file, comma-separated output, don't put the
|
|
Packit |
a38265 |
* terminating newline on stdout, so that the program output
|
|
Packit |
a38265 |
* can be used in an HTML5 <video> codecs attribute.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
fflush (stdout);
|
|
Packit |
a38265 |
fputc ('\n', stderr);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
read_page_pass1 (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OI_Info * info = (OI_Info *)user_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_table_insert (info->tracks, serialno, &read_page_pass1); /* NULL makes it barf, needs anything */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (ogg_page_bos ((ogg_page *)og)) {
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
else {
|
|
Packit |
a38265 |
return OGGZ_STOP_OK;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
oi_pass1 (OGGZ * oggz, OI_Info * info)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
long n, serialno;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_seek (oggz, 0, SEEK_SET);
|
|
Packit |
a38265 |
oggz_set_read_page (oggz, -1, read_page_pass1, info);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
while ((n = oggz_read (oggz, READ_BLOCKSIZE)) > 0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
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 |
|
|
Packit |
a38265 |
char * progname;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
char * infilename;
|
|
Packit |
a38265 |
OGGZ * oggz;
|
|
Packit |
a38265 |
OI_Info info;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
char * optstring = "hvam1";
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
static struct option long_options[] = {
|
|
Packit |
a38265 |
{"help", no_argument, 0, 'h'},
|
|
Packit |
a38265 |
{"version", no_argument, 0, 'v'},
|
|
Packit |
a38265 |
{"all", no_argument, 0, 'a'},
|
|
Packit |
a38265 |
{"mime", no_argument, 0, 'm'},
|
|
Packit |
a38265 |
{"one-line", no_argument, 0, '1'},
|
|
Packit |
a38265 |
{NULL,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 '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 'a':
|
|
Packit |
a38265 |
show_all = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'm':
|
|
Packit |
a38265 |
show_as_mime = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case '1':
|
|
Packit |
a38265 |
show_one_per_line = 1;
|
|
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 |
if (argc > optind+1) {
|
|
Packit |
a38265 |
many_files = 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
while (optind < argc) {
|
|
Packit |
a38265 |
/* Reset state for new file */
|
|
Packit |
a38265 |
memset (codecs_count, 0, sizeof(codecs_count));
|
|
Packit |
a38265 |
displayed_once = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
infilename = argv[optind++];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((oggz = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO)) == NULL) {
|
|
Packit |
a38265 |
fprintf (stderr, "%s: unable to open file %s\n", progname, infilename);
|
|
Packit |
a38265 |
return (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (many_files)
|
|
Packit |
a38265 |
printf ("%s: ", infilename);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info.oggz = oggz;
|
|
Packit |
a38265 |
info.tracks = oggz_table_new ();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oi_pass1 (oggz, &info;;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_info_apply (print_codec_name, &info;;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_table_delete (info.tracks);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_close (oggz);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ensure_newline ();
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_ok:
|
|
Packit |
a38265 |
exit (0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_err:
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|