Fix oggplay-dump-first-frame
[liboggplay.git] / src / liboggplay / oggplay_callback.c
blobe44a185538ed8dafce209729cc95b102ab478d9f
1 /*
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
7 are met:
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.
34 * oggplay_callback.c
36 * Shane Stephens <shane.stephens@annodex.net>
38 #include "oggplay_private.h"
40 #define TIME_THEORA_DECODE 0
42 #include <stdlib.h>
43 #if TIME_THEORA_DECODE
44 #include <sys/time.h>
45 #endif
46 #include <time.h>
47 #include <string.h>
49 #define THEORA_VERSION(maj,min,rev) ((maj<<16)+(min<<8)+rev)
51 void
52 oggplay_init_theora(void *user_data) {
54 OggPlayTheoraDecode * decoder = (OggPlayTheoraDecode *)user_data;
56 if (decoder == NULL) {
57 return;
60 theora_info_init(&(decoder->video_info));
61 theora_comment_init(&(decoder->video_comment));
62 decoder->granulepos_seen = 0;
63 decoder->frame_delta = 0;
64 decoder->y_width = 0;
65 decoder->convert_to_rgb = 0;
66 decoder->swap_rgb = 0;
67 decoder->decoder.decoded_type = OGGPLAY_YUV_VIDEO;
70 void
71 oggplay_shutdown_theora(void *user_data) {
72 OggPlayDecode * common;
73 OggPlayTheoraDecode * decoder = (OggPlayTheoraDecode *)user_data;
75 if (decoder == NULL) {
76 return;
79 if ((common = &(decoder->decoder)) == NULL) {
80 return;
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));
90 int
91 oggplay_callback_theora (OGGZ * oggz, ogg_packet * op, long serialno,
92 void * user_data) {
94 OggPlayTheoraDecode * decoder = (OggPlayTheoraDecode *)user_data;
95 OggPlayDecode * common = NULL;
96 ogg_int64_t granulepos = oggz_tell_granulepos(oggz);
97 yuv_buffer buffer;
98 int granuleshift;
99 long frame;
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
112 struct timeval tv;
113 struct timeval tv2;
114 int musec;
115 #endif
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;
164 } else {
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
205 return -1;
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;
215 * Decode the frame
218 #if TIME_THEORA_DECODE
219 gettimeofday(&tv, NULL);
220 #endif
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);
236 #endif
238 if (granulepos != -1) {
239 int version =
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
259 * calculation.
261 if (version >= THEORA_VERSION(3,2,1)) {
262 frame--;
264 frame += (granulepos & ((1 << granuleshift) - 1));
266 /* calculate the current location in the stream */
267 common->current_loc = frame * common->granuleperiod;
268 } else {
269 common->current_loc = -1;
274 (common->current_loc == -1)
276 (common->current_loc >= common->player->presentation_time)
280 * store the frame,
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;
290 if (op->e_o_s) {
291 common->active = 0;
292 common->player->active_tracks--;
295 return OGGZ_CONTINUE;
299 void
300 oggplay_init_cmml (void * user_data) {
302 OggPlayCmmlDecode * decoder = (OggPlayCmmlDecode *)user_data;
304 if (decoder == NULL) {
305 return;
308 decoder->decoder.decoded_type = OGGPLAY_CMML;
309 decoder->granuleshift = 32; /* default */
313 oggplay_callback_cmml (OGGZ * oggz, ogg_packet * op, long serialno,
314 void * user_data) {
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];
338 } else {
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;
351 } else {
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;
372 void
373 oggplay_init_skel (void * user_data) {
375 OggPlaySkeletonDecode * decoder = (OggPlaySkeletonDecode *)user_data;
377 #ifdef HAVE_SKELETON
378 decoder->skeleton = oggskel_new ();
379 if (decoder->skeleton == NULL)
380 return;
381 #else
382 decoder->presentation_time = 0;
383 decoder->base_time = 0;
384 #endif
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,
398 void * user_data) {
400 OggPlaySkeletonDecode * decoder = (OggPlaySkeletonDecode *)user_data;
401 int ret = -1;
402 /* check whether user_input is valid */
403 if (decoder == NULL) {
404 return OGGZ_STOP_ERR;
407 #ifdef HAVE_SKELETON
408 if (decoder->skeleton == NULL)
409 return OGGZ_STOP_ERR;
411 ret = oggskel_decode_header (decoder->skeleton, op);
412 if (ret < 0) {
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;
419 int i;
420 OggPlay * player = decoder->decoder.player;
422 sk_ret = oggskel_get_ptime_num (decoder->skeleton, &pt_num);
423 if (sk_ret != SKELETON_ERR_OK)
424 return sk_ret;
426 sk_ret = oggskel_get_ptime_denum (decoder->skeleton, &pt_den);
427 if (sk_ret != SKELETON_ERR_OK)
428 return sk_ret;
430 sk_ret = oggskel_get_btime_num (decoder->skeleton, &bt_num);
431 if (sk_ret != SKELETON_ERR_OK)
432 return sk_ret;
434 sk_ret = oggskel_get_btime_denum (decoder->skeleton, &bt_den);
435 if (sk_ret != SKELETON_ERR_OK)
436 return sk_ret;
439 /* initialise the presentation times in the player to the values recorded in the skeleton */
440 if (pt_den)
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;
453 #else
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);
462 if (pt_den != 0) {
463 decoder->presentation_time = OGGPLAY_TIME_INT_TO_FP(pt_num) / pt_den;
464 } else {
465 decoder->presentation_time = 0;
467 if (bt_den != 0) {
468 decoder->base_time = OGGPLAY_TIME_INT_TO_FP(bt_num) / bt_den;
469 } else {
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--;
478 } else {
479 int i;
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;
488 break;
492 #endif
493 return OGGZ_CONTINUE;
497 void
498 oggplay_shutdown_skel (void *user_data) {
499 OggPlaySkeletonDecode * decoder = (OggPlaySkeletonDecode *)user_data;
501 if (decoder == NULL)
502 return;
504 #ifdef HAVE_SKELETON
505 oggskel_destroy (decoder->skeleton);
506 #endif
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;
530 } else {
531 common->current_loc = -1;
536 (common->current_loc == -1)
538 (common->current_loc >= common->player->presentation_time)
542 * store the frame
544 oggplay_data_handle_audio_data(common, (short *)pcm,
545 frames, sizeof(float));
547 return FISH_SOUND_STOP_ERR;
550 return FISH_SOUND_CONTINUE;
553 void
554 oggplay_init_audio (void * user_data) {
556 OggPlayAudioDecode * decoder = (OggPlayAudioDecode *)user_data;
558 if (decoder == NULL) {
559 return;
562 decoder->sound_handle = fish_sound_new(FISH_SOUND_DECODE,
563 &(decoder->sound_info));
565 if (decoder->sound_handle == NULL) {
566 return;
569 decoder->sound_info.channels = 0;
570 fish_sound_set_decoded_float_ilv(decoder->sound_handle,
571 oggplay_fish_sound_callback_floats,
572 (void *)decoder);
574 decoder->decoder.decoded_type = OGGPLAY_FLOATS_AUDIO;
577 void
578 oggplay_shutdown_audio(void *user_data) {
580 OggPlayAudioDecode * decoder = (OggPlayAudioDecode *)user_data;
582 if (decoder == NULL) {
583 return;
586 fish_sound_delete(decoder->sound_handle);
591 oggplay_callback_audio (OGGZ * oggz, ogg_packet * op, long serialno,
592 void * user_data) {
594 OggPlayAudioDecode * decoder = (OggPlayAudioDecode *)user_data;
595 OggPlayDecode * common = NULL;
596 ogg_int64_t granulepos = oggz_tell_granulepos(oggz);
597 long bytes_read;
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,
622 op->e_o_s);
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...
638 common->active = 0;
640 if (common->player->active_tracks) common->player->active_tracks--;
641 if (common->num_header_packets >= 0) common->initialised |= -1;
643 return OGGZ_CONTINUE;
646 default:
647 /* there was no problem with decoding */
648 if (!common->num_header_packets) common->initialised |= 1;
649 break;
652 if (decoder->sound_info.channels == 0) {
653 fish_sound_command(decoder->sound_handle, FISH_SOUND_GET_INFO,
654 &(decoder->sound_info), sizeof(FishSoundInfo));
657 if (op->e_o_s) {
658 common->active = 0;
659 common->player->active_tracks--;
662 return OGGZ_CONTINUE;
665 void
666 oggplay_init_kate(void *user_data) {
668 #ifdef HAVE_KATE
669 int ret;
670 OggPlayKateDecode * decoder = (OggPlayKateDecode *)user_data;
672 if (decoder == NULL) {
673 return;
676 decoder->decoder.decoded_type = OGGPLAY_KATE;
677 kate_info_init (&(decoder->k_info));
678 kate_comment_init (&(decoder->k_comment));
680 #ifdef HAVE_TIGER
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));
688 if (ret < 0) {
689 /* what to do ? */
690 decoder->tr = NULL;
692 if (decoder->use_tiger) {
693 decoder->decoder.decoded_type = OGGPLAY_RGBA_VIDEO;
695 #endif
697 #endif
700 void
701 oggplay_shutdown_kate(void *user_data) {
703 #ifdef HAVE_KATE
704 OggPlayKateDecode * decoder = (OggPlayKateDecode *)user_data;
706 if (decoder == NULL) {
707 return;
709 #ifdef HAVE_TIGER
710 if (decoder->tr) {
711 tiger_renderer_destroy(decoder->tr);
713 #endif
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));
722 #endif
726 oggplay_callback_kate (OGGZ * oggz, ogg_packet * op, long serialno,
727 void * user_data) {
729 #ifdef HAVE_KATE
730 OggPlayKateDecode * decoder = (OggPlayKateDecode *)user_data;
731 OggPlayDecode * common = NULL;
732 ogg_int64_t granulepos = oggz_tell_granulepos(oggz);
733 int granuleshift;
734 ogg_int64_t base, offset;
735 kate_packet kp;
736 const kate_event *ev = NULL;
737 int ret;
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;
794 } else if (ret < 0){
795 return OGGZ_CONTINUE;
798 ret = kate_decode_eventout (&(decoder->k_state), &ev);
799 if (ret < 0) {
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;
808 } else {
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
821 * */
822 if (ev) {
823 if (oggplay_data_handle_kate_data(decoder, ev) != E_OGGPLAY_CONTINUE) {
824 return OGGZ_ERR_OUT_OF_MEMORY;
829 if (op->e_o_s) {
830 common->active = 0;
833 #endif
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 */
861 OggPlayDecode *
862 oggplay_initialise_decoder(OggPlay *me, int content_type, long serialno) {
864 ogg_int64_t num;
865 ogg_int64_t denom;
866 OggPlayDecode *decoder = NULL;
868 if (me == NULL)
869 return NULL;
871 decoder = oggplay_malloc (callbacks[content_type].size);
873 if (decoder == NULL)
874 return NULL;
876 decoder->serialno = serialno;
877 decoder->content_type = content_type;
878 decoder->content_type_name =
879 oggz_stream_get_content_type (me->oggz, serialno);
880 decoder->active = 1;
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
903 decoder->offset = 0;
905 oggz_get_granulerate(me->oggz, serialno, &num, &denom);
908 * convert num and denom to a 32.32 fixed point value
910 if (num != 0) {
911 decoder->granuleperiod = OGGPLAY_TIME_INT_TO_FP(denom) / num;
912 } else {
913 decoder->granuleperiod = 0;
916 if (callbacks[content_type].init != NULL) {
917 callbacks[content_type].init(decoder);
918 decoder->initialised = 0;
919 } else {
920 decoder->initialised = -1;
923 oggplay_data_initialise_list(decoder);
925 return decoder;
930 * this function needs to be called on each track to clear up allocated memory
932 void
933 oggplay_callback_shutdown(OggPlayDecode *decoder) {
935 if (decoder == NULL) {
936 return;
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
952 * of a new chain
955 oggplay_callback_predetected (OGGZ *oggz, ogg_packet *op, long serialno,
956 void *user_data) {
958 OggPlay * me = (OggPlay *)user_data;
959 int i;
960 int content_type = 0;
961 int ret = OGGZ_CONTINUE;
962 short new_stream = 1;
963 short read_more = 0;
964 ogg_int64_t granulepos = oggz_tell_granulepos(oggz);
966 if (me == NULL) {
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,
979 me->decode_data[i]);
982 new_stream = 0;
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));
1003 if (new_stream) {
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);