|
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 |
}
|