mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 15:51:11 +00:00
4fd57bbe3f
Original commit message from CVS: don't mix tabs and spaces
621 lines
16 KiB
C
621 lines
16 KiB
C
/********************************************************************
|
|
* *
|
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
|
* *
|
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
|
|
* by the XIPHOPHORUS Company http://www.xiph.org/ *
|
|
|
|
********************************************************************
|
|
|
|
function: maintain the info structure, info <-> header packets
|
|
last mod: $Id$
|
|
|
|
********************************************************************/
|
|
|
|
/* general handling of the header and the TarkinInfo structure (and
|
|
substructures) */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <ogg/ogg.h>
|
|
#include "tarkin.h"
|
|
#include "yuv.h"
|
|
#include "mem.h"
|
|
|
|
/* helpers */
|
|
static void
|
|
_v_writestring (oggpack_buffer * o, char *s, int bytes)
|
|
{
|
|
while (bytes--) {
|
|
oggpack_write (o, *s++, 8);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_v_readstring (oggpack_buffer * o, char *buf, int bytes)
|
|
{
|
|
while (bytes--) {
|
|
*buf++ = oggpack_read (o, 8);
|
|
}
|
|
}
|
|
|
|
void
|
|
tarkin_comment_init (TarkinComment * vc)
|
|
{
|
|
memset (vc, 0, sizeof (*vc));
|
|
}
|
|
|
|
void
|
|
tarkin_comment_add (TarkinComment * vc, char *comment)
|
|
{
|
|
vc->user_comments = REALLOC (vc->user_comments,
|
|
(vc->comments + 2) * sizeof (*vc->user_comments));
|
|
vc->comment_lengths = REALLOC (vc->comment_lengths,
|
|
(vc->comments + 2) * sizeof (*vc->comment_lengths));
|
|
vc->comment_lengths[vc->comments] = strlen (comment);
|
|
vc->user_comments[vc->comments] =
|
|
MALLOC (vc->comment_lengths[vc->comments] + 1);
|
|
strcpy (vc->user_comments[vc->comments], comment);
|
|
vc->comments++;
|
|
vc->user_comments[vc->comments] = NULL;
|
|
}
|
|
|
|
void
|
|
tarkin_comment_add_tag (TarkinComment * vc, char *tag, char *contents)
|
|
{
|
|
char *comment = alloca (strlen (tag) + strlen (contents) + 2); /* +2 for = and \0 */
|
|
|
|
strcpy (comment, tag);
|
|
strcat (comment, "=");
|
|
strcat (comment, contents);
|
|
tarkin_comment_add (vc, comment);
|
|
}
|
|
|
|
/* This is more or less the same as strncasecmp - but that doesn't exist
|
|
* everywhere, and this is a fairly trivial function, so we include it */
|
|
static int
|
|
tagcompare (const char *s1, const char *s2, int n)
|
|
{
|
|
int c = 0;
|
|
|
|
while (c < n) {
|
|
if (toupper (s1[c]) != toupper (s2[c]))
|
|
return !0;
|
|
c++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
tarkin_comment_query (TarkinComment * vc, char *tag, int count)
|
|
{
|
|
long i;
|
|
int found = 0;
|
|
int taglen = strlen (tag) + 1; /* +1 for the = we append */
|
|
char *fulltag = alloca (taglen + 1);
|
|
|
|
strcpy (fulltag, tag);
|
|
strcat (fulltag, "=");
|
|
|
|
for (i = 0; i < vc->comments; i++) {
|
|
if (!tagcompare (vc->user_comments[i], fulltag, taglen)) {
|
|
if (count == found)
|
|
/* We return a pointer to the data, not a copy */
|
|
return vc->user_comments[i] + taglen;
|
|
else
|
|
found++;
|
|
}
|
|
}
|
|
return NULL; /* didn't find anything */
|
|
}
|
|
|
|
int
|
|
tarkin_comment_query_count (TarkinComment * vc, char *tag)
|
|
{
|
|
int i, count = 0;
|
|
int taglen = strlen (tag) + 1; /* +1 for the = we append */
|
|
char *fulltag = alloca (taglen + 1);
|
|
|
|
strcpy (fulltag, tag);
|
|
strcat (fulltag, "=");
|
|
|
|
for (i = 0; i < vc->comments; i++) {
|
|
if (!tagcompare (vc->user_comments[i], fulltag, taglen))
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
void
|
|
tarkin_comment_clear (TarkinComment * vc)
|
|
{
|
|
if (vc) {
|
|
long i;
|
|
|
|
for (i = 0; i < vc->comments; i++)
|
|
if (vc->user_comments[i])
|
|
FREE (vc->user_comments[i]);
|
|
if (vc->user_comments)
|
|
FREE (vc->user_comments);
|
|
if (vc->comment_lengths)
|
|
FREE (vc->comment_lengths);
|
|
if (vc->vendor)
|
|
FREE (vc->vendor);
|
|
}
|
|
memset (vc, 0, sizeof (*vc));
|
|
}
|
|
|
|
/* used by synthesis, which has a full, alloced vi */
|
|
void
|
|
tarkin_info_init (TarkinInfo * vi)
|
|
{
|
|
memset (vi, 0, sizeof (*vi));
|
|
}
|
|
|
|
void
|
|
tarkin_info_clear (TarkinInfo * vi)
|
|
{
|
|
memset (vi, 0, sizeof (*vi));
|
|
}
|
|
|
|
/* Header packing/unpacking ********************************************/
|
|
|
|
static int
|
|
_tarkin_unpack_info (TarkinInfo * vi, oggpack_buffer * opb)
|
|
{
|
|
#ifdef DBG_OGG
|
|
printf ("dbg_ogg: Decoding Info: ");
|
|
#endif
|
|
vi->version = oggpack_read (opb, 32);
|
|
if (vi->version != 0)
|
|
return (-TARKIN_VERSION);
|
|
|
|
vi->n_layers = oggpack_read (opb, 8);
|
|
vi->inter.numerator = oggpack_read (opb, 32);
|
|
vi->inter.denominator = oggpack_read (opb, 32);
|
|
|
|
vi->bitrate_upper = oggpack_read (opb, 32);
|
|
vi->bitrate_nominal = oggpack_read (opb, 32);
|
|
vi->bitrate_lower = oggpack_read (opb, 32);
|
|
|
|
#ifdef DBG_OGG
|
|
printf (" n_layers %d, interleave: %d/%d, ",
|
|
vi->n_layers, vi->inter.numerator, vi->inter.denominator);
|
|
#endif
|
|
|
|
if (vi->inter.numerator < 1)
|
|
goto err_out;
|
|
if (vi->inter.denominator < 1)
|
|
goto err_out;
|
|
if (vi->n_layers < 1)
|
|
goto err_out;
|
|
|
|
if (oggpack_read (opb, 1) != 1)
|
|
goto err_out; /* EOP check */
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("Success\n");
|
|
#endif
|
|
return (0);
|
|
err_out:
|
|
#ifdef DBG_OGG
|
|
printf ("Failed\n");
|
|
#endif
|
|
tarkin_info_clear (vi);
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
static int
|
|
_tarkin_unpack_comment (TarkinComment * vc, oggpack_buffer * opb)
|
|
{
|
|
int i;
|
|
int vendorlen = oggpack_read (opb, 32);
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("dbg_ogg: Decoding comment: ");
|
|
#endif
|
|
if (vendorlen < 0)
|
|
goto err_out;
|
|
vc->vendor = _ogg_calloc (vendorlen + 1, 1);
|
|
_v_readstring (opb, vc->vendor, vendorlen);
|
|
vc->comments = oggpack_read (opb, 32);
|
|
if (vc->comments < 0)
|
|
goto err_out;
|
|
vc->user_comments =
|
|
_ogg_calloc (vc->comments + 1, sizeof (*vc->user_comments));
|
|
vc->comment_lengths =
|
|
_ogg_calloc (vc->comments + 1, sizeof (*vc->comment_lengths));
|
|
|
|
for (i = 0; i < vc->comments; i++) {
|
|
int len = oggpack_read (opb, 32);
|
|
|
|
if (len < 0)
|
|
goto err_out;
|
|
vc->comment_lengths[i] = len;
|
|
vc->user_comments[i] = _ogg_calloc (len + 1, 1);
|
|
_v_readstring (opb, vc->user_comments[i], len);
|
|
}
|
|
if (oggpack_read (opb, 1) != 1)
|
|
goto err_out; /* EOP check */
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("Success, read %d comments\n", vc->comments);
|
|
#endif
|
|
return (0);
|
|
err_out:
|
|
#ifdef DBG_OGG
|
|
printf ("Failed\n");
|
|
#endif
|
|
tarkin_comment_clear (vc);
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
/* the real encoding details are here, currently TarkinVideoLayerDesc. */
|
|
static int
|
|
_tarkin_unpack_layer_desc (TarkinInfo * vi, oggpack_buffer * opb)
|
|
{
|
|
int i, j;
|
|
|
|
vi->layer = CALLOC (vi->n_layers, (sizeof (*vi->layer)));
|
|
memset (vi->layer, 0, vi->n_layers * sizeof (*vi->layer));
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("ogg: Decoding layers description: ");
|
|
#endif
|
|
for (i = 0; i < vi->n_layers; i++) {
|
|
TarkinVideoLayer *layer = vi->layer + i;
|
|
|
|
layer->desc.width = oggpack_read (opb, 32);
|
|
layer->desc.height = oggpack_read (opb, 32);
|
|
layer->desc.a_moments = oggpack_read (opb, 32);
|
|
layer->desc.s_moments = oggpack_read (opb, 32);
|
|
layer->desc.frames_per_buf = oggpack_read (opb, 32);
|
|
layer->desc.bitstream_len = oggpack_read (opb, 32);
|
|
layer->desc.format = oggpack_read (opb, 32);
|
|
|
|
switch (layer->desc.format) {
|
|
case TARKIN_GRAYSCALE:
|
|
layer->n_comp = 1;
|
|
layer->color_fwd_xform = grayscale_to_y;
|
|
layer->color_inv_xform = y_to_grayscale;
|
|
break;
|
|
case TARKIN_RGB24:
|
|
layer->n_comp = 3;
|
|
layer->color_fwd_xform = rgb24_to_yuv;
|
|
layer->color_inv_xform = yuv_to_rgb24;
|
|
break;
|
|
case TARKIN_RGB32:
|
|
layer->n_comp = 3;
|
|
layer->color_fwd_xform = rgb32_to_yuv;
|
|
layer->color_inv_xform = yuv_to_rgb32;
|
|
break;
|
|
case TARKIN_RGBA:
|
|
layer->n_comp = 4;
|
|
layer->color_fwd_xform = rgba_to_yuv;
|
|
layer->color_inv_xform = yuv_to_rgba;
|
|
break;
|
|
default:
|
|
return -TARKIN_INVALID_COLOR_FORMAT;
|
|
};
|
|
|
|
layer->waveletbuf = (Wavelet3DBuf **) CALLOC (layer->n_comp,
|
|
sizeof (Wavelet3DBuf *));
|
|
|
|
layer->packet = MALLOC (layer->n_comp * sizeof (*layer->packet));
|
|
memset (layer->packet, 0, layer->n_comp * sizeof (*layer->packet));
|
|
|
|
for (j = 0; j < layer->n_comp; j++) {
|
|
layer->waveletbuf[j] = wavelet_3d_buf_new (layer->desc.width,
|
|
layer->desc.height, layer->desc.frames_per_buf);
|
|
layer->packet[j].data = MALLOC (layer->desc.bitstream_len);
|
|
layer->packet[j].storage = layer->desc.bitstream_len;
|
|
}
|
|
|
|
vi->max_bitstream_len += layer->desc.bitstream_len + 2 * 10 * sizeof (uint32_t) * layer->n_comp; /* truncation tables */
|
|
|
|
#ifdef DBG_OGG
|
|
printf
|
|
("\n layer%d: size %dx%dx%d, format %d, a_m %d, s_m %d, %d fpb\n",
|
|
i, layer->desc.width, layer->desc.height, layer->n_comp,
|
|
layer->desc.format, layer->desc.a_moments, layer->desc.s_moments,
|
|
layer->desc.frames_per_buf);
|
|
#endif
|
|
} /* for each layer */
|
|
|
|
if (oggpack_read (opb, 1) != 1)
|
|
goto err_out; /* EOP check */
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("Success\n");
|
|
#endif
|
|
|
|
return (0);
|
|
err_out:
|
|
#ifdef DBG_OGG
|
|
printf ("Failed\n");
|
|
#endif
|
|
tarkin_info_clear (vi);
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
/* The Tarkin header is in three packets; the initial small packet in
|
|
the first page that identifies basic parameters, a second packet
|
|
with bitstream comments and a third packet that holds the
|
|
layer description structures. */
|
|
|
|
TarkinError
|
|
tarkin_synthesis_headerin (TarkinInfo * vi, TarkinComment * vc, ogg_packet * op)
|
|
{
|
|
oggpack_buffer opb;
|
|
|
|
if (op) {
|
|
oggpack_readinit (&opb, op->packet, op->bytes);
|
|
|
|
/* Which of the three types of header is this? */
|
|
/* Also verify header-ness, tarkin */
|
|
{
|
|
char buffer[6];
|
|
int packtype = oggpack_read (&opb, 8);
|
|
|
|
memset (buffer, 0, 6);
|
|
_v_readstring (&opb, buffer, 6);
|
|
if (memcmp (buffer, "tarkin", 6)) {
|
|
/* not a tarkin header */
|
|
return (-TARKIN_NOT_TARKIN);
|
|
}
|
|
switch (packtype) {
|
|
case 0x01: /* least significant *bit* is read first */
|
|
if (!op->b_o_s) {
|
|
/* Not the initial packet */
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
if (vi->inter.numerator != 0) {
|
|
/* previously initialized info header */
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
return (_tarkin_unpack_info (vi, &opb));
|
|
|
|
case 0x03: /* least significant *bit* is read first */
|
|
if (vi->inter.denominator == 0) {
|
|
/* um... we didn't get the initial header */
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
return (_tarkin_unpack_comment (vc, &opb));
|
|
|
|
case 0x05: /* least significant *bit* is read first */
|
|
if (vi->inter.numerator == 0 || vc->vendor == NULL) {
|
|
/* um... we didn;t get the initial header or comments yet */
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
return (_tarkin_unpack_layer_desc (vi, &opb));
|
|
|
|
default:
|
|
/* Not a valid tarkin header type */
|
|
return (-TARKIN_BAD_HEADER);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (-TARKIN_BAD_HEADER);
|
|
}
|
|
|
|
/* pack side **********************************************************/
|
|
|
|
static int
|
|
_tarkin_pack_info (oggpack_buffer * opb, TarkinInfo * vi)
|
|
{
|
|
|
|
/* preamble */
|
|
oggpack_write (opb, 0x01, 8);
|
|
_v_writestring (opb, "tarkin", 6);
|
|
|
|
/* basic information about the stream */
|
|
oggpack_write (opb, 0x00, 32);
|
|
oggpack_write (opb, vi->n_layers, 8);
|
|
oggpack_write (opb, vi->inter.numerator, 32);
|
|
oggpack_write (opb, vi->inter.denominator, 32);
|
|
|
|
oggpack_write (opb, vi->bitrate_upper, 32);
|
|
oggpack_write (opb, vi->bitrate_nominal, 32);
|
|
oggpack_write (opb, vi->bitrate_lower, 32);
|
|
|
|
oggpack_write (opb, 1, 1);
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("dbg_ogg: Putting out info, inter %d/%d, n_layers %d\n",
|
|
vi->inter.numerator, vi->inter.denominator, vi->n_layers);
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
_tarkin_pack_comment (oggpack_buffer * opb, TarkinComment * vc)
|
|
{
|
|
char temp[] = "libTarkin debugging edition 20011104";
|
|
int bytes = strlen (temp);
|
|
|
|
/* preamble */
|
|
oggpack_write (opb, 0x03, 8);
|
|
_v_writestring (opb, "tarkin", 6);
|
|
|
|
/* vendor */
|
|
oggpack_write (opb, bytes, 32);
|
|
_v_writestring (opb, temp, bytes);
|
|
|
|
/* comments */
|
|
|
|
oggpack_write (opb, vc->comments, 32);
|
|
if (vc->comments) {
|
|
int i;
|
|
|
|
for (i = 0; i < vc->comments; i++) {
|
|
if (vc->user_comments[i]) {
|
|
oggpack_write (opb, vc->comment_lengths[i], 32);
|
|
_v_writestring (opb, vc->user_comments[i], vc->comment_lengths[i]);
|
|
} else {
|
|
oggpack_write (opb, 0, 32);
|
|
}
|
|
}
|
|
}
|
|
oggpack_write (opb, 1, 1);
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("dbg_ogg: Putting out %d comments\n", vc->comments);
|
|
#endif
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
_tarkin_pack_layer_desc (oggpack_buffer * opb, TarkinInfo * vi)
|
|
{
|
|
int i;
|
|
TarkinVideoLayer *layer;
|
|
|
|
#ifdef DBG_OGG
|
|
printf ("dbg_ogg: Putting out layers description:\n");
|
|
#endif
|
|
|
|
oggpack_write (opb, 0x05, 8);
|
|
_v_writestring (opb, "tarkin", 6);
|
|
|
|
for (i = 0; i < vi->n_layers; i++) {
|
|
layer = vi->layer + i;
|
|
oggpack_write (opb, layer->desc.width, 32);
|
|
oggpack_write (opb, layer->desc.height, 32);
|
|
oggpack_write (opb, layer->desc.a_moments, 32);
|
|
oggpack_write (opb, layer->desc.s_moments, 32);
|
|
oggpack_write (opb, layer->desc.frames_per_buf, 32);
|
|
oggpack_write (opb, layer->desc.bitstream_len, 32);
|
|
oggpack_write (opb, layer->desc.format, 32);
|
|
|
|
#ifdef DBG_OGG
|
|
printf (" res. %dx%d, format %d, a_m %d, s_m %d, fpb %d\n",
|
|
layer->desc.width, layer->desc.height, layer->desc.format,
|
|
layer->desc.a_moments, layer->desc.s_moments,
|
|
layer->desc.frames_per_buf);
|
|
#endif
|
|
|
|
}
|
|
oggpack_write (opb, 1, 1);
|
|
|
|
#ifdef DBG_OGG
|
|
printf (" wrote %ld bytes.\n", oggpack_bytes (opb));
|
|
#endif
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
tarkin_comment_header_out (TarkinComment * vc, ogg_packet * op)
|
|
{
|
|
|
|
oggpack_buffer opb;
|
|
|
|
oggpack_writeinit (&opb);
|
|
if (_tarkin_pack_comment (&opb, vc))
|
|
return -TARKIN_NOT_IMPLEMENTED;
|
|
|
|
op->packet = MALLOC (oggpack_bytes (&opb));
|
|
memcpy (op->packet, opb.buffer, oggpack_bytes (&opb));
|
|
|
|
op->bytes = oggpack_bytes (&opb);
|
|
op->b_o_s = 0;
|
|
op->e_o_s = 0;
|
|
op->granulepos = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
TarkinError
|
|
tarkin_analysis_headerout (TarkinStream * v,
|
|
TarkinComment * vc,
|
|
ogg_packet * op, ogg_packet * op_comm, ogg_packet * op_code)
|
|
{
|
|
int ret = -TARKIN_NOT_IMPLEMENTED;
|
|
TarkinInfo *vi;
|
|
oggpack_buffer opb;
|
|
tarkin_header_store *b = &v->headers;
|
|
|
|
vi = v->ti;
|
|
|
|
/* first header packet ********************************************* */
|
|
|
|
oggpack_writeinit (&opb);
|
|
if (_tarkin_pack_info (&opb, vi))
|
|
goto err_out;
|
|
|
|
/* build the packet */
|
|
if (b->header)
|
|
FREE (b->header);
|
|
b->header = MALLOC (oggpack_bytes (&opb));
|
|
memcpy (b->header, opb.buffer, oggpack_bytes (&opb));
|
|
op->packet = b->header;
|
|
op->bytes = oggpack_bytes (&opb);
|
|
op->b_o_s = 1;
|
|
op->e_o_s = 0;
|
|
op->granulepos = 0;
|
|
|
|
/* second header packet (comments) ********************************* */
|
|
|
|
oggpack_reset (&opb);
|
|
if (_tarkin_pack_comment (&opb, vc))
|
|
goto err_out;
|
|
|
|
if (b->header1)
|
|
FREE (b->header1);
|
|
b->header1 = MALLOC (oggpack_bytes (&opb));
|
|
memcpy (b->header1, opb.buffer, oggpack_bytes (&opb));
|
|
op_comm->packet = b->header1;
|
|
op_comm->bytes = oggpack_bytes (&opb);
|
|
op_comm->b_o_s = 0;
|
|
op_comm->e_o_s = 0;
|
|
op_comm->granulepos = 0;
|
|
|
|
/* third header packet (modes/codebooks) *************************** */
|
|
|
|
oggpack_reset (&opb);
|
|
if (_tarkin_pack_layer_desc (&opb, vi))
|
|
goto err_out;
|
|
|
|
if (b->header2)
|
|
FREE (b->header2);
|
|
b->header2 = MALLOC (oggpack_bytes (&opb));
|
|
memcpy (b->header2, opb.buffer, oggpack_bytes (&opb));
|
|
op_code->packet = b->header2;
|
|
op_code->bytes = oggpack_bytes (&opb);
|
|
op_code->b_o_s = 0;
|
|
op_code->e_o_s = 0;
|
|
op_code->granulepos = 0;
|
|
|
|
oggpack_writeclear (&opb);
|
|
return (0);
|
|
err_out:
|
|
oggpack_writeclear (&opb);
|
|
memset (op, 0, sizeof (*op));
|
|
memset (op_comm, 0, sizeof (*op_comm));
|
|
memset (op_code, 0, sizeof (*op_code));
|
|
|
|
if (b->header)
|
|
FREE (b->header);
|
|
if (b->header1)
|
|
FREE (b->header1);
|
|
if (b->header2)
|
|
FREE (b->header2);
|
|
b->header = NULL;
|
|
b->header1 = NULL;
|
|
b->header2 = NULL;
|
|
return (ret);
|
|
}
|