|
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 |
/*
|
|
Packit |
a38265 |
* oggz_auto.c
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* Conrad Parker <conrad@annodex.net>
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "config.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <stdlib.h>
|
|
Packit |
a38265 |
#include <string.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz_private.h"
|
|
Packit |
a38265 |
#include "oggz_byteorder.h"
|
|
Packit |
a38265 |
#include "dirac.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz/oggz_stream.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*#define DEBUG*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Allow use of internal metrics; ie. the user_data for these gets free'd
|
|
Packit |
a38265 |
* when the metric is overwritten, or on close */
|
|
Packit |
a38265 |
int oggz_set_metric_internal (OGGZ * oggz, long serialno, OggzMetric metric,
|
|
Packit |
a38265 |
void * user_data, int internal);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int oggz_set_metric_linear (OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
ogg_int64_t granule_rate_numerator,
|
|
Packit |
a38265 |
ogg_int64_t granule_rate_denominator);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (OGGZ * oggz, long serialno, int numheaders)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream->numheaders = numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_speex (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate = 0;
|
|
Packit |
a38265 |
int numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 68) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate = (ogg_int64_t) int32_le_at(&header[36]);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got speex rate %d\n", (int)granule_rate);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_preroll (oggz, serialno, 3);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
numheaders = (ogg_int64_t) int32_le_at(&header[68]) + 2;
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, numheaders);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_vorbis (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 30) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate = (ogg_int64_t) int32_le_at(&header[12]);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got vorbis rate %d\n", (int)granule_rate);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_preroll (oggz, serialno, 2);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 3);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#if USE_THEORA_PRE_ALPHA_3_FORMAT
|
|
Packit |
a38265 |
static int intlog(int num) {
|
|
Packit |
a38265 |
int ret=0;
|
|
Packit |
a38265 |
while(num>0){
|
|
Packit |
a38265 |
num=num/2;
|
|
Packit |
a38265 |
ret=ret+1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
return(ret);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define THEORA_VERSION(maj,min,rev) ((maj<<16)+(min<<8)+rev)
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_theora (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
int version;
|
|
Packit |
a38265 |
ogg_int32_t fps_numerator, fps_denominator;
|
|
Packit |
a38265 |
char keyframe_granule_shift = 0;
|
|
Packit |
a38265 |
int keyframe_shift;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* TODO: this should check against 42 for the relevant version numbers */
|
|
Packit |
a38265 |
if (length < 41) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
version = THEORA_VERSION(header[7], header[8], header[9]);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
fps_numerator = int32_be_at(&header[22]);
|
|
Packit |
a38265 |
fps_denominator = int32_be_at(&header[26]);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Very old theora versions used a value of 0 to mean 1.
|
|
Packit |
a38265 |
* Unfortunately theora hasn't incremented its version field,
|
|
Packit |
a38265 |
* hence we hardcode this workaround for old or broken streams.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (fps_numerator == 0) fps_numerator = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#if USE_THEORA_PRE_ALPHA_3_FORMAT
|
|
Packit |
a38265 |
/* old header format, used by Theora alpha2 and earlier */
|
|
Packit |
a38265 |
keyframe_granule_shift = (header[36] & 0xf8) >> 3;
|
|
Packit |
a38265 |
keyframe_shift = intlog (keyframe_granule_shift - 1);
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
keyframe_granule_shift = (char) ((header[40] & 0x03) << 3);
|
|
Packit |
a38265 |
keyframe_granule_shift |= (header[41] & 0xe0) >> 5; /* see TODO above */
|
|
Packit |
a38265 |
keyframe_shift = keyframe_granule_shift;
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got theora fps %d/%d, keyframe_shift %d\n",
|
|
Packit |
a38265 |
fps_numerator, fps_denominator, keyframe_shift);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, (ogg_int64_t)fps_numerator,
|
|
Packit |
a38265 |
OGGZ_AUTO_MULT * (ogg_int64_t)fps_denominator);
|
|
Packit |
a38265 |
oggz_set_granuleshift (oggz, serialno, keyframe_shift);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (version > THEORA_VERSION(3,2,0))
|
|
Packit |
a38265 |
oggz_set_first_granule (oggz, serialno, 1);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 3);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_annodex (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
/* Apply a zero metric */
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, 0, 1);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_anxdata (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 28) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate_numerator = int64_le_at(&header[8]);
|
|
Packit |
a38265 |
granule_rate_denominator = int64_le_at(&header[16]);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got AnxData rate %lld/%lld\n", granule_rate_numerator,
|
|
Packit |
a38265 |
granule_rate_denominator);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno,
|
|
Packit |
a38265 |
granule_rate_numerator,
|
|
Packit |
a38265 |
OGGZ_AUTO_MULT * granule_rate_denominator);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_flac0 (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate = (ogg_int64_t) (header[14] << 12) | (header[15] << 4) |
|
|
Packit |
a38265 |
((header[16] >> 4)&0xf);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got flac rate %d\n", (int)granule_rate);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 3);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_flac (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate = 0;
|
|
Packit |
a38265 |
int numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 51) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate = (ogg_int64_t) (header[27] << 12) | (header[28] << 4) |
|
|
Packit |
a38265 |
((header[29] >> 4)&0xf);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got flac rate %d\n", (int)granule_rate);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
numheaders = int16_be_at(&header[7]);
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, numheaders);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/**
|
|
Packit |
a38265 |
* Recognizer for OggPCM2:
|
|
Packit |
a38265 |
* http://wiki.xiph.org/index.php/OggPCM2
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_oggpcm2 (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 28) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate = (ogg_int64_t) int32_be_at(&header[16]);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got OggPCM2 rate %d\n", (int)granule_rate);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 3);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_celt (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate = 0;
|
|
Packit |
a38265 |
int numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 56) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate = (ogg_int64_t) int32_le_at(&header[40]);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got celt sample rate %d\n", (int)granule_rate);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
numheaders = (ogg_int64_t) int32_le_at(&header[52]) + 2;
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, numheaders);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_cmml (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
|
|
Packit |
a38265 |
int granuleshift;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 28) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate_numerator = int64_le_at(&header[12]);
|
|
Packit |
a38265 |
granule_rate_denominator = int64_le_at(&header[20]);
|
|
Packit |
a38265 |
if (length > 28)
|
|
Packit |
a38265 |
granuleshift = (int)header[28];
|
|
Packit |
a38265 |
else
|
|
Packit |
a38265 |
granuleshift = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got CMML rate %lld/%lld\n", granule_rate_numerator,
|
|
Packit |
a38265 |
granule_rate_denominator);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno,
|
|
Packit |
a38265 |
granule_rate_numerator,
|
|
Packit |
a38265 |
OGGZ_AUTO_MULT * granule_rate_denominator);
|
|
Packit |
a38265 |
oggz_set_granuleshift (oggz, serialno, granuleshift);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 3);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_kate (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
ogg_int32_t gps_numerator, gps_denominator;
|
|
Packit |
a38265 |
unsigned char granule_shift = 0;
|
|
Packit |
a38265 |
int numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 64) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
gps_numerator = int32_le_at(&header[24]);
|
|
Packit |
a38265 |
gps_denominator = int32_le_at(&header[28]);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_shift = (header[15]);
|
|
Packit |
a38265 |
numheaders = (header[11]);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got kate gps %d/%d, granule shift %d\n",
|
|
Packit |
a38265 |
gps_numerator, gps_denominator, granule_shift);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, gps_numerator,
|
|
Packit |
a38265 |
OGGZ_AUTO_MULT * gps_denominator);
|
|
Packit |
a38265 |
oggz_set_granuleshift (oggz, serialno, granule_shift);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, numheaders);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_dirac (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int granule_shift = 22; /* not a typo */
|
|
Packit |
a38265 |
dirac_info *info;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = oggz_malloc(sizeof(dirac_info));
|
|
Packit |
a38265 |
if (info == NULL) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (dirac_parse_info(info, data, length) == -1) {
|
|
Packit |
a38265 |
oggz_free (info);
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* the granulerate is twice the frame rate (in order to handle interlace) */
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno,
|
|
Packit |
a38265 |
2 * (ogg_int64_t)info->fps_numerator,
|
|
Packit |
a38265 |
OGGZ_AUTO_MULT * (ogg_int64_t)info->fps_denominator);
|
|
Packit |
a38265 |
oggz_set_granuleshift (oggz, serialno, granule_shift);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_free(info);
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_fisbone (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
unsigned char * header = data;
|
|
Packit |
a38265 |
long fisbone_serialno; /* The serialno referred to in this fisbone */
|
|
Packit |
a38265 |
ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
|
|
Packit |
a38265 |
int granuleshift, numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length < 48) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
fisbone_serialno = (long) int32_le_at(&header[12]);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Don't override an already assigned metric */
|
|
Packit |
a38265 |
if (oggz_stream_has_metric (oggz, fisbone_serialno)) return 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule_rate_numerator = int64_le_at(&header[20]);
|
|
Packit |
a38265 |
granule_rate_denominator = int64_le_at(&header[28]);
|
|
Packit |
a38265 |
granuleshift = (int)header[48];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("Got fisbone granulerate %lld/%lld, granuleshift %d for serialno %010lu\n",
|
|
Packit |
a38265 |
granule_rate_numerator, granule_rate_denominator, granuleshift,
|
|
Packit |
a38265 |
fisbone_serialno);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, fisbone_serialno,
|
|
Packit |
a38265 |
granule_rate_numerator,
|
|
Packit |
a38265 |
OGGZ_AUTO_MULT * granule_rate_denominator);
|
|
Packit |
a38265 |
oggz_set_granuleshift (oggz, fisbone_serialno, granuleshift);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Increment the number of headers for this stream */
|
|
Packit |
a38265 |
numheaders = oggz_stream_get_numheaders (oggz, serialno);
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, numheaders+1);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
auto_fishead (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_set_granulerate (oggz, serialno, 0, 1);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* For skeleton, numheaders will get incremented as each header is seen */
|
|
Packit |
a38265 |
oggz_stream_set_numheaders (oggz, serialno, 1);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* The first two speex packets are header and comment packets (granulepos = 0)
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
int headers_encountered;
|
|
Packit |
a38265 |
int packet_size;
|
|
Packit |
a38265 |
int encountered_first_data_packet;
|
|
Packit |
a38265 |
} auto_calc_speex_info_t;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
auto_calc_speex(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* on the first (b_o_s) packet, set calculate_data to be the number
|
|
Packit |
a38265 |
* of speex frames per packet
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
auto_calc_speex_info_t *info
|
|
Packit |
a38265 |
= (auto_calc_speex_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) {
|
|
Packit |
a38265 |
stream->calculate_data = oggz_malloc(sizeof(auto_calc_speex_info_t));
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) return -1;
|
|
Packit |
a38265 |
info = stream->calculate_data;
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 0;
|
|
Packit |
a38265 |
info->packet_size =
|
|
Packit |
a38265 |
(*(int *)(op->packet + 64)) * (*(int *)(op->packet + 56));
|
|
Packit |
a38265 |
info->headers_encountered = 1;
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (info->headers_encountered < 2) {
|
|
Packit |
a38265 |
info->headers_encountered += 1;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (now > -1) {
|
|
Packit |
a38265 |
return now;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (info->encountered_first_data_packet) {
|
|
Packit |
a38265 |
if (stream->last_granulepos > 0) {
|
|
Packit |
a38265 |
return stream->last_granulepos + info->packet_size;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* The first two CELT packets are header and comment packets (granulepos = 0)
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
int headers_encountered;
|
|
Packit |
a38265 |
int packet_size;
|
|
Packit |
a38265 |
int encountered_first_data_packet;
|
|
Packit |
a38265 |
} auto_calc_celt_info_t;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
auto_calc_celt (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* on the first (b_o_s) packet, set calculate_data to be the number
|
|
Packit |
a38265 |
* of celt frames per packet
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
auto_calc_celt_info_t *info
|
|
Packit |
a38265 |
= (auto_calc_celt_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) {
|
|
Packit |
a38265 |
stream->calculate_data = oggz_malloc(sizeof(auto_calc_celt_info_t));
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = stream->calculate_data;
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* In general, the number of frames per packet depends on the mode.
|
|
Packit |
a38265 |
* Currently (20080213) both available modes, mono and stereo, have 256
|
|
Packit |
a38265 |
* frames per packet.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
info->packet_size = 256;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info->headers_encountered = 1;
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (info->headers_encountered < 2) {
|
|
Packit |
a38265 |
info->headers_encountered += 1;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (now > -1) {
|
|
Packit |
a38265 |
return now;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (info->encountered_first_data_packet) {
|
|
Packit |
a38265 |
if (stream->last_granulepos > 0) {
|
|
Packit |
a38265 |
return stream->last_granulepos + info->packet_size;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* Header packets are marked by a set MSB in the first byte. Inter packets
|
|
Packit |
a38265 |
* are marked by a set 2MSB in the first byte. Intra packets (keyframes)
|
|
Packit |
a38265 |
* are any that are left over ;-)
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* (see http://theora.org/doc/Theora.pdf for the theora specification)
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
int encountered_first_data_packet;
|
|
Packit |
a38265 |
} auto_calc_theora_info_t;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
long keyframe_no;
|
|
Packit |
a38265 |
int keyframe_shift;
|
|
Packit |
a38265 |
unsigned char first_byte;
|
|
Packit |
a38265 |
auto_calc_theora_info_t *info;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
first_byte = op->bytes == 0 ? 0x40 : op->packet[0];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = (auto_calc_theora_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* header packet */
|
|
Packit |
a38265 |
if (first_byte & 0x80)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
if (info == NULL) {
|
|
Packit |
a38265 |
stream->calculate_data = oggz_malloc(sizeof(auto_calc_theora_info_t));
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) return -1;
|
|
Packit |
a38265 |
info = stream->calculate_data;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 0;
|
|
Packit |
a38265 |
return (ogg_int64_t)0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* known granulepos */
|
|
Packit |
a38265 |
if (now > (ogg_int64_t)(-1)) {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
return now;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* last granulepos unknown */
|
|
Packit |
a38265 |
if (stream->last_granulepos == -1) {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
return (ogg_int64_t)-1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* first data packet is -1 if gp not set
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (!info->encountered_first_data_packet) {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
return (ogg_int64_t)-1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* inter-coded packet */
|
|
Packit |
a38265 |
if (first_byte & 0x40)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
return stream->last_granulepos + 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
keyframe_shift = stream->granuleshift;
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* retrieve last keyframe number
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
keyframe_no = (int)(stream->last_granulepos >> keyframe_shift);
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* add frames since last keyframe number
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
keyframe_no += (stream->last_granulepos & ((1 << keyframe_shift) - 1)) + 1;
|
|
Packit |
a38265 |
return ((ogg_int64_t)keyframe_no) << keyframe_shift;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
auto_rcalc_theora(ogg_int64_t next_packet_gp, oggz_stream_t *stream,
|
|
Packit |
a38265 |
ogg_packet *this_packet, ogg_packet *next_packet) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int keyframe = (int)(next_packet_gp >> stream->granuleshift);
|
|
Packit |
a38265 |
int offset = (int)(next_packet_gp - (keyframe << stream->granuleshift));
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* assume kf is 60 frames ago. NOTE: This is going to cause problems,
|
|
Packit |
a38265 |
* but I can't think of what else to do. The position of the last kf
|
|
Packit |
a38265 |
* is fundamentally unknowable.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (offset == 0) {
|
|
Packit |
a38265 |
return ((keyframe - 60L) << stream->granuleshift) + 59;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
else {
|
|
Packit |
a38265 |
return (((ogg_int64_t)keyframe) << stream->granuleshift) + (offset - 1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* Vorbis packets can be short or long, and each packet overlaps the previous
|
|
Packit |
a38265 |
* and next packets. The granulepos of a packet is always the last sample
|
|
Packit |
a38265 |
* that is completely decoded at the end of decoding that packet - i.e. the
|
|
Packit |
a38265 |
* last packet before the first overlapping packet. If the sizes of packets
|
|
Packit |
a38265 |
* are 's' and 'l', then the increment will depend on the previous and next
|
|
Packit |
a38265 |
* packet types:
|
|
Packit |
a38265 |
* v prev<<1 | next
|
|
Packit |
a38265 |
* lll: l/2 3
|
|
Packit |
a38265 |
* lls: 3l/4 - s/4 2
|
|
Packit |
a38265 |
* lsl: s/2
|
|
Packit |
a38265 |
* lss: s/2
|
|
Packit |
a38265 |
* sll: l/4 + s/4 1
|
|
Packit |
a38265 |
* sls: l/2 0
|
|
Packit |
a38265 |
* ssl: s/2
|
|
Packit |
a38265 |
* sss: s/2
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* The previous and next packet types can be inferred from the current packet
|
|
Packit |
a38265 |
* (additional information is not required)
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* The two blocksizes can be determined from the first header packet, by reading
|
|
Packit |
a38265 |
* byte 28. 1 << (packet[28] >> 4) == long_size.
|
|
Packit |
a38265 |
* 1 << (packet[28] & 0xF) == short_size.
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* (see http://xiph.org/vorbis/doc/Vorbis_I_spec.html for specification)
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
int nln_increments[4];
|
|
Packit |
a38265 |
int nsn_increment;
|
|
Packit |
a38265 |
int short_size;
|
|
Packit |
a38265 |
int long_size;
|
|
Packit |
a38265 |
int encountered_first_data_packet;
|
|
Packit |
a38265 |
int last_was_long;
|
|
Packit |
a38265 |
int log2_num_modes;
|
|
Packit |
a38265 |
int mode_sizes[1];
|
|
Packit |
a38265 |
} auto_calc_vorbis_info_t;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
auto_calc_vorbis_info_t *info;
|
|
Packit |
a38265 |
int ii;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) {
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* on the first (b_o_s) packet, determine the long and short sizes,
|
|
Packit |
a38265 |
* and then calculate l/2, l/4 - s/4, 3 * l/4 - s/4, l/2 - s/2 and s/2
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
int short_size;
|
|
Packit |
a38265 |
int long_size;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
long_size = 1 << (op->packet[28] >> 4);
|
|
Packit |
a38265 |
short_size = 1 << (op->packet[28] & 0xF);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream->calculate_data = oggz_malloc(sizeof(auto_calc_vorbis_info_t));
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = (auto_calc_vorbis_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
info->nln_increments[3] = long_size >> 1;
|
|
Packit |
a38265 |
info->nln_increments[2] = 3 * (long_size >> 2) - (short_size >> 2);
|
|
Packit |
a38265 |
info->nln_increments[1] = (long_size >> 2) + (short_size >> 2);
|
|
Packit |
a38265 |
info->nln_increments[0] = info->nln_increments[3];
|
|
Packit |
a38265 |
info->short_size = short_size;
|
|
Packit |
a38265 |
info->long_size = long_size;
|
|
Packit |
a38265 |
info->nsn_increment = short_size >> 1;
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* this is a header packet */
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* marker for header packets
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (op->packet[0] & 0x1) {
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* the code pages, a whole bunch of other fairly useless stuff, AND,
|
|
Packit |
a38265 |
* RIGHT AT THE END (of a bunch of variable-length compressed rubbish that
|
|
Packit |
a38265 |
* basically has only one actual set of values that everyone uses BUT YOU
|
|
Packit |
a38265 |
* CAN'T BE SURE OF THAT, OH NO YOU CAN'T) is the only piece of data that's
|
|
Packit |
a38265 |
* actually useful to us - the packet modes (because it's inconceivable to
|
|
Packit |
a38265 |
* think people might want _just that_ and nothing else, you know, for
|
|
Packit |
a38265 |
* seeking and stuff).
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* Fortunately, because of the mandate that non-used bits must be zero
|
|
Packit |
a38265 |
* at the end of the packet, we might be able to sneakily work backwards
|
|
Packit |
a38265 |
* and find out the information we need (namely a mapping of modes to
|
|
Packit |
a38265 |
* packet sizes)
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (op->packet[0] == 5) {
|
|
Packit |
a38265 |
unsigned char *current_pos = &op->packet[op->bytes - 1];
|
|
Packit |
a38265 |
int offset;
|
|
Packit |
a38265 |
int size;
|
|
Packit |
a38265 |
int size_check;
|
|
Packit |
a38265 |
int *mode_size_ptr;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
size_t size_realloc_bytes;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* This is the format of the mode data at the end of the packet for all
|
|
Packit |
a38265 |
* Vorbis Version 1 :
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* [ 6:number_of_modes ]
|
|
Packit |
a38265 |
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
|
Packit |
a38265 |
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
|
Packit |
a38265 |
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
|
Packit |
a38265 |
* [ 1:framing(1) ]
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* e.g.:
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* <-
|
|
Packit |
a38265 |
* 0 0 0 0 0 1 0 0
|
|
Packit |
a38265 |
* 0 0 1 0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 1 0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 1|0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 0 0|0|0 0 0
|
|
Packit |
a38265 |
* 0 0 0 0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 0 0|0 0 0 0
|
|
Packit |
a38265 |
* 0 0 0 0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 0 0|0 0 0 0
|
|
Packit |
a38265 |
* 0 0 0|1|0 0 0 0 |
|
|
Packit |
a38265 |
* 0 0 0 0 0 0 0 0 V
|
|
Packit |
a38265 |
* 0 0 0|0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 0 0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0 1|0 0 0 0 0
|
|
Packit |
a38265 |
* 0 0|1|0 0 0 0 0
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* i.e. each entry is an important bit, 32 bits of 0, 8 bits of blah, a
|
|
Packit |
a38265 |
* bit of 1.
|
|
Packit |
a38265 |
* Let's find our last 1 bit first.
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
size = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
offset = 8;
|
|
Packit |
a38265 |
while (!((1 << --offset) & *current_pos)) {
|
|
Packit |
a38265 |
if (offset == 0) {
|
|
Packit |
a38265 |
offset = 8;
|
|
Packit |
a38265 |
current_pos -= 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
while (1)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* from current_pos-5:(offset+1) to current_pos-1:(offset+1) should
|
|
Packit |
a38265 |
* be zero
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
offset = (offset + 7) % 8;
|
|
Packit |
a38265 |
if (offset == 7)
|
|
Packit |
a38265 |
current_pos -= 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if
|
|
Packit |
a38265 |
(
|
|
Packit |
a38265 |
((current_pos[-5] & ~((1 << (offset + 1)) - 1)) != 0)
|
|
Packit |
a38265 |
||
|
|
Packit |
a38265 |
current_pos[-4] != 0
|
|
Packit |
a38265 |
||
|
|
Packit |
a38265 |
current_pos[-3] != 0
|
|
Packit |
a38265 |
||
|
|
Packit |
a38265 |
current_pos[-2] != 0
|
|
Packit |
a38265 |
||
|
|
Packit |
a38265 |
((current_pos[-1] & ((1 << (offset + 1)) - 1)) != 0)
|
|
Packit |
a38265 |
)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
size += 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
current_pos -= 5;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Give ourselves a chance to recover if we went back too far by using
|
|
Packit |
a38265 |
* the size check. */
|
|
Packit |
a38265 |
for (ii=0; ii < 2; ii++) {
|
|
Packit |
a38265 |
if (offset > 4) {
|
|
Packit |
a38265 |
size_check = (current_pos[0] >> (offset - 5)) & 0x3F;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
/* mask part of byte from current_pos */
|
|
Packit |
a38265 |
size_check = (current_pos[0] & ((1 << (offset + 1)) - 1));
|
|
Packit |
a38265 |
/* shift to appropriate position */
|
|
Packit |
a38265 |
size_check <<= (5 - offset);
|
|
Packit |
a38265 |
/* or in part of byte from current_pos - 1 */
|
|
Packit |
a38265 |
size_check |= (current_pos[-1] & ~((1 << (offset + 3)) - 1)) >>
|
|
Packit |
a38265 |
(offset + 3);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
size_check += 1;
|
|
Packit |
a38265 |
if (size_check == size) {
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
offset = (offset + 1) % 8;
|
|
Packit |
a38265 |
if (offset == 0)
|
|
Packit |
a38265 |
current_pos += 1;
|
|
Packit |
a38265 |
current_pos += 5;
|
|
Packit |
a38265 |
size -= 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
if (size_check != size)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
printf("WARNING: size parsing failed for VORBIS mode packets\n");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Check that size to be realloc'd doesn't overflow */
|
|
Packit |
a38265 |
size_realloc_bytes = sizeof(auto_calc_vorbis_info_t) + (size - 1) * sizeof(int);
|
|
Packit |
a38265 |
if (size_realloc_bytes < sizeof (auto_calc_vorbis_info_t)) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Store mode size information in our info struct */
|
|
Packit |
a38265 |
info = realloc(stream->calculate_data, size_realloc_bytes);
|
|
Packit |
a38265 |
if (info == NULL) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream->calculate_data = info;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
i = -1;
|
|
Packit |
a38265 |
while ((1 << (++i)) < size);
|
|
Packit |
a38265 |
info->log2_num_modes = i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
mode_size_ptr = info->mode_sizes;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for(i = 0; i < size; i++)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
offset = (offset + 1) % 8;
|
|
Packit |
a38265 |
if (offset == 0)
|
|
Packit |
a38265 |
current_pos += 1;
|
|
Packit |
a38265 |
*mode_size_ptr++ = (current_pos[0] >> offset) & 0x1;
|
|
Packit |
a38265 |
current_pos += 5;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = (auto_calc_vorbis_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* we're in a data packet! First we need to get the mode of the packet,
|
|
Packit |
a38265 |
* and from the mode, the size
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
int mode;
|
|
Packit |
a38265 |
int size;
|
|
Packit |
a38265 |
ogg_int64_t result;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
mode = (op->packet[0] >> 1) & ((1 << info->log2_num_modes) - 1);
|
|
Packit |
a38265 |
size = info->mode_sizes[mode];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* if we have a working granulepos, we use it, but only if we can't
|
|
Packit |
a38265 |
* calculate a valid gp value.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (now > -1 && stream->last_granulepos == -1) {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
info->last_was_long = size;
|
|
Packit |
a38265 |
return now;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (info->encountered_first_data_packet == 0) {
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
info->last_was_long = size;
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* otherwise, if we haven't yet had a working granulepos, we return
|
|
Packit |
a38265 |
* -1
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (stream->last_granulepos == -1) {
|
|
Packit |
a38265 |
info->last_was_long = size;
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
result = stream->last_granulepos +
|
|
Packit |
a38265 |
(
|
|
Packit |
a38265 |
(info->last_was_long ? info->long_size : info->short_size)
|
|
Packit |
a38265 |
+
|
|
Packit |
a38265 |
(size ? info->long_size : info->short_size)
|
|
Packit |
a38265 |
) / 4;
|
|
Packit |
a38265 |
info->last_was_long = size;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return result;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ogg_int64_t
|
|
Packit |
a38265 |
auto_rcalc_vorbis(ogg_int64_t next_packet_gp, oggz_stream_t *stream,
|
|
Packit |
a38265 |
ogg_packet *this_packet, ogg_packet *next_packet) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
auto_calc_vorbis_info_t *info =
|
|
Packit |
a38265 |
(auto_calc_vorbis_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int mode =
|
|
Packit |
a38265 |
(this_packet->packet[0] >> 1) & ((1 << info->log2_num_modes) - 1);
|
|
Packit |
a38265 |
int this_size = info->mode_sizes[mode] ? info->long_size : info->short_size;
|
|
Packit |
a38265 |
int next_size;
|
|
Packit |
a38265 |
ogg_int64_t r;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
mode = (next_packet->packet[0] >> 1) & ((1 << info->log2_num_modes) - 1);
|
|
Packit |
a38265 |
next_size = info->mode_sizes[mode] ? info->long_size : info->short_size;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
r = next_packet_gp - ((this_size + next_size) / 4);
|
|
Packit |
a38265 |
if (r < 0) return 0L;
|
|
Packit |
a38265 |
return r;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/**
|
|
Packit |
a38265 |
* FLAC
|
|
Packit |
a38265 |
* Defined at: http://flac.sourceforge.net/ogg_mapping.html
|
|
Packit |
a38265 |
* - Native FLAC audio frames appear as subsequent packets in the stream.
|
|
Packit |
a38265 |
* Each packet corresponds to one FLAC audio frame.
|
|
Packit |
a38265 |
* - FLAC packets may span page boundaries.
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* The frame header defines block size
|
|
Packit |
a38265 |
* http://flac.sourceforge.net/format.html#frame_header
|
|
Packit |
a38265 |
*
|
|
Packit |
a38265 |
* Note that most FLAC packets will have a granulepos, but rare cases exist
|
|
Packit |
a38265 |
* where they don't. See for example
|
|
Packit |
a38265 |
* http://rafb.net/paste/results/Pkib5w72.html
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
ogg_int64_t previous_gp;
|
|
Packit |
a38265 |
int encountered_first_data_packet;
|
|
Packit |
a38265 |
} auto_calc_flac_info_t;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
auto_calc_flac (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
auto_calc_flac_info_t *info;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) {
|
|
Packit |
a38265 |
stream->calculate_data = oggz_malloc(sizeof(auto_calc_flac_info_t));
|
|
Packit |
a38265 |
if (stream->calculate_data == NULL) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = (auto_calc_flac_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
info->previous_gp = 0;
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* this is a header packet */
|
|
Packit |
a38265 |
goto out;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
info = (auto_calc_flac_info_t *)stream->calculate_data;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* FLAC audio frames begin with marker 0xFF */
|
|
Packit |
a38265 |
if (op->packet[0] == 0xff)
|
|
Packit |
a38265 |
info->encountered_first_data_packet = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (now == -1 && op->packet[0] == 0xff && op->bytes > 2) {
|
|
Packit |
a38265 |
unsigned char bs;
|
|
Packit |
a38265 |
int block_size;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
bs = (op->packet[2] & 0xf0) >> 4;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
switch (bs) {
|
|
Packit |
a38265 |
case 0x0: /* 0000 : get from STREAMINFO metadata block */
|
|
Packit |
a38265 |
block_size = -1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x1: /* 0001 : 192 samples */
|
|
Packit |
a38265 |
block_size = 192;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
/* 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608 */
|
|
Packit |
a38265 |
case 0x2:
|
|
Packit |
a38265 |
block_size = 576;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x3:
|
|
Packit |
a38265 |
block_size = 1152;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x4:
|
|
Packit |
a38265 |
block_size = 2304;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x5:
|
|
Packit |
a38265 |
block_size = 4608;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x6: /* 0110 : get 8 bit (blocksize-1) from end of header */
|
|
Packit |
a38265 |
block_size = -1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x7: /* 0111 : get 16 bit (blocksize-1) from end of header */
|
|
Packit |
a38265 |
block_size = -1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
/* 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768 */
|
|
Packit |
a38265 |
case 0x8:
|
|
Packit |
a38265 |
block_size = 256;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0x9:
|
|
Packit |
a38265 |
block_size = 512;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0xa:
|
|
Packit |
a38265 |
block_size = 1024;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0xb:
|
|
Packit |
a38265 |
block_size = 2048;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0xc:
|
|
Packit |
a38265 |
block_size = 4096;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0xd:
|
|
Packit |
a38265 |
block_size = 8192;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0xe:
|
|
Packit |
a38265 |
block_size = 16384;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 0xf:
|
|
Packit |
a38265 |
block_size = 32768;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
default:
|
|
Packit |
a38265 |
block_size = -1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (block_size != -1) {
|
|
Packit |
a38265 |
now = info->previous_gp + block_size;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else if (now == -1 && info->encountered_first_data_packet == 0) {
|
|
Packit |
a38265 |
/* this is a header packet */
|
|
Packit |
a38265 |
now = 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
out:
|
|
Packit |
a38265 |
info->previous_gp = now;
|
|
Packit |
a38265 |
return now;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
const oggz_auto_contenttype_t oggz_auto_codec_ident[] = {
|
|
Packit |
a38265 |
{"\200theora", 7, "Theora", auto_theora, auto_calc_theora, auto_rcalc_theora},
|
|
Packit |
a38265 |
{"\001vorbis", 7, "Vorbis", auto_vorbis, auto_calc_vorbis, auto_rcalc_vorbis},
|
|
Packit |
a38265 |
{"Speex", 5, "Speex", auto_speex, auto_calc_speex, NULL},
|
|
Packit |
a38265 |
{"PCM ", 8, "PCM", auto_oggpcm2, NULL, NULL},
|
|
Packit |
a38265 |
{"CMML\0\0\0\0", 8, "CMML", auto_cmml, NULL, NULL},
|
|
Packit |
a38265 |
{"Annodex", 7, "Annodex", auto_annodex, NULL, NULL},
|
|
Packit |
a38265 |
{"fishead", 7, "Skeleton", auto_fishead, NULL, NULL},
|
|
Packit |
a38265 |
{"fLaC", 4, "Flac0", auto_flac0, auto_calc_flac, NULL},
|
|
Packit |
a38265 |
{"\177FLAC", 5, "Flac", auto_flac, auto_calc_flac, NULL},
|
|
Packit |
a38265 |
{"AnxData", 7, "AnxData", auto_anxdata, NULL, NULL},
|
|
Packit |
a38265 |
{"CELT ", 8, "CELT", auto_celt, auto_calc_celt, NULL},
|
|
Packit |
a38265 |
{"\200kate\0\0\0", 8, "Kate", auto_kate, NULL, NULL},
|
|
Packit |
a38265 |
{"BBCD\0", 5, "Dirac", auto_dirac, NULL, NULL},
|
|
Packit |
a38265 |
{"", 0, "Unknown", NULL, NULL, NULL}
|
|
Packit |
a38265 |
};
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
oggz_auto_identify (OGGZ * oggz, long serialno, unsigned char * data, long len)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (i = 0; i < OGGZ_CONTENT_UNKNOWN; i++)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
const oggz_auto_contenttype_t *codec = oggz_auto_codec_ident + i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (len >= codec->bos_str_len &&
|
|
Packit |
a38265 |
memcmp (data, codec->bos_str, codec->bos_str_len) == 0) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_content (oggz, serialno, i);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_stream_set_content (oggz, serialno, OGGZ_CONTENT_UNKNOWN);
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_auto_identify_page (OGGZ * oggz, ogg_page *og, long serialno)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
return oggz_auto_identify (oggz, serialno, og->body, og->body_len);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_auto_identify_packet (OGGZ * oggz, ogg_packet * op, long serialno)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
return oggz_auto_identify (oggz, serialno, op->packet, op->bytes);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_auto_read_bos_page (OGGZ * oggz, ogg_page * og, long serialno,
|
|
Packit |
a38265 |
void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int content = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
content = oggz_stream_get_content(oggz, serialno);
|
|
Packit |
a38265 |
if (content < 0 || content >= OGGZ_CONTENT_UNKNOWN) {
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
} else if (content == OGGZ_CONTENT_SKELETON && !ogg_page_bos(og)) {
|
|
Packit |
a38265 |
return auto_fisbone(oggz, serialno, og->body, og->body_len, user_data);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return oggz_auto_codec_ident[content].reader(oggz, serialno, og->body, og->body_len, user_data);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_auto_read_bos_packet (OGGZ * oggz, ogg_packet * op, long serialno,
|
|
Packit |
a38265 |
void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int content = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
content = oggz_stream_get_content(oggz, serialno);
|
|
Packit |
a38265 |
if (content < 0 || content >= OGGZ_CONTENT_UNKNOWN) {
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
} else if (content == OGGZ_CONTENT_SKELETON && !op->b_o_s) {
|
|
Packit |
a38265 |
return auto_fisbone(oggz, serialno, op->packet, op->bytes, user_data);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return oggz_auto_codec_ident[content].reader(oggz, serialno, op->packet, op->bytes, user_data);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ogg_int64_t
|
|
Packit |
a38265 |
oggz_auto_calculate_granulepos(int content, ogg_int64_t now,
|
|
Packit |
a38265 |
oggz_stream_t *stream, ogg_packet *op) {
|
|
Packit |
a38265 |
if (oggz_auto_codec_ident[content].calculator != NULL) {
|
|
Packit |
a38265 |
ogg_int64_t r = oggz_auto_codec_ident[content].calculator(now, stream, op);
|
|
Packit |
a38265 |
return r;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return now;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ogg_int64_t
|
|
Packit |
a38265 |
oggz_auto_calculate_gp_backwards(int content, ogg_int64_t next_packet_gp,
|
|
Packit |
a38265 |
oggz_stream_t *stream, ogg_packet *this_packet, ogg_packet *next_packet) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz_auto_codec_ident[content].r_calculator != NULL) {
|
|
Packit |
a38265 |
return oggz_auto_codec_ident[content].r_calculator(next_packet_gp,
|
|
Packit |
a38265 |
stream, this_packet, next_packet);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_auto_read_comments (OGGZ * oggz, oggz_stream_t * stream, long serialno,
|
|
Packit |
a38265 |
ogg_packet * op)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int offset = -1;
|
|
Packit |
a38265 |
long len = -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
switch (stream->content) {
|
|
Packit |
a38265 |
case OGGZ_CONTENT_VORBIS:
|
|
Packit |
a38265 |
if (op->bytes > 7 && memcmp (op->packet, "\003vorbis", 7) == 0)
|
|
Packit |
a38265 |
offset = 7;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_SPEEX:
|
|
Packit |
a38265 |
offset = 0; break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_THEORA:
|
|
Packit |
a38265 |
if (op->bytes > 7 && memcmp (op->packet, "\201theora", 7) == 0)
|
|
Packit |
a38265 |
offset = 7;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_KATE:
|
|
Packit |
a38265 |
if (op->bytes > 9 && memcmp (op->packet, "\201kate\0\0\0", 8) == 0) {
|
|
Packit |
a38265 |
/* we skip the reserved 0 byte after the signature */
|
|
Packit |
a38265 |
offset = 9;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_FLAC:
|
|
Packit |
a38265 |
if (op->bytes > 4 && (op->packet[0] & 0x7) == 4) {
|
|
Packit |
a38265 |
len = (op->packet[1]<<16) + (op->packet[2]<<8) + op->packet[3];
|
|
Packit |
a38265 |
offset = 4;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
default:
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* The length of the comments to decode is the rest of the packet,
|
|
Packit |
a38265 |
* unless otherwise determined (ie. for FLAC) */
|
|
Packit |
a38265 |
if (len == -1)
|
|
Packit |
a38265 |
len = op->bytes - offset;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (offset >= 0) {
|
|
Packit |
a38265 |
oggz_comments_decode (oggz, serialno, op->packet+offset, len);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|