Blame src/liboggz/oggz_auto.c

Packit a38265
/*
Packit a38265
   Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Packit a38265
   Organisation (CSIRO) Australia
Packit a38265
Packit a38265
   Redistribution and use in source and binary forms, with or without
Packit a38265
   modification, are permitted provided that the following conditions
Packit a38265
   are met:
Packit a38265
Packit a38265
   - Redistributions of source code must retain the above copyright
Packit a38265
   notice, this list of conditions and the following disclaimer.
Packit a38265
Packit a38265
   - Redistributions in binary form must reproduce the above copyright
Packit a38265
   notice, this list of conditions and the following disclaimer in the
Packit a38265
   documentation and/or other materials provided with the distribution.
Packit a38265
Packit a38265
   - Neither the name of CSIRO Australia nor the names of its
Packit a38265
   contributors may be used to endorse or promote products derived from
Packit a38265
   this software without specific prior written permission.
Packit a38265
Packit a38265
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit a38265
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit a38265
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
Packit a38265
   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
Packit a38265
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
Packit a38265
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
Packit a38265
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
Packit a38265
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
Packit a38265
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
Packit a38265
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit a38265
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit a38265
*/
Packit a38265
Packit a38265
/*
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