1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
|
/********************************************************************
* *
* THIS FILE IS PART OF THE OggTheora 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 Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
* *
********************************************************************
function:
last mod: $Id: decinfo.c 16503 2009-08-22 18:14:02Z giles $
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "decint.h"
/*Unpacks a series of octets from a given byte array into the pack buffer.
No checking is done to ensure the buffer contains enough data.
_opb: The pack buffer to read the octets from.
_buf: The byte array to store the unpacked bytes in.
_len: The number of octets to unpack.*/
static void oc_unpack_octets(oc_pack_buf *_opb,char *_buf,size_t _len){
while(_len-->0){
long val;
val=oc_pack_read(_opb,8);
*_buf++=(char)val;
}
}
/*Unpacks a 32-bit integer encoded by octets in little-endian form.*/
static long oc_unpack_length(oc_pack_buf *_opb){
long ret[4];
int i;
for(i=0;i<4;i++)ret[i]=oc_pack_read(_opb,8);
return ret[0]|ret[1]<<8|ret[2]<<16|ret[3]<<24;
}
static int oc_info_unpack(oc_pack_buf *_opb,th_info *_info){
long val;
/*Check the codec bitstream version.*/
val=oc_pack_read(_opb,8);
_info->version_major=(unsigned char)val;
val=oc_pack_read(_opb,8);
_info->version_minor=(unsigned char)val;
val=oc_pack_read(_opb,8);
_info->version_subminor=(unsigned char)val;
/*verify we can parse this bitstream version.
We accept earlier minors and all subminors, by spec*/
if(_info->version_major>TH_VERSION_MAJOR||
_info->version_major==TH_VERSION_MAJOR&&
_info->version_minor>TH_VERSION_MINOR){
return TH_EVERSION;
}
/*Read the encoded frame description.*/
val=oc_pack_read(_opb,16);
_info->frame_width=(ogg_uint32_t)val<<4;
val=oc_pack_read(_opb,16);
_info->frame_height=(ogg_uint32_t)val<<4;
val=oc_pack_read(_opb,24);
_info->pic_width=(ogg_uint32_t)val;
val=oc_pack_read(_opb,24);
_info->pic_height=(ogg_uint32_t)val;
val=oc_pack_read(_opb,8);
_info->pic_x=(ogg_uint32_t)val;
val=oc_pack_read(_opb,8);
_info->pic_y=(ogg_uint32_t)val;
val=oc_pack_read(_opb,32);
_info->fps_numerator=(ogg_uint32_t)val;
val=oc_pack_read(_opb,32);
_info->fps_denominator=(ogg_uint32_t)val;
if(_info->frame_width==0||_info->frame_height==0||
_info->pic_width+_info->pic_x>_info->frame_width||
_info->pic_height+_info->pic_y>_info->frame_height||
_info->fps_numerator==0||_info->fps_denominator==0){
return TH_EBADHEADER;
}
/*Note: The sense of pic_y is inverted in what we pass back to the
application compared to how it is stored in the bitstream.
This is because the bitstream uses a right-handed coordinate system, while
applications expect a left-handed one.*/
_info->pic_y=_info->frame_height-_info->pic_height-_info->pic_y;
val=oc_pack_read(_opb,24);
_info->aspect_numerator=(ogg_uint32_t)val;
val=oc_pack_read(_opb,24);
_info->aspect_denominator=(ogg_uint32_t)val;
val=oc_pack_read(_opb,8);
_info->colorspace=(th_colorspace)val;
val=oc_pack_read(_opb,24);
_info->target_bitrate=(int)val;
val=oc_pack_read(_opb,6);
_info->quality=(int)val;
val=oc_pack_read(_opb,5);
_info->keyframe_granule_shift=(int)val;
val=oc_pack_read(_opb,2);
_info->pixel_fmt=(th_pixel_fmt)val;
if(_info->pixel_fmt==TH_PF_RSVD)return TH_EBADHEADER;
val=oc_pack_read(_opb,3);
if(val!=0||oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER;
return 0;
}
static int oc_comment_unpack(oc_pack_buf *_opb,th_comment *_tc){
long len;
int i;
/*Read the vendor string.*/
len=oc_unpack_length(_opb);
if(len<0||len>oc_pack_bytes_left(_opb))return TH_EBADHEADER;
_tc->vendor=_ogg_malloc((size_t)len+1);
if(_tc->vendor==NULL)return TH_EFAULT;
oc_unpack_octets(_opb,_tc->vendor,len);
_tc->vendor[len]='\0';
/*Read the user comments.*/
_tc->comments=(int)oc_unpack_length(_opb);
len=_tc->comments;
if(len<0||len>(LONG_MAX>>2)||len<<2>oc_pack_bytes_left(_opb)){
_tc->comments=0;
return TH_EBADHEADER;
}
_tc->comment_lengths=(int *)_ogg_malloc(
_tc->comments*sizeof(_tc->comment_lengths[0]));
_tc->user_comments=(char **)_ogg_malloc(
_tc->comments*sizeof(_tc->user_comments[0]));
for(i=0;i<_tc->comments;i++){
len=oc_unpack_length(_opb);
if(len<0||len>oc_pack_bytes_left(_opb)){
_tc->comments=i;
return TH_EBADHEADER;
}
_tc->comment_lengths[i]=len;
_tc->user_comments[i]=_ogg_malloc((size_t)len+1);
if(_tc->user_comments[i]==NULL){
_tc->comments=i;
return TH_EFAULT;
}
oc_unpack_octets(_opb,_tc->user_comments[i],len);
_tc->user_comments[i][len]='\0';
}
return oc_pack_bytes_left(_opb)<0?TH_EBADHEADER:0;
}
static int oc_setup_unpack(oc_pack_buf *_opb,th_setup_info *_setup){
int ret;
/*Read the quantizer tables.*/
ret=oc_quant_params_unpack(_opb,&_setup->qinfo);
if(ret<0)return ret;
/*Read the Huffman trees.*/
return oc_huff_trees_unpack(_opb,_setup->huff_tables);
}
static void oc_setup_clear(th_setup_info *_setup){
oc_quant_params_clear(&_setup->qinfo);
oc_huff_trees_clear(_setup->huff_tables);
}
static int oc_dec_headerin(oc_pack_buf *_opb,th_info *_info,
th_comment *_tc,th_setup_info **_setup,ogg_packet *_op){
char buffer[6];
long val;
int packtype;
int ret;
val=oc_pack_read(_opb,8);
packtype=(int)val;
/*If we're at a data packet and we have received all three headers, we're
done.*/
if(!(packtype&0x80)&&_info->frame_width>0&&_tc->vendor!=NULL&&*_setup!=NULL){
return 0;
}
/*Check the codec string.*/
oc_unpack_octets(_opb,buffer,6);
if(memcmp(buffer,"theora",6)!=0)return TH_ENOTFORMAT;
switch(packtype){
/*Codec info header.*/
case 0x80:{
/*This should be the first packet, and we should not already be
initialized.*/
if(!_op->b_o_s||_info->frame_width>0)return TH_EBADHEADER;
ret=oc_info_unpack(_opb,_info);
if(ret<0)th_info_clear(_info);
else ret=3;
}break;
/*Comment header.*/
case 0x81:{
if(_tc==NULL)return TH_EFAULT;
/*We shoud have already decoded the info header, and should not yet have
decoded the comment header.*/
if(_info->frame_width==0||_tc->vendor!=NULL)return TH_EBADHEADER;
ret=oc_comment_unpack(_opb,_tc);
if(ret<0)th_comment_clear(_tc);
else ret=2;
}break;
/*Codec setup header.*/
case 0x82:{
oc_setup_info *setup;
if(_tc==NULL||_setup==NULL)return TH_EFAULT;
/*We should have already decoded the info header and the comment header,
and should not yet have decoded the setup header.*/
if(_info->frame_width==0||_tc->vendor==NULL||*_setup!=NULL){
return TH_EBADHEADER;
}
setup=(oc_setup_info *)_ogg_calloc(1,sizeof(*setup));
if(setup==NULL)return TH_EFAULT;
ret=oc_setup_unpack(_opb,setup);
if(ret<0){
oc_setup_clear(setup);
_ogg_free(setup);
}
else{
*_setup=setup;
ret=1;
}
}break;
default:{
/*We don't know what this header is.*/
return TH_EBADHEADER;
}break;
}
return ret;
}
/*Decodes one header packet.
This should be called repeatedly with the packets at the beginning of the
stream until it returns 0.*/
int th_decode_headerin(th_info *_info,th_comment *_tc,
th_setup_info **_setup,ogg_packet *_op){
oc_pack_buf opb;
if(_op==NULL)return TH_EBADHEADER;
if(_info==NULL)return TH_EFAULT;
oc_pack_readinit(&opb,_op->packet,_op->bytes);
return oc_dec_headerin(&opb,_info,_tc,_setup,_op);
}
void th_setup_free(th_setup_info *_setup){
if(_setup!=NULL){
oc_setup_clear(_setup);
_ogg_free(_setup);
}
}
|