From 57ce0321c8971f964008920003a3e8b19649df85 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 3 Feb 2002 16:30:31 +0000 Subject: Added a tarkin encoder/decoder plugin. Original commit message from CVS: Added a tarkin encoder/decoder plugin. I moved the tarking CVS code in here temporarily until they have a library (hence this plugin is in ext) test with: ./gst-launch filesrc location=/opt/data/shihad.mpg ! mpegdemux video_00! { queue ! mpeg2dec ! colorspace ! tarkinenc bitrate=3000 ! disksink location=out.ogg } ./gst-launch filesrc location=out.ogg ! tarkindec ! colorspace ! xvideosink --- ext/tarkin/info.c | 551 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 ext/tarkin/info.c (limited to 'ext/tarkin/info.c') diff --git a/ext/tarkin/info.c b/ext/tarkin/info.c new file mode 100644 index 00000000..e555e381 --- /dev/null +++ b/ext/tarkin/info.c @@ -0,0 +1,551 @@ +/******************************************************************** + * * + * 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) */ + +#include +#include +#include +#include +#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;icomments;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;icomments;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;icomments;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;icomments;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;in_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; jn_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;icomments;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;in_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); +} + -- cgit v1.2.1