Blame src/tools/oggz-info.c

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 <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
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
Packit a38265
#include "skeleton.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 1024000
Packit a38265
Packit a38265
static char * progname;
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 ("Display information about one or more Ogg files and their bitstreams\n");
Packit a38265
  printf ("\nDisplay options\n");
Packit a38265
  printf ("  -l, --length           Display content lengths\n");
Packit a38265
  printf ("  -b, --bitrate          Display bitrate information\n");
Packit a38265
  printf ("  -g, --page-stats       Display Ogg page statistics\n");
Packit a38265
  printf ("  -p, --packet-stats     Display Ogg packet statistics\n");
Packit a38265
  printf ("  -k, --skeleton         Display Extra data from OggSkeleton bitstream\n");
Packit a38265
  printf ("  -a, --all              Display all information\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 ("Byte lengths are displayed using the following units:\n");
Packit a38265
  printf ("  bytes (8 bits)\n");
Packit a38265
  printf ("  kB    kilobytes (1024 bytes)\n");
Packit a38265
  printf ("  MB    megabytes (1024*1024 bytes)\n");
Packit a38265
  printf ("  GB    gigabytes (1024*1024*1024 bytes)\n");
Packit a38265
  printf ("\n");
Packit a38265
  printf ("Bitrates are displayed using the following units:\n");
Packit a38265
  printf ("  bps   bits per second     (bit/s)\n");
Packit a38265
  printf ("  kbps  kilobits per second (1000 bit/s)\n");
Packit a38265
  printf ("  Mbps  megabits per second (1000000 bit/s)\n");
Packit a38265
  printf ("  Gbps  gigabits per second (1000000000 bit/s)\n");
Packit a38265
  printf ("\n");
Packit a38265
  printf ("Please report bugs to <ogg-dev@xiph.org>\n");
Packit a38265
}
Packit a38265
Packit a38265
static void
Packit a38265
exit_out_of_memory (void)
Packit a38265
{
Packit a38265
  fprintf (stderr, "%s: Out of memory\n", progname);
Packit a38265
  exit (1);
Packit a38265
}
Packit a38265
Packit a38265
#define SEP "------------------------------------------------------------"
Packit a38265
Packit a38265
typedef struct _OI_Info OI_Info;
Packit a38265
typedef struct _OI_Stats OI_Stats;
Packit a38265
typedef struct _OI_TrackInfo OI_TrackInfo;
Packit a38265
Packit a38265
/* Let's get functional */
Packit a38265
typedef int (*OI_TrackFunc) (OI_Info * info, OI_TrackInfo * oit, long serialno);
Packit a38265
Packit a38265
/* Out of memory return value from OI_TrackFunc, aborts oggz_info_apply() */
Packit a38265
#define OIT_OOM (-1)
Packit a38265
Packit a38265
struct _OI_Info {
Packit a38265
  OGGZ * oggz;
Packit a38265
  OggzTable * tracks;
Packit a38265
  ogg_int64_t duration;
Packit a38265
  long length_total;
Packit a38265
  long overhead_length_total;
Packit a38265
};
Packit a38265
Packit a38265
struct _OI_Stats {
Packit a38265
  /* Pass 1 */
Packit a38265
  long count;
Packit a38265
  long length_total;
Packit a38265
  long length_min;
Packit a38265
  long length_max;
Packit a38265
  long overhead_length_total;
Packit a38265
Packit a38265
  /* Pass 2 */
Packit a38265
  long length_avg;
Packit a38265
  ogg_int64_t length_deviation_total;
Packit a38265
  double length_stddev;
Packit a38265
};
Packit a38265
Packit a38265
struct _OI_TrackInfo {
Packit a38265
  OI_Stats pages;
Packit a38265
  OI_Stats packets;
Packit a38265
  const char * codec_name;
Packit a38265
  char * codec_info;
Packit a38265
  int has_fishead;
Packit a38265
  int has_fisbone;
Packit a38265
  fishead_packet fhInfo;
Packit a38265
  fisbone_packet fbInfo;
Packit a38265
};
Packit a38265
Packit a38265
static int show_length = 0;
Packit a38265
static int show_bitrate = 0;
Packit a38265
static int show_page_stats = 0;
Packit a38265
static int show_packet_stats = 0;
Packit a38265
static int show_extra_skeleton_info = 0;
Packit a38265
Packit a38265
static ogg_int64_t
Packit a38265
gp_to_granule (OGGZ * oggz, long serialno, ogg_int64_t granulepos)
Packit a38265
{
Packit a38265
  int granuleshift;
Packit a38265
  ogg_int64_t iframe, pframe, granule;
Packit a38265
Packit a38265
  granuleshift = oggz_get_granuleshift (oggz, serialno);
Packit a38265
Packit a38265
  iframe = granulepos >> granuleshift;
Packit a38265
  pframe = granulepos - (iframe << granuleshift);
Packit a38265
  granule = iframe + pframe;
Packit a38265
Packit a38265
  if (oggz_stream_get_content (oggz, serialno) == OGGZ_CONTENT_DIRAC)
Packit a38265
    granule >>= 9;
Packit a38265
Packit a38265
  return granule;
Packit a38265
}
Packit a38265
Packit a38265
static double
Packit a38265
gp_to_time (OGGZ * oggz, long serialno, ogg_int64_t granulepos)
Packit a38265
{
Packit a38265
  ogg_int64_t gr_n, gr_d;
Packit a38265
  ogg_int64_t granule;
Packit a38265
Packit a38265
  if (granulepos == -1) return -1.0;
Packit a38265
  if (oggz_get_granulerate (oggz, serialno, &gr_n, &gr_d) != 0) return -1.0;
Packit a38265
Packit a38265
  granule = gp_to_granule (oggz, serialno, granulepos);
Packit a38265
Packit a38265
  return (double)((double)(granule * gr_d) / (double)gr_n);
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
oggz_info_apply (OI_TrackFunc func, OI_Info * info)
Packit a38265
{
Packit a38265
  OI_TrackInfo * oit;
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
    oit = oggz_table_nth (info->tracks, i, &serialno);
Packit a38265
    if (oit) {
Packit a38265
      if (func (info, oit, serialno) == OIT_OOM)
Packit a38265
        exit_out_of_memory();
Packit a38265
    }
Packit a38265
  }
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static void
Packit a38265
oi_stats_clear (OI_Stats * stats)
Packit a38265
{
Packit a38265
  stats->count = 0;
Packit a38265
Packit a38265
  stats->length_total = 0;
Packit a38265
  stats->length_min = LONG_MAX;
Packit a38265
  stats->length_max = 0;
Packit a38265
  stats->overhead_length_total = 0;
Packit a38265
Packit a38265
  stats->length_avg = 0;
Packit a38265
  stats->length_deviation_total = 0;
Packit a38265
  stats->length_stddev = 0;
Packit a38265
}
Packit a38265
Packit a38265
static OI_TrackInfo *
Packit a38265
oggz_info_trackinfo_new (void)
Packit a38265
{
Packit a38265
  OI_TrackInfo * oit;
Packit a38265
Packit a38265
  oit = malloc (sizeof (OI_TrackInfo));
Packit a38265
  if (oit == NULL) return NULL;
Packit a38265
Packit a38265
  oi_stats_clear (&oit->pages);
Packit a38265
  oi_stats_clear (&oit->packets);
Packit a38265
Packit a38265
  oit->codec_name = NULL;
Packit a38265
  oit->codec_info = NULL;
Packit a38265
Packit a38265
  oit->has_fishead = 0;
Packit a38265
  oit->has_fisbone = 0;
Packit a38265
Packit a38265
  return oit;
Packit a38265
}
Packit a38265
Packit a38265
static long
Packit a38265
oi_bitrate (long bytes, ogg_int64_t ms)
Packit a38265
{
Packit a38265
  if (ms == 0) return 0;
Packit a38265
  else return (long) (((ogg_int64_t)bytes * 8 * 1000) / ms);
Packit a38265
}
Packit a38265
Packit a38265
static void
Packit a38265
oi_stats_print (OI_Info * info, OI_Stats * stats, char * label)
Packit a38265
{
Packit a38265
  printf ("\t%s-Length-Maximum: ", label);
Packit a38265
  ot_fprint_bytes (stdout, stats->length_max);
Packit a38265
  putchar ('\n');
Packit a38265
Packit a38265
  printf ("\t%s-Length-StdDev: ", label);
Packit a38265
  ot_fprint_bytes (stdout, stats->length_stddev);
Packit a38265
  putchar ('\n');
Packit a38265
Packit a38265
#if 0
Packit a38265
  printf ("\t%s-Length-Maximum: %ld bytes\n", label, stats->length_max);
Packit a38265
  /*printf ("\t%s-Length-Average: %ld bytes\n", label, stats->length_avg);*/
Packit a38265
  printf ("\t%s-Length-StdDev: %.0f bytes\n", label, stats->length_stddev);
Packit a38265
  /*
Packit a38265
  printf ("\tRange: [%ld - %ld] bytes, Std.Dev. %.3f bytes\n",
Packit a38265
	  stats->length_min, stats->length_max, stats->length_stddev);
Packit a38265
  */
Packit a38265
#endif
Packit a38265
}
Packit a38265
Packit a38265
static void
Packit a38265
ot_fishead_print(OI_TrackInfo *oit) {
Packit a38265
  if (oit->has_fishead) {
Packit a38265
    /*
Packit a38265
    printf("\tPresentation Time: %.2f\n", (double)oit->fhInfo.ptime_n/oit->fhInfo.ptime_d);
Packit a38265
    printf("\tBase Time: %.2f\n", (double)oit->fhInfo.btime_n/oit->fhInfo.btime_d);
Packit a38265
    */
Packit a38265
    printf("\tSkeleton version: %d.%d\n", oit->fhInfo.version_major, oit->fhInfo.version_minor);
Packit a38265
    /*printf("\tUTC: %s\n", oit->fhInfo.UTC);*/
Packit a38265
  }
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
ot_fisbone_print(OI_Info * info, OI_TrackInfo *oit) {
Packit a38265
Packit a38265
  char *allocated, *messages, *token;
Packit a38265
  size_t len;
Packit a38265
  
Packit a38265
  if (oit->has_fisbone) {
Packit a38265
    printf("\n\tExtra information from Ogg Skeleton track:\n");
Packit a38265
    /*printf("\tserialno: %010u\n", oit->fbInfo.serial_no);*/
Packit a38265
    printf("\tNumber of header packets: %d\n", oit->fbInfo.nr_header_packet);
Packit a38265
    printf("\tGranule rate: %.2f\n", (double)oit->fbInfo.granule_rate_n/oit->fbInfo.granule_rate_d);
Packit a38265
    printf("\tGranule shift: %d\n", (int)oit->fbInfo.granule_shift);
Packit a38265
    printf("\tStart granule: ");
Packit a38265
    ot_fprint_granulepos(stdout, info->oggz, oit->fbInfo.serial_no, oit->fbInfo.start_granule);
Packit a38265
    printf (" ; ");
Packit a38265
    ot_fprint_time (stdout, gp_to_time (info->oggz, oit->fbInfo.serial_no, oit->fbInfo.start_granule));
Packit a38265
    printf ("\n");
Packit a38265
    printf("\tPreroll: %d\n", oit->fbInfo.preroll);
Packit a38265
Packit a38265
    len = oit->fbInfo.current_header_size+1;
Packit a38265
    allocated = messages = _ogg_calloc(len, sizeof(char));
Packit a38265
    if (messages == NULL) return OIT_OOM;
Packit a38265
    strncpy(messages, oit->fbInfo.message_header_fields, len);
Packit a38265
    messages[len-1] = '\0';
Packit a38265
Packit a38265
    printf("\tMessage Header Fields:\n");
Packit a38265
    while (1) {
Packit a38265
      token = strchr(messages, '\r');
Packit a38265
      if (token == NULL)
Packit a38265
        break;
Packit a38265
      *token = '\0';
Packit a38265
      printf("\t %s", token);
Packit a38265
Packit a38265
      token++;
Packit a38265
      if (*token == '\n')
Packit a38265
        token++;
Packit a38265
      messages = token;
Packit a38265
    }
Packit a38265
    printf("\n");
Packit a38265
    _ogg_free(allocated);
Packit a38265
  }
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
/* oggz_info_trackinfo_print() */
Packit a38265
static int
Packit a38265
oit_print (OI_Info * info, OI_TrackInfo * oit, long serialno)
Packit a38265
{
Packit a38265
  if (oit->codec_name) {
Packit a38265
    printf ("\n%s: serialno %010lu\n", oit->codec_name, serialno);
Packit a38265
  } else {
Packit a38265
    printf ("\n???: serialno %010lu\n", serialno);
Packit a38265
  }
Packit a38265
  printf ("\t%ld packets in %ld pages, %.1f packets/page, %.3f%% Ogg overhead\n",
Packit a38265
	  oit->packets.count, oit->pages.count,
Packit a38265
	  (double)oit->packets.count / (double)oit->pages.count,
Packit a38265
          oit->pages.length_stddev == 0 ? 0.0 : 100.0*oit->pages.overhead_length_total/oit->pages.length_total);
Packit a38265
Packit a38265
  if (show_length) {
Packit a38265
    fputs("\tContent-Length: ", stdout);
Packit a38265
    ot_fprint_bytes (stdout, oit->pages.length_total);
Packit a38265
    putchar ('\n');
Packit a38265
  }
Packit a38265
Packit a38265
  if (show_bitrate) {
Packit a38265
    fputs ("\tContent-Bitrate-Average: ", stdout);
Packit a38265
    ot_print_bitrate (oi_bitrate (oit->pages.length_total, info->duration));
Packit a38265
    putchar ('\n');
Packit a38265
  }
Packit a38265
Packit a38265
  if (oit->codec_info != NULL) {
Packit a38265
    fputs (oit->codec_info, stdout);
Packit a38265
  }
Packit a38265
Packit a38265
  if (show_page_stats) {
Packit a38265
    oi_stats_print (info, &oit->pages, "Page");
Packit a38265
  }
Packit a38265
Packit a38265
  if (show_packet_stats) {
Packit a38265
    oi_stats_print (info, &oit->packets, "Packet");
Packit a38265
  }
Packit a38265
Packit a38265
  if (show_extra_skeleton_info && oit->has_fishead) {
Packit a38265
    ot_fishead_print(oit);
Packit a38265
  }
Packit a38265
  if (show_extra_skeleton_info && oit->has_fisbone) {
Packit a38265
    if (ot_fisbone_print(info, oit) == OIT_OOM)
Packit a38265
      return OIT_OOM;
Packit a38265
  }
Packit a38265
Packit a38265
  return 0;
Packit a38265
 }
Packit a38265
Packit a38265
static void
Packit a38265
oi_stats_average (OI_Stats * stats)
Packit a38265
{
Packit a38265
  if (stats->count > 0) {
Packit a38265
    stats->length_avg = stats->length_total / stats->count;
Packit a38265
  } else {
Packit a38265
    stats->length_avg = 0;
Packit a38265
  }
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
oit_calc_average (OI_Info * info, OI_TrackInfo * oit, long serialno)
Packit a38265
{
Packit a38265
  oi_stats_average (&oit->pages);
Packit a38265
  oi_stats_average (&oit->packets);
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static void
Packit a38265
oi_stats_stddev (OI_Stats * stats)
Packit a38265
{
Packit a38265
  double variance;
Packit a38265
Packit a38265
  if (stats->count <= 1) {
Packit a38265
    stats->length_stddev = 0.0;
Packit a38265
  }
Packit a38265
  else {
Packit a38265
    variance = (double)stats->length_deviation_total / (double)(stats->count - 1);
Packit a38265
    stats->length_stddev = sqrt (variance);
Packit a38265
  }
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
oit_calc_stddev (OI_Info * info, OI_TrackInfo * oit, long serialno)
Packit a38265
{
Packit a38265
  oi_stats_stddev (&oit->pages);
Packit a38265
  oi_stats_stddev (&oit->packets);
Packit a38265
  return 0;
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
  OI_TrackInfo * oit;
Packit a38265
  long bytes;
Packit a38265
Packit a38265
  oit = oggz_table_lookup (info->tracks, serialno);
Packit a38265
  if (oit == NULL) {
Packit a38265
    oit = oggz_info_trackinfo_new ();
Packit a38265
    if (oit == NULL) return -1;
Packit a38265
    oggz_table_insert (info->tracks, serialno, oit);
Packit a38265
  }
Packit a38265
Packit a38265
  if (ogg_page_bos ((ogg_page *)og)) {
Packit a38265
    oit->codec_name = ot_page_identify (oggz, og, &oit->codec_info);
Packit a38265
  }
Packit a38265
Packit a38265
  bytes = og->header_len + og->body_len;
Packit a38265
Packit a38265
  /* Increment the total stream length */
Packit a38265
  info->length_total += bytes;
Packit a38265
  info->overhead_length_total += og->header_len;
Packit a38265
Packit a38265
  /* Increment the page statistics */
Packit a38265
  oit->pages.count++;
Packit a38265
  oit->pages.length_total += bytes;
Packit a38265
  if (bytes < oit->pages.length_min)
Packit a38265
    oit->pages.length_min = bytes;
Packit a38265
  if (bytes > oit->pages.length_max)
Packit a38265
    oit->pages.length_max = bytes;
Packit a38265
  oit->pages.overhead_length_total += og->header_len;
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
read_page_pass2 (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
Packit a38265
{
Packit a38265
  OI_Info * info = (OI_Info *)user_data;
Packit a38265
  OI_TrackInfo * oit;
Packit a38265
  long bytes, deviation;
Packit a38265
Packit a38265
  oit = oggz_table_lookup (info->tracks, serialno);
Packit a38265
Packit a38265
  /* Increment the page length deviation squared total */
Packit a38265
  bytes = og->header_len + og->body_len;
Packit a38265
  deviation = bytes - oit->pages.length_avg;
Packit a38265
  oit->pages.length_deviation_total += (deviation * deviation);
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
read_packet_pass1 (OGGZ * oggz, oggz_packet * zp, long serialno,
Packit a38265
		   void * user_data)
Packit a38265
{
Packit a38265
  OI_Info * info = (OI_Info *)user_data;
Packit a38265
  ogg_packet * op = &zp->op;
Packit a38265
  OI_TrackInfo * oit;
Packit a38265
Packit a38265
  oit = oggz_table_lookup (info->tracks, serialno);
Packit a38265
Packit a38265
  /* Increment the packet statistics */
Packit a38265
  oit->packets.count++;
Packit a38265
  oit->packets.length_total += op->bytes;
Packit a38265
  if (op->bytes < oit->packets.length_min)
Packit a38265
    oit->packets.length_min = op->bytes;
Packit a38265
  if (op->bytes > oit->packets.length_max)
Packit a38265
    oit->packets.length_max = op->bytes;
Packit a38265
Packit a38265
  if (!op->e_o_s && !memcmp(op->packet, FISBONE_IDENTIFIER, 8)) {
Packit a38265
    fisbone_packet fp;
Packit a38265
    int ret = fisbone_from_ogg(op, &fp);
Packit a38265
    if (ret<0) return ret;
Packit a38265
    oit = oggz_table_lookup (info->tracks, fp.serial_no);
Packit a38265
    if (oit) {
Packit a38265
      oit->has_fisbone = 1;
Packit a38265
      oit->fbInfo = fp;
Packit a38265
    }
Packit a38265
    else {
Packit a38265
      fprintf(stderr, "Warning: logical stream %08x referenced by skeleton was not found\n",fp.serial_no);
Packit a38265
      fisbone_clear(&fp);
Packit a38265
    }
Packit a38265
  } else if (!op->e_o_s && !memcmp(op->packet, FISHEAD_IDENTIFIER, 8)) {
Packit a38265
    fishead_packet fp;
Packit a38265
    int ret = fishead_from_ogg(op, &fp);
Packit a38265
    if (ret<0) return ret;
Packit a38265
    oit->has_fishead = 1;
Packit a38265
    oit->fhInfo = fp;    
Packit a38265
  }
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
read_packet_pass2 (OGGZ * oggz, oggz_packet * zp, long serialno,
Packit a38265
		   void * user_data)
Packit a38265
{
Packit a38265
  OI_Info * info = (OI_Info *)user_data;
Packit a38265
  ogg_packet * op = &zp->op;
Packit a38265
  OI_TrackInfo * oit;
Packit a38265
  long deviation;
Packit a38265
  
Packit a38265
  oit = oggz_table_lookup (info->tracks, serialno);
Packit a38265
Packit a38265
  /* Increment the packet length deviation squared total */
Packit a38265
  deviation = op->bytes - oit->packets.length_avg;
Packit a38265
  oit->packets.length_deviation_total += (deviation * deviation);
Packit a38265
Packit a38265
  return 0;
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
  int ntracks, i;
Packit a38265
  OI_TrackInfo * oit;
Packit a38265
Packit a38265
  oggz_seek (oggz, 0, SEEK_SET);
Packit a38265
  oggz_set_read_page (oggz, -1, read_page_pass1, info);
Packit a38265
  oggz_set_read_callback (oggz, -1, read_packet_pass1, info);
Packit a38265
Packit a38265
  while ((n = oggz_read (oggz, READ_BLOCKSIZE)) > 0);
Packit a38265
Packit a38265
  /* We only return an error from our user callback on OOM */
Packit a38265
  if (n == OGGZ_ERR_STOP_ERR || n == OGGZ_ERR_OUT_OF_MEMORY)
Packit a38265
    exit_out_of_memory ();
Packit a38265
Packit a38265
  oggz_info_apply (oit_calc_average, info);
Packit a38265
Packit a38265
  /* Now we are at the end of the file, calculate the duration */
Packit a38265
  info->duration = oggz_tell_units (oggz);
Packit a38265
Packit a38265
  /* Find the Skeleton track if present, and subtract the presentation time */
Packit a38265
  ntracks = oggz_table_size (info->tracks);
Packit a38265
  for (i = 0; i < ntracks; i++) {
Packit a38265
    oit = oggz_table_nth (info->tracks, i, &serialno);
Packit a38265
    if (oit->has_fishead) {
Packit a38265
      info->duration -= 1000 * oit->fhInfo.ptime_n / oit->fhInfo.ptime_d;
Packit a38265
      break;
Packit a38265
    }
Packit a38265
  }
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
oi_pass2 (OGGZ * oggz, OI_Info * info)
Packit a38265
{
Packit a38265
  long n;
Packit a38265
Packit a38265
  oggz_seek (oggz, 0, SEEK_SET);
Packit a38265
  oggz_set_read_page (oggz, -1, read_page_pass2, info);
Packit a38265
  oggz_set_read_callback (oggz, -1, read_packet_pass2, info);
Packit a38265
Packit a38265
  while ((n = oggz_read (oggz, READ_BLOCKSIZE)) > 0);
Packit a38265
  if (n == OGGZ_ERR_OUT_OF_MEMORY)
Packit a38265
    exit_out_of_memory();
Packit a38265
Packit a38265
  oggz_info_apply (oit_calc_stddev, info);
Packit a38265
Packit a38265
  return 0;
Packit a38265
}
Packit a38265
Packit a38265
static int
Packit a38265
oit_delete (OI_Info * info, OI_TrackInfo * oit, long serialno)
Packit a38265
{
Packit a38265
  if (oit->codec_info) {
Packit a38265
    if (oit->has_fisbone)
Packit a38265
      fisbone_clear (&oit->fbInfo);
Packit a38265
    free (oit->codec_info);
Packit a38265
  }
Packit a38265
  free (oit);
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
  int i;
Packit a38265
  int show_all = 0;
Packit a38265
Packit a38265
  int many_files = 0;
Packit a38265
  char * infilename;
Packit a38265
  OGGZ * oggz;
Packit a38265
  OI_Info info;
Packit a38265
Packit a38265
  char * optstring = "hvlbgpka";
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
    {"length", no_argument, 0, 'l'},
Packit a38265
    {"bitrate", no_argument, 0, 'b'},
Packit a38265
    {"page-stats", no_argument, 0, 'g'},
Packit a38265
    {"packet-stats", no_argument, 0, 'p'},
Packit a38265
    {"skeleton", no_argument, 0, 'k'},
Packit a38265
    {"all", no_argument, 0, 'a'},
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 'l': /* length */
Packit a38265
      show_length = 1;
Packit a38265
      break;
Packit a38265
    case 'b': /* bitrate */
Packit a38265
      show_bitrate = 1;
Packit a38265
      break;
Packit a38265
    case 'g': /* page stats */
Packit a38265
      show_page_stats = 1;
Packit a38265
      break;
Packit a38265
    case 'p': /* packet stats */
Packit a38265
      show_packet_stats = 1;
Packit a38265
      break;
Packit a38265
    case 'k': /* extra skeleton info */
Packit a38265
      show_extra_skeleton_info = 1;
Packit a38265
      break;
Packit a38265
    case 'a':
Packit a38265
      show_all = 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 (show_all) {
Packit a38265
    show_length = 1;
Packit a38265
    show_bitrate = 1;
Packit a38265
    show_page_stats = 1;
Packit a38265
    show_packet_stats = 1;
Packit a38265
    show_extra_skeleton_info = 1;
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
    infilename = argv[optind++];
Packit a38265
Packit a38265
    if ((oggz = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO)) == NULL) {
Packit a38265
      perror (infilename);
Packit a38265
      return (1);
Packit a38265
    }
Packit a38265
Packit a38265
    info.oggz = oggz;
Packit a38265
    info.tracks = oggz_table_new ();
Packit a38265
    info.length_total = 0;
Packit a38265
    info.overhead_length_total = 0;
Packit a38265
    
Packit a38265
    oi_pass1 (oggz, &info;;
Packit a38265
Packit a38265
    oi_pass2 (oggz, &info;;
Packit a38265
    
Packit a38265
    /* Print summary information */
Packit a38265
    if (many_files)
Packit a38265
      printf ("Filename: %s\n", infilename);
Packit a38265
    fputs ("Content-Duration: ", stdout);
Packit a38265
    ot_fprint_time (stdout, (double)info.duration / 1000.0);
Packit a38265
    putchar ('\n');
Packit a38265
    
Packit a38265
    if (show_length) {
Packit a38265
      fputs ("Content-Length: ", stdout);
Packit a38265
      ot_fprint_bytes (stdout, info.length_total);
Packit a38265
      putchar ('\n');
Packit a38265
    }
Packit a38265
    
Packit a38265
    if (show_bitrate) {
Packit a38265
      fputs ("Content-Bitrate-Average: ", stdout);
Packit a38265
      ot_print_bitrate (oi_bitrate (info.length_total, info.duration));
Packit a38265
      putchar ('\n');
Packit a38265
    }
Packit a38265
Packit a38265
    oggz_info_apply (oit_print, &info;;
Packit a38265
    
Packit a38265
    oggz_info_apply (oit_delete, &info;;
Packit a38265
    oggz_table_delete (info.tracks);
Packit a38265
Packit a38265
    oggz_close (oggz);
Packit a38265
    
Packit a38265
    if (optind < argc) puts (SEP);
Packit a38265
  }
Packit a38265
Packit a38265
 exit_ok:
Packit a38265
  exit (0);
Packit a38265
Packit a38265
 exit_err:
Packit a38265
  exit (1);
Packit a38265
}