2 Copyright (C) 2003 Commonwealth Scientific and Industrial Research
3 Organisation (CSIRO) Australia
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 - Neither the name of CSIRO Australia nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Shane Stephens <shane.stephens@annodex.net>
38 #include "oggplay_private.h"
40 #define TIME_THEORA_DECODE 0
43 #if TIME_THEORA_DECODE
49 #define THEORA_VERSION(maj,min,rev) ((maj<<16)+(min<<8)+rev)
52 oggplay_init_theora(void *user_data
) {
54 OggPlayTheoraDecode
* decoder
= (OggPlayTheoraDecode
*)user_data
;
56 if (decoder
== NULL
) {
60 theora_info_init(&(decoder
->video_info
));
61 theora_comment_init(&(decoder
->video_comment
));
62 decoder
->granulepos_seen
= 0;
63 decoder
->frame_delta
= 0;
65 decoder
->convert_to_rgb
= 0;
66 decoder
->swap_rgb
= 0;
67 decoder
->decoder
.decoded_type
= OGGPLAY_YUV_VIDEO
;
71 oggplay_shutdown_theora(void *user_data
) {
72 OggPlayDecode
* common
;
73 OggPlayTheoraDecode
* decoder
= (OggPlayTheoraDecode
*)user_data
;
75 if (decoder
== NULL
) {
79 if ((common
= &(decoder
->decoder
)) == NULL
) {
83 if (common
->initialised
== 1 && decoder
->decoder
.num_header_packets
== 0) {
84 theora_clear(&(decoder
->video_handle
));
86 theora_info_clear(&(decoder
->video_info
));
87 theora_comment_clear(&(decoder
->video_comment
));
91 oggplay_callback_theora (OGGZ
* oggz
, ogg_packet
* op
, long serialno
,
94 OggPlayTheoraDecode
* decoder
= (OggPlayTheoraDecode
*)user_data
;
95 OggPlayDecode
* common
= NULL
;
96 ogg_int64_t granulepos
= oggz_tell_granulepos(oggz
);
100 OggPlayErrorCode ret
;
102 /* check whether user_data is valid */
103 if (decoder
== NULL
) {
104 return OGGZ_STOP_ERR
;
107 if ((common
= &(decoder
->decoder
)) == NULL
) {
108 return OGGZ_STOP_ERR
;
111 #if TIME_THEORA_DECODE
117 if (!common
->active
) {
119 * don't decode other packets
121 return OGGZ_CONTINUE
;
124 if ((granulepos
> -1) && (common
->last_granulepos
> granulepos
)) {
126 * the granule position is not monotonically increasing,
127 * something wrong with the page!
128 * skipping this page.....
130 return OGGZ_CONTINUE
;
134 * always decode headers
136 if (theora_packet_isheader(op
) &&
137 common
->num_header_packets
> 0 &&
138 common
->initialised
!= -1)
140 if (theora_decode_header(&(decoder
->video_info
), &(decoder
->video_comment
), op
) < 0) {
141 common
->initialised
|= -1;
142 return OGGZ_CONTINUE
;
146 * initialise width/stride/height data (this is common to all frames).
147 * Use the buffer stride for the width to avoid passing negative stride
148 * issues on to the user.
151 if (--(common
->num_header_packets
) == 0) {
152 decoder
->y_width
= decoder
->y_stride
= decoder
->video_info
.frame_width
;
153 decoder
->y_height
= decoder
->video_info
.frame_height
;
155 if (decoder
->video_info
.pixelformat
== OC_PF_444
) {
156 decoder
->uv_width
= decoder
->uv_stride
= decoder
->video_info
.frame_width
;
157 decoder
->uv_height
= decoder
->video_info
.frame_height
;
158 } else if (decoder
->video_info
.pixelformat
== OC_PF_422
) {
159 decoder
->uv_width
= decoder
->uv_stride
= decoder
->video_info
.frame_width
/ 2;
160 decoder
->uv_height
= decoder
->video_info
.frame_height
;
161 } else if (decoder
->video_info
.pixelformat
== OC_PF_420
) {
162 decoder
->uv_width
= decoder
->uv_stride
= decoder
->video_info
.frame_width
/ 2;
163 decoder
->uv_height
= decoder
->video_info
.frame_height
/ 2;
165 common
->initialised
|= -1;
166 return OGGZ_CONTINUE
;
169 if (decoder
->y_width
== 0 ||
170 decoder
->y_height
== 0 ||
171 decoder
->uv_width
== 0 ||
172 decoder
->uv_height
== 0) {
173 /* it's a theora track with one of it's plane's dimension 0
174 * decoding this track is not possible.
176 common
->initialised
|= -1;
177 return OGGZ_CONTINUE
;
180 /* Ensure the offsets do not push the viewable area outside of the decoded frame. */
183 ((decoder
->video_info
.height
- decoder
->video_info
.offset_y
)<decoder
->video_info
.frame_height
)
185 ((decoder
->video_info
.width
- decoder
->video_info
.offset_x
)<decoder
->video_info
.frame_width
)
188 common
->initialised
|= -1;
189 return OGGZ_CONTINUE
;
192 if (theora_decode_init(&(decoder
->video_handle
), &(decoder
->video_info
))) {
193 common
->initialised
|= -1;
194 return OGGZ_CONTINUE
;
197 common
->initialised
|= 1;
199 return OGGZ_CONTINUE
;
200 } else if (common
->num_header_packets
!= 0) {
202 * Invalid Ogg file. Missing headers
209 * if we get to here then we've passed all the header packets
211 if (common
->current_loc
== -1)
212 common
->current_loc
= 0;
218 #if TIME_THEORA_DECODE
219 gettimeofday(&tv
, NULL
);
222 if (theora_decode_packetin(&(decoder
->video_handle
), op
) < 0) {
223 return OGGZ_CONTINUE
;
226 if (theora_decode_YUVout(&(decoder
->video_handle
), &buffer
) < 0) {
227 return OGGZ_CONTINUE
;
230 #if TIME_THEORA_DECODE
231 gettimeofday(&tv2
, NULL
);
232 musec
= tv2
.tv_usec
- tv
.tv_usec
;
233 if (tv2
.tv_sec
> tv
.tv_sec
)
234 musec
+= (tv2
.tv_sec
- tv
.tv_sec
) * 1000000;
235 printf("decode took %dus\n", musec
);
238 if (granulepos
!= -1) {
240 THEORA_VERSION(decoder
->video_info
.version_major
,
241 decoder
->video_info
.version_minor
,
242 decoder
->video_info
.version_subminor
);
245 * save last granule position in order to be able to validate
246 * that it's monotonically increasing
248 common
->last_granulepos
= granulepos
;
250 /* calculate the frame number */
251 granuleshift
= oggz_get_granuleshift(oggz
, serialno
);
252 frame
= (granulepos
>> granuleshift
);
253 /* From theora bitstream version 3.2.1 onwards, frame granule numbers are
254 * relative to the end of the frame, i.e. frame granule numbers start at 1.
255 * We calcualte the presentation time as frame_number * granule_period,
256 * but that's only correct if frame numbers start at 0 (else it's the end
257 * time), so subtract 1 from the frame number if this is a theora stream
258 * of version 3.2.1 or greater to ensure correct presentation time
261 if (version
>= THEORA_VERSION(3,2,1)) {
264 frame
+= (granulepos
& ((1 << granuleshift
) - 1));
266 /* calculate the current location in the stream */
267 common
->current_loc
= frame
* common
->granuleperiod
;
269 common
->current_loc
= -1;
274 (common
->current_loc
== -1)
276 (common
->current_loc
>= common
->player
->presentation_time
)
281 * use the buffer stride for the width to avoid passing negative stride
282 * issues on to the user.
284 ret
= oggplay_data_handle_theora_frame(decoder
, &buffer
);
285 if (ret
!= E_OGGPLAY_CONTINUE
) {
286 return OGGZ_ERR_OUT_OF_MEMORY
;
292 common
->player
->active_tracks
--;
295 return OGGZ_CONTINUE
;
300 oggplay_init_cmml (void * user_data
) {
302 OggPlayCmmlDecode
* decoder
= (OggPlayCmmlDecode
*)user_data
;
304 if (decoder
== NULL
) {
308 decoder
->decoder
.decoded_type
= OGGPLAY_CMML
;
309 decoder
->granuleshift
= 32; /* default */
313 oggplay_callback_cmml (OGGZ
* oggz
, ogg_packet
* op
, long serialno
,
316 OggPlayCmmlDecode
* decoder
= (OggPlayCmmlDecode
*)user_data
;
317 OggPlayDecode
* common
= NULL
;
318 ogg_int64_t granulepos
= oggz_tell_granulepos (oggz
);
319 OggPlayErrorCode ret
;
321 if (decoder
== NULL
) {
322 return OGGZ_STOP_ERR
;
325 if ((common
= &(decoder
->decoder
)) == NULL
) {
326 return OGGZ_STOP_ERR
;
329 if (common
->num_header_packets
) {
331 * Process the headers of the CMML stream.
334 if (common
->num_header_packets
== 3) {
335 /* The CMML ident header packet */
336 if (memcmp(op
->packet
, "CMML\0\0\0\0", 8) == 0) {
337 decoder
->granuleshift
= op
->packet
[28];
339 /* Missing ident header ... */
340 common
->initialised
|= -1;
342 } else if (common
->num_header_packets
== 2) {
343 /* CMML secondary header, with xml preamble and cmml tag */
344 } else if (common
->num_header_packets
== 1) {
345 /* CMML secondary header, head tag */
348 if (!(--common
->num_header_packets
))
349 common
->initialised
|= 1;
353 * Process the CMML stream content.
356 if (decoder
->granuleshift
> 0) {
357 granulepos
>>= decoder
->granuleshift
;
360 common
->current_loc
= granulepos
* common
->granuleperiod
;
362 ret
= oggplay_data_handle_cmml_data (common
, op
->packet
, op
->bytes
);
363 if (ret
!= E_OGGPLAY_CONTINUE
) {
364 return OGGZ_ERR_OUT_OF_MEMORY
;
368 return OGGZ_CONTINUE
;
373 oggplay_init_skel (void * user_data
) {
375 OggPlaySkeletonDecode
* decoder
= (OggPlaySkeletonDecode
*)user_data
;
378 decoder
->skeleton
= oggskel_new ();
379 if (decoder
->skeleton
== NULL
)
382 decoder
->presentation_time
= 0;
383 decoder
->base_time
= 0;
387 static inline unsigned long extract_int32(unsigned char *data
) {
388 return data
[0] | (data
[1] << 8) | (data
[2] << 16) | (data
[3] << 24);
391 static inline ogg_int64_t
extract_int64(unsigned char *data
) {
392 return ((ogg_int64_t
)(extract_int32(data
))) |
393 (((ogg_int64_t
)(extract_int32(data
+ 4))) << 32);
397 oggplay_callback_skel (OGGZ
* oggz
, ogg_packet
* op
, long serialno
,
400 OggPlaySkeletonDecode
* decoder
= (OggPlaySkeletonDecode
*)user_data
;
402 /* check whether user_input is valid */
403 if (decoder
== NULL
) {
404 return OGGZ_STOP_ERR
;
408 if (decoder
->skeleton
== NULL
)
409 return OGGZ_STOP_ERR
;
411 ret
= oggskel_decode_header (decoder
->skeleton
, op
);
413 /* error occured while decoding */
414 return OGGZ_STOP_ERR
;
415 } else if (ret
== 0) {
416 ogg_int64_t pt_num
, pt_den
, bt_num
, bt_den
;
417 OggSkeletonError sk_ret
= -1;
418 ogg_uint32_t preroll
= 0;
420 OggPlay
* player
= decoder
->decoder
.player
;
422 sk_ret
= oggskel_get_ptime_num (decoder
->skeleton
, &pt_num
);
423 if (sk_ret
!= SKELETON_ERR_OK
)
426 sk_ret
= oggskel_get_ptime_denum (decoder
->skeleton
, &pt_den
);
427 if (sk_ret
!= SKELETON_ERR_OK
)
430 sk_ret = oggskel_get_btime_num (decoder->skeleton, &bt_num);
431 if (sk_ret != SKELETON_ERR_OK)
434 sk_ret = oggskel_get_btime_denum (decoder->skeleton, &bt_den);
435 if (sk_ret != SKELETON_ERR_OK)
439 /* initialise the presentation times in the player to the values recorded in the skeleton */
441 decoder
->decoder
.player
->presentation_time
= OGGPLAY_TIME_INT_TO_FP(pt_num
) / pt_den
;
443 /* set the preroll for each track */
444 for (i
= 1; i
< player
->num_tracks
; ++i
) {
445 sk_ret
= oggskel_get_preroll (decoder
->skeleton
, player
->decode_data
[i
]->serialno
, &preroll
);
446 if (sk_ret
== SKELETON_ERR_OK
) {
447 player
->decode_data
[i
]->preroll
= preroll
;
450 /* got the EOS packet of skeleton stream mark stream initialised */
451 decoder
->decoder
.initialised
= 1;
454 if (strncmp((char *)op
->packet
, "fishead", 7) == 0) {
455 ogg_int64_t pt_num
, pt_den
, bt_num
, bt_den
;
457 pt_num
= extract_int64(op
->packet
+ 12);
458 pt_den
= extract_int64(op
->packet
+ 20);
459 bt_num
= extract_int64(op
->packet
+ 28);
460 bt_den
= extract_int64(op
->packet
+ 36);
463 decoder
->presentation_time
= OGGPLAY_TIME_INT_TO_FP(pt_num
) / pt_den
;
465 decoder
->presentation_time
= 0;
468 decoder
->base_time
= OGGPLAY_TIME_INT_TO_FP(bt_num
) / bt_den
;
470 decoder
->base_time
= 0;
473 /* initialise the presentation times in the player to the values recorded in the skeleton */
474 decoder
->decoder
.player
->presentation_time
= decoder
->presentation_time
;
476 decoder
->decoder
.initialised
= 1;
477 decoder
->decoder
.num_header_packets
--;
480 long preroll
= extract_int32(op
->packet
+ 44);
481 long serialno
= extract_int32(op
->packet
+ 12);
482 OggPlay
* player
= decoder
->decoder
.player
;
483 //ogg_int64_t start_granule = extract_int64(op->packet + 36);
485 for (i
= 1; i
< player
->num_tracks
; i
++) {
486 if (player
->decode_data
[i
]->serialno
== serialno
) {
487 player
->decode_data
[i
]->preroll
= preroll
;
493 return OGGZ_CONTINUE
;
498 oggplay_shutdown_skel (void *user_data
) {
499 OggPlaySkeletonDecode
* decoder
= (OggPlaySkeletonDecode
*)user_data
;
505 oggskel_destroy (decoder
->skeleton
);
510 oggplay_fish_sound_callback_floats(FishSound
* fsound
, float ** pcm
,
511 long frames
, void *user_data
) {
513 OggPlayAudioDecode
* decoder
= (OggPlayAudioDecode
*)user_data
;
514 OggPlayDecode
* common
= NULL
;
516 if (decoder
== NULL
) {
517 return FISH_SOUND_STOP_ERR
;
520 if ((common
= &(decoder
->decoder
)) == NULL
) {
521 return FISH_SOUND_STOP_ERR
;
525 * calculate the current location here so that it's only updated when
526 * audio data is actually available for processing
528 if (common
->last_granulepos
> 0) {
529 common
->current_loc
= common
->last_granulepos
* common
->granuleperiod
;
531 common
->current_loc
= -1;
536 (common
->current_loc
== -1)
538 (common
->current_loc
>= common
->player
->presentation_time
)
544 oggplay_data_handle_audio_data(common
, (short *)pcm
,
545 frames
, sizeof(float));
547 return FISH_SOUND_STOP_ERR
;
550 return FISH_SOUND_CONTINUE
;
554 oggplay_init_audio (void * user_data
) {
556 OggPlayAudioDecode
* decoder
= (OggPlayAudioDecode
*)user_data
;
558 if (decoder
== NULL
) {
562 decoder
->sound_handle
= fish_sound_new(FISH_SOUND_DECODE
,
563 &(decoder
->sound_info
));
565 if (decoder
->sound_handle
== NULL
) {
569 decoder
->sound_info
.channels
= 0;
570 fish_sound_set_decoded_float_ilv(decoder
->sound_handle
,
571 oggplay_fish_sound_callback_floats
,
574 decoder
->decoder
.decoded_type
= OGGPLAY_FLOATS_AUDIO
;
578 oggplay_shutdown_audio(void *user_data
) {
580 OggPlayAudioDecode
* decoder
= (OggPlayAudioDecode
*)user_data
;
582 if (decoder
== NULL
) {
586 fish_sound_delete(decoder
->sound_handle
);
591 oggplay_callback_audio (OGGZ
* oggz
, ogg_packet
* op
, long serialno
,
594 OggPlayAudioDecode
* decoder
= (OggPlayAudioDecode
*)user_data
;
595 OggPlayDecode
* common
= NULL
;
596 ogg_int64_t granulepos
= oggz_tell_granulepos(oggz
);
599 /* check user input (user_data) */
600 if (decoder
== NULL
) {
601 return OGGZ_STOP_ERR
;
604 if ((common
= &(decoder
->decoder
)) == NULL
) {
605 return OGGZ_STOP_ERR
;
608 if (granulepos
> 0 && (!common
->active
)) {
609 return OGGZ_CONTINUE
;
612 if ((granulepos
> -1) && (common
->last_granulepos
> granulepos
)) {
613 return OGGZ_CONTINUE
;
616 /* Blindly register that we've processed a header packet. */
617 if (common
->num_header_packets
) --common
->num_header_packets
;
619 common
->last_granulepos
= granulepos
;
621 fish_sound_prepare_truncation (decoder
->sound_handle
, op
->granulepos
,
624 bytes_read
= fish_sound_decode (decoder
->sound_handle
, op
->packet
, op
->bytes
);
625 switch (bytes_read
) {
626 case FISH_SOUND_ERR_OUT_OF_MEMORY
:
627 /* we ran out of memory... stop decoding. */
628 return OGGZ_ERR_OUT_OF_MEMORY
;
630 case FISH_SOUND_ERR_GENERIC
:
633 * error occured while decoding the audio track
634 * disable the track, but if there are other tracks to decode
635 * contine decoding...
640 if (common
->player
->active_tracks
) common
->player
->active_tracks
--;
641 if (common
->num_header_packets
>= 0) common
->initialised
|= -1;
643 return OGGZ_CONTINUE
;
647 /* there was no problem with decoding */
648 if (!common
->num_header_packets
) common
->initialised
|= 1;
652 if (decoder
->sound_info
.channels
== 0) {
653 fish_sound_command(decoder
->sound_handle
, FISH_SOUND_GET_INFO
,
654 &(decoder
->sound_info
), sizeof(FishSoundInfo
));
659 common
->player
->active_tracks
--;
662 return OGGZ_CONTINUE
;
666 oggplay_init_kate(void *user_data
) {
670 OggPlayKateDecode
* decoder
= (OggPlayKateDecode
*)user_data
;
672 if (decoder
== NULL
) {
676 decoder
->decoder
.decoded_type
= OGGPLAY_KATE
;
677 kate_info_init (&(decoder
->k_info
));
678 kate_comment_init (&(decoder
->k_comment
));
681 decoder
->use_tiger
= 1;
682 decoder
->overlay_dest
= -1;
683 decoder
->swap_rgb
= 0;
684 decoder
->default_width
= -1;
685 decoder
->default_height
= -1;
687 ret
= tiger_renderer_create(&(decoder
->tr
));
692 if (decoder
->use_tiger
) {
693 decoder
->decoder
.decoded_type
= OGGPLAY_RGBA_VIDEO
;
701 oggplay_shutdown_kate(void *user_data
) {
704 OggPlayKateDecode
* decoder
= (OggPlayKateDecode
*)user_data
;
706 if (decoder
== NULL
) {
711 tiger_renderer_destroy(decoder
->tr
);
715 if (decoder
->decoder
.initialised
== 1) {
716 kate_clear (&(decoder
->k_state
));
719 kate_info_clear (&(decoder
->k_info
));
720 kate_comment_clear (&(decoder
->k_comment
));
726 oggplay_callback_kate (OGGZ
* oggz
, ogg_packet
* op
, long serialno
,
730 OggPlayKateDecode
* decoder
= (OggPlayKateDecode
*)user_data
;
731 OggPlayDecode
* common
= NULL
;
732 ogg_int64_t granulepos
= oggz_tell_granulepos(oggz
);
734 ogg_int64_t base
, offset
;
736 const kate_event
*ev
= NULL
;
740 * Basic error checking.
742 if (decoder
== NULL
) {
743 return OGGZ_STOP_ERR
;
746 if ((common
= &(decoder
->decoder
)) == NULL
) {
747 return OGGZ_STOP_ERR
;
751 * Stop processing the Ogg packet if the stream is not active.
753 if (!common
->active
) {
754 return OGGZ_CONTINUE
;
757 /* create a kate_packet from the received ogg_packet */
758 kate_packet_wrap (&kp
, op
->bytes
, op
->packet
);
761 * Decode the headers of the kate stream.
763 if (common
->num_header_packets
) {
764 ret
= kate_decode_headerin (&(decoder
->k_info
), &(decoder
->k_comment
), &kp
);
766 if (ret
== KATE_E_OUT_OF_MEMORY
) {
767 return OGGZ_ERR_OUT_OF_MEMORY
;
770 common
->initialised
|= (ret
< 0 ? -1 : ret
);
771 common
->num_header_packets
--;
773 /* if we _successfully_ processed all the headers initialise the decoder */
774 if (!common
->num_header_packets
&& (common
->initialised
== 1)) {
775 ret
= kate_decode_init (&(decoder
->k_state
), &(decoder
->k_info
));
777 if (ret
== KATE_E_OUT_OF_MEMORY
) {
778 return OGGZ_ERR_OUT_OF_MEMORY
;
779 } else if (ret
< 0) {
780 common
->initialised
|= -1;
784 return OGGZ_CONTINUE
;
788 * Decode the payload of the stream.
791 ret
= kate_decode_packetin (&(decoder
->k_state
), &kp
);
792 if (ret
== KATE_E_OUT_OF_MEMORY
) {
793 return OGGZ_ERR_OUT_OF_MEMORY
;
795 return OGGZ_CONTINUE
;
798 ret
= kate_decode_eventout (&(decoder
->k_state
), &ev
);
800 return OGGZ_CONTINUE
;
803 if (granulepos
!= -1) {
804 granuleshift
= oggz_get_granuleshift(oggz
, serialno
);
805 base
= (granulepos
>> granuleshift
);
806 offset
= granulepos
- (base
<< granuleshift
);
807 common
->current_loc
= (base
+offset
) * common
->granuleperiod
;
809 common
->current_loc
= -1;
814 (common
->current_loc
== -1)
816 (common
->current_loc
>= common
->player
->presentation_time
)
820 * process the data from the packet
823 if (oggplay_data_handle_kate_data(decoder
, ev
) != E_OGGPLAY_CONTINUE
) {
824 return OGGZ_ERR_OUT_OF_MEMORY
;
835 return OGGZ_CONTINUE
;
839 OggPlayCallbackFunctions callbacks
[] = {
840 {oggplay_init_theora
, oggplay_callback_theora
, oggplay_shutdown_theora
,
841 sizeof(OggPlayTheoraDecode
)}, /* THEORA */
842 {oggplay_init_audio
, oggplay_callback_audio
, oggplay_shutdown_audio
,
843 sizeof(OggPlayAudioDecode
)}, /* VORBIS */
844 {oggplay_init_audio
, oggplay_callback_audio
, oggplay_shutdown_audio
,
845 sizeof(OggPlayAudioDecode
)}, /* SPEEX */
846 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* PCM */
847 {oggplay_init_cmml
, oggplay_callback_cmml
, NULL
, sizeof(OggPlayCmmlDecode
)}, /* CMML */
848 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* ANX2 */
849 {oggplay_init_skel
, oggplay_callback_skel
, oggplay_shutdown_skel
,
850 sizeof(OggPlaySkeletonDecode
)}, /* SKELETON */
851 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* FLAC0 */
852 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* FLAC */
853 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* ANXDATA */
854 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* CELT */
855 {oggplay_init_kate
, oggplay_callback_kate
, oggplay_shutdown_kate
,
856 sizeof(OggPlayKateDecode
)}, /* KATE */
857 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)}, /* DIRAC */
858 {NULL
, NULL
, NULL
, sizeof(OggPlayDecode
)} /* UNKNOWN */
862 oggplay_initialise_decoder(OggPlay
*me
, int content_type
, long serialno
) {
866 OggPlayDecode
*decoder
= NULL
;
871 decoder
= oggplay_malloc (callbacks
[content_type
].size
);
876 decoder
->serialno
= serialno
;
877 decoder
->content_type
= content_type
;
878 decoder
->content_type_name
=
879 oggz_stream_get_content_type (me
->oggz
, serialno
);
881 decoder
->final_granulepos
= -1;
882 decoder
->player
= me
;
883 decoder
->decoded_type
= OGGPLAY_TYPE_UNKNOWN
;
884 decoder
->num_header_packets
=
885 oggz_stream_get_numheaders (me
->oggz
, serialno
);
888 * set the StreamInfo to unitialised until we get some real data in
890 decoder
->stream_info
= OGGPLAY_STREAM_UNINITIALISED
;
893 * set to -1 until headers decoded
895 decoder
->current_loc
= -1;
896 decoder
->last_granulepos
= 0;
899 * the offset is how far advanced or delayed this track is to the "standard"
900 * time position. An offset of 1000, for example, indicates that data for
901 * this track arrives 1 second in advance of data for other tracks
905 oggz_get_granulerate(me
->oggz
, serialno
, &num
, &denom
);
908 * convert num and denom to a 32.32 fixed point value
911 decoder
->granuleperiod
= OGGPLAY_TIME_INT_TO_FP(denom
) / num
;
913 decoder
->granuleperiod
= 0;
916 if (callbacks
[content_type
].init
!= NULL
) {
917 callbacks
[content_type
].init(decoder
);
918 decoder
->initialised
= 0;
920 decoder
->initialised
= -1;
923 oggplay_data_initialise_list(decoder
);
930 * this function needs to be called on each track to clear up allocated memory
933 oggplay_callback_shutdown(OggPlayDecode
*decoder
) {
935 if (decoder
== NULL
) {
939 if (callbacks
[decoder
->content_type
].shutdown
!= NULL
) {
940 callbacks
[decoder
->content_type
].shutdown(decoder
);
943 oggplay_data_shutdown_list(decoder
);
945 oggplay_free(decoder
);
950 * this is the callback that is used before all track types have been
951 * determined - i.e. at the beginning of an ogg bitstream or at the start
955 oggplay_callback_predetected (OGGZ
*oggz
, ogg_packet
*op
, long serialno
,
958 OggPlay
* me
= (OggPlay
*)user_data
;
960 int content_type
= 0;
961 int ret
= OGGZ_CONTINUE
;
962 short new_stream
= 1;
964 ogg_int64_t granulepos
= oggz_tell_granulepos(oggz
);
967 return OGGZ_STOP_ERR
;
970 content_type
= oggz_stream_get_content (me
->oggz
, serialno
);
972 for (i
= 0; i
< me
->num_tracks
; i
++) {
973 if (serialno
== me
->decode_data
[i
]->serialno
) {
975 * call appropriate callback
977 if (callbacks
[content_type
].callback
!= NULL
) {
978 ret
= callbacks
[content_type
].callback(oggz
, op
, serialno
,
985 /* a track that hasn't got all it's headers, but others are already having
986 * valueable data. A badly multiplexed Ogg file, as the specification
987 * requires that all headers has to be before any data comes.
988 * Instead of marking the whole file as a bad one, try to decode
989 * the streams, which headers are successfully decoded.
990 * and disable the tracks that haven't got enough header info.
992 if (granulepos
&& me
->decode_data
[i
]->num_header_packets
) {
993 me
->decode_data
[i
]->initialised
= -1;
997 * check whether there is a stream that has not
998 * decoded all it's headers
1000 read_more
|= (me
->decode_data
[i
]->num_header_packets
&& (me
->decode_data
[i
]->initialised
!= -1));
1004 /* check for possible overflow ... */
1007 (++me
->num_tracks
<= 0)
1009 (OGGPLAY_TYPE_MAX(size_t)/(me
->num_tracks
) < sizeof(OggPlayCallbackInfo
))
1011 (OGGPLAY_TYPE_MAX(size_t)/me
->num_tracks
< sizeof(long))
1014 return OGGZ_STOP_ERR
;
1017 me
->callback_info
= oggplay_realloc (me
->callback_info
,
1018 sizeof (OggPlayCallbackInfo
) * me
->num_tracks
);
1019 if (me
->callback_info
== NULL
)
1020 return OGGZ_ERR_OUT_OF_MEMORY
;
1022 me
->decode_data
= oggplay_realloc (me
->decode_data
,
1023 sizeof (long) * me
->num_tracks
);
1024 if (me
->decode_data
== NULL
)
1025 return OGGZ_ERR_OUT_OF_MEMORY
;
1027 me
->decode_data
[me
->num_tracks
- 1] =
1028 oggplay_initialise_decoder(me
, content_type
, serialno
);
1029 if (me
->decode_data
[me
->num_tracks
- 1] == NULL
)
1030 return OGGZ_ERR_OUT_OF_MEMORY
;
1033 * call appropriate callback
1035 if (callbacks
[content_type
].callback
!= NULL
) {
1036 ret
= callbacks
[content_type
].callback(oggz
, op
, serialno
,
1037 me
->decode_data
[me
->num_tracks
- 1]);
1039 } else if (!read_more
) {
1041 * all tracks' headers has been processed
1042 * initialisation phase done, process the payloads.
1044 me
->all_tracks_initialised
= 1;
1046 /* set up all the callbacks for the detected streams */
1047 for (i
= 0; i
< me
->num_tracks
; i
++) {
1048 serialno
= me
->decode_data
[i
]->serialno
;
1049 content_type
= oggz_stream_get_content (me
->oggz
, serialno
);
1050 if (oggz_set_read_callback (me
->oggz
, serialno
,
1051 callbacks
[content_type
].callback
,
1052 me
->decode_data
[i
]) != 0)
1054 return OGGZ_STOP_ERR
;
1058 /* disable the callback for unforeseen streams */
1059 oggz_set_read_callback (me
->oggz
, -1, NULL
, NULL
);
1062 /* read the header part of the ogg content in a packet-by-packet manner */
1063 return ((ret
< 0) ? ret
: OGGZ_STOP_OK
);