Commit 2a1bba02 authored by conrad's avatar conrad

Make oggzinfo do something useful :-)

* This implements raw bitrate display towards ticket:73
* It also computes some stats, including min/max/avg and standard deviation of
page and packet sizes


git-svn-id: http://svn.annodex.net/liboggz/trunk@1033 8158c8cd-e7e1-0310-9fa4-c5954c97daef
parent 0015d48f
......@@ -26,7 +26,7 @@ bin_PROGRAMS = $(oggz_read_programs) $(oggz_rw_programs)
noinst_PROGRAMS = $(oggz_read_noinst_programs)
oggzinfo_SOURCES = oggzinfo.c
oggzinfo_LDADD = $(OGGZ_LIBS)
oggzinfo_LDADD = $(OGGZ_LIBS) -lm
oggzed_SOURCES = oggzed.c
oggzed_LDADD = $(OGGZ_LIBS)
......
......@@ -32,6 +32,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> /* LONG_MAX */
#include <math.h>
#include <oggz/oggz.h>
#ifndef WIN32
......@@ -40,29 +42,260 @@
#define PRId64 "ld"
#endif
typedef struct _OI_Info OI_Info;
typedef struct _OI_Stats OI_Stats;
typedef struct _OI_TrackInfo OI_TrackInfo;
static int got_an_eos = 0;
/* Let's get functional */
typedef void (*OI_TrackFunc) (OI_Info * info, OI_TrackInfo * oit, long serialno);
static int
read_packet (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
struct _OI_Info {
OggzTable * tracks;
ogg_int64_t duration;
long length_total;
};
struct _OI_Stats {
/* Pass 1 */
long count;
long length_total;
long length_min;
long length_max;
/* Pass 2 */
long length_avg;
long length_deviation_total;
double length_stddev;
};
struct _OI_TrackInfo {
OI_Stats pages;
OI_Stats packets;
};
static void
oggzinfo_apply (OI_TrackFunc func, OI_Info * info)
{
#if 0
if (got_an_eos) {
printf ("[%010ld]\t%ld bytes\tgranulepos %ld\n", serialno, op->bytes,
(long)op->granulepos);
}
#endif
OI_TrackInfo * oit;
long serialno;
int n, i;
if (op->b_o_s) {
printf ("%010ld: [%" PRId64 "] BOS", serialno, op->granulepos);
printf (" %8s\n", op->packet);
n = oggz_table_size (info->tracks);
for (i = 0; i < n; i++) {
oit = oggz_table_nth (info->tracks, i, &serialno);
if (oit) func (info, oit, serialno);
}
}
static void
oi_stats_clear (OI_Stats * stats)
{
stats->count = 0;
stats->length_total = 0;
stats->length_min = LONG_MAX;
stats->length_max = 0;
stats->length_avg = 0;
stats->length_deviation_total = 0;
stats->length_stddev = 0;
}
static OI_TrackInfo *
oggzinfo_trackinfo_new (void)
{
OI_TrackInfo * oit;
oit = malloc (sizeof (OI_TrackInfo));
oi_stats_clear (&oit->pages);
oi_stats_clear (&oit->packets);
return oit;
}
static long
oi_bitrate (long bytes, ogg_int64_t ms)
{
return (long) (((ogg_int64_t)bytes * 8 * 1000) / ms);
}
static void
oi_stats_print (OI_Info * info, OI_Stats * stats, char * label)
{
printf ("\t%s-Length-Maximum: %ld bytes\n", label, stats->length_max);
/*printf ("\t%s-Length-Average: %ld bytes\n", label, stats->length_avg);*/
printf ("\t%s-Length-StdDev: %.3f bytes\n", label, stats->length_stddev);
/*
printf ("\tRange: [%ld - %ld] bytes, Std.Dev. %.3f bytes\n",
stats->length_min, stats->length_max, stats->length_stddev);
*/
printf ("\n");
}
/* oggzinfo_trackinfo_print() */
static void
oit_print (OI_Info * info, OI_TrackInfo * oit, long serialno)
{
printf ("%010ld:\n", serialno);
if (op->e_o_s) {
got_an_eos = 1;
printf ("%010ld: [%" PRId64 "] EOS\n", serialno, op->granulepos);
printf ("\t%ld packets in %ld pages, %.3f packets/page\n",
oit->packets.count, oit->pages.count,
(double)oit->packets.count / (double)oit->pages.count);
printf ("\tContent-Length: %ld bytes\n", oit->pages.length_total);
printf ("\tContent-Bitrate-Average: %ld bps\n",
oi_bitrate (oit->pages.length_total, info->duration));
printf ("\n");
/* Page stats */
oi_stats_print (info, &oit->pages, "Page");
/* Packet stats */
oi_stats_print (info, &oit->packets, "Packet");
}
static void
oi_stats_average (OI_Stats * stats)
{
stats->length_avg = stats->length_total / stats->count;
}
static void
oit_calc_average (OI_Info * info, OI_TrackInfo * oit, long serialno)
{
oi_stats_average (&oit->pages);
oi_stats_average (&oit->packets);
}
static void
oi_stats_stddev (OI_Stats * stats)
{
double variance;
variance = (double)stats->length_deviation_total / (double)(stats->count - 1);
stats->length_stddev = sqrt (variance);
}
static void
oit_calc_stddev (OI_Info * info, OI_TrackInfo * oit, long serialno)
{
oi_stats_stddev (&oit->pages);
oi_stats_stddev (&oit->packets);
}
static int
read_page_pass1 (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
{
OI_Info * info = (OI_Info *)user_data;
OI_TrackInfo * oit;
long bytes;
oit = oggz_table_lookup (info->tracks, serialno);
if (oit == NULL) {
oit = oggzinfo_trackinfo_new ();
oggz_table_insert (info->tracks, serialno, oit);
}
bytes = og->header_len + og->body_len;
/* Increment the total stream length */
info->length_total += bytes;
/* Increment the page statistics */
oit->pages.count++;
oit->pages.length_total += bytes;
if (bytes < oit->pages.length_min)
oit->pages.length_min = bytes;
if (bytes > oit->pages.length_max)
oit->pages.length_max = bytes;
return 0;
}
static int
read_page_pass2 (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
{
OI_Info * info = (OI_Info *)user_data;
OI_TrackInfo * oit;
long bytes, deviation;
oit = oggz_table_lookup (info->tracks, serialno);
/* Increment the page length deviation squared total */
bytes = og->header_len + og->body_len;
deviation = bytes - oit->pages.length_avg;
oit->pages.length_deviation_total += (deviation * deviation);
return 0;
}
static int
read_packet_pass1 (OGGZ * oggz, ogg_packet * op, long serialno,
void * user_data)
{
OI_Info * info = (OI_Info *)user_data;
OI_TrackInfo * oit;
oit = oggz_table_lookup (info->tracks, serialno);
/* Increment the packet statistics */
oit->packets.count++;
oit->packets.length_total += op->bytes;
if (op->bytes < oit->packets.length_min)
oit->packets.length_min = op->bytes;
if (op->bytes > oit->packets.length_max)
oit->packets.length_max = op->bytes;
return 0;
}
static int
read_packet_pass2 (OGGZ * oggz, ogg_packet * op, long serialno,
void * user_data)
{
OI_Info * info = (OI_Info *)user_data;
OI_TrackInfo * oit;
long deviation;
oit = oggz_table_lookup (info->tracks, serialno);
/* Increment the packet length deviation squared total */
deviation = op->bytes - oit->packets.length_avg;
oit->packets.length_deviation_total += (deviation * deviation);
return 0;
}
static int
oi_pass1 (OGGZ * oggz, OI_Info * info)
{
long n;
oggz_seek (oggz, 0, SEEK_SET);
oggz_set_read_page (oggz, -1, read_page_pass1, info);
oggz_set_read_callback (oggz, -1, read_packet_pass1, info);
while ((n = oggz_read (oggz, 1024)) > 0);
oggzinfo_apply (oit_calc_average, info);
return 0;
}
static int
oi_pass2 (OGGZ * oggz, OI_Info * info)
{
long n;
oggz_seek (oggz, 0, SEEK_SET);
oggz_set_read_page (oggz, -1, read_page_pass2, info);
oggz_set_read_callback (oggz, -1, read_packet_pass2, info);
while ((n = oggz_read (oggz, 1024)) > 0);
oggzinfo_apply (oit_calc_stddev, info);
return 0;
}
......@@ -70,22 +303,40 @@ int
main (int argc, char ** argv)
{
OGGZ * oggz;
long n;
OI_Info info;
if (argc < 2) {
printf ("Usage: %s filename\n", argv[0]);
return (1);
}
if ((oggz = oggz_open ((char *)argv[1], OGGZ_READ)) == NULL) {
if ((oggz = oggz_open ((char *)argv[1], OGGZ_READ|OGGZ_AUTO)) == NULL) {
printf ("unable to open file %s\n", argv[1]);
return (1);
}
oggz_set_read_callback (oggz, -1, read_packet, NULL);
while ((n = oggz_read (oggz, 1024)) > 0);
info.tracks = oggz_table_new ();
info.length_total = 0;
oi_pass1 (oggz, &info);
oggz_seek_units (oggz, 0, SEEK_END);
info.duration = oggz_tell_units (oggz);
oi_pass2 (oggz, &info);
oggz_close (oggz);
/* Print summary information */
printf ("Duration: %lld ms\n", info.duration);
printf ("Content-Length: %ld bytes\n", info.length_total);
printf ("Content-Bitrate-Average: %ld bps\n",
oi_bitrate (info.length_total, info.duration));
printf ("\n");
oggzinfo_apply (oit_print, &info);
oggz_table_delete (info.tracks);
return (0);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment