1 /********************************************************************
3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2005 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
16 ********************************************************************/
24 #include "theora/theora.h"
28 static int _ilog(unsigned int v
){
37 const char *theora_version_string(void){
41 ogg_uint32_t
theora_version_number(void){
42 return (VERSION_MAJOR
<<16) + (VERSION_MINOR
<<8) + (VERSION_SUB
);
46 static void _tp_readbuffer(oggpack_buffer
*opb
, char *buf
, const long len
)
51 for (i
= 0; i
< len
; i
++) {
52 theora_read(opb
, 8, &ret
);
57 static void _tp_readlsbint(oggpack_buffer
*opb
, long *value
)
62 for (i
= 0; i
< 4; i
++) {
63 theora_read(opb
,8,&ret
[i
]);
65 *value
= ret
[0]|ret
[1]<<8|ret
[2]<<16|ret
[3]<<24;
68 void theora_info_init(theora_info
*c
) {
69 memset(c
,0,sizeof(*c
));
70 c
->codec_setup
=_ogg_calloc(1,sizeof(codec_setup_info
));
73 void theora_info_clear(theora_info
*c
) {
74 codec_setup_info
*ci
=c
->codec_setup
;
77 if(ci
->qmats
) _ogg_free(ci
->qmats
);
79 if(ci
->range_table
[i
]) _ogg_free(ci
->range_table
[i
]);
80 ClearHuffmanTrees(ci
->HuffRoot
);
83 memset(c
,0,sizeof(*c
));
86 void theora_clear(theora_state
*t
){
88 CP_INSTANCE
*cpi
=(CP_INSTANCE
*)(t
->internal_encode
);
89 PB_INSTANCE
*pbi
=(PB_INSTANCE
*)(t
->internal_decode
);
91 if (cpi
) theora_encoder_clear (cpi
);
95 theora_info_clear(&pbi
->info
);
97 ClearFragmentInfo(pbi
);
101 _ogg_free(t
->internal_decode
);
104 t
->internal_encode
=NULL
;
105 t
->internal_decode
=NULL
;
109 /********************** The toplevel: decode ***********************/
111 static int _theora_unpack_info(theora_info
*ci
, oggpack_buffer
*opb
){
114 theora_read(opb
,8,&ret
);
115 ci
->version_major
=(unsigned char)ret
;
116 theora_read(opb
,8,&ret
);
117 ci
->version_minor
=(unsigned char)ret
;
118 theora_read(opb
,8,&ret
);
119 ci
->version_subminor
=(unsigned char)ret
;
121 if(ci
->version_major
!=VERSION_MAJOR
)return(OC_VERSION
);
122 if(ci
->version_minor
>VERSION_MINOR
)return(OC_VERSION
);
124 theora_read(opb
,16,&ret
);
126 theora_read(opb
,16,&ret
);
128 theora_read(opb
,24,&ret
);
130 theora_read(opb
,24,&ret
);
131 ci
->frame_height
=ret
;
132 theora_read(opb
,8,&ret
);
134 theora_read(opb
,8,&ret
);
136 /* Change offset_y to have the meaning everyone expects it to have */
137 ci
->offset_y
= ci
->height
- ci
->frame_height
- ci
->offset_y
;
139 theora_read(opb
,32,&ret
);
140 ci
->fps_numerator
=ret
;
141 theora_read(opb
,32,&ret
);
142 ci
->fps_denominator
=ret
;
143 theora_read(opb
,24,&ret
);
144 ci
->aspect_numerator
=ret
;
145 theora_read(opb
,24,&ret
);
146 ci
->aspect_denominator
=ret
;
148 theora_read(opb
,8,&ret
);
150 theora_read(opb
,24,&ret
);
151 ci
->target_bitrate
=ret
;
152 theora_read(opb
,6,&ret
);
155 theora_read(opb
,5,&ret
);
156 ci
->keyframe_frequency_force
=1<<ret
;
158 theora_read(opb
,2,&ret
);
160 if(ci
->pixelformat
==OC_PF_RSVD
)
161 return (OC_BADHEADER
);
162 /* 4:2:2 and 4:4:4 not currently implemented */
163 else if(ci
->pixelformat
!= OC_PF_420
)
166 /* spare configuration bits */
167 if ( theora_read(opb
,3,&ret
) == -1 )
168 return (OC_BADHEADER
);
173 static int _theora_unpack_comment(theora_comment
*tc
, oggpack_buffer
*opb
){
177 _tp_readlsbint(opb
,&len
);
178 if(len
<0)return(OC_BADHEADER
);
179 tc
->vendor
=_ogg_calloc(1,len
+1);
180 _tp_readbuffer(opb
,tc
->vendor
, len
);
181 tc
->vendor
[len
]='\0';
183 _tp_readlsbint(opb
,&tmp
);
185 if(tc
->comments
<0)goto parse_err
;
186 tc
->user_comments
=_ogg_calloc(tc
->comments
,sizeof(*tc
->user_comments
));
187 tc
->comment_lengths
=_ogg_calloc(tc
->comments
,sizeof(*tc
->comment_lengths
));
188 for(i
=0;i
<tc
->comments
;i
++){
189 _tp_readlsbint(opb
,&len
);
190 if(len
<0)goto parse_err
;
191 tc
->user_comments
[i
]=_ogg_calloc(1,len
+1);
192 _tp_readbuffer(opb
,tc
->user_comments
[i
],len
);
193 tc
->user_comments
[i
][len
]='\0';
194 tc
->comment_lengths
[i
]=len
;
199 theora_comment_clear(tc
);
200 return(OC_BADHEADER
);
203 static int _theora_unpack_tables(theora_info
*c
, oggpack_buffer
*opb
){
204 codec_setup_info
*ci
;
207 ci
=(codec_setup_info
*)c
->codec_setup
;
209 ret
=ReadFilterTables(ci
, opb
);
211 ret
=ReadQTables(ci
, opb
);
213 ret
=ReadHuffmanTrees(ci
, opb
);
219 int theora_decode_header(theora_info
*ci
, theora_comment
*cc
, ogg_packet
*op
){
223 if(!op
)return OC_BADHEADER
;
226 opb
= _ogg_malloc(sizeof(oggpack_buffer
));
227 oggpackB_readinit(opb
,op
->packet
,op
->bytes
);
229 opb
= _ogg_malloc(oggpack_buffersize());
230 oggpackB_readinit(opb
,op
->packet
);
236 theora_read(opb
,8,&ret
);
238 if(!(typeflag
&0x80)) {
240 return(OC_NOTFORMAT
);
243 _tp_readbuffer(opb
,id
,6);
244 if(memcmp(id
,"theora",6)) {
246 return(OC_NOTFORMAT
);
252 /* Not the initial packet */
254 return(OC_BADHEADER
);
256 if(ci
->version_major
!=0){
257 /* previously initialized info header */
262 ret
= _theora_unpack_info(ci
,opb
);
267 if(ci
->version_major
==0){
268 /* um... we didn't get the initial header */
270 return(OC_BADHEADER
);
273 ret
= _theora_unpack_comment(cc
,opb
);
278 if(ci
->version_major
==0 || cc
->vendor
==NULL
){
279 /* um... we didn't get the initial header or comments yet */
281 return(OC_BADHEADER
);
284 ret
= _theora_unpack_tables(ci
,opb
);
290 if(ci
->version_major
==0 || cc
->vendor
==NULL
||
291 ((codec_setup_info
*)ci
->codec_setup
)->HuffRoot
[0]==NULL
){
292 /* we haven't gotten the three required headers */
293 return(OC_BADHEADER
);
295 /* ignore any trailing header packets for forward compatibility */
296 return(OC_NEWPACKET
);
299 /* I don't think it's possible to get this far, but better safe.. */
301 return(OC_BADHEADER
);
304 int theora_decode_init(theora_state
*th
, theora_info
*c
){
306 codec_setup_info
*ci
;
308 ci
=(codec_setup_info
*)c
->codec_setup
;
309 memset(th
, 0, sizeof(*th
));
310 th
->internal_decode
=pbi
=_ogg_calloc(1,sizeof(*pbi
));
311 th
->internal_encode
=NULL
;
315 dsp_static_init (&pbi
->dsp
);
317 memcpy(&pbi
->info
,c
,sizeof(*c
));
318 pbi
->info
.codec_setup
=NULL
;
322 InitFrameDetails(pbi
);
324 pbi
->keyframe_granule_shift
=_ilog(c
->keyframe_frequency_force
-1);
326 pbi
->LastFrameQualityValue
= 0;
327 pbi
->DecoderErrorCode
= 0;
329 /* Clear down the YUVtoRGB conversion skipped list. */
330 memset(pbi
->skipped_display_fragments
, 0, pbi
->UnitFragments
);
332 /* Initialise quantiser and in-loop filter */
333 CopyQTables(pbi
, ci
);
334 CopyFilterTables(pbi
, ci
);
337 InitHuffmanTrees(pbi
, ci
);
343 int theora_decode_packetin(theora_state
*th
,ogg_packet
*op
){
345 PB_INSTANCE
*pbi
=(PB_INSTANCE
*)(th
->internal_decode
);
347 pbi
->DecoderErrorCode
= 0;
350 oggpackB_readinit(pbi
->opb
,op
->packet
,op
->bytes
);
352 oggpackB_readinit(pbi
->opb
,op
->packet
);
356 /* verify that this is a video frame */
357 theora_read(pbi
->opb
,1,&ret
);
360 ret
=LoadAndDecode(pbi
);
364 if(pbi
->PostProcessingLevel
)
367 if(op
->granulepos
>-1)
368 th
->granulepos
=op
->granulepos
;
370 if(th
->granulepos
==-1){
373 if(pbi
->FrameType
==KEY_FRAME
){
374 long frames
= th
->granulepos
& ((1<<pbi
->keyframe_granule_shift
)-1);
375 th
->granulepos
>>=pbi
->keyframe_granule_shift
;
376 th
->granulepos
+=frames
+1;
377 th
->granulepos
<<=pbi
->keyframe_granule_shift
;
393 int theora_decode_YUVout(theora_state
*th
,yuv_buffer
*yuv
){
394 PB_INSTANCE
*pbi
=(PB_INSTANCE
*)(th
->internal_decode
);
396 yuv
->y_width
= pbi
->info
.width
;
397 yuv
->y_height
= pbi
->info
.height
;
398 yuv
->y_stride
= pbi
->YStride
;
400 yuv
->uv_width
= pbi
->info
.width
/ 2;
401 yuv
->uv_height
= pbi
->info
.height
/ 2;
402 yuv
->uv_stride
= pbi
->UVStride
;
404 if(pbi
->PostProcessingLevel
){
405 yuv
->y
= &pbi
->PostProcessBuffer
[pbi
->ReconYDataOffset
];
406 yuv
->u
= &pbi
->PostProcessBuffer
[pbi
->ReconUDataOffset
];
407 yuv
->v
= &pbi
->PostProcessBuffer
[pbi
->ReconVDataOffset
];
409 yuv
->y
= &pbi
->LastFrameRecon
[pbi
->ReconYDataOffset
];
410 yuv
->u
= &pbi
->LastFrameRecon
[pbi
->ReconUDataOffset
];
411 yuv
->v
= &pbi
->LastFrameRecon
[pbi
->ReconVDataOffset
];
414 /* we must flip the internal representation,
415 so make the stride negative and start at the end */
416 yuv
->y
+= yuv
->y_stride
* (yuv
->y_height
- 1);
417 yuv
->u
+= yuv
->uv_stride
* (yuv
->uv_height
- 1);
418 yuv
->v
+= yuv
->uv_stride
* (yuv
->uv_height
- 1);
419 yuv
->y_stride
= - yuv
->y_stride
;
420 yuv
->uv_stride
= - yuv
->uv_stride
;
425 /* returns, in seconds, absolute time of current packet in given
427 double theora_granule_time(theora_state
*th
,ogg_int64_t granulepos
){
428 #ifndef THEORA_DISABLE_FLOAT
429 CP_INSTANCE
*cpi
=(CP_INSTANCE
*)(th
->internal_encode
);
430 PB_INSTANCE
*pbi
=(PB_INSTANCE
*)(th
->internal_decode
);
435 ogg_int64_t iframe
=granulepos
>>pbi
->keyframe_granule_shift
;
436 ogg_int64_t pframe
=granulepos
-(iframe
<<pbi
->keyframe_granule_shift
);
438 return (iframe
+pframe
)*
439 ((double)pbi
->info
.fps_denominator
/pbi
->info
.fps_numerator
);
444 return(-1); /* negative granulepos or float calculations disabled */
447 /* check for header flag */
448 int theora_packet_isheader(ogg_packet
*op
)
450 return (op
->packet
[0] & 0x80) ? 1 : 0;
453 /* check for keyframe */
454 int theora_packet_iskeyframe(ogg_packet
*op
)
456 if (op
->packet
[0] & 0x80) return -1; /* not a data packet */
457 return (op
->packet
[0] & 0x40) ? 0 : 1; /* inter or intra */
460 /* returns the shift radix used to split the granulepos into two fields */
461 int theora_granule_shift(theora_info
*ti
)
463 return _ilog(ti
->keyframe_frequency_force
- 1);
466 /* returns frame number of current packet in given logical stream */
467 ogg_int64_t
theora_granule_frame(theora_state
*th
,ogg_int64_t granulepos
){
468 CP_INSTANCE
*cpi
=(CP_INSTANCE
*)(th
->internal_encode
);
469 PB_INSTANCE
*pbi
=(PB_INSTANCE
*)(th
->internal_decode
);
474 ogg_int64_t iframe
=granulepos
>>pbi
->keyframe_granule_shift
;
475 ogg_int64_t pframe
=granulepos
-(iframe
<<pbi
->keyframe_granule_shift
);
477 return (iframe
+pframe
);