Fix for initialised value check for kate and tiger
[liboggplay.git] / src / liboggplay / oggplay.c
blob53bacf2d746a44f9f1d859324b7a14ffc0b59b16
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.c
36 * Shane Stephens <shane.stephens@annodex.net>
37 * Michael Martin
40 #include "oggplay_private.h"
41 #include "oggplay_buffer.h"
43 #include <string.h>
44 #include <stdlib.h>
46 #define OGGZ_READ_CHUNK_SIZE 8192
48 OggPlay *
49 oggplay_new_with_reader(OggPlayReader *reader) {
51 OggPlay * me = NULL;
53 /* check whether the reader is valid. */
54 if (reader == NULL)
55 return NULL;
57 me = (OggPlay *)oggplay_malloc (sizeof(OggPlay));
58 if (me == NULL)
59 return NULL;
61 me->reader = reader;
62 me->decode_data = NULL;
63 me->callback_info = NULL;
64 me->num_tracks = 0;
65 me->all_tracks_initialised = 0;
66 me->callback_period = 0;
67 me->callback = NULL;
68 me->target = 0L;
69 me->active_tracks = 0;
70 me->buffer = NULL;
71 me->shutdown = 0;
72 me->trash = NULL;
73 me->oggz = NULL;
74 me->pt_update_valid = 1;
75 me->duration = -1;
77 return me;
81 OggPlayErrorCode
82 oggplay_initialise(OggPlay *me, int block) {
84 OggPlayErrorCode return_val;
85 int i;
87 if (me == NULL) {
88 return E_OGGPLAY_BAD_OGGPLAY;
91 return_val = me->reader->initialise(me->reader, block);
93 if (return_val != E_OGGPLAY_OK) {
94 return return_val;
98 * this is the cut-off time value below which packets will be ignored. Initialise it to 0 here.
99 * We'll reinitialise it when/if we encounter a skeleton header
101 me->presentation_time = 0;
104 * start to retrieve data, until we get all of the track info. We need
105 * to do this now so that the user can query us for this info before entering
106 * the main loop
108 me->oggz = oggz_new(OGGZ_READ | OGGZ_AUTO);
109 if (me->oggz == NULL)
110 return E_OGGPLAY_OGGZ_UNHAPPY;
112 if (oggz_io_set_read(me->oggz, me->reader->io_read, me->reader) != 0)
113 return E_OGGPLAY_OGGZ_UNHAPPY;
115 if (oggz_io_set_seek(me->oggz, me->reader->io_seek, me->reader) != 0)
116 return E_OGGPLAY_OGGZ_UNHAPPY;
118 if (oggz_io_set_tell(me->oggz, me->reader->io_tell, me->reader) != 0)
119 return E_OGGPLAY_OGGZ_UNHAPPY;
121 if (oggz_set_read_callback(me->oggz, -1, oggplay_callback_predetected, me))
122 return E_OGGPLAY_OGGZ_UNHAPPY;
124 while (1) {
125 i = oggz_read (me->oggz, OGGZ_READ_CHUNK_SIZE);
127 switch (i) {
128 case 0:
130 * EOF reached while processing headers,
131 * possible erroneous file, mark it as such.
133 case OGGZ_ERR_HOLE_IN_DATA:
134 /* there was a whole in the data */
135 return E_OGGPLAY_BAD_INPUT;
137 case OGGZ_ERR_OUT_OF_MEMORY:
138 /* ran out of memory during decoding! */
139 return E_OGGPLAY_OUT_OF_MEMORY;
141 case OGGZ_ERR_STOP_ERR:
142 /* error occured while initialising headers
143 - only occures with bad OggPlay handle */
144 return E_OGGPLAY_BAD_OGGPLAY;
146 case OGGZ_ERR_BAD_OGGZ:
147 /* bad Oggz handle */
148 return E_OGGPLAY_OGGZ_UNHAPPY;
150 case OGGZ_ERR_STOP_OK:
151 /* while initialising the streams, we read the
152 header packets in a packet-by-packet manner */
153 break;
155 default:
157 if (i < 0)
158 return E_OGGPLAY_BAD_INPUT;
161 if (me->all_tracks_initialised) {
162 break;
167 * set all the tracks to inactive
169 for (i = 0; i < me->num_tracks; i++) {
170 me->decode_data[i]->active = 0;
174 * if the buffer was set up before initialisation, prepare it now
176 if (me->buffer != NULL) {
177 oggplay_buffer_prepare(me);
180 return E_OGGPLAY_OK;
184 OggPlay *
185 oggplay_open_with_reader(OggPlayReader *reader) {
187 OggPlay *me = NULL;
188 int r = E_OGGPLAY_TIMEOUT;
190 if ((me = oggplay_new_with_reader(reader)) == NULL)
191 return NULL;
193 while (r == E_OGGPLAY_TIMEOUT) {
194 r = oggplay_initialise(me, 0);
197 if (r != E_OGGPLAY_OK) {
199 /* in case of error close the OggPlay handle */
200 oggplay_close(me);
202 return NULL;
205 return me;
209 * API function to prevent bad input, and to prevent data callbacks being registered
210 * in buffer mode
212 OggPlayErrorCode
213 oggplay_set_data_callback(OggPlay *me, OggPlayDataCallback callback,
214 void *user) {
216 if (me == NULL) {
217 return E_OGGPLAY_BAD_OGGPLAY;
220 if (me->buffer != NULL) {
221 return E_OGGPLAY_BUFFER_MODE;
224 oggplay_set_data_callback_force(me, callback, user);
225 return E_OGGPLAY_OK;
230 * internal function that doesn't perform error checking. Used so the buffer
231 * can register a callback!
233 void
234 oggplay_set_data_callback_force(OggPlay *me, OggPlayDataCallback callback,
235 void *user) {
237 me->callback = callback;
238 me->callback_user_ptr = user;
243 OggPlayErrorCode
244 oggplay_set_callback_num_frames(OggPlay *me, int track, int frames) {
246 if (me == NULL) {
247 return E_OGGPLAY_BAD_OGGPLAY;
250 if (track < 0 || track >= me->num_tracks) {
251 return E_OGGPLAY_BAD_TRACK;
254 me->callback_period = me->decode_data[track]->granuleperiod * frames;
255 me->target = me->presentation_time + me->callback_period - 1;
257 return E_OGGPLAY_OK;
260 OggPlayErrorCode
261 oggplay_set_callback_period(OggPlay *me, int track, int milliseconds) {
263 if (me == NULL) {
264 return E_OGGPLAY_BAD_OGGPLAY;
267 if (track < 0 || track >= me->num_tracks) {
268 return E_OGGPLAY_BAD_TRACK;
271 me->callback_period = OGGPLAY_TIME_INT_TO_FP(((ogg_int64_t)milliseconds))/1000;
272 me->target = me->presentation_time + me->callback_period - 1;
274 return E_OGGPLAY_OK;
277 OggPlayErrorCode
278 oggplay_set_offset(OggPlay *me, int track, ogg_int64_t offset) {
280 if (me == NULL) {
281 return E_OGGPLAY_BAD_OGGPLAY;
284 if (track < 0 || track >= me->num_tracks) {
285 return E_OGGPLAY_BAD_TRACK;
288 me->decode_data[track]->offset = OGGPLAY_TIME_INT_TO_FP(offset) / 1000;
290 return E_OGGPLAY_OK;
294 OggPlayErrorCode
295 oggplay_get_video_fps(OggPlay *me, int track, int* fps_denom, int* fps_num) {
296 OggPlayTheoraDecode *decode;
298 if (me == NULL) {
299 return E_OGGPLAY_BAD_OGGPLAY;
302 if (track < 0 || track >= me->num_tracks) {
303 return E_OGGPLAY_BAD_TRACK;
306 if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
307 return E_OGGPLAY_WRONG_TRACK_TYPE;
310 decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
312 if ((decode->video_info.fps_denominator == 0)
313 || (decode->video_info.fps_numerator == 0)) {
314 return E_OGGPLAY_UNINITIALISED;
317 (*fps_denom) = decode->video_info.fps_denominator;
318 (*fps_num) = decode->video_info.fps_numerator;
320 return E_OGGPLAY_OK;
323 OggPlayErrorCode
324 oggplay_get_video_aspect_ratio(OggPlay *me, int track, int* aspect_denom, int* aspect_num) {
325 OggPlayTheoraDecode *decode;
327 if (me == NULL) {
328 return E_OGGPLAY_BAD_OGGPLAY;
331 if (track < 0 || track >= me->num_tracks) {
332 return E_OGGPLAY_BAD_TRACK;
335 if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
336 return E_OGGPLAY_WRONG_TRACK_TYPE;
339 decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
341 if ((decode->video_info.aspect_denominator == 0)
342 || (decode->video_info.aspect_numerator == 0)) {
343 return E_OGGPLAY_UNINITIALISED;
346 (*aspect_denom) = decode->video_info.aspect_denominator;
347 (*aspect_num) = decode->video_info.aspect_numerator;
349 return E_OGGPLAY_OK;
352 OggPlayErrorCode
353 oggplay_convert_video_to_rgb(OggPlay *me, int track, int convert, int swap_rgb) {
354 OggPlayTheoraDecode *decode;
356 if (me == NULL) {
357 return E_OGGPLAY_BAD_OGGPLAY;
360 if (track < 0 || track >= me->num_tracks) {
361 return E_OGGPLAY_BAD_TRACK;
364 if (me->decode_data[track]->content_type != OGGZ_CONTENT_THEORA) {
365 return E_OGGPLAY_WRONG_TRACK_TYPE;
368 decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
370 if (decode->convert_to_rgb != convert || decode->swap_rgb != swap_rgb) {
371 decode->convert_to_rgb = convert;
372 decode->swap_rgb = swap_rgb;
373 me->decode_data[track]->decoded_type = convert ? OGGPLAY_RGBA_VIDEO : OGGPLAY_YUV_VIDEO;
375 /* flush any records created with previous type */
376 oggplay_data_free_list(me->decode_data[track]->data_list);
377 me->decode_data[track]->data_list = NULL;
380 return E_OGGPLAY_OK;
383 OggPlayErrorCode
384 oggplay_get_video_y_size(OggPlay *me, int track, int *y_width, int *y_height) {
386 OggPlayTheoraDecode *decode;
388 if (me == NULL) {
389 return E_OGGPLAY_BAD_OGGPLAY;
392 if (track < 0 || track >= me->num_tracks) {
393 return E_OGGPLAY_BAD_TRACK;
396 if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
397 return E_OGGPLAY_WRONG_TRACK_TYPE;
400 decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
402 if (decode->y_width == 0) {
403 return E_OGGPLAY_UNINITIALISED;
406 (*y_width) = decode->y_width;
407 (*y_height) = decode->y_height;
409 return E_OGGPLAY_OK;
413 OggPlayErrorCode
414 oggplay_get_video_uv_size(OggPlay *me, int track, int *uv_width, int *uv_height)
417 OggPlayTheoraDecode *decode;
419 if (me == NULL) {
420 return E_OGGPLAY_BAD_OGGPLAY;
423 if (track < 0 || track >= me->num_tracks) {
424 return E_OGGPLAY_BAD_TRACK;
427 if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
428 return E_OGGPLAY_WRONG_TRACK_TYPE;
431 decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
433 if (decode->y_width == 0) {
434 return E_OGGPLAY_UNINITIALISED;
437 (*uv_width) = decode->uv_width;
438 (*uv_height) = decode->uv_height;
440 return E_OGGPLAY_OK;
444 OggPlayErrorCode
445 oggplay_get_audio_channels(OggPlay *me, int track, int* channels) {
447 OggPlayAudioDecode *decode;
449 if (me == NULL) {
450 return E_OGGPLAY_BAD_OGGPLAY;
453 if (track < 0 || track >= me->num_tracks) {
454 return E_OGGPLAY_BAD_TRACK;
457 if (me->decode_data[track]->decoded_type != OGGPLAY_FLOATS_AUDIO) {
458 return E_OGGPLAY_WRONG_TRACK_TYPE;
461 decode = (OggPlayAudioDecode *)(me->decode_data[track]);
463 if (decode->sound_info.channels == 0) {
464 return E_OGGPLAY_UNINITIALISED;
466 (*channels) = decode->sound_info.channels;
467 return E_OGGPLAY_OK;
471 OggPlayErrorCode
472 oggplay_get_audio_samplerate(OggPlay *me, int track, int* rate) {
474 OggPlayAudioDecode * decode;
476 if (me == NULL) {
477 return E_OGGPLAY_BAD_OGGPLAY;
480 if (track < 0 || track >= me->num_tracks) {
481 return E_OGGPLAY_BAD_TRACK;
484 if (me->decode_data[track]->decoded_type != OGGPLAY_FLOATS_AUDIO) {
485 return E_OGGPLAY_WRONG_TRACK_TYPE;
488 decode = (OggPlayAudioDecode *)(me->decode_data[track]);
490 if (decode->sound_info.channels == 0) {
491 return E_OGGPLAY_UNINITIALISED;
493 (*rate) = decode->sound_info.samplerate;
494 return E_OGGPLAY_OK;
498 OggPlayErrorCode
499 oggplay_get_kate_category(OggPlay *me, int track, const char** category) {
501 OggPlayKateDecode * decode;
503 if (me == NULL) {
504 return E_OGGPLAY_BAD_OGGPLAY;
507 if (track < 0 || track >= me->num_tracks) {
508 return E_OGGPLAY_BAD_TRACK;
511 if (me->decode_data[track]->content_type != OGGZ_CONTENT_KATE) {
512 return E_OGGPLAY_WRONG_TRACK_TYPE;
515 decode = (OggPlayKateDecode *)(me->decode_data[track]);
517 #ifdef HAVE_KATE
518 if (decode->decoder.initialised == 1) {
519 (*category) = decode->k_state.ki->category;
520 return E_OGGPLAY_OK;
522 else return E_OGGPLAY_UNINITIALISED;
523 #else
524 return E_OGGPLAY_NO_KATE_SUPPORT;
525 #endif
528 OggPlayErrorCode
529 oggplay_get_kate_language(OggPlay *me, int track, const char** language) {
531 OggPlayKateDecode * decode;
533 if (me == NULL) {
534 return E_OGGPLAY_BAD_OGGPLAY;
537 if (track < 0 || track >= me->num_tracks) {
538 return E_OGGPLAY_BAD_TRACK;
541 if (me->decode_data[track]->content_type != OGGZ_CONTENT_KATE) {
542 return E_OGGPLAY_WRONG_TRACK_TYPE;
545 decode = (OggPlayKateDecode *)(me->decode_data[track]);
547 #ifdef HAVE_KATE
548 if (decode->decoder.initialised == 1) {
549 (*language) = decode->k_state.ki->language;
550 return E_OGGPLAY_OK;
552 else return E_OGGPLAY_UNINITIALISED;
553 #else
554 return E_OGGPLAY_NO_KATE_SUPPORT;
555 #endif
558 OggPlayErrorCode
559 oggplay_set_kate_tiger_rendering(OggPlay *me, int track, int use_tiger, int swap_rgb, int default_width, int default_height) {
561 OggPlayKateDecode * decode;
563 if (me == NULL) {
564 return E_OGGPLAY_BAD_OGGPLAY;
567 if (track < 0 || track >= me->num_tracks) {
568 return E_OGGPLAY_BAD_TRACK;
571 if (me->decode_data[track]->content_type != OGGZ_CONTENT_KATE) {
572 return E_OGGPLAY_WRONG_TRACK_TYPE;
575 decode = (OggPlayKateDecode *)(me->decode_data[track]);
577 #ifdef HAVE_KATE
578 #ifdef HAVE_TIGER
579 if (decode->decoder.initialised == 1 && decode->tr) {
580 decode->use_tiger = use_tiger;
581 decode->swap_rgb = swap_rgb;
582 decode->default_width = default_width;
583 decode->default_height = default_height;
584 decode->decoder.decoded_type = use_tiger ? OGGPLAY_RGBA_VIDEO : OGGPLAY_KATE;
585 return E_OGGPLAY_OK;
587 else return E_OGGPLAY_UNINITIALISED;
588 #else
589 return E_OGGPLAY_NO_TIGER_SUPPORT;
590 #endif
591 #else
592 return E_OGGPLAY_NO_KATE_SUPPORT;
593 #endif
596 OggPlayErrorCode
597 oggplay_overlay_kate_track_on_video(OggPlay *me, int kate_track, int video_track) {
599 OggPlayKateDecode * decode;
601 if (me == NULL) {
602 return E_OGGPLAY_BAD_OGGPLAY;
605 if (kate_track < 0 || kate_track >= me->num_tracks) {
606 return E_OGGPLAY_BAD_TRACK;
608 if (video_track < 0 || video_track >= me->num_tracks) {
609 return E_OGGPLAY_BAD_TRACK;
612 if (me->decode_data[kate_track]->content_type != OGGZ_CONTENT_KATE) {
613 return E_OGGPLAY_WRONG_TRACK_TYPE;
616 if (me->decode_data[kate_track]->decoded_type != OGGPLAY_RGBA_VIDEO) {
617 return E_OGGPLAY_WRONG_TRACK_TYPE;
620 if (me->decode_data[video_track]->content_type != OGGZ_CONTENT_THEORA) {
621 return E_OGGPLAY_WRONG_TRACK_TYPE;
624 if (me->decode_data[video_track]->decoded_type != OGGPLAY_RGBA_VIDEO) {
625 return E_OGGPLAY_WRONG_TRACK_TYPE;
628 decode = (OggPlayKateDecode *)(me->decode_data[kate_track]);
630 #ifdef HAVE_KATE
631 #ifdef HAVE_TIGER
632 decode->overlay_dest = video_track;
633 return E_OGGPLAY_OK;
634 #else
635 return E_OGGPLAY_NO_TIGER_SUPPORT;
636 #endif
637 #else
638 return E_OGGPLAY_NO_KATE_SUPPORT;
639 #endif
642 #define MAX_CHUNK_COUNT 10
644 OggPlayErrorCode
645 oggplay_step_decoding(OggPlay *me) {
647 OggPlayCallbackInfo ** info;
648 int num_records;
649 int r;
650 int i;
651 int need_data = 0;
652 int chunk_count = 0;
654 if (me == NULL) {
655 return E_OGGPLAY_BAD_OGGPLAY;
659 * check whether the OggPlayDataCallback is set for the given
660 * OggPlay handle. If not return with error as there's no callback
661 * function processing the decoded data.
663 if (me->callback == NULL) {
664 return E_OGGPLAY_UNINITIALISED;
668 * clean up any trash pointers. As soon as the current buffer has a
669 * frame taken out, we know the old buffer will no longer be used.
674 me->trash != NULL
676 (me->buffer == NULL || me->buffer->last_emptied > -1)
679 oggplay_take_out_trash(me, me->trash);
680 me->trash = NULL;
683 read_more_data:
685 while (1) {
687 * if there are no active tracks, we might need to return some data
688 * left over at the end of a once-active track that has had all of its
689 * data processed. Look through the tracks to find these overhangs
691 int r;
693 if (me->active_tracks == 0) {
694 int remaining = 0;
695 for (i = 0; i < me->num_tracks; i++) {
696 if (me->decode_data[i]->current_loc +
697 me->decode_data[i]->granuleperiod >= me->target + me->decode_data[i]->offset) {
698 remaining++;
701 if (remaining == 0) {
702 return E_OGGPLAY_OK;
707 * if any of the tracks have not yet met the target (modified by that
708 * track's offset), then retrieve more data
710 need_data = 0;
711 for (i = 0; i < me->num_tracks; i++) {
712 if (me->decode_data[i]->active == 0)
713 continue;
714 if (me->decode_data[i]->content_type == OGGZ_CONTENT_CMML)
715 continue;
716 if (me->decode_data[i]->content_type == OGGZ_CONTENT_KATE)
717 continue;
720 me->decode_data[i]->current_loc
722 me->target + me->decode_data[i]->offset
725 need_data = 1;
726 break;
730 if (!need_data) {
731 break;
735 * get a chunk of data. If we're at the end of the file, then we must
736 * have some final frames to render (?). E_OGGPLAY_END_OF_FILE is
737 * only returned if there is *no* more data.
740 if (chunk_count > MAX_CHUNK_COUNT) {
741 return E_OGGPLAY_TIMEOUT;
744 chunk_count += 1;
746 r = oggz_read(me->oggz, OGGZ_READ_CHUNK_SIZE);
748 switch (r) {
749 case 0:
750 /* end-of-file */
752 num_records = oggplay_callback_info_prepare(me, &info);
754 * set all of the tracks to inactive
756 for (i = 0; i < me->num_tracks; i++) {
757 me->decode_data[i]->active = 0;
759 me->active_tracks = 0;
761 if (info != NULL) {
762 me->callback (me, num_records, info, me->callback_user_ptr);
763 oggplay_callback_info_destroy(me, info);
767 * ensure all tracks have their final data packet set to end_of_stream
768 * But skip doing this if we're shutting down --- me->buffer may not
769 * be in a safe state.
771 if (me->buffer != NULL && !me->shutdown) {
772 oggplay_buffer_set_last_data(me, me->buffer);
775 /* we reached the end of the stream */
776 return E_OGGPLAY_OK;
778 case OGGZ_ERR_HOLE_IN_DATA:
779 /* there was a whole in the data */
780 return E_OGGPLAY_BAD_INPUT;
782 case OGGZ_ERR_STOP_ERR:
784 * one of the callback functions requested us to stop.
785 * as this currently happens only when one of the
786 * OggzReadPacket callback functions does not receive
787 * the user provided data, i.e. the OggPlayDecode struct
788 * for the track mark it as a memory problem, since this
789 * could happen only if something is wrong with the memory,
790 * e.g. some buffer overflow.
793 case OGGZ_ERR_OUT_OF_MEMORY:
794 /* ran out of memory during decoding! */
795 return E_OGGPLAY_OUT_OF_MEMORY;
797 default:
798 break;
802 * prepare a callback
804 num_records = oggplay_callback_info_prepare (me, &info);
805 if (info != NULL) {
806 r = me->callback (me, num_records, info, me->callback_user_ptr);
807 oggplay_callback_info_destroy (me, info);
808 } else {
809 r = 0;
813 * clean the data lists
815 for (i = 0; i < me->num_tracks; i++) {
816 oggplay_data_clean_list (me->decode_data[i]);
820 * there was an error during info prepare!
821 * abort decoding!
823 if (num_records < 0) {
824 return num_records;
827 /* if we received an shutdown event, dont try to read more data...*/
828 if (me->shutdown) {
829 return E_OGGPLAY_OK;
832 /* we require more data for decoding */
833 if (info == NULL) {
834 goto read_more_data;
837 me->target += me->callback_period;
838 if (r == -1) {
839 return E_OGGPLAY_USER_INTERRUPT;
842 return E_OGGPLAY_CONTINUE;
846 OggPlayErrorCode
847 oggplay_start_decoding(OggPlay *me) {
849 int r;
851 while (1) {
852 r = oggplay_step_decoding(me);
853 if (r == E_OGGPLAY_CONTINUE || r == E_OGGPLAY_TIMEOUT) {
854 continue;
856 return (OggPlayErrorCode)r;
860 OggPlayErrorCode
861 oggplay_close(OggPlay *me) {
863 int i;
865 if (me == NULL) {
866 return E_OGGPLAY_BAD_OGGPLAY;
869 if (me->reader != NULL) {
870 me->reader->destroy(me->reader);
873 /* */
874 if (me->decode_data != NULL) {
875 for (i = 0; i < me->num_tracks; i++) {
876 oggplay_callback_shutdown(me->decode_data[i]);
880 if (me->oggz)
881 oggz_close(me->oggz);
883 if (me->buffer != NULL) {
884 oggplay_buffer_shutdown(me, me->buffer);
887 if (me->callback_info != NULL) {
888 oggplay_free(me->callback_info);
891 oggplay_free(me->decode_data);
892 oggplay_free(me);
894 return E_OGGPLAY_OK;
898 * this function is required to release the frame_sem in the buffer, if
899 * the buffer is being used.
901 void
902 oggplay_prepare_for_close(OggPlay *me) {
904 me->shutdown = 1;
905 if (me->buffer != NULL) {
906 SEM_SIGNAL(((OggPlayBuffer *)(me->buffer))->frame_sem);
911 oggplay_get_available(OggPlay *me) {
913 ogg_int64_t current_time, current_byte;
915 if (me == NULL) {
916 return E_OGGPLAY_BAD_OGGPLAY;
919 current_time = oggz_tell_units(me->oggz);
920 current_byte = (ogg_int64_t)oggz_tell(me->oggz);
922 return me->reader->available(me->reader, current_byte, current_time);
926 ogg_int64_t
927 oggplay_get_duration(OggPlay *me) {
929 if (me == NULL) {
930 return E_OGGPLAY_BAD_OGGPLAY;
933 /* If the reader has a duration function we always call that
934 * function to find the duration. We never cache the result
935 * of that function.
937 * If there is no reader duration function we use our cached
938 * duration value, or do a liboggz seek to find it and cache
939 * that.
941 if (me->reader->duration) {
942 ogg_int64_t d = me->reader->duration(me->reader);
943 if (d >= 0) {
944 me->duration = d;
948 if (me->duration < 0) {
949 ogg_int64_t pos;
950 pos = oggz_tell_units(me->oggz);
951 me->duration = oggz_seek_units(me->oggz, 0, SEEK_END);
952 oggz_seek_units(me->oggz, pos, SEEK_SET);
953 oggplay_seek_cleanup(me, pos);
956 return me->duration;
960 oggplay_media_finished_retrieving(OggPlay *me) {
962 if (me == NULL) {
963 return E_OGGPLAY_BAD_OGGPLAY;
966 if (me->reader == NULL) {
967 return E_OGGPLAY_BAD_READER;
970 return me->reader->finished_retrieving(me->reader);