source: trunk/ff_MovieImport.c @ 1271

Revision 1271, 18.8 KB checked in by astrange, 4 years ago (diff)

Enable Indeo 5 decoder.

Refs #417.
Fix lack of mention of "MPEG-4" in the readme along the way.

Line 
1/*****************************************************************************
2*
3*  Avi Import Component QuickTime Component Interface
4*
5*  Copyright(C) 2006 Christoph Naegeli <chn1@mac.com>
6*
7*  This library is free software; you can redistribute it and/or
8*  modify it under the terms of the GNU Lesser General Public
9*  License as published by the Free Software Foundation; either
10*  version 2.1 of the License, or (at your option) any later version.
11
12*  This library is distributed in the hope that it will be useful,
13*  but WITHOUT ANY WARRANTY; without even the implied warranty of
14*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*  Lesser General Public License for more details.
16
17*  You should have received a copy of the GNU Lesser General Public
18*  License along with this library; if not, write to the Free Software
19*  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20*
21****************************************************************************/
22
23#include "ff_MovieImportVersion.h"
24#include "ff_private.h"
25#include "Codecprintf.h"
26#include "riff.h"
27#include "SubImport.h"
28#include "CommonUtils.h"
29
30/* This one is a little big in ffmpeg and private anyway */
31#define PROBE_BUF_SIZE 64
32
33#include <CoreServices/CoreServices.h>
34#include <QuickTime/QuickTime.h>
35#include <pthread.h>
36
37#define MOVIEIMPORT_BASENAME()          FFAvi_MovieImport
38#define MOVIEIMPORT_GLOBALS()           ff_global_ptr storage
39
40#define CALLCOMPONENT_BASENAME()        MOVIEIMPORT_BASENAME()
41#define CALLCOMPONENT_GLOBALS()         MOVIEIMPORT_GLOBALS()
42
43#define COMPONENT_DISPATCH_FILE         "ff_MovieImportDispatch.h"
44#define COMPONENT_UPP_SELECT_ROOT()     MovieImport
45
46#include <CoreServices/Components.k.h>
47#include <QuickTime/QuickTimeComponents.k.h>
48#include <QuickTime/ComponentDispatchHelper.c>
49
50#pragma mark -
51
52static int PerianLockMgrCallback(void **mutex, enum AVLockOp op)
53{
54        pthread_mutex_t **m = (pthread_mutex_t **)mutex;
55        int ret = 0;
56       
57        switch (op) {
58                case AV_LOCK_CREATE:
59                        *m = malloc(sizeof(pthread_mutex_t));
60                        ret = pthread_mutex_init(*m, NULL);
61                        break;
62                case AV_LOCK_OBTAIN:
63                        ret = pthread_mutex_lock(*m);
64                        break;
65                case AV_LOCK_RELEASE:
66                        ret = pthread_mutex_unlock(*m);
67                        break;
68                case AV_LOCK_DESTROY:
69                        ret = pthread_mutex_destroy(*m);
70                        free(*m);
71        }
72       
73        return ret;
74}
75
76#define REGISTER_MUXER(x) { \
77        extern AVOutputFormat x##_muxer; \
78                av_register_output_format(&x##_muxer); }
79#define REGISTER_DEMUXER(x) { \
80        extern AVInputFormat x##_demuxer; \
81                av_register_input_format(&x##_demuxer); }
82#define REGISTER_MUXDEMUX(x)  REGISTER_MUXER(x); REGISTER_DEMUXER(x)
83#define REGISTER_PROTOCOL(x) { \
84        extern URLProtocol x##_protocol; \
85                register_protocol(&x##_protocol); }
86
87#define REGISTER_ENCODER(x) { \
88        extern AVCodec x##_encoder; \
89                register_avcodec(&x##_encoder); }
90#define REGISTER_DECODER(x) { \
91        extern AVCodec x##_decoder; \
92                avcodec_register(&x##_decoder); }
93#define REGISTER_ENCDEC(x)  REGISTER_ENCODER(x); REGISTER_DECODER(x)
94
95#define REGISTER_PARSER(x) { \
96        extern AVCodecParser x##_parser; \
97                av_register_codec_parser(&x##_parser); }
98#define REGISTER_BSF(x) { \
99        extern AVBitStreamFilter x##_bsf; \
100                av_register_bitstream_filter(&x##_bsf); }
101
102void init_FFmpeg()
103{
104        /* This one is used because Global variables are initialized ONE time
105        * until the application quits. Thus, we have to make sure we're initialize
106        * the libavformat only once or we get an endlos loop when registering the same
107        * element twice!! */
108        static Boolean inited = FALSE;
109        int unlock = PerianInitEnter(&inited);
110       
111        /* Register the Parser of ffmpeg, needed because we do no proper setup of the libraries */
112        if(!inited) {
113                inited = TRUE;
114                avcodec_init();
115                av_lockmgr_register(PerianLockMgrCallback);
116
117                REGISTER_DEMUXER(avi);
118                REGISTER_DEMUXER(flv);
119                REGISTER_DEMUXER(tta);
120                REGISTER_DEMUXER(nuv);
121                REGISTER_PARSER(ac3);
122                REGISTER_PARSER(mpegaudio);
123               
124                REGISTER_DECODER(msmpeg4v1);
125                REGISTER_DECODER(msmpeg4v2);
126                REGISTER_DECODER(msmpeg4v3);
127                REGISTER_DECODER(mpeg4);
128                REGISTER_DECODER(h264);
129                REGISTER_DECODER(flv);
130                REGISTER_DECODER(flashsv);
131                REGISTER_DECODER(vp3);
132                REGISTER_DECODER(vp6);
133                REGISTER_DECODER(vp6f);
134                REGISTER_DECODER(h263i);
135                REGISTER_DECODER(huffyuv);
136                REGISTER_DECODER(ffvhuff);
137                REGISTER_DECODER(mpeg1video);
138                REGISTER_DECODER(mpeg2video);
139                REGISTER_DECODER(fraps);
140                REGISTER_DECODER(snow);
141                REGISTER_DECODER(nuv);
142               
143                REGISTER_DECODER(wmav1);
144                REGISTER_DECODER(wmav2);
145                REGISTER_DECODER(adpcm_swf);
146                REGISTER_DECODER(vorbis);
147                REGISTER_DECODER(mp1);
148                REGISTER_DECODER(mp2);
149                REGISTER_DECODER(tta);
150                REGISTER_DECODER(dca);
151                REGISTER_DECODER(nellymoser);
152               
153                REGISTER_DECODER(dvdsub);
154                REGISTER_DECODER(tscc);
155                REGISTER_DECODER(vp6a);
156                REGISTER_DECODER(zmbv);
157                REGISTER_DECODER(indeo2);
158                REGISTER_DECODER(indeo3);
159                REGISTER_DECODER(indeo5);
160               
161                av_log_set_callback(FFMpegCodecprintf);
162        }
163       
164        PerianInitExit(unlock);
165}
166
167/************************************
168** Base Component Manager Routines **
169*************************************/
170
171ComponentResult FFAvi_MovieImportOpen(ff_global_ptr storage, ComponentInstance self)
172{
173        ComponentResult result;
174    ComponentDescription descout;
175       
176        /* Check for Mac OS 10.4 & QT 7 */
177        result = check_system();
178        require_noerr(result,bail);
179       
180    GetComponentInfo((Component)self, &descout, 0, 0, 0);
181       
182        storage = malloc(sizeof(ff_global_context));
183        if(!storage) goto bail;
184       
185        memset(storage, 0, sizeof(ff_global_context));
186        storage->ci = self;
187       
188        SetComponentInstanceStorage(storage->ci, (Handle)storage);
189       
190        storage->componentType = descout.componentSubType;
191        storage->movieLoadState = kMovieLoadStateLoading;
192bail:
193                return result;
194} /* FFAvi_MovieImportOpen() */
195
196ComponentResult FFAvi_MovieImportClose(ff_global_ptr storage, ComponentInstance self)
197{
198        /* Free all global storage */
199        if(storage->imgHdl)
200                DisposeHandle((Handle)storage->imgHdl);
201        if(storage->sndHdl)
202                DisposeHandle((Handle)storage->sndHdl);
203       
204        if(storage->stream_map)
205                av_free(storage->stream_map);
206       
207        if(storage->format_context)
208                av_close_input_file(storage->format_context);
209       
210        int i;
211        for(i=0; i<MAX_STREAMS; i++)
212        {
213                if(storage->firstFrames[i].data != NULL)
214                        av_free_packet(storage->firstFrames + i);
215        }
216       
217        if(storage)
218                free(storage);
219       
220        return noErr;
221} /* FFAvi_MovieImportClose() */
222
223ComponentResult FFAvi_MovieImportVersion(ff_global_ptr storage)
224{
225        return kFFAviComponentVersion;
226} /* FFAvi_MovieImportVersion() */
227
228#pragma mark -
229
230/********************************
231** Configuration Stuff is here **
232*********************************/
233
234ComponentResult FFAvi_MovieImportGetMIMETypeList(ff_global_ptr storage, QTAtomContainer *mimeInfo)
235{
236        ComponentResult err = noErr;
237        switch (storage->componentType) {
238                case 'VfW ':
239                case 'VFW ':
240                case 'AVI ':
241                        err = GetComponentResource((Component)storage->ci, 'mime', kAVIthngResID, (Handle*)mimeInfo);
242                        break;
243                case 'FLV ':
244                        err = GetComponentResource((Component)storage->ci, 'mime', kFLVthngResID, (Handle*)mimeInfo);
245                        break;
246                case 'TTA ':
247                        err = GetComponentResource((Component)storage->ci, 'mime', kTTAthngResID, (Handle*)mimeInfo);
248                        break;
249                case 'NUV ':
250                        err = GetComponentResource((Component)storage->ci, 'mime', kNuvthngResID, (Handle*)mimeInfo);
251                        break;
252                default:
253                        err = GetComponentResource((Component)storage->ci, 'mime', kAVIthngResID, (Handle*)mimeInfo);
254                        break;
255        }
256        return err;
257} /* FFAvi_MovieImportGetMIMETypeList() */
258
259ComponentResult FFAvi_MovieImportSetProgressProc(ff_global_ptr storage, MovieProgressUPP prog, long refcon)
260{
261        storage->prog = prog;
262        storage->refcon = refcon;
263       
264        if(!storage->prog)
265                storage->refcon = 0;
266       
267        return noErr;
268} /* FFAvi_MovieImportSetProgressProc() */
269
270ComponentResult FFAvi_MovieImportSetSampleDescription(ff_global_ptr storage, SampleDescriptionHandle desc, OSType media)
271{
272        ComponentResult result = noErr;
273       
274        switch(media) {
275                case VideoMediaType:
276                        if(storage->imgHdl) /* already one stored */
277                                DisposeHandle((Handle)storage->imgHdl);
278                       
279                        storage->imgHdl = (ImageDescriptionHandle)desc;
280                        if(storage->imgHdl)
281                                result = HandToHand((Handle*)&storage->imgHdl);
282                                break;
283                case SoundMediaType:
284                        if(storage->sndHdl)
285                                DisposeHandle((Handle)storage->sndHdl);
286                       
287                        storage->sndHdl = (SoundDescriptionHandle)desc;
288                        if(storage->sndHdl)
289                                result = HandToHand((Handle*)&storage->sndHdl);
290                                break;
291                default:
292                        break;
293        }
294       
295        return result;
296} /* FFAvi_MovieImportSetSampleDescription() */
297
298ComponentResult FFAvi_MovieImportGetDestinationMediaType(ff_global_ptr storage, OSType *mediaType)
299{
300        *mediaType = VideoMediaType;
301        return noErr;
302} /* FFAvi_MovieImportGetDestinationMediaType() */
303
304#pragma mark -
305
306/****************************
307** Import Stuff comes here **
308*****************************/
309
310ComponentResult FFAvi_MovieImportValidate(ff_global_ptr storage, const FSSpec *theFile, Handle theData, Boolean *valid)
311{
312        ComponentResult result = noErr;
313        Handle dataRef = NULL;
314        OSType dataRefType;
315       
316        *valid = FALSE;
317       
318        result = QTNewDataReferenceFromFSSpec(theFile, 0, &dataRef, &dataRefType);
319        require_noerr(result,bail);
320       
321        result = MovieImportValidateDataRef(storage->ci, dataRef, dataRefType, (UInt8*)valid);
322       
323bail:
324                if(dataRef)
325                        DisposeHandle(dataRef);
326       
327        return result;
328} /* FFAvi_MovieImportValidate() */
329
330// this function is a small avi parser to get the video track's fourcc as
331// fast as possible, so we can decide whether we can handle the necessary
332// image description extensions for the format in ValidateDataRef() quickly
333OSType get_avi_strf_fourcc(ByteIOContext *pb)
334{
335        OSType tag, subtag;
336        unsigned int size;
337       
338        if (get_be32(pb) != 'RIFF')
339                return 0;
340       
341        // file size
342        get_le32(pb);
343       
344        if (get_be32(pb) != 'AVI ')
345                return 0;
346       
347        while (!url_feof(pb)) {
348                tag = get_be32(pb);
349                size = get_le32(pb);
350               
351                if (tag == 'LIST') {
352                        subtag = get_be32(pb);
353                       
354                        // only lists we care about: hdrl & strl, so skip the rest
355                        if (subtag != 'hdrl' && subtag != 'strl')
356                                url_fskip(pb, size - 4 + (size & 1));
357                       
358                } else if (tag == 'strf') {
359                        // 16-byte offset to the fourcc
360                        url_fskip(pb, 16);
361                        return get_be32(pb);
362                } else if (tag == 'strh'){
363                        // 4-byte offset to the fourcc
364                        OSType tag1 = get_be32(pb);
365                        if(tag1 == 'iavs' || tag1 == 'ivas')
366                                return get_be32(pb);
367                        else
368                                url_fskip(pb, size + (size & 1) - 4);
369                } else
370                        url_fskip(pb, size + (size & 1));
371        }
372        return 0;
373}
374
375ComponentResult FFAvi_MovieImportValidateDataRef(ff_global_ptr storage, Handle dataRef, OSType dataRefType, UInt8 *valid)
376{
377        ComponentResult result = noErr;
378        DataHandler dataHandler = NULL;
379        uint8_t buf[PROBE_BUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE] = {0};
380        AVProbeData pd;
381        ByteIOContext *byteContext;
382
383        /* default */
384        *valid = 0;
385       
386        /* Get a data handle and read a probe of data */
387        result = OpenADataHandler(dataRef, dataRefType, NULL, 0, NULL, kDataHCanRead, &dataHandler);
388        if(result || !dataHandler) goto bail;
389       
390        pd.buf = buf;
391        pd.buf_size = PROBE_BUF_SIZE;
392       
393        result = DataHScheduleData(dataHandler, (Ptr)pd.buf, 0, PROBE_BUF_SIZE, 0, NULL, NULL);
394        require_noerr(result,bail);
395       
396        init_FFmpeg();
397        storage->format = av_probe_input_format(&pd, 1);
398        if(storage->format != NULL) {
399                *valid = 255; /* This means we can read the data */
400               
401                /* we don't do MJPEG's Huffman tables right yet, and DV video seems to have
402                an aspect ratio coded in the bitstream that ffmpeg doesn't read, so let Apple's
403                AVI importer handle AVIs with these two video types */
404                if (IS_AVI(storage->componentType)) {
405                        /* Prepare the iocontext structure */
406                        result = url_open_dataref(&byteContext, dataRef, dataRefType, NULL, NULL, NULL);
407                        require_noerr(result, bail);
408                       
409                        OSType fourcc = get_avi_strf_fourcc(byteContext);
410                        enum CodecID id = ff_codec_get_id(ff_codec_bmp_tags, BSWAP(fourcc));
411                       
412                        if (id == CODEC_ID_MJPEG || id == CODEC_ID_DVVIDEO || id == CODEC_ID_RAWVIDEO || id == CODEC_ID_MSVIDEO1 || id == CODEC_ID_MSRLE)
413                                *valid = 0;
414                       
415                        url_fclose(byteContext);
416                }
417        }
418               
419bail:
420                if(dataHandler)
421                        CloseComponent(dataHandler);
422       
423        return result;
424} /* FFAvi_MovieImportValidateDataRef() */
425
426
427ComponentResult FFAvi_MovieImportFile(ff_global_ptr storage, const FSSpec *theFile, Movie theMovie, Track targetTrack,
428                                                                          Track *usedTrack, TimeValue atTime, TimeValue *addedDuration, long inFlags, long *outFlags)
429{
430        ComponentResult result;
431        Handle dataRef = NULL;
432        OSType dataRefType;
433        FSRef theFileFSRef;
434       
435        *outFlags = 0;
436       
437        result = QTNewDataReferenceFromFSSpec(theFile, 0, &dataRef, &dataRefType);
438        require_noerr(result,bail);
439       
440        result = MovieImportDataRef(storage->ci, dataRef, dataRefType, theMovie, targetTrack, usedTrack, atTime, addedDuration,
441                                                                inFlags, outFlags);
442        require_noerr(result, bail);
443       
444        result = FSpMakeFSRef(theFile, &theFileFSRef);
445        require_noerr(result, bail);
446               
447bail:
448                if(dataRef)
449                        DisposeHandle(dataRef);
450       
451        return result;
452} /* FFAvi_MovieImportFile() */
453
454ComponentResult FFAvi_MovieImportDataRef(ff_global_ptr storage, Handle dataRef, OSType dataRefType, Movie theMovie, Track targetTrack,
455                                                                                 Track *usedTrack, TimeValue atTime, TimeValue *addedDuration, long inFlags, long *outFlags)
456{
457        ComponentResult result = noErr;
458        ByteIOContext *byteContext;
459        AVFormatContext *ic = NULL;
460        AVFormatParameters params;
461        OSType mediaType;
462        Media media;
463        int count, hadIndex, j;
464               
465        /* make sure that in case of error, the flag movieImportResultComplete is not set */
466        *outFlags = 0;
467       
468        /* probe the format first */
469        UInt8 valid = 0;
470        FFAvi_MovieImportValidateDataRef(storage, dataRef, dataRefType, &valid);
471        if(valid != 255)
472                goto bail;
473                       
474        /* Prepare the iocontext structure */
475        result = url_open_dataref(&byteContext, dataRef, dataRefType, &storage->dataHandler, &storage->dataHandlerSupportsWideOffsets, &storage->dataSize);
476        storage->isStreamed = dataRefType == URLDataHandlerSubType;
477        require_noerr(result, bail);
478       
479        /* Open the Format Context */
480        memset(&params, 0, sizeof(params));
481        result = av_open_input_stream(&ic, byteContext, "", storage->format, &params);
482        require_noerr(result,bail);
483        storage->format_context = ic;
484       
485        // AVIs without an index currently add a few entries to the index so it can
486        // determine codec parameters.  Check for index existence here before it
487        // reads any packets.
488        hadIndex = 1;
489        for (j = 0; j < ic->nb_streams; j++) {
490                if (ic->streams[j]->nb_index_entries <= 1)
491                {
492                        hadIndex = 0;
493                        break;
494                }
495        }
496       
497        /* Get the Stream Infos if not already read */
498        result = av_find_stream_info(ic);
499       
500        // -1 means it couldn't understand at least one stream
501        // which might just mean we don't have its video decoder enabled
502        if(result < 0 && result != -1)
503                goto bail;
504       
505        // we couldn't find any streams, bail with an error.
506        if(ic->nb_streams == 0) {
507                result = -1; //is there a more appropriate error code?
508                goto bail;
509        }
510       
511        //determine a header offset (needed by index-based import).
512        result = determine_header_offset(storage);
513        if(result < 0)
514                goto bail;
515       
516        /* Initialize the Movie */
517        storage->movie = theMovie;
518        if(inFlags & movieImportMustUseTrack) {
519                storage->map_count = 1;
520                prepare_track(storage, targetTrack, dataRef, dataRefType);
521        } else {
522                storage->map_count = ic->nb_streams;
523                result = prepare_movie(storage, theMovie, dataRef, dataRefType);
524                if (result != 0)
525                        goto bail;
526        }
527       
528        /* replace the SampleDescription if user called MovieImportSetSampleDescription() */
529        if(storage->imgHdl) {
530                for(j = 0; j < storage->map_count; j++) {
531                        NCStream ncstream = storage->stream_map[j];
532                        GetMediaHandlerDescription(ncstream.media, &mediaType, NULL, NULL);
533                        if(mediaType == VideoMediaType && ncstream.sampleHdl) {
534                                DisposeHandle((Handle)ncstream.sampleHdl);
535                                ncstream.sampleHdl = (SampleDescriptionHandle)storage->imgHdl;
536                        }
537                }
538        }
539        if(storage->sndHdl) {
540                for(j = 0; j < storage->map_count; j++) {
541                        NCStream ncstream = storage->stream_map[j];
542                        GetMediaHandlerDescription(ncstream.media, &mediaType, NULL, NULL);
543                        if(mediaType == SoundMediaType && ncstream.sampleHdl) {
544                                DisposeHandle((Handle)ncstream.sampleHdl);
545                                ncstream.sampleHdl = (SampleDescriptionHandle)storage->sndHdl;
546                        }
547                }
548        }
549       
550        count = 0; media = NULL;
551        for(j = 0; j < storage->map_count; j++) {
552                media = storage->stream_map[j].media;
553                if(media)
554                        count++;
555        }
556       
557        if(count > 1)
558                *outFlags |= movieImportResultUsedMultipleTracks;
559       
560        /* The usedTrack parameter. Count the number of Tracks and set usedTrack if we operated
561                * on a single track. Note that this requires the media to be set by track counting above*/
562        if(usedTrack && count == 1 && media)
563                *usedTrack = GetMediaTrack(media);
564       
565        result = noErr;
566
567        *addedDuration = 0;
568       
569        //attempt to import using indexes.
570        result = import_using_index(storage, &hadIndex, addedDuration);
571        require_noerr(result, bail);
572       
573        if(hadIndex) {
574                //file had an index and was imported; we are done.
575                *outFlags |= movieImportResultComplete;
576               
577        } else if(inFlags & movieImportWithIdle) {
578                if(addedDuration && ic->duration > 0) {
579                        TimeScale movieTimeScale = GetMovieTimeScale(theMovie);
580                        *addedDuration = movieTimeScale * ic->duration / AV_TIME_BASE;
581                       
582                        //create a placeholder track so that progress displays correctly.
583                        create_placeholder_track(storage->movie, &storage->placeholderTrack, *addedDuration, dataRef, dataRefType);
584                       
585                        //give the data handler a hint as to how fast we need the data.
586                        //suggest a speed that's faster than the bare minimum.
587                        //if there's an error, the data handler probably doesn't support
588                        //this, so we can just ignore.
589                        DataHPlaybackHints(storage->dataHandler, 0, 0, -1, (storage->dataSize * 1.15) / ((double)ic->duration / AV_TIME_BASE));
590                }
591                       
592                //import with idle. Decode a little bit of data now.
593                import_with_idle(storage, inFlags, outFlags, 10, 300, true);
594        } else {
595                //QuickTime didn't request import with idle, so do it all now.
596                import_with_idle(storage, inFlags, outFlags, 0, 0, true);                       
597        }
598       
599        LoadExternalSubtitlesFromFileDataRef(dataRef, dataRefType, theMovie);
600
601bail:
602        if(result == noErr)
603                storage->movieLoadState = kMovieLoadStateLoaded;
604        else
605                storage->movieLoadState = kMovieLoadStateError;
606               
607        if (result == -1)
608                result = invalidMovie; // a bit better error message
609       
610        return result;
611} /* FFAvi_MovieImportDataRef */
612
613ComponentResult FFAvi_MovieImportSetIdleManager(ff_global_ptr storage, IdleManager im) {
614        storage->idleManager = im;
615        return noErr;
616}
617
618ComponentResult FFAvi_MovieImportIdle(ff_global_ptr storage, long inFlags, long *outFlags) {
619        ComponentResult err = noErr;
620        TimeValue currentIdleTime = GetMovieTime(storage->movie, NULL);
621        TimeScale movieTimeScale = GetMovieTimeScale(storage->movie);
622        int addSamples = false;
623       
624        storage->idlesSinceLastAdd++;
625       
626        if (currentIdleTime == storage->lastIdleTime && storage->idlesSinceLastAdd > 5 || 
627                storage->loadedTime < currentIdleTime + 5*movieTimeScale)
628        {
629                storage->idlesSinceLastAdd = 0;
630                addSamples = true;
631        }
632       
633        err = import_with_idle(storage, inFlags | movieImportWithIdle, outFlags, 0, 1000, addSamples);
634       
635        storage->lastIdleTime = currentIdleTime;
636        return err;
637}
638
639ComponentResult FFAvi_MovieImportGetLoadState(ff_global_ptr storage, long *importerLoadState) {
640        *importerLoadState = storage->movieLoadState;
641        return(noErr);
642}
643
644ComponentResult FFAvi_MovieImportGetMaxLoadedTime(ff_global_ptr storage, TimeValue *time) {
645        *time = storage->loadedTime;
646        return(noErr);
647}
Note: See TracBrowser for help on using the repository browser.