Changeset 204

Show
Ignore:
Timestamp:
12/10/06 04:48:09 (2 years ago)
Author:
allan
Message:

- idling import patch for movies without index + Graham's changes to said patch.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Perian-Info.plist

    r17 r204  
    77        <key>CFBundleExecutable</key> 
    88        <string>Perian</string> 
     9        <key>CFBundleGetInfoString</key> 
     10        <string>0.1 (SVNREVISION ffmpeg: FFMPEGREVISION), Copyright 2006 The Perian Team</string> 
    911        <key>CFBundleIdentifier</key> 
    10         <string>com.yourcompany.Perian</string> 
     12        <string>org.perian.Perian</string> 
    1113        <key>CFBundleInfoDictionaryVersion</key> 
    1214        <string>6.0</string> 
     
    1618        <string>????</string> 
    1719        <key>CFBundleVersion</key> 
    18         <string>0.1</string> 
    19         <key>CFBundleGetInfoString</key> 
    20         <string>0.1 (SVNREVISION ffmpeg: FFMPEGREVISION), Copyright 2006 The Perian Team</string> 
     20        <string>0.5</string> 
    2121        <key>CSResourcesFileMapped</key> 
    2222        <string>yes</string> 
  • trunk/PerianAviImporter.r

    r148 r204  
    3535#define kFFAvi_MovieImportFlags \ 
    3636( canMovieImportFiles | canMovieImportInPlace | canMovieImportDataReferences | canMovieImportValidateFile \ 
    37                 | canMovieImportValidateDataReferences | hasMovieImportMIMEList | movieImportMustGetDestinationMediaType
    38                 | cmpThreadSafe ) 
     37                | canMovieImportValidateDataReferences | canMovieImportWithIdle | hasMovieImportMIMEList
     38                | movieImportMustGetDestinationMediaType | cmpThreadSafe ) 
    3939 
    4040/* Component Manager Things -  
  • trunk/ff_MovieImport.c

    r176 r204  
    4444#define COMPONENT_UPP_SELECT_ROOT()     MovieImport 
    4545 
    46 struct _ff_global_context { 
    47         ComponentInstance ci; 
    48         OSType componentType; 
    49          
    50         /* For feedback during import */ 
    51         MovieProgressUPP prog; 
    52         long refcon; 
    53          
    54         /* for overwriting the default sample descriptions */ 
    55         ImageDescriptionHandle imgHdl; 
    56         SoundDescriptionHandle sndHdl; 
    57         AVInputFormat           *format; 
    58 }; 
    59 typedef struct _ff_global_context ff_global_context; 
    60 typedef ff_global_context *ff_global_ptr; 
    61  
    6246#include <CoreServices/Components.k.h> 
    6347#include <QuickTime/QuickTimeComponents.k.h> 
     
    122106         
    123107        storage->componentType = descout.componentSubType; 
     108        storage->movieLoadState = kMovieLoadStateLoading; 
    124109bail: 
    125110                return result; 
     
    133118        if(storage->sndHdl) 
    134119                DisposeHandle((Handle)storage->sndHdl); 
     120         
     121        if(storage->stream_map) 
     122                av_free(storage->stream_map); 
     123         
     124        if(storage->format_context) 
     125                av_close_input_file(storage->format_context); 
    135126         
    136127        if(storage) 
     
    317308                        /* Prepare the iocontext structure */ 
    318309                        memset(&byteContext, 0, sizeof(byteContext)); 
    319                         result = url_open_dataref(&byteContext, dataRef, dataRefType); 
     310                        result = url_open_dataref(&byteContext, dataRef, dataRefType, NULL, NULL, NULL); 
    320311                        require_noerr(result, bail); 
    321312                         
     
    375366        AVFormatContext *ic = NULL; 
    376367        AVFormatParameters params; 
    377         int64_t dataOffset; 
    378368        AVPacket pkt; 
    379         NCStream *map = NULL; 
    380         int map_count,j,count; 
    381369        OSType mediaType; 
    382         Track track; 
    383370        Media media; 
    384         TimeRecord time; 
    385         int i; 
    386         short hadIndex = 0; 
    387          
     371        int count, hadIndex, i, j; 
     372                 
    388373        /* make sure that in case of error, the flag movieImportResultComplete is not set */ 
    389374        *outFlags = 0; 
     
    394379        if(valid != 255) 
    395380                goto bail; 
    396          
     381                
    397382        /* Prepare the iocontext structure */ 
    398383        memset(&byteContext, 0, sizeof(byteContext)); 
    399         result = url_open_dataref(&byteContext, dataRef, dataRefType); 
     384        result = url_open_dataref(&byteContext, dataRef, dataRefType, &storage->dataHandler, &storage->dataHandlerSupportsWideOffsets, &storage->dataSize); 
    400385        require_noerr(result, bail); 
    401386         
     
    404389        result = av_open_input_stream(&ic, &byteContext, "", storage->format, &params); 
    405390        require_noerr(result,bail); 
     391        storage->format_context = ic; 
    406392         
    407393        /* Get the Stream Infos if not already read */ 
     
    410396                goto bail; 
    411397         
    412         /* Seek backwards to get a manually read packet for file offset */ 
    413         if(ic->streams[0]->index_entries == NULL || storage->componentType == 'FLV ') 
    414         { 
    415                 if (IS_AVI(storage->componentType)) 
    416                         //Try to seek to the first frame; don't care if it fails 
    417                         // Is this really needed for AVIs w/out an index? It seems to work fine without,  
    418                         // and it seems that with it the first frame is skipped. 
    419                         av_seek_frame(ic, -1, 0, 0); 
    420                 dataOffset = 0; 
    421         } 
    422         else 
    423         { 
    424                 result = av_seek_frame(ic, -1, 0, 0); 
    425                 if(result < 0) goto bail; 
    426                  
    427                 ic->iformat->read_packet(ic, &pkt); 
    428                 /* read_packet will give the first decodable packet. However, that isn't necessarily 
    429                         the first entry in the index, so look for an entry with a matching size. */ 
    430                 for (i = 0; i < ic->streams[pkt.stream_index]->nb_index_entries; i++) { 
    431                         if (pkt.size == ic->streams[pkt.stream_index]->index_entries[i].size) { 
    432                                 dataOffset = pkt.pos - ic->streams[pkt.stream_index]->index_entries[i].pos; 
    433                                 break; 
     398        //determine a header offset (needed by index-based import). 
     399        result = determine_header_offset(storage); 
     400        if(result < 0) 
     401                goto bail; 
     402         
     403        /* Initialize the Movie */ 
     404        storage->movie = theMovie; 
     405        if(inFlags & movieImportMustUseTrack) { 
     406                storage->map_count = 1; 
     407                prepare_track(ic, &storage->stream_map, targetTrack, dataRef, dataRefType); 
     408        } else { 
     409                storage->map_count = ic->nb_streams; 
     410                prepare_movie(ic, &storage->stream_map, theMovie, dataRef, dataRefType); 
     411        } 
     412         
     413        /* replace the SampleDescription if user called MovieImportSetSampleDescription() */ 
     414        if(storage->imgHdl) { 
     415                for(j = 0; j < storage->map_count; j++) { 
     416                        NCStream ncstream = storage->stream_map[j]; 
     417                        GetMediaHandlerDescription(ncstream.media, &mediaType, NULL, NULL); 
     418                        if(mediaType == VideoMediaType && ncstream.sampleHdl) { 
     419                                DisposeHandle((Handle)ncstream.sampleHdl); 
     420                                ncstream.sampleHdl = (SampleDescriptionHandle)storage->imgHdl; 
    434421                        } 
    435422                } 
    436                 av_free_packet(&pkt); 
    437         } 
    438          
    439         /* Initialize the Movie */ 
    440         if(inFlags & movieImportMustUseTrack) { 
    441                 map_count = 1; 
    442                 prepare_track(ic, &map, targetTrack, dataRef, dataRefType); 
    443         } else { 
    444                 map_count = ic->nb_streams; 
    445                 prepare_movie(ic, &map, theMovie, dataRef, dataRefType); 
    446         } 
    447          
    448         /* replace the SampleDescription if user called MovieImportSetSampleDescription() */ 
    449         if(storage->imgHdl) { 
    450                 for(j = 0; j < map_count; j++) { 
    451                         GetMediaHandlerDescription(map[j].media, &mediaType, NULL, NULL); 
    452                         if(mediaType == VideoMediaType && map[j].sampleHdl) { 
    453                                 DisposeHandle((Handle)map[j].sampleHdl); 
    454                                 map[j].sampleHdl = (SampleDescriptionHandle)storage->imgHdl; 
     423        } 
     424        if(storage->sndHdl) { 
     425                for(j = 0; j < storage->map_count; j++) { 
     426                        NCStream ncstream = storage->stream_map[j]; 
     427                        GetMediaHandlerDescription(ncstream.media, &mediaType, NULL, NULL); 
     428                        if(mediaType == SoundMediaType && ncstream.sampleHdl) { 
     429                                DisposeHandle((Handle)ncstream.sampleHdl); 
     430                                ncstream.sampleHdl = (SampleDescriptionHandle)storage->sndHdl; 
    455431                        } 
    456432                } 
    457433        } 
    458         if(storage->sndHdl) { 
    459                 for(j = 0; j < map_count; j++) { 
    460                         GetMediaHandlerDescription(map[j].media, &mediaType, NULL, NULL); 
    461                         if(mediaType == SoundMediaType && map[j].sampleHdl) { 
    462                                 DisposeHandle((Handle)map[j].sampleHdl); 
    463                                 map[j].sampleHdl = (SampleDescriptionHandle)storage->sndHdl; 
    464                         } 
    465                 } 
    466         } 
    467          
    468         /* Import the Data*/ 
    469         /* FIXME: Implement the progress upp */ 
    470         /* note: flv builds a partial index that's unusable, so force importing without an index */ 
    471         if (!(storage->componentType == 'FLV ')) 
    472                 hadIndex = import_avi(ic, map, dataOffset); 
    473          
    474         if (!hadIndex) 
    475                 import_without_index(ic, map, dataOffset); 
    476          
    477         /* Insert the Medias into the Tracks */ 
    478         result = noErr; 
    479         for(j = 0; j < map_count && result == noErr; j++) { 
    480                 media = map[j].media; 
    481                 if(media) { 
    482                         /* we could handle this stream. 
    483                         * convert the atTime parameter to track scale. 
    484                         * FIXME: check if that's correct */                      
    485                         time.value.hi = 0; 
    486                         time.value.lo = atTime; 
    487                         time.scale = GetMovieTimeScale(theMovie); 
    488                         time.base = NULL; 
    489                         ConvertTimeScale(&time, GetMediaTimeScale(media)); 
    490                          
    491                         track = GetMediaTrack(media); 
    492                         result = InsertMediaIntoTrack(track, time.value.lo, 0, GetMediaDuration(media), fixed1); 
    493                 } 
    494         } 
    495         require_noerr(result,bail); 
    496          
    497         /* Set return values of the function */ 
    498434         
    499435        count = 0; media = NULL; 
    500         for(j = 0; j < map_count; j++) { 
    501                 media = map[j].media; 
     436        for(j = 0; j < storage->map_count; j++) { 
     437                media = storage->stream_map[j].media; 
    502438                if(media) 
    503439                        count++; 
    504440        } 
     441         
     442        if(count > 1) 
     443                *outFlags |= movieImportResultUsedMultipleTracks; 
    505444         
    506445        /* The usedTrack parameter. Count the number of Tracks and set usedTrack if we operated 
     
    509448                *usedTrack = GetMediaTrack(media); 
    510449         
    511         /* the addedDuration parameter */ 
    512         if(addedDuration) { 
    513                 *addedDuration = 0; 
    514                 for(j = 0; j < map_count; j++) { 
    515                         media = map[j].media; 
    516                         if(media) { 
    517                                 time.value.hi = 0; 
    518                                 time.value.lo = GetMediaDuration(media); 
    519                                 time.scale = GetMediaTimeScale(media); 
    520                                 time.base = NULL; 
    521                                 ConvertTimeScale(&time, GetMovieTimeScale(theMovie)); 
    522                                  
    523                                 /* if that's longer than before, replace */ 
    524                                 if(time.value.lo > *addedDuration) 
    525                                         *addedDuration = time.value.lo; 
    526                         } 
     450        result = noErr; 
     451 
     452        *addedDuration = 0; 
     453         
     454        //attempt to import using indexes. 
     455        result = import_using_index(storage, &hadIndex, addedDuration); 
     456        require_noerr(result, bail); 
     457         
     458        if(hadIndex) { 
     459                //file had an index and was imported; we are done. 
     460                *outFlags |= movieImportResultComplete; 
     461                 
     462        } else if(inFlags & movieImportWithIdle) { 
     463                if(addedDuration && ic->duration > 0) { 
     464                        TimeValue sampleTime; 
     465                        TimeScale movieTimeScale = GetMovieTimeScale(theMovie); 
     466                        *addedDuration = movieTimeScale * ic->duration / AV_TIME_BASE; 
     467                         
     468                        //create a placeholder track so that progress displays correctly. 
     469                        create_placeholder_track(storage, *addedDuration, dataRef, dataRefType); 
     470                         
     471                        //give the data handler a hint as to how fast we need the data. 
     472                        //suggest a speed that's faster than the bare minimum. 
     473                        //if there's an error, the data handler probably doesn't support 
     474                        //this, so we can just ignore. 
     475                        DataHPlaybackHints(storage->dataHandler, 0, 0, -1, (storage->dataSize * 1.15) / ((double)ic->duration / AV_TIME_BASE)); 
    527476                } 
    528         } 
    529          
    530         /* now set the outflags, set to zero at the beginning of the function */ 
    531         if(outFlags) { 
    532                 if(count > 1) 
    533                         *outFlags |= movieImportResultUsedMultipleTracks; 
    534                  
    535                 /* set the finished flag */ 
    536                 *outFlags |= movieImportResultComplete; 
     477                         
     478                //import with idle. Decode a little bit of data now. 
     479                import_with_idle(storage, inFlags, outFlags, 10, 300); 
     480        } else { 
     481                //QuickTime didn't request import with idle, so do it all now. 
     482                import_with_idle(storage, inFlags, outFlags, 0, 0);                      
    537483        } 
    538484         
    539485bail: 
    540                 /* Free all the data structures used */ 
    541                 if(ic) 
    542                         av_close_input_file(ic); 
    543         if(map) 
    544                 av_free(map); 
     486        if(result == noErr) 
     487                storage->movieLoadState == kMovieLoadStateLoaded; 
     488        else 
     489                storage->movieLoadState == kMovieLoadStateError; 
    545490         
    546491        return result; 
    547492} /* FFAvi_MovieImportDataRef */ 
     493 
     494ComponentResult FFAvi_MovieImportSetIdleManager(ff_global_ptr storage, IdleManager im) { 
     495        storage->idleManager = im; 
     496} 
     497 
     498ComponentResult FFAvi_MovieImportIdle(ff_global_ptr storage, long inFlags, long *outFlags) { 
     499        return(import_with_idle(storage, inFlags | movieImportWithIdle, outFlags, 0, 1000));     
     500} 
     501 
     502ComponentResult FFAvi_MovieImportGetLoadState(ff_global_ptr storage, long *importerLoadState) { 
     503        *importerLoadState = storage->movieLoadState; 
     504        return(noErr); 
     505} 
     506 
     507ComponentResult FFAvi_MovieImportGetMaxLoadedTime(ff_global_ptr storage, TimeValue *time) { 
     508        *time = storage->loadedTime; 
     509        return(noErr); 
     510} 
  • trunk/ff_MovieImportDispatch.h

    r60 r204  
    6161                ComponentError  (SetSettingsFromAtomContainer) 
    6262                ComponentError  (SetOffsetAndLimit64) 
    63                 ComponentError        (Idle) 
     63                ComponentCall (Idle) 
    6464                ComponentCall   (ValidateDataRef) 
    65                 ComponentError        (GetLoadState) 
    66                 ComponentError        (GetMaxLoadedTime) 
     65                ComponentCall (GetLoadState) 
     66                ComponentCall (GetMaxLoadedTime) 
    6767                ComponentError  (EstimateCompletionTime) 
    6868                ComponentError  (SetDontBlock) 
    6969                ComponentError  (GetDontBlock) 
    70                 ComponentError        (SetIdleManager) 
     70                ComponentCall (SetIdleManager) 
    7171                ComponentError  (SetNewMovieFlags) 
    7272                ComponentCall   (GetDestinationMediaType) 
  • trunk/ff_dataref.c

    r194 r204  
    194194 
    195195/* This is the public function to open bytecontext withs datarefs */ 
    196 OSStatus url_open_dataref(ByteIOContext *pb, Handle dataRef, OSType dataRefType
     196OSStatus url_open_dataref(ByteIOContext *pb, Handle dataRef, OSType dataRefType, DataHandler *dataHandler, Boolean *wideSupport, int64_t *dataSize
    197197{ 
    198198        URLContext *uc; 
     
    220220         
    221221        err = up->url_open(uc, uc->filename, URL_RDONLY); 
     222                 
    222223        if(err < 0) { 
    223224                av_free(uc); 
     
    230231        } 
    231232         
     233        if(dataHandler) 
     234                *dataHandler = private->dh; 
     235         
     236        if(wideSupport) 
     237                *wideSupport = private->supportsWideOffsets; 
     238         
     239        if(dataSize) 
     240                *dataSize = private->size;       
     241         
    232242        return noErr; 
    233243} /* url_open_dataref() */ 
  • trunk/ff_private.c

    r196 r204  
    3030#include <CoreServices/CoreServices.h> 
    3131#include <AudioToolbox/AudioToolbox.h> 
     32#include <QuickTime/QuickTime.h> 
    3233 
    3334/* This routine checks if the system requirements are fullfilled */ 
     
    512513} /* prepare_movie() */ 
    513514 
     515int determine_header_offset(ff_global_ptr storage) { 
     516        AVFormatContext *formatContext; 
     517        AVPacket packet; 
     518        int result, i; 
     519         
     520        formatContext = storage->format_context; 
     521        result = noErr; 
     522        storage->header_offset = 0; 
     523         
     524        /* Seek backwards to get a manually read packet for file offset */ 
     525        if(formatContext->streams[0]->index_entries == NULL || storage->componentType == 'FLV ') 
     526        { 
     527                if (IS_AVI(storage->componentType)) 
     528                        //Try to seek to the first frame; don't care if it fails 
     529                        // Is this really needed for AVIs w/out an index? It seems to work fine without,  
     530                        // and it seems that with it the first frame is skipped. 
     531                        av_seek_frame(formatContext, -1, 0, 0); 
     532                storage->header_offset = 0; 
     533        } 
     534        else 
     535        { 
     536                result = av_seek_frame(formatContext, -1, 0, 0); 
     537                if(result < 0) goto bail; 
     538                 
     539                formatContext->iformat->read_packet(formatContext, &packet); 
     540                /* read_packet will give the first decodable packet. However, that isn't necessarily 
     541                        the first entry in the index, so look for an entry with a matching size. */ 
     542                for (i = 0; i < formatContext->streams[packet.stream_index]->nb_index_entries; i++) { 
     543                        if (packet.size == formatContext->streams[packet.stream_index]->index_entries[i].size) { 
     544                                storage->header_offset = packet.pos - formatContext->streams[packet.stream_index]->index_entries[i].pos; 
     545                                break; 
     546                        } 
     547                } 
     548                av_free_packet(&packet); 
     549                 
     550                // seek back to the beginning, otherwise av_read_frame-based decoding will skip a few packets. 
     551                av_seek_frame(formatContext, -1, 0, 0); 
     552        } 
     553                 
     554bail: 
     555        return(result); 
     556} 
     557 
    514558/* This function imports the avi represented by the AVFormatContext to the movie media represented 
    515559 * in the map function. The aviheader_offset is used to calculate the packet offset from the 
    516560 * beginning of the file. It returns whether it was successful or not (i.e. whether the file had an index) */ 
    517 short import_avi(AVFormatContext *ic, NCStream *map, int64_t aviheader_offset) 
    518 
     561int import_using_index(ff_global_ptr storage, int *hadIndex, TimeValue *addedDuration) { 
    519562        int j, k, l; 
     563        NCStream *map; 
    520564        NCStream *ncstr; 
     565        AVFormatContext *ic; 
    521566        AVStream *stream; 
    522567        AVCodecContext *codec; 
    523568        SampleReference64Ptr sampleRec; 
    524         int64_t offset,duration; 
    525         OSStatus err; 
     569        int64_t header_offset, offset, duration; 
    526570        short flags; 
    527         short hadIndex = 0; 
    528571        int sampleNum; 
     572        ComponentResult result = noErr; 
     573         
     574        map = storage->stream_map; 
     575        ic = storage->format_context; 
     576        header_offset = storage->header_offset; 
     577 
     578        *hadIndex = 0; 
     579         
     580        //FLVs have unusable indexes, so don't even bother. 
     581        if(storage->componentType == 'FLV ') 
     582                goto bail; 
    529583         
    530584        /* process each stream in ic */ 
    531585        for(j = 0; j < ic->nb_streams; j++) { 
    532                  
    533586                ncstr = &map[j]; 
    534587                stream = ncstr->str; 
     
    539592                        continue; 
    540593                 
     594                /* no index, we might as well skip */ 
     595                if(stream->nb_index_entries == 0) 
     596                        continue; 
     597                 
    541598                sampleNum = 0; 
    542599                ncstr->sampleTable = calloc(stream->nb_index_entries, sizeof(SampleReference64Record)); 
     
    545602                for(k = 0; k < stream->nb_index_entries; k++) { 
    546603                         
    547                         hadIndex = 1; 
     604                        *hadIndex = 1; 
    548605                         
    549606                        /* file offset */ 
    550                         offset = aviheader_offset + stream->index_entries[k].pos; 
     607                        offset = header_offset + stream->index_entries[k].pos; 
    551608                         
    552609                        /* flags */ 
     
    605662                } 
    606663                /* Add all of the samples to the media */ 
    607                 err = AddMediaSampleReferences64(ncstr->media, ncstr->sampleHdl, sampleNum, ncstr->sampleTable, NULL); 
     664                AddMediaSampleReferences64(ncstr->media, ncstr->sampleHdl, sampleNum, ncstr->sampleTable, NULL); 
    608665                free(ncstr->sampleTable); 
    609666        } 
    610         return hadIndex; 
    611 } /* import_avi() */ 
    612  
    613 /* This function imports the video file using standard av_read_frame() calls,  
    614  * which works on files that don't have an index */ 
    615 void import_without_index(AVFormatContext *ic, NCStream *map, int64_t aviheader_offset) 
    616 
    617         int i; 
    618         NCStream *ncstr; 
     667         
     668        if(*hadIndex == 0) 
     669                //No index, the remainder of this function will fail. 
     670                goto bail; 
     671         
     672        // insert media and set addedDuration; 
     673        for(j = 0; j < storage->map_count && result == noErr; j++) { 
     674                Media media = storage->stream_map[j].media; 
     675                if(media) { 
     676                        Track track; 
     677                        TimeRecord time; 
     678                        TimeValue mediaDuration; 
     679                        TimeScale mediaTimeScale; 
     680                        TimeScale movieTimeScale; 
     681 
     682                        mediaDuration = GetMediaDuration(media); 
     683                        mediaTimeScale = GetMediaTimeScale(media); 
     684                        movieTimeScale = GetMovieTimeScale(storage->movie); 
     685                         
     686                        /* we could handle this stream. 
     687                        * convert the atTime parameter to track scale. 
     688                        * FIXME: check if that's correct */ 
     689                        time.value.hi = 0; 
     690                        time.value.lo = storage->atTime; 
     691                        time.scale = movieTimeScale; 
     692                        time.base = NULL; 
     693                        ConvertTimeScale(&time, mediaTimeScale); 
     694                         
     695                        track = GetMediaTrack(media); 
     696                        result = InsertMediaIntoTrack(track, time.value.lo, 0, mediaDuration, fixed1); 
     697 
     698                        if(result != noErr) 
     699                                goto bail; 
     700                         
     701                        time.value.hi = 0; 
     702                        time.value.lo = mediaDuration; 
     703                        time.scale = mediaTimeScale; 
     704                        time.base = NULL; 
     705                        ConvertTimeScale(&time, movieTimeScale); 
     706                         
     707                        if(time.value.lo > *addedDuration) 
     708                                *addedDuration = time.value.lo; 
     709                } 
     710        } 
     711         
     712        storage->loadedTime = *addedDuration; 
     713         
     714bail: 
     715        return result; 
     716} /* import_using_index() */ 
     717 
     718/* Import function for movies that lack an index. 
     719 * Supports progressive importing, but will not idle if maxFrames == 0. 
     720 */ 
     721ComponentResult import_with_idle(ff_global_ptr storage, long inFlags, long *outFlags, int minFrames, int maxFrames) { 
     722        SampleReference64Record sampleRec; 
     723        DataHandler dataHandler; 
     724        AVFormatContext *formatContext; 
     725        AVCodecContext *codecContext; 
    619726        AVStream *stream; 
    620         AVCodecContext *codec; 
    621         SampleReference64Record sampleRec; 
     727        AVPacket packet; 
     728        NCStream *ncstream; 
     729        ComponentResult dataResult; //used for data handler operations that can fail. 
     730        ComponentResult result; 
     731        TimeValue minLoadedTime; 
     732        int64_t availableSize, margin; 
     733        long idling; 
     734        int readResult, framesProcessed, i; 
    622735        short flags; 
    623         AVPacket pkt; 
    624          
    625         while(av_read_frame(ic, &pkt) == noErr) 
    626         { 
    627                 ncstr = &map[pkt.stream_index]; 
    628                 stream = ncstr->str; 
    629                 codec = stream->codec; 
    630                  
     736         
     737        dataHandler = storage->dataHandler; 
     738        formatContext = storage->format_context; 
     739        dataResult = noErr; 
     740        result = noErr; 
     741        minLoadedTime = 0; 
     742        availableSize = 0; 
     743        margin = 0; 
     744        idling = (inFlags & movieImportWithIdle); 
     745        framesProcessed = 0; 
     746                 
     747        if(idling) { 
     748                //get the size of immediately available data 
     749                if(storage->dataHandlerSupportsWideOffsets) { 
     750                        wide wideSize; 
     751                         
     752                        dataResult = DataHGetAvailableFileSize64(storage->dataHandler, &wideSize); 
     753                        if(dataResult == noErr) availableSize = ((int64_t)wideSize.hi << 32) + wideSize.lo; 
     754                } else { 
     755                        long longSize; 
     756                         
     757                        dataResult = DataHGetAvailableFileSize(storage->dataHandler, &longSize); 
     758                        if(dataResult == noErr) availableSize = longSize; 
     759                } 
     760        } 
     761         
     762        // record stream durations before we add any samples so that we know what to tell InsertMediaIntoTrack later 
     763        for(i = 0; i < storage->map_count; i++) { 
     764                ncstream = &storage->stream_map[i]; 
     765                Media media = ncstream->media; 
     766                 
     767                if(media) 
     768                        ncstream->duration = GetMediaDuration(media); 
     769        } 
     770         
     771        while((readResult = av_read_frame(formatContext, &packet)) == 0) {               
     772                ncstream = &storage->stream_map[packet.stream_index]; 
     773                stream = ncstream->str; 
     774                codecContext = stream->codec; 
    631775                flags = 0; 
    632                 if((pkt.flags & PKT_FLAG_KEY) == 0) 
     776                 
     777                if((packet.flags & PKT_FLAG_KEY) == 0) 
    633778                        flags |= mediaSampleNotSync; 
    634779                 
    635780                memset(&sampleRec, 0, sizeof(sampleRec)); 
    636                 sampleRec.dataOffset.hi = pkt.pos >> 32; 
    637                 sampleRec.dataOffset.lo = (uint32_t) pkt.pos; 
    638                 sampleRec.dataSize = pkt.size; 
     781                sampleRec.dataOffset.hi = packet.pos >> 32; 
     782                sampleRec.dataOffset.lo = (uint32_t)packet.pos; 
     783                sampleRec.dataSize = packet.size; 
    639784                sampleRec.sampleFlags = flags; 
     785                 
     786                if(packet.size > storage->largestPacketSize) 
     787                        storage->largestPacketSize = packet.size; 
    640788                 
    641789                if(sampleRec.dataSize <= 0) 
    642790                        continue; 
    643791                 
    644                 if (codec->codec_type == CODEC_TYPE_AUDIO && !ncstr->vbr) 
    645                         sampleRec.numberOfSamples = (pkt.size * ncstr->asbd.mFramesPerPacket) / ncstr->asbd.mBytesPerPacket; 
     792                if(codecContext->codec_type == CODEC_TYPE_AUDIO && !ncstream->vbr) 
     793                        sampleRec.numberOfSamples = (packet.size * ncstream->asbd.mFramesPerPacket) / ncstream->asbd.mBytesPerPacket; 
    646794                else 
    647                         sampleRec.numberOfSamples = 1; 
    648                  
    649                 // we have a sample waiting to be added; calculate the duration and add it 
    650                 if (ncstr->lastSample.numberOfSamples > 0) { 
    651                         ncstr->lastSample.durationPerSample = (pkt.pts - ncstr->lastpts) * ncstr->base.num; 
    652                         AddMediaSampleReferences64(ncstr->media, ncstr->sampleHdl, 1, &ncstr->lastSample, NULL); 
    653                 } 
    654                  
    655                 if (pkt.duration == 0) { 
    656                         // no duration, we'll have to wait for the next packet to calculate it 
     795                        sampleRec.numberOfSamples = 1; //packet.duration; 
     796                 
     797                //add any samples waiting to be added 
     798                if(ncstream->lastSample.numberOfSamples > 0) { 
     799                        //calculate the duration of the sample before adding it 
     800                        ncstream->lastSample.durationPerSample = (packet.pts - ncstream->lastpts) * ncstream->base.num; 
     801                         
     802                        AddMediaSampleReferences64(ncstream->media, ncstream->sampleHdl, 1, &ncstream->lastSample, NULL); 
     803                } 
     804                 
     805                if(packet.duration == 0) { 
     806                        //no duration, we'll have to wait for the next packet to calculate it 
    657807                        // keep the duration of the last sample, so we can use it if it's the last frame 
    658                         sampleRec.durationPerSample = ncstr->lastSample.durationPerSample; 
    659                         ncstr->lastSample = sampleRec; 
    660                         ncstr->lastpts = pkt.pts; 
    661                          
     808                        sampleRec.durationPerSample = ncstream->lastSample.durationPerSample; 
     809                        ncstream->lastSample = sampleRec; 
     810                        ncstream->lastpts = packet.pts; 
    662811                } else { 
    663                         ncstr->lastSample.numberOfSamples = 0; 
    664                         if (codec->codec_type == CODEC_TYPE_AUDIO && !ncstr->vbr) 
     812                        ncstream->lastSample.numberOfSamples = 0; 
     813                         
     814                        if(codecContext->codec_type == CODEC_TYPE_AUDIO && !ncstream->vbr) 
    665815                                sampleRec.durationPerSample = 1; 
    666816                        else 
    667                                 sampleRec.durationPerSample = pkt.duration * ncstr->base.num; 
    668                         AddMediaSampleReferences64(ncstr->media, ncstr->sampleHdl, 1, &sampleRec, NULL); 
    669                 } 
    670 #if 0 
    671                 if(codec->codec_type == CODEC_TYPE_VIDEO) 
    672                 { 
    673                         if(pkt.duration == 0) 
    674                                 sampleRec.durationPerSample = map->base.num; 
     817                                sampleRec.durationPerSample = ncstream->base.num * packet.duration; 
     818 
     819                        AddMediaSampleReferences64(ncstream->media, ncstream->sampleHdl, 1, &sampleRec, NULL); 
     820                } 
     821                 
     822                framesProcessed++; 
     823                 
     824                //if we're idling, try really not to read past the end of available data 
     825                //otherwise we will cause blocking i/o. 
     826                if(idling && framesProcessed >= minFrames && availableSize > 0 && availableSize < storage->dataSize) { 
     827                        margin = availableSize - (packet.pos + packet.size); 
     828                        if(margin < (storage->largestPacketSize * 8)) { // 8x fudge factor for comfortable margin, could be tweaked. 
     829                                av_free_packet(&packet); 
     830                                break; 
     831                        } 
     832                } 
     833                 
     834                av_free_packet(&packet); 
     835                 
     836                //stop processing if we've hit the max frame limit 
     837                if(maxFrames > 0 && framesProcessed >= maxFrames) 
     838                        break; 
     839        } 
     840                 
     841        if(readResult != 0) { 
     842                //if readResult != 0, we've hit the end of the stream. 
     843                //add any pending last frames. 
     844                for(i = 0; i < formatContext->nb_streams; i++) { 
     845                        ncstream = &storage->stream_map[i]; 
     846                        if(ncstream->lastSample.numberOfSamples > 0) 
     847                                AddMediaSampleReferences64(ncstream->media, ncstream->sampleHdl, 1, &ncstream->lastSample, NULL); 
     848                } 
     849        } 
     850         
     851        for(i = 0; i < storage->map_count && result == noErr; i++) { 
     852                ncstream = &storage->stream_map[i]; 
     853                Media media = ncstream->media; 
     854                 
     855                if(media) { 
     856                        Track track = GetMediaTrack(media); 
     857                        TimeScale mediaTimeScale = GetMediaTimeScale(media); 
     858                        TimeValue prevDuration = ncstream->duration; 
     859                        TimeValue mediaDuration = GetMediaDuration(media); 
     860                        TimeValue addedDuration = mediaDuration - prevDuration; 
     861                        TimeValue mediaLoadedTime = GetMovieTimeScale(storage->movie) * (double)mediaDuration / (double)mediaTimeScale; 
     862                         
     863                        if(minLoadedTime == 0 || mediaLoadedTime < minLoadedTime) 
     864                                minLoadedTime = mediaLoadedTime; 
     865                         
     866                        if(addedDuration > 0) { 
     867                                result = InsertMediaIntoTrack(track, -1, prevDuration, addedDuration, fixed1); 
     868                        } 
     869                } 
     870        } 
     871         
     872        //set the loaded time to the length of the shortest track. 
     873        storage->loadedTime = minLoadedTime; 
     874         
     875        if(readResult != 0) { 
     876                //remove the placeholder track 
     877                if(storage->placeholderTrack != NULL) { 
     878                        DisposeMovieTrack(storage->placeholderTrack); 
     879                        storage->placeholderTrack = NULL; 
     880                } 
     881                 
     882                //set the movie load state to complete, as well as mark the import output flag. 
     883                storage->movieLoadState = kMovieLoadStateComplete; 
     884                *outFlags |= movieImportResultComplete;          
     885        } else { 
     886                //if we're not yet done with the import, calculate the movie load state. 
     887                int64_t timeToCompleteFile; //time until the file should be completely available, in terms of AV_TIME_BASE 
     888                long dataRate; 
     889                 
     890                dataResult = DataHGetDataRate(storage->dataHandler, 0, &dataRate); 
     891                if(dataResult == noErr) { 
     892                        timeToCompleteFile = (AV_TIME_BASE * (storage->dataSize - availableSize)) / dataRate; 
     893                         
     894                        if(storage->loadedTime > (10 * GetMovieTimeScale(storage->movie)) && timeToCompleteFile < (storage->format_context->duration * .85)) 
     895                                storage->movieLoadState = kMovieLoadStatePlaythroughOK; 
    675896                        else 
    676                                 sampleRec.durationPerSample = map->base.num * pkt.duration; 
    677                         sampleRec.numberOfSamples = 1; 
    678                 } 
    679                 else if (codec->codec_type == CODEC_TYPE_AUDIO) 
    680                 { 
    681                         if(ncstr->vbr) { 
    682                                 if(codec->frame_size == ncstr->base.num) { 
    683                                         sampleRec.durationPerSample = codec->frame_size; 
    684                                         sampleRec.numberOfSamples = 1; 
    685                                 } else if (ncstr->asbd.mFormatID == kAudioFormatMPEG4AAC) { 
    686                                         /* AVI-mux GUI, the author of which created this hack in the first place, 
    687                                         * seems to special-case getting an AAC audio sample's duration this way */ 
    688                                         sampleRec.durationPerSample = ic->streams[pkt.stream_index]->time_base.num; 
    689                                         sampleRec.numberOfSamples = 1; 
    690                                 } else { 
    691 </