Mercurial > SDL_sound_CoreAudio
annotate decoders/quicktime.c @ 474:c66080364dff
Most decoders now report total sample play time, now. Technically, this
breaks binary compatibility with the 1.0 branch, since it extends the
Sound_Sample struct, but most (all?) programs are just passing pointers
allocated by SDL_sound around, and might be okay.
Source-level compatibility is not broken...yet! :)
--ryan.
-------- Original Message --------
Subject: SDL_sound patch: Finding total length of time of sound file.
Date: Sun, 26 Jan 2003 09:31:17 -0800 (PST)
Hi Ryan,
I am working with Eric Wing and helping him modify
SDL_sound. AS part of our efforts in improving and
enhancing SDL_sound, we like to submit this patch. We
modified the codecs to find the total time of a sound
file. Below is the explanation of the patch. The
patch is appended as an attachment to this email.
* MOTIVATION:
We needed the ability to get the total play time of a
sample (And we noticed that we're not the only ones).
Since SDL_sound blocks direct access to the specific
decoders, there is no way for a user to know this
information short of decoding the whole thing.
Because of this, we believe this will be a useful
addition, even though the accuracy may not be perfect
(subject to each decoder) or the information may not
always be available.
* CONTRIBUTORS:
Wesley Leong (modified the majority of the codecs and
verified the results)
Eric Wing (showed everyone how to do modify codec,
modified mikmod)
Wang Lam (modified a handful of codecs, researched
into specs and int overflow)
Ahilan Anantha (modified a few codecs and helped with
integer math)
* GENERAL ISSUES:
We chose the value to be milliseconds as an Sint32.
Milliseconds because that's what Sound_Seek takes as a
parameter and -1 to allow for instances/codecs where
the value could not be determined. We are
not sure if this is the final convention you want, so
we are willing to work with you on this.
We also expect the total_time field to be set on open
and never again modified by SDL_sound. Users may
access it directly much like the sample buffer and
buffer_size. We thought about recomputing the time
on DecodeAll, but since users may seek or decode small
chunks first, not all the data may be there. So this
is better done by the user. This may be good
information to document.
Currently, all the main codecs are implemented except
for QuickTime.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sat, 08 May 2004 08:19:50 +0000 |
parents | cbb15ecf423a |
children | 3e705c9180e5 |
rev | line source |
---|---|
318 | 1 /* |
2 * SDL_sound -- An abstract sound format decoding API. | |
3 * Copyright (C) 2001 Ryan C. Gordon. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2.1 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * QuickTime decoder for sound formats that QuickTime supports. | |
22 * April 28, 2002 | |
23 * | |
24 * This driver handles .mov files with a sound track. In | |
25 * theory, it could handle any format that QuickTime supports. | |
26 * In practice, it may only handle a select few of these formats. | |
27 * | |
28 * It seems able to play back AIFF and other standard Mac formats. | |
29 * Rewinding is not supported yet. | |
30 * | |
31 * The routine QT_create_data_ref() needs to be | |
32 * tweaked to support different media types. | |
33 * This code was originally written to get MP3 support, | |
34 * as it turns out, this isn't possible using this method. | |
35 * | |
36 * The only way to get streaming MP3 support through QuickTime, | |
37 * and hence support for SDL_RWops, is to write | |
38 * a DataHandler component, which suddenly gets much more difficult :-( | |
39 * | |
40 * This file was written by Darrell Walisser (walisser@mac.com) | |
41 * Portions have been borrowed from the "MP3Player" sample code, | |
42 * courtesy of Apple. | |
43 */ | |
44 | |
45 #if HAVE_CONFIG_H | |
46 # include <config.h> | |
47 #endif | |
48 | |
49 #ifdef SOUND_SUPPORTS_QUICKTIME | |
50 #ifdef macintosh | |
51 typedef long int32_t; | |
52 # define OPAQUE_UPP_TYPES 0 | |
53 # include <QuickTime.h> | |
54 #else | |
55 # include <QuickTime/QuickTime.h> | |
56 # include <Carbon/Carbon.h> | |
57 #endif | |
58 | |
59 #include <stdio.h> | |
60 #include <stdlib.h> | |
61 #include <stdint.h> | |
62 #include <string.h> | |
63 | |
64 #include "SDL_sound.h" | |
65 | |
66 #define __SDL_SOUND_INTERNAL__ | |
67 #include "SDL_sound_internal.h" | |
68 | |
69 static int QT_init(void); | |
70 static void QT_quit(void); | |
71 static int QT_open(Sound_Sample *sample, const char *ext); | |
72 static void QT_close(Sound_Sample *sample); | |
73 static Uint32 QT_read(Sound_Sample *sample); | |
74 static int QT_rewind(Sound_Sample *sample); | |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
75 static int QT_seek(Sound_Sample *sample, Uint32 ms); |
318 | 76 |
77 #define QT_MAX_INPUT_BUFFER (32*1024) /* Maximum size of internal buffer (internal->buffer_size) */ | |
78 | |
79 static const char *extensions_quicktime[] = { "mov", NULL }; | |
80 const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime = | |
81 { | |
82 { | |
83 extensions_quicktime, | |
84 "QuickTime format", | |
85 "Darrell Walisser <dwaliss1@purdue.edu>", | |
86 "http://www.icculus.org/SDL_sound/" | |
87 }, | |
88 | |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
89 QT_init, /* init() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
90 QT_quit, /* quit() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
91 QT_open, /* open() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
92 QT_close, /* close() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
93 QT_read, /* read() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
94 QT_rewind, /* rewind() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
95 QT_seek /* seek() method */ |
318 | 96 }; |
97 | |
98 typedef struct { | |
99 | |
100 ExtendedSoundComponentData compData; | |
101 Handle hSource; /* source media buffer */ | |
102 Media sourceMedia; /* sound media identifier */ | |
103 TimeValue getMediaAtThisTime; | |
104 TimeValue sourceDuration; | |
105 Boolean isThereMoreSource; | |
106 UInt32 maxBufferSize; | |
107 | |
108 } SCFillBufferData, *SCFillBufferDataPtr; | |
109 | |
110 typedef struct { | |
111 | |
112 Movie movie; | |
113 Track track; | |
114 Media media; | |
115 AudioFormatAtomPtr atom; | |
116 SoundComponentData source_format; | |
117 SoundComponentData dest_format; | |
118 SoundConverter converter; | |
119 SCFillBufferData buffer_data; | |
120 SoundConverterFillBufferDataUPP fill_buffer_proc; | |
121 | |
122 } qt_t; | |
123 | |
124 | |
125 | |
126 | |
127 /* | |
128 * This procedure creates a description of the raw data | |
129 * read from SDL_RWops so that QuickTime can identify | |
130 * the codec it needs to use to decompress it. | |
131 */ | |
132 static Handle QT_create_data_ref (const char *file_extension) { | |
133 | |
134 Handle tmp_handle, data_ref; | |
135 StringPtr file_name = "\p"; /* empty since we don't know the file name! */ | |
136 OSType file_type; | |
137 StringPtr mime_type; | |
138 long atoms[3]; | |
139 | |
140 /* | |
141 if (__Sound_strcasecmp (file_extension, "mp3")==0) { | |
142 file_type = 'MPEG'; | |
143 mime_type = "\pvideo/mpeg"; | |
144 } | |
145 else { | |
146 | |
147 return NULL; | |
148 } | |
149 */ | |
150 | |
151 if (__Sound_strcasecmp (file_extension, "mov") == 0) { | |
152 | |
153 file_type = 'MooV'; | |
154 mime_type = "\pvideo/quicktime"; | |
155 } | |
156 else { | |
157 | |
158 return NULL; | |
159 } | |
160 | |
161 tmp_handle = NewHandle(0); | |
162 assert (tmp_handle != NULL); | |
163 assert (noErr == PtrToHand (&tmp_handle, &data_ref, sizeof(Handle))); | |
164 assert (noErr == PtrAndHand (file_name, data_ref, file_name[0]+1)); | |
165 | |
166 atoms[0] = EndianU32_NtoB (sizeof(long) * 3); | |
167 atoms[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType); | |
168 atoms[2] = EndianU32_NtoB (file_type); | |
169 | |
170 assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*3)); | |
171 | |
172 atoms[0] = EndianU32_NtoB (sizeof(long)*2 + mime_type[0]+1); | |
173 atoms[1] = EndianU32_NtoB (kDataRefExtensionMIMEType); | |
174 | |
175 assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*2)); | |
176 assert (noErr == PtrAndHand (mime_type, data_ref, mime_type[0]+1)); | |
177 | |
178 return data_ref; | |
179 } | |
180 | |
181 /* | |
182 * This procedure is a hook for QuickTime to grab data from the | |
183 * SDL_RWOps data structure when it needs it | |
184 */ | |
185 static pascal OSErr QT_get_movie_data_proc (long offset, long size, | |
186 void *data, void *user_data) | |
187 { | |
188 SDL_RWops* rw = (SDL_RWops*)user_data; | |
189 OSErr error; | |
190 | |
191 if (offset == SDL_RWseek (rw, offset, SEEK_SET)) { | |
192 | |
193 if (size == SDL_RWread (rw, data, 1, size)) { | |
194 error = noErr; | |
195 } | |
196 else { | |
197 error = notEnoughDataErr; | |
198 } | |
199 } | |
200 else { | |
201 error = fileOffsetTooBigErr; | |
202 } | |
203 | |
204 return (error); | |
205 } | |
206 | |
207 /* * ---------------------------- | |
208 * SoundConverterFillBufferDataProc | |
209 * | |
210 * the callback routine that provides the source data for conversion - | |
211 * it provides data by setting outData to a pointer to a properly | |
212 * filled out ExtendedSoundComponentData structure | |
213 */ | |
214 static pascal Boolean QT_sound_converter_fill_buffer_data_proc (SoundComponentDataPtr *outData, void *inRefCon) | |
215 { | |
216 SCFillBufferDataPtr pFillData = (SCFillBufferDataPtr)inRefCon; | |
217 | |
218 OSErr err = noErr; | |
219 | |
220 /* if after getting the last chunk of data the total time is over | |
221 * the duration, we're done | |
222 */ | |
223 if (pFillData->getMediaAtThisTime >= pFillData->sourceDuration) { | |
224 pFillData->isThereMoreSource = false; | |
225 pFillData->compData.desc.buffer = NULL; | |
226 pFillData->compData.desc.sampleCount = 0; | |
227 pFillData->compData.bufferSize = 0; | |
228 } | |
229 | |
230 if (pFillData->isThereMoreSource) { | |
231 | |
232 long sourceBytesReturned; | |
233 long numberOfSamples; | |
234 TimeValue sourceReturnedTime, durationPerSample; | |
235 | |
236 HUnlock(pFillData->hSource); | |
237 | |
238 err = GetMediaSample | |
239 (pFillData->sourceMedia,/* specifies the media for this operation */ | |
240 pFillData->hSource, /* function returns the sample data into this handle */ | |
241 pFillData->maxBufferSize, /* maximum number of bytes of sample data to be returned */ | |
242 &sourceBytesReturned, /* the number of bytes of sample data returned */ | |
243 pFillData->getMediaAtThisTime,/* starting time of the sample to | |
244 be retrieved (must be in | |
245 Media's TimeScale) */ | |
246 &sourceReturnedTime,/* indicates the actual time of the returned sample data */ | |
247 &durationPerSample, /* duration of each sample in the media */ | |
248 NULL, /* sample description corresponding to the returned sample data (NULL to ignore) */ | |
249 NULL, /* index value to the sample description that corresponds | |
250 to the returned sample data (NULL to ignore) */ | |
251 0, /* maximum number of samples to be returned (0 to use a | |
252 value that is appropriate for the media) */ | |
253 &numberOfSamples, /* number of samples it actually returned */ | |
254 NULL); /* flags that describe the sample (NULL to ignore) */ | |
255 | |
256 HLock(pFillData->hSource); | |
257 | |
258 if ((noErr != err) || (sourceBytesReturned == 0)) { | |
259 pFillData->isThereMoreSource = false; | |
260 pFillData->compData.desc.buffer = NULL; | |
261 pFillData->compData.desc.sampleCount = 0; | |
262 | |
263 if ((err != noErr) && (sourceBytesReturned > 0)) | |
264 DebugStr("\pGetMediaSample - Failed in FillBufferDataProc"); | |
265 } | |
266 | |
267 pFillData->getMediaAtThisTime = sourceReturnedTime + (durationPerSample * numberOfSamples); | |
268 pFillData->compData.bufferSize = sourceBytesReturned; | |
269 } | |
270 | |
271 /* set outData to a properly filled out ExtendedSoundComponentData struct */ | |
272 *outData = (SoundComponentDataPtr)&pFillData->compData; | |
273 | |
274 return (pFillData->isThereMoreSource); | |
275 } | |
276 | |
277 | |
278 static int QT_init_internal () { | |
279 | |
280 OSErr error; | |
281 | |
282 error = EnterMovies(); /* initialize the movie toolbox */ | |
283 | |
284 return (error == noErr); | |
285 } | |
286 | |
287 static void QT_quit_internal () { | |
288 | |
289 ExitMovies(); | |
290 } | |
291 | |
292 static qt_t* QT_open_internal (Sound_Sample *sample, const char *extension) | |
293 { | |
294 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
295 | |
296 qt_t *instance; | |
297 OSErr error; | |
298 Movie movie; | |
299 Track sound_track; | |
300 Media sound_track_media; | |
301 AudioFormatAtomPtr source_sound_decomp_atom; | |
302 | |
303 SoundDescriptionV1Handle source_sound_description; | |
304 Handle source_sound_description_extension; | |
305 Size source_sound_description_extension_size; | |
306 Handle data_ref; | |
307 | |
308 data_ref = QT_create_data_ref (extension); | |
309 | |
310 /* create a movie that will read data using SDL_RWops */ | |
311 error = NewMovieFromUserProc | |
312 (&movie, | |
313 0, | |
314 NULL, | |
315 NewGetMovieUPP(QT_get_movie_data_proc), | |
316 (void*) internal->rw, | |
317 data_ref, | |
318 'hndl'); | |
319 | |
320 if (error != noErr) { | |
321 | |
322 return NULL; | |
323 } | |
324 | |
325 /* get the first sound track of the movie; other tracks will be ignored */ | |
326 sound_track = GetMovieIndTrackType (movie, 1, SoundMediaType, movieTrackMediaType); | |
327 if (sound_track == NULL) { | |
328 | |
329 /* movie needs a sound track! */ | |
330 | |
331 return NULL; | |
332 } | |
333 | |
334 /* get and return the sound track media */ | |
335 sound_track_media = GetTrackMedia (sound_track); | |
336 if (sound_track_media == NULL) { | |
337 | |
338 return NULL; | |
339 } | |
340 | |
341 /* create a description of the source sound so we can convert it later */ | |
342 source_sound_description = (SoundDescriptionV1Handle)NewHandle(0); | |
343 assert (source_sound_description != NULL); /* out of memory */ | |
344 | |
345 GetMediaSampleDescription (sound_track_media, 1, | |
346 (SampleDescriptionHandle)source_sound_description); | |
347 error = GetMoviesError(); | |
348 if (error != noErr) { | |
349 | |
350 return NULL; | |
351 } | |
352 | |
353 source_sound_description_extension = NewHandle(0); | |
354 assert (source_sound_description_extension != NULL); /* out of memory */ | |
355 | |
356 error = GetSoundDescriptionExtension ((SoundDescriptionHandle) source_sound_description, | |
357 &source_sound_description_extension, | |
358 siDecompressionParams); | |
359 | |
360 if (error == noErr) { | |
361 | |
362 /* copy extension to atom format description if we have an extension */ | |
363 | |
364 source_sound_description_extension_size = | |
365 GetHandleSize (source_sound_description_extension); | |
366 HLock (source_sound_description_extension); | |
367 | |
368 source_sound_decomp_atom = (AudioFormatAtom*) | |
369 NewPtr (source_sound_description_extension_size); | |
370 assert (source_sound_decomp_atom != NULL); /* out of memory */ | |
371 | |
372 BlockMoveData (*source_sound_description_extension, | |
373 source_sound_decomp_atom, | |
374 source_sound_description_extension_size); | |
375 | |
376 HUnlock (source_sound_description_extension); | |
377 } | |
378 | |
379 else { | |
380 | |
381 source_sound_decomp_atom = NULL; | |
382 } | |
383 | |
384 instance = (qt_t*) malloc (sizeof(*instance)); | |
385 assert (instance != NULL); /* out of memory */ | |
386 | |
387 instance->movie = movie; | |
388 instance->track = sound_track; | |
389 instance->media = sound_track_media; | |
390 instance->atom = source_sound_decomp_atom; | |
391 | |
392 instance->source_format.flags = 0; | |
393 instance->source_format.format = (*source_sound_description)->desc.dataFormat; | |
394 instance->source_format.numChannels = (*source_sound_description)->desc.numChannels; | |
395 instance->source_format.sampleSize = (*source_sound_description)->desc.sampleSize; | |
396 instance->source_format.sampleRate = (*source_sound_description)->desc.sampleRate; | |
397 instance->source_format.sampleCount = 0; | |
398 instance->source_format.buffer = NULL; | |
399 instance->source_format.reserved = 0; | |
400 | |
401 instance->dest_format.flags = 0; | |
402 instance->dest_format.format = kSoundNotCompressed; | |
403 instance->dest_format.numChannels = (*source_sound_description)->desc.numChannels; | |
404 instance->dest_format.sampleSize = (*source_sound_description)->desc.sampleSize; | |
405 instance->dest_format.sampleRate = (*source_sound_description)->desc.sampleRate; | |
406 instance->dest_format.sampleCount = 0; | |
407 instance->dest_format.buffer = NULL; | |
408 instance->dest_format.reserved = 0; | |
409 | |
410 sample->actual.channels = (*source_sound_description)->desc.numChannels; | |
411 sample->actual.rate = (*source_sound_description)->desc.sampleRate >> 16; | |
412 | |
413 if ((*source_sound_description)->desc.sampleSize == 16) { | |
414 | |
415 sample->actual.format = AUDIO_S16SYS; | |
416 } | |
417 else if ((*source_sound_description)->desc.sampleSize == 8) { | |
418 | |
419 sample->actual.format = AUDIO_U8; | |
420 } | |
421 else { | |
422 | |
423 /* 24-bit or others... (which SDL can't handle) */ | |
424 return NULL; | |
425 } | |
426 | |
427 DisposeHandle (source_sound_description_extension); | |
428 DisposeHandle ((Handle)source_sound_description); | |
429 | |
430 /* This next code sets up the SoundConverter component */ | |
431 error = SoundConverterOpen (&instance->source_format, &instance->dest_format, | |
432 &instance->converter); | |
433 | |
434 if (error != noErr) { | |
435 | |
436 return NULL; | |
437 } | |
438 | |
439 error = SoundConverterSetInfo (instance->converter, siDecompressionParams, | |
440 instance->atom); | |
441 if (error == siUnknownInfoType) { | |
442 | |
443 /* ignore */ | |
444 } | |
445 else if (error != noErr) { | |
446 | |
447 /* reall error */ | |
448 return NULL; | |
449 } | |
450 | |
451 error = SoundConverterBeginConversion (instance->converter); | |
452 if (error != noErr) { | |
453 | |
454 return NULL; | |
455 } | |
456 | |
457 instance->buffer_data.sourceMedia = instance->media; | |
458 instance->buffer_data.getMediaAtThisTime = 0; | |
459 instance->buffer_data.sourceDuration = GetMediaDuration(instance->media); | |
460 instance->buffer_data.isThereMoreSource = true; | |
461 instance->buffer_data.maxBufferSize = QT_MAX_INPUT_BUFFER; | |
462 /* allocate source media buffer */ | |
463 instance->buffer_data.hSource = NewHandle((long)instance->buffer_data.maxBufferSize); | |
464 assert (instance->buffer_data.hSource != NULL); /* out of memory */ | |
465 | |
466 instance->buffer_data.compData.desc = instance->source_format; | |
467 instance->buffer_data.compData.desc.buffer = (Byte *)*instance->buffer_data.hSource; | |
468 instance->buffer_data.compData.desc.flags = kExtendedSoundData; | |
469 instance->buffer_data.compData.recordSize = sizeof(ExtendedSoundComponentData); | |
470 instance->buffer_data.compData.extendedFlags = | |
471 kExtendedSoundSampleCountNotValid | kExtendedSoundBufferSizeValid; | |
472 instance->buffer_data.compData.bufferSize = 0; | |
473 | |
474 instance->fill_buffer_proc = | |
475 NewSoundConverterFillBufferDataUPP (QT_sound_converter_fill_buffer_data_proc); | |
476 | |
477 return (instance); | |
478 | |
479 } /* QT_open_internal */ | |
480 | |
481 static void QT_close_internal (qt_t *instance) | |
482 { | |
483 | |
484 } /* QT_close_internal */ | |
485 | |
486 static Uint32 QT_read_internal(Sound_Sample *sample) | |
487 { | |
488 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
489 qt_t *instance = (qt_t*) internal->decoder_private; | |
490 long output_bytes, output_frames, output_flags; | |
491 OSErr error; | |
492 | |
493 error = SoundConverterFillBuffer | |
494 (instance->converter, /* a sound converter */ | |
495 instance->fill_buffer_proc, /* the callback UPP */ | |
496 &instance->buffer_data, /* refCon passed to FillDataProc */ | |
497 internal->buffer, /* the decompressed data 'play' buffer */ | |
498 internal->buffer_size, /* size of the 'play' buffer */ | |
499 &output_bytes, /* number of output bytes */ | |
500 &output_frames, /* number of output frames */ | |
501 &output_flags); /* fillbuffer retured advisor flags */ | |
502 | |
503 if (output_flags & kSoundConverterHasLeftOverData) { | |
504 | |
505 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; | |
506 } | |
507 else { | |
508 | |
509 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
510 } | |
511 | |
512 if (error != noErr) { | |
513 | |
514 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
515 } | |
516 | |
517 return (output_bytes); | |
518 | |
519 } /* QT_read_internal */ | |
520 | |
521 static int QT_rewind_internal (Sound_Sample *sample) | |
522 { | |
523 | |
524 return 0; | |
525 | |
526 } /* QT_rewind_internal */ | |
527 | |
528 | |
529 | |
530 static int QT_init(void) | |
531 { | |
532 return (QT_init_internal()); | |
533 | |
534 } /* QT_init */ | |
535 | |
536 static void QT_quit(void) | |
537 { | |
538 QT_quit_internal(); | |
539 | |
540 } /* QT_quit */ | |
541 | |
542 static int QT_open(Sound_Sample *sample, const char *ext) | |
543 { | |
544 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
545 qt_t *instance; | |
546 | |
547 instance = QT_open_internal(sample, ext); | |
548 internal->decoder_private = (void*)instance; | |
549 | |
474
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
550 sample->total_time = -1; /* return -1 for total time of song for now */ |
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
551 |
318 | 552 return(instance != NULL); |
553 | |
554 } /* QT_open */ | |
555 | |
556 | |
557 static void QT_close(Sound_Sample *sample) | |
558 { | |
559 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
560 qt_t *instance = (qt_t *) internal->decoder_private; | |
561 | |
562 QT_close_internal (instance); | |
563 | |
564 free (instance); | |
565 | |
566 } /* QT_close */ | |
567 | |
568 | |
569 static Uint32 QT_read(Sound_Sample *sample) | |
570 { | |
571 return(QT_read_internal(sample)); | |
572 | |
573 } /* QT_read */ | |
574 | |
575 | |
576 static int QT_rewind(Sound_Sample *sample) | |
577 { | |
578 | |
579 return(QT_rewind_internal(sample)); | |
580 | |
581 } /* QT_rewind */ | |
582 | |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
583 |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
584 static int QT_seek(Sound_Sample *sample, Uint32 ms) |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
585 { |
351 | 586 BAIL_MACRO("QUICKTIME: Seeking not implemented", 0); |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
587 } /* QT_seek */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
588 |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
589 |
318 | 590 #endif /* SOUND_SUPPORTS_QUICKTIME */ |
591 | |
592 /* end of quicktime.c ... */ | |
593 |