root/branches/perian-1.0/ff_private.c

Revision 461, 33.8 kB (checked in by dconrad, 2 years ago)

When idle importing, only add samples to the track if the movie is paused unless necessary. Also speed up idle importing of local files considerably. Closes #143

Line 
1 /*****************************************************************************
2 *
3 *  Avi Import Component Private Functions
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_private.h"
24 #include "avcodec.h"
25 #include "mpegaudio.h"
26 #include "allformats.h"
27 #include "Codecprintf.h"
28 #include "CommonUtils.h"
29 #include "CodecIDs.h"
30
31 #include <CoreServices/CoreServices.h>
32 #include <AudioToolbox/AudioToolbox.h>
33 #include <QuickTime/QuickTime.h>
34
35 #include "bitstream_info.h"
36 #include "MatroskaCodecIDs.h"
37
38 /* This routine checks if the system requirements are fullfilled */
39 ComponentResult check_system()
40 {
41         ComponentResult result;
42         long systemVersion;
43        
44         result = Gestalt(gestaltSystemVersion, &systemVersion);
45         require_noerr(result,bail);
46        
47         /* Make sure we have at least 10.4 installed...*/
48         if(systemVersion < 0x00001040)
49                 result = -1;
50        
51 bail:
52                 return result;
53 } /* check_system() */
54
55 /* This routine does register the ffmpeg parsers which would normally
56  * be registred through the normal initialization process */
57 void register_parsers()
58 {
59         /* Do we need more parsers here? */
60 //    av_register_codec_parser(&mpegaudio_parser);
61 //      av_register_codec_parser(&ac3_parser);
62 } /* register_parsers() */
63
64
65 /* This function prepares the target Track to receivve the movie data,
66  * it is called if QT has asked an import operation which should just
67  * load this track. After success, *outmap points to a valid stream maping
68  * Return values:
69  *        0: ok
70  *      < 0: couldn't find a matching track
71  */
72 int prepare_track(ff_global_ptr storage, Track targetTrack, Handle dataRef, OSType dataRefType)
73 {
74         int j;
75         AVStream *st = NULL;
76         AVStream *outstr = NULL;
77         Media media;
78         NCStream *map = NULL;
79         AVFormatContext *ic = storage->format_context;
80        
81         /* If the track has already a media, return an err */
82         media = GetTrackMedia(targetTrack);
83         if(media) goto err;
84        
85         /* Search the AVFormatContext for a video stream */
86         for(j = 0; j < ic->nb_streams && !outstr; j++) {
87                 st = ic->streams[j];
88                 if(st->codec->codec_type == CODEC_TYPE_VIDEO)
89                         outstr = st;
90         }
91         /* Search the AVFormatContext for an audio stream (no video stream exists) */
92         for(j = 0; j < ic->nb_streams && !outstr; j++) {
93                 st = ic->streams[j];
94                 if(st->codec->codec_type == CODEC_TYPE_AUDIO)
95                         outstr = st;
96         }
97         /* Still no stream, then err */
98         if(!outstr) goto err;
99        
100         /* prepare the stream map & initialize*/
101         map = av_mallocz(sizeof(NCStream));
102         map->index = st->index;
103         map->str = outstr;
104        
105         if(st->codec->codec_type == CODEC_TYPE_VIDEO)
106                 initialize_video_map(map, targetTrack, dataRef, dataRefType, storage->firstFrames + st->index);
107         else if(st->codec->codec_type == CODEC_TYPE_AUDIO)
108                 initialize_audio_map(map, targetTrack, dataRef, dataRefType, storage->firstFrames + st->index);
109        
110         /* return the map */
111         storage->stream_map = map;
112        
113         return 0;
114 err:
115                 if(map)
116                         av_free(map);
117         return -1;
118 } /* prepare_track() */
119
120 /* Initializes the map & targetTrack to receive video data */
121 void initialize_video_map(NCStream *map, Track targetTrack, Handle dataRef, OSType dataRefType, AVPacket *firstFrame)
122 {
123         Media media;
124         ImageDescriptionHandle imgHdl;
125         Handle imgDescExt = NULL;
126         AVCodecContext *codec;
127         double num,den;
128        
129         codec = map->str->codec;
130        
131         map->base = map->str->time_base;
132         if(map->base.den > 100000) {
133                 /* if that's the case, then we probably ran out of timevalues!
134                 * a timescale of 100000 allows a movie duration of 5-6 hours
135                 * so I think this will be enough */
136                 den = map->base.den;
137                 num = map->base.num;
138                
139                 /* we use the following approach ##.### frames per second.
140                         * afterwards rounding */
141                 den = den / num * 1000.0;
142                 map->base.num = 1000;
143                 map->base.den = round(den);
144         }
145        
146         media = NewTrackMedia(targetTrack, VideoMediaType, map->base.den, dataRef, dataRefType);
147         map->media = media;
148        
149         /* Create the Image Description Handle */
150         imgHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
151         (*imgHdl)->idSize = sizeof(ImageDescription);
152        
153         if (codec->codec_tag)
154                 (*imgHdl)->cType = BSWAP(codec->codec_tag);
155         else
156                 // need to lookup the fourcc from the codec_id
157                 (*imgHdl)->cType = map_video_codec_to_mov_tag(codec->codec_id);
158 //      FourCCprintf("fourcc: ", (*imgHdl)->cType);
159        
160         (*imgHdl)->temporalQuality = codecMaxQuality;
161         (*imgHdl)->spatialQuality = codecMaxQuality;
162         (*imgHdl)->width = codec->width;
163         (*imgHdl)->height = codec->height;
164         (*imgHdl)->hRes = 72 << 16;
165         (*imgHdl)->vRes = 72 << 16;
166         (*imgHdl)->depth = codec->bits_per_sample;
167         (*imgHdl)->clutID = -1; // no color lookup table...
168        
169         /* Create the strf image description extension (see AVI's BITMAPINFOHEADER) */
170         imgDescExt = create_strf_ext(codec);
171         if (imgDescExt) {
172                 AddImageDescriptionExtension(imgHdl, imgDescExt, 'strf');
173                 DisposeHandle(imgDescExt);
174         }
175        
176         map->sampleHdl = (SampleDescriptionHandle)imgHdl;
177        
178 } /* initialize_video_map() */
179
180 /* Initializes the map & targetTrack to receive audio data */
181 void initialize_audio_map(NCStream *map, Track targetTrack, Handle dataRef, OSType dataRefType, AVPacket *firstFrame)
182 {
183         Media media;
184         SoundDescriptionHandle sndHdl;
185         AudioStreamBasicDescription asbd;
186         AVCodecContext *codec;
187         UInt32 ioSize;
188         OSStatus err;
189        
190         uint8_t *cookie = NULL;
191         int cookieSize = 0;
192        
193         codec = map->str->codec;
194         map->base = map->str->time_base;
195        
196         media = NewTrackMedia(targetTrack, SoundMediaType, codec->sample_rate, dataRef, dataRefType);
197        
198         map->media = media;
199        
200         memset(&asbd,0,sizeof(asbd));
201         map_avi_to_mov_tag(codec->codec_id, &asbd, map);
202         if(asbd.mFormatID == 0) /* no know codec, use the ms tag */
203                 asbd.mFormatID = 'ms\0\0' + codec->codec_tag; /* the number is stored in the last byte => big endian */
204        
205         /* Ask the AudioToolbox about vbr of the codec */
206         ioSize = sizeof(UInt32);
207         AudioFormatGetProperty(kAudioFormatProperty_FormatIsVBR, sizeof(AudioStreamBasicDescription), &asbd, &ioSize, &map->vbr);
208        
209         /* ask the toolbox about more information */
210         ioSize = sizeof(AudioStreamBasicDescription);
211         AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &ioSize, &asbd);
212        
213         /* Set some fields of the AudioStreamBasicDescription. Then ask the AudioToolbox
214                 * to fill as much as possible before creating the SoundDescriptionHandle */
215         asbd.mSampleRate = codec->sample_rate;
216         asbd.mChannelsPerFrame = codec->channels;
217         if(!map->vbr) /* This works for all the tested codecs. but is there any better way? */
218                 asbd.mBytesPerPacket = codec->block_align; /* this is tested for alaw/mulaw/msadpcm */
219         asbd.mFramesPerPacket = codec->frame_size; /* works for mp3, all other codecs this is 0 anyway */
220         asbd.mBitsPerChannel = codec->bits_per_sample;
221        
222         // this probably isn't quite right; FLV doesn't set frame_size or block_align,
223         // but we need > 0 frames per packet or Apple's mp3 decoder won't work
224         if (asbd.mBytesPerPacket == 0 && asbd.mFramesPerPacket == 0)
225                 asbd.mFramesPerPacket = 1;
226        
227         // if we don't have mBytesPerPacket, we can't import as CBR. Probably should be VBR, and the codec
228         // either lied about kAudioFormatProperty_FormatIsVBR or isn't present
229         if (asbd.mBytesPerPacket == 0)
230                 map->vbr = 1;
231        
232         /* If we have vbr audio, the media scale most likely has to be set to the time_base denumerator */
233         if(map->vbr) {
234                 /* if we have mFramesPerPacket, set mBytesPerPacket to 0 as this can cause
235                 * errors if set incorrectly. But in vbr, we just need the mFramesPerPacket
236                 * value */
237                 if(asbd.mFramesPerPacket)
238                         asbd.mBytesPerPacket = 0;
239                 SetMediaTimeScale(media, map->str->time_base.den);
240         }
241        
242         /* FIXME. in the MSADPCM codec, we get a wrong mFramesPerPacket entry because
243                 * of the difference in the sample_rate and the time_base denumerator. So we
244                 * recalculate here the mFramesPerPacket entry */
245         if(asbd.mBytesPerPacket) {
246                 /* For calculation, lets assume a packet duration of 1, use ioSize as tmp storage */
247                 ioSize = map->str->time_base.num * codec->sample_rate / map->str->time_base.den;
248                 /* downscale to correct bytes_per_packet */
249                 asbd.mFramesPerPacket = ioSize * asbd.mBytesPerPacket / codec->block_align;
250         }
251        
252         AudioChannelLayout acl;
253         int aclSize = 0;  //Set this if you intend to use it
254         memset(&acl, 0, sizeof(AudioChannelLayout));
255
256         /* We have to parse the format */
257         int useDefault = 1;
258         if(asbd.mFormatID == kAudioFormatAC3 || asbd.mFormatID == 'ms \0')
259         {
260                 if(parse_ac3_bitstream(&asbd, &acl, firstFrame->data, firstFrame->size))
261                 {
262                         useDefault = 0;
263                         aclSize = sizeof(AudioChannelLayout);
264                 }
265         }
266         if(useDefault && asbd.mChannelsPerFrame > 2)
267         {
268                 acl = GetDefaultChannelLayout(&asbd);
269                 aclSize = sizeof(AudioChannelLayout);
270         }
271         err = QTSoundDescriptionCreate(&asbd, aclSize == 0 ? NULL : &acl, aclSize, NULL, 0, kQTSoundDescriptionKind_Movie_LowestPossibleVersion, &sndHdl);
272         if(err) fprintf(stderr, "AVI IMPORTER: Error creating the sound description\n");
273        
274         /* Create the magic cookie */
275         cookie = create_cookie(codec, &cookieSize, asbd.mFormatID);
276         if(cookie) {
277                 err = QTSoundDescriptionSetProperty(sndHdl, kQTPropertyClass_SoundDescription, kQTSoundDescriptionPropertyID_MagicCookie,
278                                                                                         cookieSize, cookie);
279                 if(err) fprintf(stderr, "AVI IMPORTER: Error appending the magic cookie to the sound description\n");
280                 av_free(cookie);
281         }
282        
283         map->sampleHdl = (SampleDescriptionHandle)sndHdl;
284         map->asbd = asbd;
285 } /* initialize_audio_map() */
286
287 OSType map_video_codec_to_mov_tag(enum CodecID codec_id)
288 {
289         switch(codec_id) {
290                 case CODEC_ID_FLV1:
291                         return 'FLV1';
292                 case CODEC_ID_VP6F:
293                         return 'VP6F';
294                 case CODEC_ID_FLASHSV:
295                         return 'FSV1';
296         }
297         return 0;
298 }
299
300 /* maps the codec_id tag of libavformat to a constant the AudioToolbox can work with */
301 void map_avi_to_mov_tag(enum CodecID codec_id, AudioStreamBasicDescription *asbd, NCStream *map)
302 {
303         switch(codec_id) {
304                 case CODEC_ID_MP2:
305                         asbd->mFormatID = kAudioFormatMPEGLayer2;
306                         break;
307                 case CODEC_ID_MP3:
308                         asbd->mFormatID = kAudioFormatMPEGLayer3;
309                         break;
310                 case CODEC_ID_AC3:
311                         asbd->mFormatID = kAudioFormatAC3;
312                         map->vbr = 1;
313                         break;
314                 case CODEC_ID_PCM_S16LE:
315                         asbd->mFormatID = kAudioFormatLinearPCM;
316                         asbd->mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
317                         break;
318                 case CODEC_ID_PCM_U8:
319                         asbd->mFormatID = kAudioFormatLinearPCM;
320                         asbd->mFormatFlags = kLinearPCMFormatFlagIsBigEndian;
321                         break;
322                 case CODEC_ID_PCM_ALAW:
323                         asbd->mFormatID = kAudioFormatALaw;
324                         break;
325                 case CODEC_ID_PCM_MULAW:
326                         asbd->mFormatID = kAudioFormatULaw;
327                         break;
328                 case CODEC_ID_ADPCM_MS:
329                         asbd->mFormatID = kMicrosoftADPCMFormat;
330                         break;
331                 case CODEC_ID_AAC:
332                         asbd->mFormatID = kAudioFormatMPEG4AAC;
333                         break;
334                 case CODEC_ID_VORBIS:
335                         asbd->mFormatID = 'OggV';
336                         break;
337                 case CODEC_ID_DTS:
338                         asbd->mFormatID = kAudioFormatDTS;
339                         map->vbr = 1;
340                         break;
341                 case CODEC_ID_ADPCM_SWF:
342                         asbd->mFormatID = kAudioFormatFlashADPCM;
343                         break;
344                 default:
345                         break;
346         }
347 } /* map_avi_to_mov_tag() */
348
349 /* This function creates a magic cookie basec on the codec parameter and formatID
350  * Return value: a pointer to a magic cookie which has to be av_free()'d
351  * in cookieSize, the size of the magic cookie is returned to the caller */
352 uint8_t *create_cookie(AVCodecContext *codec, int *cookieSize, UInt32 formatID)
353 {
354         uint8_t *result = NULL;
355         uint8_t *ptr;
356         AudioFormatAtom formatAtom;
357         AudioTerminatorAtom termAtom;
358         long waveSize;
359         uint8_t *waveAtom = NULL;
360         int size = 0;
361        
362         /* Do we need an endia atom, too? */
363        
364         /* initialize the user Atom
365                 * 8 bytes                       for the atom size & atom type
366                 * 18 bytes                      for the already extracted part, see wav.c in the ffmpeg project
367                 * extradata_size        for the data still stored in the AVCodecContext structure */
368         waveSize = 18 + codec->extradata_size + 8;
369         waveAtom = av_malloc(waveSize);
370        
371         /* now construct the wave atom */
372         /* QT Atoms are big endian, I think but the WAVE data should be little endian */
373         ptr = write_int32(waveAtom, EndianS32_NtoB(waveSize));
374         ptr = write_int32(ptr, EndianS32_NtoB(formatID));
375         ptr = write_int16(ptr, EndianS16_NtoL(codec->codec_tag));
376         ptr = write_int16(ptr, EndianS16_NtoL(codec->channels));
377         ptr = write_int32(ptr, EndianS32_NtoL(codec->sample_rate));
378         ptr = write_int32(ptr, EndianS32_NtoL(codec->bit_rate / 8));
379         ptr = write_int16(ptr, EndianS16_NtoL(codec->block_align));
380         ptr = write_int16(ptr, EndianS16_NtoL(codec->bits_per_sample));
381         ptr = write_int16(ptr, EndianS16_NtoL(codec->extradata_size));
382         /* now the remaining stuff */
383         ptr = write_data(ptr, codec->extradata, codec->extradata_size);
384        
385         /* Calculate the size of the cookie */
386         size  = sizeof(formatAtom) + sizeof(termAtom) + waveSize;
387        
388         /* Audio Format Atom */
389         formatAtom.size = EndianS32_NtoB(sizeof(AudioFormatAtom));
390         formatAtom.atomType = EndianS32_NtoB(kAudioFormatAtomType);
391         formatAtom.format = EndianS32_NtoB(formatID);
392        
393         /* Terminator Atom */
394         termAtom.atomType = EndianS32_NtoB(kAudioTerminatorAtomType);
395         termAtom.size = EndianS32_NtoB(sizeof(AudioTerminatorAtom));
396        
397         result = av_malloc(size);
398        
399         /* use ptr to write to the result */
400         ptr = result;
401        
402         /* format atom */
403         ptr = write_data(ptr, (uint8_t*)&formatAtom, sizeof(formatAtom));
404         ptr = write_data(ptr, waveAtom, waveSize);
405         ptr = write_data(ptr, (uint8_t*)&termAtom, sizeof(termAtom));
406        
407 bail:
408                 *cookieSize = size;
409         if(waveAtom)
410                 av_free(waveAtom);
411         return result;
412 } /* create_cookie() */
413
414 /* This function creates an image description extension that some codecs need to be able
415  * to decode properly, a copy of the strf (BITMAPINFOHEADER) chunk in the avi.
416  * Return value: a handle to an image description extension which has to be DisposeHandle()'d
417  * in cookieSize, the size of the image description extension is returned to the caller */
418 Handle create_strf_ext(AVCodecContext *codec)
419 {
420         Handle result = NULL;
421         uint8_t *ptr;
422         long size;
423        
424         /* initialize the extension
425                 * 40 bytes                      for the BITMAPINFOHEADER stucture, see avienc.c in the ffmpeg project
426                 * extradata_size        for the data still stored in the AVCodecContext structure */
427         size = 40 + codec->extradata_size;
428         result = NewHandle(size);
429         if (result == NULL)
430                 goto bail;
431        
432         /* construct the BITMAPINFOHEADER structure */
433         /* QT Atoms are big endian, but the STRF atom should be little endian */
434         ptr = write_int32((uint8_t *)*result, EndianS32_NtoL(size)); /* size */
435         ptr = write_int32(ptr, EndianS32_NtoL(codec->width));
436         ptr = write_int32(ptr, EndianS32_NtoL(codec->height));
437         ptr = write_int16(ptr, EndianS16_NtoL(1)); /* planes */
438        
439         ptr = write_int16(ptr, EndianS16_NtoL(codec->bits_per_sample ? codec->bits_per_sample : 24)); /* depth */
440         /* compression type */
441         ptr = write_int32(ptr, EndianS32_NtoL(codec->codec_tag));
442         ptr = write_int32(ptr, EndianS32_NtoL(codec->width * codec->height * 3));
443         ptr = write_int32(ptr, EndianS32_NtoL(0));
444         ptr = write_int32(ptr, EndianS32_NtoL(0));
445         ptr = write_int32(ptr, EndianS32_NtoL(0));
446         ptr = write_int32(ptr, EndianS32_NtoL(0));
447        
448         /* now the remaining stuff */
449         ptr = write_data(ptr, codec->extradata, codec->extradata_size);
450        
451         if (codec->extradata_size & 1) {
452                 uint8_t zero = 0;
453                 ptr = write_data(ptr, &zero, 1);
454         }
455        
456 bail:
457         return result;
458 } /* create_extension() */
459
460 /* Add the meta data that lavf exposes to the movie */
461 static void add_metadata(AVFormatContext *ic, Movie theMovie)
462 {
463     QTMetaDataRef movie_metadata;
464     OSType key, err;
465    
466     err = QTCopyMovieMetaData(theMovie, &movie_metadata);
467     if (err) return;
468    
469         if (strlen(ic->title)) {
470                 key = kQTMetaDataCommonKeyDisplayName;
471                 QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon,
472                                   (UInt8 *)&key, sizeof(key), (UInt8 *)ic->title, strlen(ic->title), kQTMetaDataTypeUTF8, NULL);
473         }
474         if (strlen(ic->author)) {
475                 key = kQTMetaDataCommonKeyAuthor;
476                 QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon,
477                                   (UInt8 *)&key, sizeof(key), (UInt8 *)ic->author, strlen(ic->author), kQTMetaDataTypeUTF8, NULL);
478         }
479         if (strlen(ic->copyright)) {
480                 key = kQTMetaDataCommonKeyCopyright;
481                 QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon,
482                                   (UInt8 *)&key, sizeof(key), (UInt8 *)ic->copyright, strlen(ic->copyright), kQTMetaDataTypeUTF8, NULL);
483         }
484         if (strlen(ic->comment)) {
485                 key = kQTMetaDataCommonKeyComment;
486                 QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon,
487                                   (UInt8 *)&key, sizeof(key), (UInt8 *)ic->comment, strlen(ic->comment), kQTMetaDataTypeUTF8, NULL);
488         }
489         if (strlen(ic->album)) {
490                 key = kQTMetaDataCommonKeyComment;
491                 QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon,
492                                   (UInt8 *)&key, sizeof(key), (UInt8 *)ic->album, strlen(ic->album), kQTMetaDataTypeUTF8, NULL);
493         }
494         if (strlen(ic->genre)) {
495                 key = kQTMetaDataCommonKeyGenre;
496                 QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon,
497                                   (UInt8 *)&key, sizeof(key), (UInt8 *)ic->genre, strlen(ic->genre), kQTMetaDataTypeUTF8, NULL);
498         }
499     QTMetaDataRelease(movie_metadata);
500 }
501
502 /* This function prepares the movie to receivve the movie data,
503  * After success, *out_map points to a valid stream maping
504  * Return values:
505  *        0: ok
506  */
507 int prepare_movie(ff_global_ptr storage, Movie theMovie, Handle dataRef, OSType dataRefType)
508 {
509         int j;
510         AVStream *st;
511         NCStream *map;
512         Track track;
513         Track first_audio_track = NULL;
514         AVFormatContext *ic = storage->format_context;
515        
516         /* make the stream map structure */
517         map = av_mallocz(ic->nb_streams * sizeof(NCStream));
518        
519         for(j = 0; j < ic->nb_streams; j++) {
520                
521                 st = ic->streams[j];
522                 map[j].index = st->index;
523                 map[j].str = st;
524                 map[j].duration = -1;
525                
526                 if(st->codec->codec_type == CODEC_TYPE_VIDEO) {
527                         track = NewMovieTrack(theMovie, st->codec->width << 16, st->codec->height << 16, kNoVolume);
528                         initialize_video_map(&map[j], track, dataRef, dataRefType, storage->firstFrames + j);
529                 } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
530                         track = NewMovieTrack(theMovie, 0, 0, kFullVolume);
531                         initialize_audio_map(&map[j], track, dataRef, dataRefType, storage->firstFrames + j);
532                        
533                         if (first_audio_track == NULL)
534                                 first_audio_track = track;
535                         else
536                                 SetTrackAlternate(track, first_audio_track);
537                 }
538         }
539        
540     add_metadata(ic, theMovie);
541    
542         storage->stream_map = map;
543        
544         return 0;
545 } /* prepare_movie() */
546
547 int determine_header_offset(ff_global_ptr storage) {
548         AVFormatContext *formatContext;
549         AVPacket packet;
550         int result, i;
551        
552         formatContext = storage->format_context;
553         result = noErr;
554         storage->header_offset = 0;
555        
556         /* Seek backwards to get a manually read packet for file offset */
557         if(formatContext->streams[0]->index_entries == NULL || storage->componentType == 'FLV ')
558         {
559                 if (IS_AVI(storage->componentType))
560                         //Try to seek to the first frame; don't care if it fails
561                         // Is this really needed for AVIs w/out an index? It seems to work fine without,
562                         // and it seems that with it the first frame is skipped.
563                         av_seek_frame(formatContext, -1, 0, 0);
564                 storage->header_offset = 0;
565         }
566         else
567         {
568                 int streamsRead = 0;
569                 AVStream *st;
570                
571                 result = av_seek_frame(formatContext, -1, 0, 0);
572                 if(result < 0) goto bail;
573                
574                 av_read_frame(formatContext, &packet);
575                 st = formatContext->streams[packet.stream_index];
576                
577                 /* read_packet will give the first decodable packet. However, that isn't necessarily
578                         the first entry in the index, so look for an entry with a matching size. */
579                 for (i = 0; i < st->nb_index_entries; i++) {
580                         if (packet.dts == st->index_entries[i].timestamp) {
581                                 storage->header_offset = packet.pos - st->index_entries[i].pos;
582                                 break;
583                         }
584                 }
585                 while(streamsRead < formatContext->nb_streams)
586                 {
587                         int streamIndex = packet.stream_index;
588                         if(storage->firstFrames[streamIndex].size == 0)
589                         {
590                                 memcpy(storage->firstFrames + streamIndex, &packet, sizeof(AVPacket));
591                                 streamsRead++;
592                                 if(streamsRead == formatContext->nb_streams)
593                                         break;
594                         }
595                         else
596                                 av_free_packet(&packet);
597                         formatContext->iformat->read_packet(formatContext, &packet);
598                 }
599                
600                 // seek back to the beginning, otherwise av_read_frame-based decoding will skip a few packets.
601                 av_seek_frame(formatContext, -1, 0, 0);
602         }
603                
604 bail:
605         return(result);
606 }
607
608 /* This function imports the avi represented by the AVFormatContext to the movie media represented
609  * in the map function. The aviheader_offset is used to calculate the packet offset from the
610  * beginning of the file. It returns whether it was successful or not (i.e. whether the file had an index) */
611 int import_using_index(ff_global_ptr storage, int *hadIndex, TimeValue *addedDuration) {
612         int j, k, l;
613         NCStream *map;
614         NCStream *ncstr;
615         AVFormatContext *ic;
616         AVStream *stream;
617         AVCodecContext *codec;
618         SampleReference64Ptr sampleRec;
619         int64_t header_offset, offset, duration;
620         short flags;
621         int sampleNum;
622         ComponentResult result = noErr;
623        
624         map = storage->stream_map;
625         ic = storage->format_context;
626         header_offset = storage->header_offset;
627
628         *hadIndex = 0;
629        
630         // AVIs without an index currently add one entry to the index; assume that
631         // such a small index means that we should idle import instead. It shouldn't
632         // take much longer if the index really is this small anyways.
633         for (j = 0; j < ic->nb_streams; j++) {
634                 if (map[j].str->nb_index_entries <= 1)
635                         goto bail;
636         }
637        
638         //FLVs have unusable indexes, so don't even bother.
639         if(storage->componentType == 'FLV ')
640                 goto bail;
641        
642         /* process each stream in ic */
643         for(j = 0; j < ic->nb_streams; j++) {
644                 ncstr = &map[j];
645                 stream = ncstr->str;
646                 codec = stream->codec;
647                
648                 /* no stream we can read */
649                 if(!ncstr->media)
650                         continue;
651                
652                 /* no index, we might as well skip */
653                 if(stream->nb_index_entries == 0)
654                         continue;
655                
656                 sampleNum = 0;
657                 ncstr->sampleTable = calloc(stream->nb_index_entries, sizeof(SampleReference64Record));
658                        
659                 /* now parse the index entries */
660                 for(k = 0; k < stream->nb_index_entries; k++) {
661                        
662                         /* file offset */
663                         offset = header_offset + stream->index_entries[k].pos;
664                        
665                         /* flags */
666                         flags = 0;
667                         if((stream->index_entries[k].flags & AVINDEX_KEYFRAME) == 0)
668                                 flags |= mediaSampleNotSync;
669                        
670                         sampleRec = &ncstr->sampleTable[sampleNum++];
671                        
672                         /* set as many fields in sampleRec as possible */
673                         sampleRec->dataOffset.hi = offset >> 32;
674                         sampleRec->dataOffset.lo = (uint32_t)offset;
675                         sampleRec->dataSize = stream->index_entries[k].size;
676                         sampleRec->sampleFlags = flags;
677                        
678                         /* some samples have a data_size of zero. if that's the case, ignore them
679                                 * they seem to be used to stretch the frame duration & are already handled
680                                 * by the previous pkt */
681                         if(sampleRec->dataSize <= 0) {
682                                 sampleNum--;
683                                 continue;
684                         }
685                        
686                         /* switch for the remaining fields */
687                         if(codec->codec_type == CODEC_TYPE_VIDEO) {
688                                
689                                 /* Calculate the frame duration */
690                                 duration = 1;
691                                 for(l = k+1; l < stream->nb_index_entries; l++) {
692                                         if(stream->index_entries[l].size > 0)
693                                                 break;
694                                         duration++;
695                                 }
696                                
697                                 sampleRec->durationPerSample = map->base.num * duration;
698                                 sampleRec->numberOfSamples = 1;
699                         }
700                         else if(codec->codec_type == CODEC_TYPE_AUDIO) {
701                                
702                                 /* FIXME: check if that's really the right thing to do here */
703                                 if(ncstr->vbr) {
704                                         sampleRec->numberOfSamples = 1;
705                                        
706                                         if (k + 1 < stream->nb_index_entries)
707                                                 sampleRec->durationPerSample = (stream->index_entries[k+1].timestamp - stream->index_entries[k].timestamp) * ncstr->base.num;
708                                         else if (sampleNum - 2 >= 0)
709                                                 // if we're at the last index entry, use the duration of the previous sample
710                                                 // FIXME: this probably could be better
711                                                 sampleRec->durationPerSample = ncstr->sampleTable[sampleNum-2].durationPerSample;
712                                        
713                                 } else {
714                                         sampleRec->durationPerSample = 1;
715                                         sampleRec->numberOfSamples = (stream->index_entries[k].size * ncstr->asbd.mFramesPerPacket) / ncstr->asbd.mBytesPerPacket;
716                                 }
717                         }
718                 }
719                 if(sampleNum != 0)
720                 {
721                         /* Add all of the samples to the media */
722                         AddMediaSampleReferences64(ncstr->media, ncstr->sampleHdl, sampleNum, ncstr->sampleTable, NULL);
723                         free(ncstr->sampleTable);                       
724
725                         /* The index is both present and not empty */
726                         *hadIndex = 1;
727                 }
728         }
729        
730         if(*hadIndex == 0)
731                 //No index, the remainder of this function will fail.
732                 goto bail;
733        
734         // insert media and set addedDuration;
735         for(j = 0; j < storage->map_count && result == noErr; j++) {
736                 Media media = storage->stream_map[j].media;
737                 if(media) {
738                         Track track;
739                         TimeRecord time;
740                         TimeValue mediaDuration;
741                         TimeScale mediaTimeScale;
742                         TimeScale movieTimeScale;
743
744                         mediaDuration = GetMediaDuration(media);
745                         mediaTimeScale = GetMediaTimeScale(media);
746                         movieTimeScale = GetMovieTimeScale(storage->movie);
747                        
748                         /* we could handle this stream.
749                         * convert the atTime parameter to track scale.
750                         * FIXME: check if that's correct */
751                         time.value.hi = 0;
752                         time.value.lo = storage->atTime;
753                         time.scale = movieTimeScale;
754                         time.base = NULL;
755                         ConvertTimeScale(&time, mediaTimeScale);
756                        
757                         track = GetMediaTrack(media);
758                         result = InsertMediaIntoTrack(track, time.value.lo, 0, mediaDuration, fixed1);
759
760                         if(result != noErr)
761                                 goto bail;
762                        
763                         time.value.hi = 0;
764                         time.value.lo = mediaDuration;
765                         time.scale = mediaTimeScale;
766                         time.base = NULL;
767                         ConvertTimeScale(&time, movieTimeScale);
768                        
769                         if(time.value.lo > *addedDuration)
770                                 *addedDuration = time.value.lo;
771                 }
772         }
773        
774         storage->loadedTime = *addedDuration;
775        
776 bail:
777         return result;
778 } /* import_using_index() */
779
780 /* Import function for movies that lack an index.
781  * Supports progressive importing, but will not idle if maxFrames == 0.
782  */
783 ComponentResult import_with_idle(ff_global_ptr storage, long inFlags, long *outFlags, int minFrames, int maxFrames, bool addSamples) {
784         SampleReference64Record sampleRec;
785         DataHandler dataHandler;
786         AVFormatContext *formatContext;
787         AVCodecContext *codecContext;
788         AVStream *stream;
789         AVPacket packet;
790         NCStream *ncstream;
791         ComponentResult dataResult; //used for data handler operations that can fail.
792         ComponentResult result;
793         TimeValue minLoadedTime;
794         int64_t availableSize, margin;
795         long idling;
796         int readResult, framesProcessed, i;
797         short flags;
798        
799         dataHandler = storage->dataHandler;
800         formatContext = storage->format_context;
801         dataResult = noErr;
802         result = noErr;
803         minLoadedTime = -1;
804         availableSize = 0;
805         margin = 0;
806         idling = (inFlags & movieImportWithIdle);
807         framesProcessed = 0;
808                
809         if(idling) {
810                 //get the size of immediately available data
811                 if(storage->dataHandlerSupportsWideOffsets) {
812                         wide wideSize;
813                        
814                         dataResult = DataHGetAvailableFileSize64(storage->dataHandler, &wideSize);
815                         if(dataResult == noErr) availableSize = ((int64_t)wideSize.hi << 32) + wideSize.lo;
816                 } else {
817                         long longSize;
818                        
819                         dataResult = DataHGetAvailableFileSize(storage->dataHandler, &longSize);
820                         if(dataResult == noErr) availableSize = longSize;
821                 }
822         }
823        
824         // record stream durations before we add any samples so that we know what to tell InsertMediaIntoTrack later
825         for(i = 0; i < storage->map_count; i++) {
826                 ncstream = &storage->stream_map[i];
827                 Media media = ncstream->media;
828                
829                 if(media && ncstream->duration == -1)
830                         ncstream->duration = GetMediaDuration(media);
831         }
832        
833         while((readResult = av_read_frame(formatContext, &packet)) == 0) {             
834                 ncstream = &storage->stream_map[packet.stream_index];
835                 stream = ncstream->str;
836                 codecContext = stream->codec;
837                 flags = 0;
838                
839                 if((packet.flags & PKT_FLAG_KEY) == 0)
840                         flags |= mediaSampleNotSync;
841                
842                 memset(&sampleRec, 0, sizeof(sampleRec));
843                 sampleRec.dataOffset.hi = packet.pos >> 32;
844                 sampleRec.dataOffset.lo = (uint32_t)packet.pos;
845                 sampleRec.dataSize = packet.size;
846                 sampleRec.sampleFlags = flags;
847                
848                 if(packet.size > storage->largestPacketSize)
849                         storage->largestPacketSize = packet.size;
850                
851                 if(sampleRec.dataSize <= 0)
852                         continue;
853                
854                 if(codecContext->codec_type == CODEC_TYPE_AUDIO && !ncstream->vbr)
855                         sampleRec.numberOfSamples = (packet.size * ncstream->asbd.mFramesPerPacket) / ncstream->asbd.mBytesPerPacket;
856                 else
857                         sampleRec.numberOfSamples = 1; //packet.duration;
858                
859                 //add any samples waiting to be added
860                 if(ncstream->lastSample.numberOfSamples > 0) {
861                         //calculate the duration of the sample before adding it
862                         ncstream->lastSample.durationPerSample = (packet.pts - ncstream->lastpts) * ncstream->base.num;
863                        
864                         AddMediaSampleReferences64(ncstream->media, ncstream->sampleHdl, 1, &ncstream->lastSample, NULL);
865                 }
866                
867                 if(packet.duration == 0) {
868                         //no duration, we'll have to wait for the next packet to calculate it
869                         // keep the duration of the last sample, so we can use it if it's the last frame
870                         sampleRec.durationPerSample = ncstream->lastSample.durationPerSample;
871                         ncstream->lastSample = sampleRec;
872                         ncstream->lastpts = packet.pts;
873                 } else {
874                         ncstream->lastSample.numberOfSamples = 0;
875                        
876                         if(codecContext->codec_type == CODEC_TYPE_AUDIO && !ncstream->vbr)
877                                 sampleRec.durationPerSample = 1;
878                         else
879                                 sampleRec.durationPerSample = ncstream->base.num * packet.duration;
880
881                         AddMediaSampleReferences64(ncstream->media, ncstream->sampleHdl, 1, &sampleRec, NULL);
882                 }
883                
884                 framesProcessed++;
885                
886                 //if we're idling, try really not to read past the end of available data
887                 //otherwise we will cause blocking i/o.
888                 if(idling && framesProcessed >= minFrames && availableSize > 0 && availableSize < storage->dataSize) {
889                         margin = availableSize - (packet.pos + packet.size);
890                         if(margin < (storage->largestPacketSize * 8)) { // 8x fudge factor for comfortable margin, could be tweaked.
891                                 av_free_packet(&packet);
892                                 break;
893                         }
894                 }
895                
896                 av_free_packet(&packet);
897                
898                 //stop processing if we've hit the max frame limit
899                 if(maxFrames > 0 && framesProcessed >= maxFrames)
900                         break;
901         }
902                
903         if(readResult != 0) {
904                 //if readResult != 0, we've hit the end of the stream.