Mercurial > SDL_sound_CoreAudio
annotate decoders/quicktime.c @ 363:0b0457462ccc
Updated.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Thu, 13 Jun 2002 23:15:15 +0000 |
parents | 069ce624d6cf |
children | cbb15ecf423a |
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 #include <assert.h> | |
64 | |
65 #include "SDL_sound.h" | |
66 | |
67 #define __SDL_SOUND_INTERNAL__ | |
68 #include "SDL_sound_internal.h" | |
69 | |
70 static int QT_init(void); | |
71 static void QT_quit(void); | |
72 static int QT_open(Sound_Sample *sample, const char *ext); | |
73 static void QT_close(Sound_Sample *sample); | |
74 static Uint32 QT_read(Sound_Sample *sample); | |
75 static int QT_rewind(Sound_Sample *sample); | |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
76 static int QT_seek(Sound_Sample *sample, Uint32 ms); |
318 | 77 |
78 #define QT_MAX_INPUT_BUFFER (32*1024) /* Maximum size of internal buffer (internal->buffer_size) */ | |
79 | |
80 static const char *extensions_quicktime[] = { "mov", NULL }; | |
81 const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime = | |
82 { | |
83 { | |
84 extensions_quicktime, | |
85 "QuickTime format", | |
86 "Darrell Walisser <dwaliss1@purdue.edu>", | |
87 "http://www.icculus.org/SDL_sound/" | |
88 }, | |
89 | |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
90 QT_init, /* init() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
91 QT_quit, /* quit() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
92 QT_open, /* open() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
93 QT_close, /* close() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
94 QT_read, /* read() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
95 QT_rewind, /* rewind() method */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
96 QT_seek /* seek() method */ |
318 | 97 }; |
98 | |
99 typedef struct { | |
100 | |
101 ExtendedSoundComponentData compData; | |
102 Handle hSource; /* source media buffer */ | |
103 Media sourceMedia; /* sound media identifier */ | |
104 TimeValue getMediaAtThisTime; | |
105 TimeValue sourceDuration; | |
106 Boolean isThereMoreSource; | |
107 UInt32 maxBufferSize; | |
108 | |
109 } SCFillBufferData, *SCFillBufferDataPtr; | |
110 | |
111 typedef struct { | |
112 | |
113 Movie movie; | |
114 Track track; | |
115 Media media; | |
116 AudioFormatAtomPtr atom; | |
117 SoundComponentData source_format; | |
118 SoundComponentData dest_format; | |
119 SoundConverter converter; | |
120 SCFillBufferData buffer_data; | |
121 SoundConverterFillBufferDataUPP fill_buffer_proc; | |
122 | |
123 } qt_t; | |
124 | |
125 | |
126 | |
127 | |
128 /* | |
129 * This procedure creates a description of the raw data | |
130 * read from SDL_RWops so that QuickTime can identify | |
131 * the codec it needs to use to decompress it. | |
132 */ | |
133 static Handle QT_create_data_ref (const char *file_extension) { | |
134 | |
135 Handle tmp_handle, data_ref; | |
136 StringPtr file_name = "\p"; /* empty since we don't know the file name! */ | |
137 OSType file_type; | |
138 StringPtr mime_type; | |
139 long atoms[3]; | |
140 | |
141 /* | |
142 if (__Sound_strcasecmp (file_extension, "mp3")==0) { | |
143 file_type = 'MPEG'; | |
144 mime_type = "\pvideo/mpeg"; | |
145 } | |
146 else { | |
147 | |
148 return NULL; | |
149 } | |
150 */ | |
151 | |
152 if (__Sound_strcasecmp (file_extension, "mov") == 0) { | |
153 | |
154 file_type = 'MooV'; | |
155 mime_type = "\pvideo/quicktime"; | |
156 } | |
157 else { | |
158 | |
159 return NULL; | |
160 } | |
161 | |
162 tmp_handle = NewHandle(0); | |
163 assert (tmp_handle != NULL); | |
164 assert (noErr == PtrToHand (&tmp_handle, &data_ref, sizeof(Handle))); | |
165 assert (noErr == PtrAndHand (file_name, data_ref, file_name[0]+1)); | |
166 | |
167 atoms[0] = EndianU32_NtoB (sizeof(long) * 3); | |
168 atoms[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType); | |
169 atoms[2] = EndianU32_NtoB (file_type); | |
170 | |
171 assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*3)); | |
172 | |
173 atoms[0] = EndianU32_NtoB (sizeof(long)*2 + mime_type[0]+1); | |
174 atoms[1] = EndianU32_NtoB (kDataRefExtensionMIMEType); | |
175 | |
176 assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*2)); | |
177 assert (noErr == PtrAndHand (mime_type, data_ref, mime_type[0]+1)); | |
178 | |
179 return data_ref; | |
180 } | |
181 | |
182 /* | |
183 * This procedure is a hook for QuickTime to grab data from the | |
184 * SDL_RWOps data structure when it needs it | |
185 */ | |
186 static pascal OSErr QT_get_movie_data_proc (long offset, long size, | |
187 void *data, void *user_data) | |
188 { | |
189 SDL_RWops* rw = (SDL_RWops*)user_data; | |
190 OSErr error; | |
191 | |
192 if (offset == SDL_RWseek (rw, offset, SEEK_SET)) { | |
193 | |
194 if (size == SDL_RWread (rw, data, 1, size)) { | |
195 error = noErr; | |
196 } | |
197 else { | |
198 error = notEnoughDataErr; | |
199 } | |
200 } | |
201 else { | |
202 error = fileOffsetTooBigErr; | |
203 } | |
204 | |
205 return (error); | |
206 } | |
207 | |
208 /* * ---------------------------- | |
209 * SoundConverterFillBufferDataProc | |
210 * | |
211 * the callback routine that provides the source data for conversion - | |
212 * it provides data by setting outData to a pointer to a properly | |
213 * filled out ExtendedSoundComponentData structure | |
214 */ | |
215 static pascal Boolean QT_sound_converter_fill_buffer_data_proc (SoundComponentDataPtr *outData, void *inRefCon) | |
216 { | |
217 SCFillBufferDataPtr pFillData = (SCFillBufferDataPtr)inRefCon; | |
218 | |
219 OSErr err = noErr; | |
220 | |
221 /* if after getting the last chunk of data the total time is over | |
222 * the duration, we're done | |
223 */ | |
224 if (pFillData->getMediaAtThisTime >= pFillData->sourceDuration) { | |
225 pFillData->isThereMoreSource = false; | |
226 pFillData->compData.desc.buffer = NULL; | |
227 pFillData->compData.desc.sampleCount = 0; | |
228 pFillData->compData.bufferSize = 0; | |
229 } | |
230 | |
231 if (pFillData->isThereMoreSource) { | |
232 | |
233 long sourceBytesReturned; | |
234 long numberOfSamples; | |
235 TimeValue sourceReturnedTime, durationPerSample; | |
236 | |
237 HUnlock(pFillData->hSource); | |
238 | |
239 err = GetMediaSample | |
240 (pFillData->sourceMedia,/* specifies the media for this operation */ | |
241 pFillData->hSource, /* function returns the sample data into this handle */ | |
242 pFillData->maxBufferSize, /* maximum number of bytes of sample data to be returned */ | |
243 &sourceBytesReturned, /* the number of bytes of sample data returned */ | |
244 pFillData->getMediaAtThisTime,/* starting time of the sample to | |
245 be retrieved (must be in | |
246 Media's TimeScale) */ | |
247 &sourceReturnedTime,/* indicates the actual time of the returned sample data */ | |
248 &durationPerSample, /* duration of each sample in the media */ | |
249 NULL, /* sample description corresponding to the returned sample data (NULL to ignore) */ | |
250 NULL, /* index value to the sample description that corresponds | |
251 to the returned sample data (NULL to ignore) */ | |
252 0, /* maximum number of samples to be returned (0 to use a | |
253 value that is appropriate for the media) */ | |
254 &numberOfSamples, /* number of samples it actually returned */ | |
255 NULL); /* flags that describe the sample (NULL to ignore) */ | |
256 | |
257 HLock(pFillData->hSource); | |
258 | |
259 if ((noErr != err) || (sourceBytesReturned == 0)) { | |
260 pFillData->isThereMoreSource = false; | |
261 pFillData->compData.desc.buffer = NULL; | |
262 pFillData->compData.desc.sampleCount = 0; | |
263 | |
264 if ((err != noErr) && (sourceBytesReturned > 0)) | |
265 DebugStr("\pGetMediaSample - Failed in FillBufferDataProc"); | |
266 } | |
267 | |
268 pFillData->getMediaAtThisTime = sourceReturnedTime + (durationPerSample * numberOfSamples); | |
269 pFillData->compData.bufferSize = sourceBytesReturned; | |
270 } | |
271 | |
272 /* set outData to a properly filled out ExtendedSoundComponentData struct */ | |
273 *outData = (SoundComponentDataPtr)&pFillData->compData; | |
274 | |
275 return (pFillData->isThereMoreSource); | |
276 } | |
277 | |
278 | |
279 static int QT_init_internal () { | |
280 | |
281 OSErr error; | |
282 | |
283 error = EnterMovies(); /* initialize the movie toolbox */ | |
284 | |
285 return (error == noErr); | |
286 } | |
287 | |
288 static void QT_quit_internal () { | |
289 | |
290 ExitMovies(); | |
291 } | |
292 | |
293 static qt_t* QT_open_internal (Sound_Sample *sample, const char *extension) | |
294 { | |
295 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
296 | |
297 qt_t *instance; | |
298 OSErr error; | |
299 Movie movie; | |
300 Track sound_track; | |
301 Media sound_track_media; | |
302 AudioFormatAtomPtr source_sound_decomp_atom; | |
303 | |
304 SoundDescriptionV1Handle source_sound_description; | |
305 Handle source_sound_description_extension; | |
306 Size source_sound_description_extension_size; | |
307 Handle data_ref; | |
308 | |
309 data_ref = QT_create_data_ref (extension); | |
310 | |
311 /* create a movie that will read data using SDL_RWops */ | |
312 error = NewMovieFromUserProc | |
313 (&movie, | |
314 0, | |
315 NULL, | |
316 NewGetMovieUPP(QT_get_movie_data_proc), | |
317 (void*) internal->rw, | |
318 data_ref, | |
319 'hndl'); | |
320 | |
321 if (error != noErr) { | |
322 | |
323 return NULL; | |
324 } | |
325 | |
326 /* get the first sound track of the movie; other tracks will be ignored */ | |
327 sound_track = GetMovieIndTrackType (movie, 1, SoundMediaType, movieTrackMediaType); | |
328 if (sound_track == NULL) { | |
329 | |
330 /* movie needs a sound track! */ | |
331 | |
332 return NULL; | |
333 } | |
334 | |
335 /* get and return the sound track media */ | |
336 sound_track_media = GetTrackMedia (sound_track); | |
337 if (sound_track_media == NULL) { | |
338 | |
339 return NULL; | |
340 } | |
341 | |
342 /* create a description of the source sound so we can convert it later */ | |
343 source_sound_description = (SoundDescriptionV1Handle)NewHandle(0); | |
344 assert (source_sound_description != NULL); /* out of memory */ | |
345 | |
346 GetMediaSampleDescription (sound_track_media, 1, | |
347 (SampleDescriptionHandle)source_sound_description); | |
348 error = GetMoviesError(); | |
349 if (error != noErr) { | |
350 | |
351 return NULL; | |
352 } | |
353 | |
354 source_sound_description_extension = NewHandle(0); | |
355 assert (source_sound_description_extension != NULL); /* out of memory */ | |
356 | |
357 error = GetSoundDescriptionExtension ((SoundDescriptionHandle) source_sound_description, | |
358 &source_sound_description_extension, | |
359 siDecompressionParams); | |
360 | |
361 if (error == noErr) { | |
362 | |
363 /* copy extension to atom format description if we have an extension */ | |
364 | |
365 source_sound_description_extension_size = | |
366 GetHandleSize (source_sound_description_extension); | |
367 HLock (source_sound_description_extension); | |
368 | |
369 source_sound_decomp_atom = (AudioFormatAtom*) | |
370 NewPtr (source_sound_description_extension_size); | |
371 assert (source_sound_decomp_atom != NULL); /* out of memory */ | |
372 | |
373 BlockMoveData (*source_sound_description_extension, | |
374 source_sound_decomp_atom, | |
375 source_sound_description_extension_size); | |
376 | |
377 HUnlock (source_sound_description_extension); | |
378 } | |
379 | |
380 else { | |
381 | |
382 source_sound_decomp_atom = NULL; | |
383 } | |
384 | |
385 instance = (qt_t*) malloc (sizeof(*instance)); | |
386 assert (instance != NULL); /* out of memory */ | |
387 | |
388 instance->movie = movie; | |
389 instance->track = sound_track; | |
390 instance->media = sound_track_media; | |
391 instance->atom = source_sound_decomp_atom; | |
392 | |
393 instance->source_format.flags = 0; | |
394 instance->source_format.format = (*source_sound_description)->desc.dataFormat; | |
395 instance->source_format.numChannels = (*source_sound_description)->desc.numChannels; | |
396 instance->source_format.sampleSize = (*source_sound_description)->desc.sampleSize; | |
397 instance->source_format.sampleRate = (*source_sound_description)->desc.sampleRate; | |
398 instance->source_format.sampleCount = 0; | |
399 instance->source_format.buffer = NULL; | |
400 instance->source_format.reserved = 0; | |
401 | |
402 instance->dest_format.flags = 0; | |
403 instance->dest_format.format = kSoundNotCompressed; | |
404 instance->dest_format.numChannels = (*source_sound_description)->desc.numChannels; | |
405 instance->dest_format.sampleSize = (*source_sound_description)->desc.sampleSize; | |
406 instance->dest_format.sampleRate = (*source_sound_description)->desc.sampleRate; | |
407 instance->dest_format.sampleCount = 0; | |
408 instance->dest_format.buffer = NULL; | |
409 instance->dest_format.reserved = 0; | |
410 | |
411 sample->actual.channels = (*source_sound_description)->desc.numChannels; | |
412 sample->actual.rate = (*source_sound_description)->desc.sampleRate >> 16; | |
413 | |
414 if ((*source_sound_description)->desc.sampleSize == 16) { | |
415 | |
416 sample->actual.format = AUDIO_S16SYS; | |
417 } | |
418 else if ((*source_sound_description)->desc.sampleSize == 8) { | |
419 | |
420 sample->actual.format = AUDIO_U8; | |
421 } | |
422 else { | |
423 | |
424 /* 24-bit or others... (which SDL can't handle) */ | |
425 return NULL; | |
426 } | |
427 | |
428 DisposeHandle (source_sound_description_extension); | |
429 DisposeHandle ((Handle)source_sound_description); | |
430 | |
431 /* This next code sets up the SoundConverter component */ | |
432 error = SoundConverterOpen (&instance->source_format, &instance->dest_format, | |
433 &instance->converter); | |
434 | |
435 if (error != noErr) { | |
436 | |
437 return NULL; | |
438 } | |
439 | |
440 error = SoundConverterSetInfo (instance->converter, siDecompressionParams, | |
441 instance->atom); | |
442 if (error == siUnknownInfoType) { | |
443 | |
444 /* ignore */ | |
445 } | |
446 else if (error != noErr) { | |
447 | |
448 /* reall error */ | |
449 return NULL; | |
450 } | |
451 | |
452 error = SoundConverterBeginConversion (instance->converter); | |
453 if (error != noErr) { | |
454 | |
455 return NULL; | |
456 } | |
457 | |
458 instance->buffer_data.sourceMedia = instance->media; | |
459 instance->buffer_data.getMediaAtThisTime = 0; | |
460 instance->buffer_data.sourceDuration = GetMediaDuration(instance->media); | |
461 instance->buffer_data.isThereMoreSource = true; | |
462 instance->buffer_data.maxBufferSize = QT_MAX_INPUT_BUFFER; | |
463 /* allocate source media buffer */ | |
464 instance->buffer_data.hSource = NewHandle((long)instance->buffer_data.maxBufferSize); | |
465 assert (instance->buffer_data.hSource != NULL); /* out of memory */ | |
466 | |
467 instance->buffer_data.compData.desc = instance->source_format; | |
468 instance->buffer_data.compData.desc.buffer = (Byte *)*instance->buffer_data.hSource; | |
469 instance->buffer_data.compData.desc.flags = kExtendedSoundData; | |
470 instance->buffer_data.compData.recordSize = sizeof(ExtendedSoundComponentData); | |
471 instance->buffer_data.compData.extendedFlags = | |
472 kExtendedSoundSampleCountNotValid | kExtendedSoundBufferSizeValid; | |
473 instance->buffer_data.compData.bufferSize = 0; | |
474 | |
475 instance->fill_buffer_proc = | |
476 NewSoundConverterFillBufferDataUPP (QT_sound_converter_fill_buffer_data_proc); | |
477 | |
478 return (instance); | |
479 | |
480 } /* QT_open_internal */ | |
481 | |
482 static void QT_close_internal (qt_t *instance) | |
483 { | |
484 | |
485 } /* QT_close_internal */ | |
486 | |
487 static Uint32 QT_read_internal(Sound_Sample *sample) | |
488 { | |
489 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
490 qt_t *instance = (qt_t*) internal->decoder_private; | |
491 long output_bytes, output_frames, output_flags; | |
492 OSErr error; | |
493 | |
494 error = SoundConverterFillBuffer | |
495 (instance->converter, /* a sound converter */ | |
496 instance->fill_buffer_proc, /* the callback UPP */ | |
497 &instance->buffer_data, /* refCon passed to FillDataProc */ | |
498 internal->buffer, /* the decompressed data 'play' buffer */ | |
499 internal->buffer_size, /* size of the 'play' buffer */ | |
500 &output_bytes, /* number of output bytes */ | |
501 &output_frames, /* number of output frames */ | |
502 &output_flags); /* fillbuffer retured advisor flags */ | |
503 | |
504 if (output_flags & kSoundConverterHasLeftOverData) { | |
505 | |
506 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; | |
507 } | |
508 else { | |
509 | |
510 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
511 } | |
512 | |
513 if (error != noErr) { | |
514 | |
515 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
516 } | |
517 | |
518 return (output_bytes); | |
519 | |
520 } /* QT_read_internal */ | |
521 | |
522 static int QT_rewind_internal (Sound_Sample *sample) | |
523 { | |
524 | |
525 return 0; | |
526 | |
527 } /* QT_rewind_internal */ | |
528 | |
529 | |
530 | |
531 static int QT_init(void) | |
532 { | |
533 return (QT_init_internal()); | |
534 | |
535 } /* QT_init */ | |
536 | |
537 static void QT_quit(void) | |
538 { | |
539 QT_quit_internal(); | |
540 | |
541 } /* QT_quit */ | |
542 | |
543 static int QT_open(Sound_Sample *sample, const char *ext) | |
544 { | |
545 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
546 qt_t *instance; | |
547 | |
548 instance = QT_open_internal(sample, ext); | |
549 internal->decoder_private = (void*)instance; | |
550 | |
551 return(instance != NULL); | |
552 | |
553 } /* QT_open */ | |
554 | |
555 | |
556 static void QT_close(Sound_Sample *sample) | |
557 { | |
558 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
559 qt_t *instance = (qt_t *) internal->decoder_private; | |
560 | |
561 QT_close_internal (instance); | |
562 | |
563 free (instance); | |
564 | |
565 } /* QT_close */ | |
566 | |
567 | |
568 static Uint32 QT_read(Sound_Sample *sample) | |
569 { | |
570 return(QT_read_internal(sample)); | |
571 | |
572 } /* QT_read */ | |
573 | |
574 | |
575 static int QT_rewind(Sound_Sample *sample) | |
576 { | |
577 | |
578 return(QT_rewind_internal(sample)); | |
579 | |
580 } /* QT_rewind */ | |
581 | |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
582 |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
583 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
|
584 { |
351 | 585 BAIL_MACRO("QUICKTIME: Seeking not implemented", 0); |
328
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
586 } /* QT_seek */ |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
587 |
a7c1dbcf5e00
Added a seek method stub.
Ryan C. Gordon <icculus@icculus.org>
parents:
318
diff
changeset
|
588 |
318 | 589 #endif /* SOUND_SUPPORTS_QUICKTIME */ |
590 | |
591 /* end of quicktime.c ... */ | |
592 |