Commit 7984a0fb authored by ivo's avatar ivo

Kate stream information support in ogginfo. Patch by ogg.k.ogg.k. Closes #1360.

svn path=/trunk/vorbis-tools/; revision=14860
parent b8681f28
......@@ -2,8 +2,9 @@ vorbis-tools 1.2.1 -- Unreleased
* Fixed an error in configure.ac; --with-speex/flac work again (#1319)
* Corrected problems in the Visual Studio project files
* ogg123: backported fix from libfishsound to patch the speex decoder (#1347)
* ogg123: backported fix from libfishsound to patch the Speex decoder (#1347)
* oggenc: fixed a core dump while resampling from FLAC (#1316)
* ogginfo: support for information in Kate streams (#1360)
vorbis-tools 1.2.0 -- 2008-02-21
......
......@@ -100,6 +100,7 @@ AC_ARG_ENABLE(vcut, [ --disable-vcut Skip building vcut], build_vcut="$en
AC_ARG_ENABLE(vorbiscomment, [ --disable-vorbiscomment Skip building vorbiscomment], build_vorbiscomment="$enableval", build_vorbiscomment="yes")
AC_ARG_WITH(flac, [ --without-flac Do not compile FLAC support], build_flac="$withval", build_flac="yes")
AC_ARG_WITH(speex, [ --without-speex Do not compile Speex support], build_speex="$withval", build_speex="yes")
AC_ARG_WITH(kate, [ --without-kate Do not compile Kate support], build_kate="$withval", build_kate="yes")
dnl --------------------------------------------------
dnl Check for generally needed libraries
......@@ -251,6 +252,50 @@ fi
AM_CONDITIONAL(HAVE_LIBSPEEX, test "x$have_libspeex" = "xyes")
AC_SUBST(SPEEX_LIBS)
dnl ------------------- Kate -------------------------
KATE_CFLAGS=""
KATE_LIBS=""
if test "x$build_kate" = xyes; then
AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes)
if test "x$HAVE_PKG_CONFIG" = "xyes"
then
PKG_CHECK_MODULES(KATE, oggkate, HAVE_KATE=yes, HAVE_KATE=no)
fi
if test "x$HAVE_KATE" = "xno"
then
dnl fall back to the old school test
AC_CHECK_LIB(m,log,KATE_LIBS="-lm")
AC_CHECK_LIB(kate, [kate_decode_init],
[HAVE_KATE=yes; KATE_LIBS="-lkate $KATE_LIBS $OGG_LIBS"],
AC_MSG_WARN(libkate missing)
HAVE_KATE=no, [$KATE_LIBS $OGG_LIBS]
)
AC_CHECK_LIB(oggkate, [kate_ogg_decode_headerin],
[HAVE_KATE=yes; KATE_LIBS="-loggkate $KATE_LIBS $OGG_LIBS"],
AC_MSG_WARN(libkate missing)
HAVE_KATE=no, [$KATE_LIBS $OGG_LIBS]
)
AC_CHECK_HEADER(kate/kate.h,,
AC_MSG_WARN(libkate headers missing)
HAVE_KATE=no,[ ])
AC_CHECK_HEADER(kate/oggkate.h,,
AC_MSG_WARN(liboggkate headers missing)
HAVE_KATE=no,[ ])
fi
if test "x$HAVE_KATE" = xyes; then
AC_DEFINE(HAVE_KATE, 1, [Defined if we have libkate])
else
build_kate="no"
KATE_CFLAGS=""
KATE_LIBS=""
fi
fi
AM_CONDITIONAL(HAVE_KATE, test "x$HAVE_KATE" = "xyes")
AC_SUBST(KATE_CFLAGS)
AC_SUBST(KATE_LIBS)
dnl --------------------------------------------------
dnl Check for headers
dnl --------------------------------------------------
......@@ -358,4 +403,8 @@ will NOT be built with Speex read support.])
AC_MSG_WARN([curl libraries and/or headers missing, ogg123
will NOT be built with http support.])
fi
if test "x$HAVE_KATE" != xyes; then
AC_MSG_WARN([Kate libraries and/or headers missing, ogginfo
will be built with LIMITED Kate read support.])
fi
fi
......@@ -14,9 +14,9 @@ bin_PROGRAMS = ogginfo
mandir = @MANDIR@
man_MANS = $(mans)
INCLUDES = @SHARE_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ @I18N_CFLAGS@
INCLUDES = @SHARE_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ @KATE_CFLAGS@ @I18N_CFLAGS@
ogginfo_LDADD = @SHARE_LIBS@ @VORBIS_LIBS@ @OGG_LIBS@ @LIBICONV@ @I18N_LIBS@
ogginfo_LDADD = @SHARE_LIBS@ @VORBIS_LIBS@ @KATE_LIBS@ @OGG_LIBS@ @LIBICONV@ @I18N_LIBS@
ogginfo_DEPENDENCIES = @SHARE_LIBS@
ogginfo_SOURCES = $(ogginfosources)
......
......@@ -21,6 +21,10 @@
#include <ogg/ogg.h>
#include <vorbis/codec.h>
#ifdef HAVE_KATE
#include <kate/oggkate.h>
#endif
#include <locale.h>
#include "utf8.h"
#include "i18n.h"
......@@ -116,6 +120,27 @@ typedef struct {
ogg_int64_t framenum_expected;
} misc_theora_info;
typedef struct {
#ifdef HAVE_KATE
kate_info ki;
kate_comment kc;
#else
int num_headers;
#endif
int major;
int minor;
char language[16];
char category[16];
ogg_int64_t bytes;
ogg_int64_t lastgranulepos;
ogg_int64_t firstgranulepos;
int doneheaders;
} misc_kate_info;
static int printlots = 0;
static int printinfo = 1;
static int printwarn = 1;
static int verbose = 1;
......@@ -634,6 +659,214 @@ static void vorbis_end(stream_processor *stream)
free(stream->data);
}
static void kate_process(stream_processor *stream, ogg_page *page )
{
ogg_packet packet;
misc_kate_info *inf = stream->data;
int header=0, packets=0;
int res;
#ifdef HAVE_KATE
int i;
const char *encoding = NULL, *directionality = NULL;
#endif
ogg_stream_pagein(&stream->os, page);
if(!inf->doneheaders)
header = 1;
while(1) {
res = ogg_stream_packetout(&stream->os, &packet);
if(res < 0) {
warn(_("Warning: discontinuity in stream (%d)\n"), stream->num);
continue;
}
else if (res == 0)
break;
packets++;
if(!inf->doneheaders) {
#ifdef HAVE_KATE
int ret = kate_ogg_decode_headerin(&inf->ki, &inf->kc, &packet);
if(ret < 0) {
warn(_("Warning: Could not decode kate header "
"packet %d - invalid kate stream (%d)\n"),
packet.packetno, stream->num);
continue;
}
else if (ret > 0) {
inf->doneheaders=1;
}
#else
/* if we're not building against libkate, do some limited checks */
if (packet.bytes<64 || memcmp(packet.packet+1, "kate\0\0\0\0", 8)) {
warn(_("Warning: packet %d does not seem to be a kate header - "
"invalid kate stream (%d)\n"),
packet.packetno, stream->num);
continue;
}
if (packet.packetno==inf->num_headers) {
inf->doneheaders=1;
}
#endif
if (packet.packetno==0) {
#ifdef HAVE_KATE
inf->major = inf->ki.bitstream_version_major;
inf->minor = inf->ki.bitstream_version_minor;
memcpy(inf->language, inf->ki.language, 16);
inf->language[15] = 0;
memcpy(inf->category, inf->ki.category, 16);
inf->category[15] = 0;
#else
inf->major = packet.packet[9];
inf->minor = packet.packet[10];
inf->num_headers = packet.packet[11];
memcpy(inf->language, packet.packet+32, 16);
inf->language[15] = 0;
memcpy(inf->category, packet.packet+48, 16);
inf->category[15] = 0;
#endif
}
if(inf->doneheaders) {
if(ogg_page_granulepos(page) != 0 || ogg_stream_packetpeek(&stream->os, NULL) == 1)
warn(_("Warning: Kate stream %d does not have headers "
"correctly framed. Terminal header page contains "
"additional packets or has non-zero granulepos\n"),
stream->num);
info(_("Kate headers parsed for stream %d, "
"information follows...\n"), stream->num);
info(_("Version: %d.%d\n"), inf->major, inf->minor);
#ifdef HAVE_KATE
info(_("Vendor: %s\n"), inf->kc.vendor);
#endif
if (*inf->language) {
info(_("Language: %s\n"), inf->language);
}
else {
info(_("No language set\n"));
}
if (*inf->category) {
info(_("Category: %s\n"), inf->category);
}
else {
info(_("No category set\n"));
}
#ifdef HAVE_KATE
switch (inf->ki.text_encoding) {
case kate_utf8: encoding=_("utf-8"); break;
default: encoding=NULL; break;
}
if (encoding) {
info(_("Character encoding: %s\n"),encoding);
}
else {
info(_("Unknown character encoding\n"));
}
if (printlots) {
switch (inf->ki.text_directionality) {
case kate_l2r_t2b: directionality=_("left to right, top to bottom"); break;
case kate_r2l_t2b: directionality=_("right to left, top to bottom"); break;
case kate_t2b_r2l: directionality=_("top to bottom, right to left"); break;
case kate_t2b_l2r: directionality=_("top to bottom, left to right"); break;
default: directionality=NULL; break;
}
if (directionality) {
info(_("Text directionality: %s\n"),directionality);
}
else {
info(_("Unknown text directionality\n"));
}
info("%u regions, %u styles, %u curves, %u motions, %u palettes,\n"
"%u bitmaps, %u font ranges, %u font mappings\n",
inf->ki.nregions, inf->ki.nstyles,
inf->ki.ncurves, inf->ki.nmotions,
inf->ki.npalettes, inf->ki.nbitmaps,
inf->ki.nfont_ranges, inf->ki.nfont_mappings);
}
if(inf->ki.gps_numerator == 0 || inf->ki.gps_denominator == 0)
warn(_("Invalid zero granulepos rate\n"));
else
info(_("Granulepos rate %d/%d (%.02f gps)\n"),
inf->ki.gps_numerator, inf->ki.gps_denominator,
(float)inf->ki.gps_numerator/(float)inf->ki.gps_denominator);
if(inf->kc.comments > 0)
info(_("User comments section follows...\n"));
for(i=0; i < inf->kc.comments; i++) {
const char *comment = inf->kc.user_comments[i];
check_xiph_comment(stream, i, comment,
inf->kc.comment_lengths[i]);
}
#endif
info(_("\n"));
}
}
}
if(!header) {
ogg_int64_t gp = ogg_page_granulepos(page);
if(gp > 0) {
if(gp < inf->lastgranulepos)
warn(_("Warning: granulepos in stream %d decreases from %"
I64FORMAT " to %" I64FORMAT "\n" ),
stream->num, inf->lastgranulepos, gp);
inf->lastgranulepos = gp;
}
else if(packets && gp<0) { /* zero granpos on data is valid for kate */
/* Only do this if we saw at least one packet ending on this page.
* It's legal (though very unusual) to have no packets in a page at
* all - this is occasionally used to have an empty EOS page */
warn(_("Negative granulepos (%lld) on kate stream outside of headers. This file was created by a buggy encoder\n"), gp);
}
if(inf->firstgranulepos < 0) { /* Not set yet */
}
inf->bytes += page->header_len + page->body_len;
}
}
#ifdef HAVE_KATE
static void kate_end(stream_processor *stream)
{
misc_kate_info *inf = stream->data;
long minutes, seconds, milliseconds;
double bitrate, time;
/* This should be lastgranulepos - startgranulepos, or something like that*/
//time = (double)(inf->lastgranulepos>>inf->ki.granule_shift) * inf->ki.gps_denominator / inf->ki.gps_numerator;
ogg_int64_t gbase=inf->lastgranulepos>>inf->ki.granule_shift;
ogg_int64_t goffset=inf->lastgranulepos-(gbase<<inf->ki.granule_shift);
time = (double)(gbase+goffset) / ((float)inf->ki.gps_numerator/(float)inf->ki.gps_denominator);
minutes = (long)time / 60;
seconds = (long)time - minutes*60;
milliseconds = (long)((time - minutes*60 - seconds)*1000);
bitrate = inf->bytes*8 / time / 1000.0;
info(_("Kate stream %d:\n"
"\tTotal data length: %" I64FORMAT " bytes\n"
"\tPlayback length: %ldm:%02ld.%03lds\n"
"\tAverage bitrate: %f kb/s\n"),
stream->num,inf->bytes, minutes, seconds, milliseconds, bitrate);
kate_comment_clear(&inf->kc);
kate_info_clear(&inf->ki);
free(stream->data);
}
#else
static void kate_end(stream_processor *stream)
{
}
#endif
static void process_null(stream_processor *stream, ogg_page *page)
{
/* This is for invalid streams. */
......@@ -727,6 +960,24 @@ static void vorbis_start(stream_processor *stream)
}
static void kate_start(stream_processor *stream)
{
misc_kate_info *info;
stream->type = "kate";
stream->process_page = kate_process;
stream->process_end = kate_end;
stream->data = calloc(1, sizeof(misc_kate_info));
info = stream->data;
#ifdef HAVE_KATE
kate_comment_init(&info->kc);
kate_info_init(&info->ki);
#endif
}
static stream_processor *find_stream_processor(stream_set *set, ogg_page *page)
{
ogg_uint32_t serial = ogg_page_serialno(page);
......@@ -813,7 +1064,7 @@ static stream_processor *find_stream_processor(stream_set *set, ogg_page *page)
else if(packet.bytes >= 8 && memcmp(packet.packet, "KW-DIRAC", 8)==0)
other_start(stream, "dirac (old style)");
else if(packet.bytes >= 9 && memcmp(packet.packet, "\x80kate\0\0\0\0", 9)==0)
other_start(stream, "kate");
kate_start(stream);
else
other_start(stream, NULL);
......@@ -1017,6 +1268,8 @@ int main(int argc, char **argv) {
}
}
if(verbose > 1)
printlots = 0;
if(verbose < 1)
printinfo = 0;
if(verbose < 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