Blame src/tools/oggz-codecs.c

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
}