source: trunk/FFusionCodec.c @ 1027

Revision 1027, 61.5 KB checked in by astrange, 6 years ago (diff)

Color conversions:

  • Simplify API and move bits out of FFusion
  • Fix up & enable SSE2 Y420toY422 asm; compiled code surrounding it is still awful

Build system:

  • Fix problems with Xcode GUI vs xcodebuild finding different SVN paths
  • Don't revert/repatch ffmpeg unless it's actually being built
  • Update cflags for Perian itself
  • Remove some patches that aren't needed anymore
  • Turn off more h264 decoder features we don't use

Subtitles:

  • Push font weights through the parser (not supported in rendering yet)
  • Drop shapes in the parser (a hack but too difficult in the renderer)
  • More correct font sizes for \fn & \fs tags
  • Slightly faster font lookup

Maybe some more too

Line 
1//---------------------------------------------------------------------------
2//FFusion
3//Alternative DivX Codec for MacOS X
4//version 2.2 (build 72)
5//by Jerome Cornet
6//Copyright 2002-2003 Jerome Cornet
7//parts by Dan Christiansen
8//Copyright 2003 Dan Christiansen
9//from DivOSX by Jamby
10//Copyright 2001-2002 Jamby
11//uses libavcodec from ffmpeg 0.4.6
12//
13//This library is free software; you can redistribute it and/or
14//modify it under the terms of the GNU Lesser General Public
15//License as published by the Free Software Foundation; either
16//version 2.1 of the License, or (at your option) any later version.
17//
18//This library is distributed in the hope that it will be useful,
19//but WITHOUT ANY WARRANTY; without even the implied warranty of
20//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21//Lesser General Public License for more details.
22//
23//You should have received a copy of the GNU Lesser General Public
24//License along with this library; if not, write to the Free Software
25//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26//
27//---------------------------------------------------------------------------
28// Source Code
29//---------------------------------------------------------------------------
30
31#include <Carbon/Carbon.h>
32#include <QuickTime/QuickTime.h>
33#include <Accelerate/Accelerate.h>
34
35#include "FFusionCodec.h"
36#include "EI_Image.h"
37#include "avcodec.h"
38#include "Codecprintf.h"
39#include "ColorConversions.h"
40#include "bitstream_info.h"
41#include "FrameBuffer.h"
42#include "CommonUtils.h"
43#include "pthread.h"
44
45#define PERIAN_PREF_DOMAIN CFSTR("org.perian.Perian")
46
47void inline swapFrame(AVFrame * *a, AVFrame * *b)
48{
49        AVFrame *t = *a;
50        *a = *b;
51        *b = t;
52}
53
54//---------------------------------------------------------------------------
55// Types
56//---------------------------------------------------------------------------
57
58// 32 because that's ffmpeg's INTERNAL_BUFFER_SIZE
59#define FFUSION_MAX_BUFFERS 32
60
61typedef struct
62{
63        AVFrame         *frame;
64        short           retainCount;
65        short           ffmpegUsing;
66        long            frameNumber;
67        AVFrame         returnedFrame;
68} FFusionBuffer;
69
70typedef enum
71{
72        PACKED_QUICKTIME_KNOWS_ORDER, /* This is for non-stupid container formats which actually know the difference between decode and display order */
73        PACKED_ALL_IN_FIRST_FRAME, /* This is for the divx hack which contains a P frame and all subsequent B frames in a single frame. Ex: I, PB, -, PB, -, I...*/
74        PACKED_DELAY_BY_ONE_FRAME /* This is for stupid containers where frames are soley writen in decode order.  Ex: I, P, B, P, B, P, I.... */
75} FFusionPacked;
76
77/* Why do these small structs?  It makes the usage of these variables clearer, no other reason */
78
79/* globs used by the BeginBand routine */
80struct begin_glob
81{
82        FFusionParserContext    *parser;
83        long                    lastFrame;
84        long                    lastIFrame;
85        int                             lastFrameType;
86        int                             futureType;
87        FrameData               *lastPFrameData;
88};
89
90/* globs used by the DecodeBand routine */
91struct decode_glob
92{
93        long                    lastFrame;
94        FFusionBuffer   *futureBuffer;
95};
96
97struct per_frame_decode_stats
98{
99        unsigned                begin_calls;
100        unsigned                decode_calls;
101        unsigned                draw_calls;
102        unsigned                end_calls;
103};
104
105struct decode_stats
106{
107        struct per_frame_decode_stats type[4];
108        int             max_frames_begun;
109        int             max_frames_decoded;
110};
111
112typedef struct
113{
114    ComponentInstance           self;
115    ComponentInstance           delegateComponent;
116    ComponentInstance           target;
117    ImageCodecMPDrawBandUPP     drawBandUPP;
118    Handle                      pixelTypes;
119    AVCodec                     *avCodec;
120    AVCodecContext      *avContext;
121    OSType                      componentType;
122    char                        hasy420;
123        FILE                    *fileLog;
124        AVFrame                 lastDisplayedFrame;
125        FFusionPacked   packedType;
126        FFusionBuffer   buffers[FFUSION_MAX_BUFFERS];   // the buffers which the codec has retained
127        int                             lastAllocatedBuffer;            // the index of the buffer which was last allocated
128                                                                                                // by the codec (and is the latest in decode order)     
129        int                             shouldUseReturnedFrame;
130        struct begin_glob       begin;
131        FFusionData             data;
132        struct decode_glob      decode;
133        struct decode_stats stats;
134        ColorConversionFuncs colorConv;
135} FFusionGlobalsRecord, *FFusionGlobals;
136
137typedef struct
138{
139    long                        width;
140    long                        height;
141    long                        depth;
142    OSType                      pixelFormat;
143        int                             decoded;
144        long                    frameNumber;
145        long                    GOPStartFrameNumber;
146        long                    bufferSize;
147        FFusionBuffer   *buffer;
148        FrameData               *frameData;
149} FFusionDecompressRecord;
150
151
152//---------------------------------------------------------------------------
153// Prototypes of private subroutines
154//---------------------------------------------------------------------------
155
156static OSErr FFusionDecompress(FFusionGlobals glob, AVCodecContext *context, UInt8 *dataPtr, ICMDataProcRecordPtr dataProc, long width, long height, AVFrame *picture, long length);
157static int FFusionGetBuffer(AVCodecContext *s, AVFrame *pic);
158static void FFusionReleaseBuffer(AVCodecContext *s, AVFrame *pic);
159static void releaseBuffer(AVCodecContext *s, FFusionBuffer *buf);
160static FFusionBuffer *retainBuffer(FFusionGlobals glob, FFusionBuffer *buf);
161static void SetupMultithreadedDecoding(AVCodecContext *s, enum CodecID codecID);
162
163int GetPPUserPreference();
164void SetPPUserPreference(int value);
165pascal OSStatus HandlePPDialogWindowEvent(EventHandlerCallRef  nextHandler, EventRef theEvent, void* userData);
166pascal OSStatus HandlePPDialogControlEvent(EventHandlerCallRef  nextHandler, EventRef theEvent, void* userData);
167void ChangeHintText(int value, ControlRef staticTextField);
168
169extern void init_FFmpeg();
170extern CFMutableStringRef CopyHomeDirectory();
171
172#define FFusionDebugPrint(x...) if (glob->fileLog) Codecprintf(glob->fileLog, x);
173#define not(x) ((x) ? "" : "not ")
174
175//---------------------------------------------------------------------------
176// Component Dispatcher
177//---------------------------------------------------------------------------
178
179#define IMAGECODEC_BASENAME()           FFusionCodec
180#define IMAGECODEC_GLOBALS()            FFusionGlobals storage
181
182#define CALLCOMPONENT_BASENAME()        IMAGECODEC_BASENAME()
183#define CALLCOMPONENT_GLOBALS()         IMAGECODEC_GLOBALS()
184
185#define COMPONENT_UPP_PREFIX()          uppImageCodec
186#define COMPONENT_DISPATCH_FILE         "FFusionCodecDispatch.h"
187#define COMPONENT_SELECT_PREFIX()       kImageCodec
188
189#define GET_DELEGATE_COMPONENT()        (storage->delegateComponent)
190
191#include <QuickTime/ImageCodec.k.h>
192#include <QuickTime/ComponentDispatchHelper.c>
193
194static void *launchUpdateChecker(void *args)
195{
196        FSRef *ref = (FSRef *)args;
197    LSOpenFSRef(ref, NULL);
198        free(ref);
199        return NULL;
200}
201
202Boolean FFusionAlreadyRanUpdateCheck = 0;
203
204void FFusionRunUpdateCheck()
205{
206        if (FFusionAlreadyRanUpdateCheck) return;
207
208    CFDateRef lastRunDate = CFPreferencesCopyAppValue(CFSTR("NextRunDate"), PERIAN_PREF_DOMAIN);
209        if(lastRunDate && CFGetTypeID(lastRunDate) != CFDateGetTypeID())
210        {
211                CFRelease(lastRunDate);
212                lastRunDate = NULL;
213        }
214    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
215   
216        FFusionAlreadyRanUpdateCheck = 1;
217       
218        if (lastRunDate) {
219                Boolean exit = CFDateGetAbsoluteTime(lastRunDate) > now;
220                CFRelease(lastRunDate);
221                if (exit) return;
222        }
223   
224    //Two places to check, home dir and /
225   
226    CFMutableStringRef location = CopyHomeDirectory();
227    CFStringAppend(location, CFSTR("/Library/PreferencePanes/Perian.prefPane/Contents/Resources/PerianUpdateChecker.app"));
228   
229    char fileRep[1024];
230    FSRef *updateCheckRef = malloc(sizeof(FSRef));
231    Boolean doCheck = FALSE;
232   
233    if(CFStringGetFileSystemRepresentation(location, fileRep, 1024))
234        if(FSPathMakeRef((UInt8 *)fileRep, updateCheckRef, NULL) == noErr)
235            doCheck = TRUE;
236   
237    CFRelease(location);
238    if(doCheck == FALSE)
239    {
240        CFStringRef absLocation = CFSTR("/Library/PreferencePanes/Perian.prefPane/Contents/Resources/PerianUpdateChecker.app");
241        if(CFStringGetFileSystemRepresentation(absLocation, fileRep, 1024))
242            if(FSPathMakeRef((UInt8 *)fileRep, updateCheckRef, NULL) != noErr)
243                return;  //We have failed
244    }
245        pthread_t thread;
246        pthread_create(&thread, NULL, launchUpdateChecker, updateCheckRef);
247}
248
249static void RecomputeMaxCounts(FFusionGlobals glob)
250{
251        int i;
252        unsigned begun = 0, decoded = 0, ended = 0, drawn = 0;
253       
254        for (i = 0; i < 4; i++) {
255                struct per_frame_decode_stats *f = &glob->stats.type[i];
256               
257                begun += f->begin_calls;
258                decoded += f->decode_calls;
259                drawn += f->draw_calls;
260                ended += f->end_calls;
261        }
262       
263        signed begin_diff = begun - ended, decode_diff = decoded - drawn;
264       
265        if (abs(begin_diff) > glob->stats.max_frames_begun) glob->stats.max_frames_begun = begin_diff;
266        if (abs(decode_diff) > glob->stats.max_frames_decoded) glob->stats.max_frames_decoded = decode_diff;
267}
268
269static void DumpFrameDropStats(FFusionGlobals glob)
270{
271        static const char types[4] = {'?', 'I', 'P', 'B'};
272        int i;
273       
274        if (!glob->fileLog || glob->decode.lastFrame == 0) return;
275       
276        Codecprintf(glob->fileLog, "%p frame drop stats\nType\t| BeginBand\t| DecodeBand\t| DrawBand\t| dropped before decode\t| dropped before draw\n", glob);
277       
278        for (i = 0; i < 4; i++) {
279                struct per_frame_decode_stats *f = &glob->stats.type[i];
280                               
281                Codecprintf(glob->fileLog, "%c\t| %d\t\t| %d\t\t| %d\t\t| %d/%f%%\t\t| %d/%f%%\n", types[i], f->begin_calls, f->decode_calls, f->draw_calls,
282                                        f->begin_calls - f->decode_calls,(f->begin_calls > f->decode_calls) ? ((float)(f->begin_calls - f->decode_calls)/(float)f->begin_calls) * 100. : 0.,
283                                        f->decode_calls - f->draw_calls,(f->decode_calls > f->draw_calls) ? ((float)(f->decode_calls - f->draw_calls)/(float)f->decode_calls) * 100. : 0.);
284        }
285}
286
287static enum PixelFormat FindPixFmtFromVideo(AVCodec *codec, AVCodecContext *avctx, Ptr data, int bufferSize)
288{
289    AVCodecContext tmpContext;
290    AVFrame tmpFrame;
291    int got_picture;
292    enum PixelFormat pix_fmt;
293   
294    avcodec_get_context_defaults2(&tmpContext, CODEC_TYPE_VIDEO);
295    tmpContext.width = avctx->width;
296    tmpContext.height = avctx->height;
297    tmpContext.codec_tag = avctx->codec_tag;
298   
299    avcodec_open(&tmpContext, codec);
300    avcodec_decode_video(&tmpContext, &tmpFrame, &got_picture, (UInt8*)data, bufferSize);
301    pix_fmt = tmpContext.pix_fmt;
302    avcodec_close(&tmpContext);
303   
304    return pix_fmt;
305}
306
307//---------------------------------------------------------------------------
308// Component Routines
309//---------------------------------------------------------------------------
310
311// -- This Image Decompressor Use the Base Image Decompressor Component --
312//      The base image decompressor is an Apple-supplied component
313//      that makes it easier for developers to create new decompressors.
314//      The base image decompressor does most of the housekeeping and
315//      interface functions required for a QuickTime decompressor component,
316//      including scheduling for asynchronous decompression.
317
318//-----------------------------------------------------------------
319// Component Open Request - Required
320//-----------------------------------------------------------------
321
322pascal ComponentResult FFusionCodecOpen(FFusionGlobals glob, ComponentInstance self)
323{
324    ComponentResult err;
325    ComponentDescription descout;
326    ComponentDescription cd;
327    Component c = 0;
328    long bitfield;
329       
330    cd.componentType = 'imdc';
331    cd.componentSubType = 'y420';
332    cd.componentManufacturer = 0;
333    cd.componentFlags = 0;
334    cd.componentFlagsMask = 0;
335   
336    GetComponentInfo((Component)self, &descout, 0, 0, 0);
337       
338  //  FourCCprintf("Opening component for type ", descout.componentSubType);
339    // Allocate memory for our globals, set them up and inform the component manager that we've done so
340       
341    glob = (FFusionGlobals)NewPtrClear(sizeof(FFusionGlobalsRecord));
342   
343    if (err = MemError())
344    {
345        Codecprintf(NULL, "Unable to allocate globals! Exiting.\n");           
346    }
347    else
348    {
349                CFStringRef pathToLogFile = CFPreferencesCopyAppValue(CFSTR("DebugLogFile"), PERIAN_PREF_DOMAIN);
350                if(pathToLogFile && CFGetTypeID(pathToLogFile) != CFStringGetTypeID())
351                        pathToLogFile = NULL;
352                char path[PATH_MAX];
353        SetComponentInstanceStorage(self, (Handle)glob);
354
355        glob->self = self;
356        glob->target = self;
357        glob->drawBandUPP = NULL;
358        glob->pixelTypes = NewHandle(10 * sizeof(OSType));
359        glob->avCodec = 0;
360        glob->hasy420 = 0;
361        glob->componentType = descout.componentSubType;
362                glob->packedType = PACKED_ALL_IN_FIRST_FRAME;  //Unless we have reason to believe otherwise.
363                glob->data.frames = NULL;
364                glob->begin.parser = NULL;
365                if (pathToLogFile) {
366                        CFStringGetCString(pathToLogFile, path, PATH_MAX, kCFStringEncodingUTF8);
367                        CFRelease(pathToLogFile);
368                        glob->fileLog = fopen(path, "a");
369                }
370                glob->shouldUseReturnedFrame = 0;
371
372//        c = FindNextComponent(c, &cd);
373               
374        if (c != 0)
375        {           
376            Gestalt(gestaltSystemVersion, &bitfield);
377           
378            if (bitfield >= 0x1010)
379            {
380  //              Codecprintf(glob->fileLog, "Use speedy y420 component\n");
381                glob->hasy420 = 1;
382            }
383        }
384        else
385        {
386  //          Codecprintf(glob->fileLog, "Use slow y420 component\n");
387        }
388               
389        // Open and target an instance of the base decompressor as we delegate
390        // most of our calls to the base decompressor instance
391       
392        err = OpenADefaultComponent(decompressorComponentType, kBaseCodecType, &glob->delegateComponent);
393        if (!err)
394        {
395            ComponentSetTarget(glob->delegateComponent, self);
396        }
397        else
398        {
399            Codecprintf(glob->fileLog, "Error opening the base image decompressor! Exiting.\n");
400        }
401               
402                // we allocate some space for copying the frame data since we need some padding at the end
403                // for ffmpeg's optimized bitstream readers. Size doesn't really matter, it'll grow if need be
404                FFusionDataSetup(&(glob->data), 256, 1024*1024);
405        FFusionRunUpdateCheck();
406    }
407   
408    FFusionDebugPrint("%p opened for '%s'\n", glob, FourCCString(glob->componentType));
409    return err;
410}
411
412//-----------------------------------------------------------------
413// Component Close Request - Required
414//-----------------------------------------------------------------
415
416pascal ComponentResult FFusionCodecClose(FFusionGlobals glob, ComponentInstance self)
417{
418    FFusionDebugPrint("%p closed.\n", glob);
419        DumpFrameDropStats(glob);
420
421    // Make sure to close the base component and deallocate our storage
422    if (glob) 
423    {
424        if (glob->delegateComponent) 
425        {
426            CloseComponent(glob->delegateComponent);
427        }
428       
429        if (glob->drawBandUPP) 
430        {
431            DisposeImageCodecMPDrawBandUPP(glob->drawBandUPP);
432        }
433                               
434        if (glob->avContext)
435        {
436                        if (glob->avContext->extradata)
437                                free(glob->avContext->extradata);
438                                               
439                        if (glob->avContext->codec) avcodec_close(glob->avContext);
440            av_free(glob->avContext);
441        }
442               
443                if (glob->begin.parser)
444                {
445                        freeFFusionParser(glob->begin.parser);
446                }
447               
448                if (glob->pixelTypes)
449                {
450                        DisposeHandle(glob->pixelTypes);
451                }
452               
453                FFusionDataFree(&(glob->data));
454       
455                if(glob->fileLog)
456                        fclose(glob->fileLog);
457               
458        memset(glob, 0, sizeof(FFusionGlobalsRecord));
459        DisposePtr((Ptr)glob);
460    }
461       
462    return noErr;
463}
464
465//-----------------------------------------------------------------
466// Component Version Request - Required
467//-----------------------------------------------------------------
468
469pascal ComponentResult FFusionCodecVersion(FFusionGlobals glob)
470{
471    return kFFusionCodecVersion;
472}
473
474//-----------------------------------------------------------------
475// Component Target Request
476//-----------------------------------------------------------------
477// Allows another component to "target" you i.e., you call
478// another component whenever you would call yourself (as a result
479// of your component being used by another component)
480//-----------------------------------------------------------------
481
482pascal ComponentResult FFusionCodecTarget(FFusionGlobals glob, ComponentInstance target)
483{
484    glob->target = target;
485       
486    return noErr;
487}
488
489//-----------------------------------------------------------------
490// Component GetMPWorkFunction Request
491//-----------------------------------------------------------------
492// Allows your image decompressor component to perform asynchronous
493// decompression in a single MP task by taking advantage of the
494// Base Decompressor. If you implement this selector, your DrawBand
495// function must be MP-safe. MP safety means not calling routines
496// that may move or purge memory and not calling any routines which
497// might cause 68K code to be executed. Ideally, your DrawBand
498// function should not make any API calls whatsoever. Obviously
499// don't implement this if you're building a 68k component.
500//-----------------------------------------------------------------
501
502pascal ComponentResult FFusionCodecGetMPWorkFunction(FFusionGlobals glob, ComponentMPWorkFunctionUPP *workFunction, void **refCon)
503{
504        if (glob->drawBandUPP == NULL)
505                glob->drawBandUPP = NewImageCodecMPDrawBandUPP((ImageCodecMPDrawBandProcPtr)FFusionCodecDrawBand);
506       
507        return ImageCodecGetBaseMPWorkFunction(glob->delegateComponent, workFunction, refCon, glob->drawBandUPP, glob);
508}
509
510//-----------------------------------------------------------------
511// ImageCodecInitialize
512//-----------------------------------------------------------------
513// The first function call that your image decompressor component
514// receives from the base image decompressor is always a call to
515// ImageCodecInitialize . In response to this call, your image
516// decompressor component returns an ImageSubCodecDecompressCapabilities
517// structure that specifies its capabilities.
518//-----------------------------------------------------------------
519
520pascal ComponentResult FFusionCodecInitialize(FFusionGlobals glob, ImageSubCodecDecompressCapabilities *cap)
521{
522        Boolean doExperimentalFlags = CFPreferencesGetAppBooleanValue(CFSTR("ExperimentalQTFlags"), PERIAN_PREF_DOMAIN, NULL);
523       
524    // Secifies the size of the ImageSubCodecDecompressRecord structure
525    // and say we can support asyncronous decompression
526    // With the help of the base image decompressor, any image decompressor
527    // that uses only interrupt-safe calls for decompression operations can
528    // support asynchronous decompression.
529       
530    cap->decompressRecordSize = sizeof(FFusionDecompressRecord) + 12;
531    cap->canAsync = true;
532       
533        // QT 7
534        if(cap->recordSize > offsetof(ImageSubCodecDecompressCapabilities, baseCodecShouldCallDecodeBandForAllFrames))
535        {
536                cap->subCodecIsMultiBufferAware = true;
537                cap->subCodecSupportsOutOfOrderDisplayTimes = true;
538                cap->baseCodecShouldCallDecodeBandForAllFrames = true;
539                cap->subCodecSupportsScheduledBackwardsPlaybackWithDifferenceFrames = !doExperimentalFlags;
540                cap->subCodecSupportsDrawInDecodeOrder = doExperimentalFlags; 
541                cap->subCodecSupportsDecodeSmoothing = true; 
542        }
543       
544    return noErr;
545}
546
547static inline int shouldDecode(FFusionGlobals glob, enum CodecID codecID)
548{
549        FFusionDecodeAbilities decode = FFUSION_PREFER_DECODE;
550        if (glob->componentType == 'avc1')
551                decode = ffusionIsParsedVideoDecodable(glob->begin.parser);
552        if(decode > FFUSION_CANNOT_DECODE && 
553           (codecID == CODEC_ID_H264 || codecID == CODEC_ID_MPEG4) && CFPreferencesGetAppBooleanValue(CFSTR("PreferAppleCodecs"), PERIAN_PREF_DOMAIN, NULL))
554                decode = FFUSION_PREFER_NOT_DECODE;
555        if(decode > FFUSION_CANNOT_DECODE)
556                if(forcePerianToDecode())
557                        decode = FFUSION_PREFER_DECODE;
558        return decode > FFUSION_PREFER_NOT_DECODE;
559}
560
561//-----------------------------------------------------------------
562// ImageCodecPreflight
563//-----------------------------------------------------------------
564// The base image decompressor gets additional information about the
565// capabilities of your image decompressor component by calling
566// ImageCodecPreflight. The base image decompressor uses this
567// information when responding to a call to the ImageCodecPredecompress
568// function, which the ICM makes before decompressing an image. You
569// are required only to provide values for the wantedDestinationPixelSize
570// and wantedDestinationPixelTypes fields and can also modify other
571// fields if necessary.
572//-----------------------------------------------------------------
573
574pascal ComponentResult FFusionCodecPreflight(FFusionGlobals glob, CodecDecompressParams *p)
575{
576    OSType *pos;
577    int index;
578    CodecCapabilities *capabilities = p->capabilities;
579        long count = 0;
580        Handle imgDescExt;
581        OSErr err = noErr;
582       
583    // We first open libavcodec library and the codec corresponding
584    // to the fourCC if it has not been done before
585   
586        FFusionDebugPrint("%p Preflight called.\n", glob);
587        FFusionDebugPrint("%p Frame dropping is %senabled\n", glob, not(IsFrameDroppingEnabled()));
588       
589    if (!glob->avCodec)
590    {
591                enum CodecID codecID = CODEC_ID_MPEG4;
592               
593                init_FFmpeg();
594                initFFusionParsers();
595               
596        switch (glob->componentType)
597        {
598            case 'MPG4':        // MS-MPEG4 v1
599            case 'mpg4':
600            case 'DIV1':
601            case 'div1':
602                codecID = CODEC_ID_MSMPEG4V1;
603                                break;
604                               
605            case 'MP42':        // MS-MPEG4 v2
606            case 'mp42':
607            case 'DIV2':
608            case 'div2':
609                codecID = CODEC_ID_MSMPEG4V2;
610                                break;
611                               
612            case 'div6':        // DivX 3
613            case 'DIV6':
614            case 'div5':
615            case 'DIV5':
616            case 'div4':
617            case 'DIV4':
618            case 'div3':
619            case 'DIV3':
620            case 'MP43':
621            case 'mp43':
622            case 'MPG3':
623            case 'mpg3':
624            case 'AP41':
625            case 'COL0':
626            case 'col0':
627            case 'COL1':
628            case 'col1':
629            case '3IVD':        // 3ivx
630            case '3ivd':
631                codecID = CODEC_ID_MSMPEG4V3;
632                                break;
633                               
634                        case 'mp4v':    // MPEG4 part 2 in mov/mp4
635                                glob->packedType = PACKED_QUICKTIME_KNOWS_ORDER;
636            case 'divx':        // DivX 4
637            case 'DIVX':
638            case 'mp4s':
639            case 'MP4S':
640            case 'm4s2':
641            case 'M4S2':
642            case 0x04000000:
643            case 'UMP4':
644            case 'DX50':        // DivX 5
645            case 'XVID':        // XVID
646            case 'xvid':
647            case 'XviD':
648            case 'XVIX':
649            case 'BLZ0':
650            case '3IV2':        // 3ivx
651            case '3iv2':
652                        case 'RMP4':    // Miscellaneous
653                        case 'SEDG':
654                        case 'WV1F':
655                        case 'FMP4':
656                        case 'SMP4':
657                codecID = CODEC_ID_MPEG4;
658                                break;
659
660                        case 'avc1':    // H.264 in mov/mp4/mkv
661                                glob->packedType = PACKED_QUICKTIME_KNOWS_ORDER;
662                        case 'H264':    // H.264 in AVI
663                        case 'h264':
664                        case 'X264':
665                        case 'x264':
666                        case 'AVC1':
667                        case 'DAVC':
668                        case 'VSSH':
669                                codecID = CODEC_ID_H264;
670                                break;
671
672                        case 'FLV1':
673                                codecID = CODEC_ID_FLV1;
674                                break;
675
676                        case 'FSV1':
677                                codecID = CODEC_ID_FLASHSV;
678                                break;
679
680                        case 'VP60':
681                        case 'VP61':
682                        case 'VP62':
683                                codecID = CODEC_ID_VP6;
684                                break;
685
686                        case 'VP6F':
687                        case 'FLV4':
688                                codecID = CODEC_ID_VP6F;
689                                break;
690
691                        case 'I263':
692                        case 'i263':
693                                codecID = CODEC_ID_H263I;
694                                break;
695
696                        case 'VP30':
697                        case 'VP31':
698                                glob->shouldUseReturnedFrame = TRUE;
699                                codecID = CODEC_ID_VP3;
700                                break;
701                               
702                        case 'HFYU':
703                                codecID = CODEC_ID_HUFFYUV;
704                                break;
705
706                        case 'FFVH':
707                                codecID = CODEC_ID_FFVHUFF;
708                                break;
709                               
710                        case 'MPEG':
711                        case 'mpg1':
712                        case 'mp1v':
713                                codecID = CODEC_ID_MPEG1VIDEO;
714                                break;
715                               
716                        case 'MPG2':
717                        case 'mpg2':
718                        case 'mp2v':
719                                codecID = CODEC_ID_MPEG2VIDEO;
720                                break;
721                               
722                        case 'FPS1':
723                                codecID = CODEC_ID_FRAPS;
724                                break;
725                               
726                        case 'SNOW':
727                                codecID = CODEC_ID_SNOW;
728                                break;
729
730            case 'RJPG':
731            case 'NUV1':
732                codecID = CODEC_ID_NUV;
733                break;
734                        case 'tscc':
735                                codecID = CODEC_ID_TSCC;
736                                break;
737                               
738                        case 'ZMBV':
739                                codecID = CODEC_ID_ZMBV;
740                                break;
741                               
742                        case 'VP6A':
743                                codecID = CODEC_ID_VP6A;
744                                break;
745                               
746            default:
747                                Codecprintf(glob->fileLog, "Warning! Unknown codec type! Using MPEG4 by default.\n");
748        }
749               
750                glob->avCodec = avcodec_find_decoder(codecID);
751//              if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER)
752                        glob->begin.parser = ffusionParserInit(codecID);
753               
754                if ((codecID == CODEC_ID_MPEG4 || codecID == CODEC_ID_H264) && !glob->begin.parser)
755                        Codecprintf(glob->fileLog, "This is a parseable format, but we couldn't open a parser!\n");
756               
757        // we do the same for the AVCodecContext since all context values are
758        // correctly initialized when calling the alloc function
759       
760        glob->avContext = avcodec_alloc_context();
761               
762                // Use low delay
763                glob->avContext->flags |= CODEC_FLAG_LOW_DELAY;
764               
765        // Image size is mandatory for DivX-like codecs
766       
767        glob->avContext->width = (**p->imageDescription).width;
768        glob->avContext->height = (**p->imageDescription).height;
769                glob->avContext->bits_per_coded_sample = (**p->imageDescription).depth;
770               
771        // We also pass the FourCC since it allows the H263 hybrid decoder
772        // to make the difference between the various flavours of DivX
773        glob->avContext->codec_tag = Endian32_Swap(glob->componentType);
774       
775                // avc1 requires the avcC extension
776                if (glob->componentType == 'avc1') {
777                        count = isImageDescriptionExtensionPresent(p->imageDescription, 'avcC');
778                       
779                        if (count >= 1) {
780                                imgDescExt = NewHandle(0);
781                                GetImageDescriptionExtension(p->imageDescription, &imgDescExt, 'avcC', 1);
782                               
783                                glob->avContext->extradata = calloc(1, GetHandleSize(imgDescExt) + FF_INPUT_BUFFER_PADDING_SIZE);
784                                memcpy(glob->avContext->extradata, *imgDescExt, GetHandleSize(imgDescExt));
785                                glob->avContext->extradata_size = GetHandleSize(imgDescExt);
786                               
787                                DisposeHandle(imgDescExt);
788                        } else {
789                                count = isImageDescriptionExtensionPresent(p->imageDescription, 'strf');
790                               
791                                // avc1 in AVI, need to reorder frames
792                                if (count >= 1)
793                                        glob->packedType = PACKED_ALL_IN_FIRST_FRAME;
794                        }
795                } else if (glob->componentType == 'mp4v') {
796                        count = isImageDescriptionExtensionPresent(p->imageDescription, 'esds');
797                       
798                        if (count >= 1) {
799                                imgDescExt = NewHandle(0);
800                                GetImageDescriptionExtension(p->imageDescription, &imgDescExt, 'esds', 1);
801                               
802                                ReadESDSDescExt(imgDescExt, &glob->avContext->extradata, &glob->avContext->extradata_size);
803                               
804                                DisposeHandle(imgDescExt);
805                        }
806                } else {
807                        count = isImageDescriptionExtensionPresent(p->imageDescription, 'strf');
808                       
809                        if (count >= 1) {
810                                imgDescExt = NewHandle(0);
811                                GetImageDescriptionExtension(p->imageDescription, &imgDescExt, 'strf', 1);
812                               
813                                if (GetHandleSize(imgDescExt) - 40 > 0) {
814                                        glob->avContext->extradata = calloc(1, GetHandleSize(imgDescExt) - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
815                                        memcpy(glob->avContext->extradata, *imgDescExt + 40, GetHandleSize(imgDescExt) - 40);
816                                        glob->avContext->extradata_size = GetHandleSize(imgDescExt) - 40;
817                                }
818                                DisposeHandle(imgDescExt);
819                        }
820                }
821               
822                FFusionDebugPrint("%p preflighted for %dx%d '%s'. (%d bytes of extradata)\n", glob, (**p->imageDescription).width, (**p->imageDescription).height, FourCCString(glob->componentType), glob->avContext->extradata_size);
823       
824                if(glob->avContext->extradata_size != 0 && glob->begin.parser != NULL)
825                        ffusionParseExtraData(glob->begin.parser, glob->avContext->extradata, glob->avContext->extradata_size);
826               
827                if (glob->fileLog)
828                        ffusionLogDebugInfo(glob->begin.parser, glob->fileLog);
829               
830                if (!shouldDecode(glob, codecID))
831                        err = featureUnsupported;
832               
833                // some hooks into ffmpeg's buffer allocation to get frames in
834                // decode order without delay more easily
835                glob->avContext->opaque = glob;
836                glob->avContext->get_buffer = FFusionGetBuffer;
837                glob->avContext->release_buffer = FFusionReleaseBuffer;
838               
839                // multi-slice decoding
840                SetupMultithreadedDecoding(glob->avContext, codecID);
841               
842                //fast flag
843                if (CFPreferencesGetAppBooleanValue(CFSTR("UseFastDecode"), PERIAN_PREF_DOMAIN, NULL))
844                        glob->avContext->flags2 |= CODEC_FLAG2_FAST;
845               
846        // Finally we open the avcodec
847       
848        if (avcodec_open(glob->avContext, glob->avCodec))
849        {
850            Codecprintf(glob->fileLog, "Error opening avcodec!\n");
851           
852                        err = paramErr;
853        }
854               
855        // this format doesn't have enough information in its headers
856                // we have to decode the first frame
857                if (glob->avContext->pix_fmt == PIX_FMT_NONE && p->bufferSize && p->data)
858            glob->avContext->pix_fmt = FindPixFmtFromVideo(glob->avCodec, glob->avContext, p->data, p->bufferSize);
859    }
860   
861    // Specify the minimum image band height supported by the component
862    // bandInc specifies a common factor of supported image band heights -
863    // if your component supports only image bands that are an even
864    // multiple of some number of pixels high report this common factor in bandInc
865   
866    capabilities->bandMin = (**p->imageDescription).height;
867    capabilities->bandInc = capabilities->bandMin;
868       
869    // libavcodec 0.4.x is no longer stream based i.e. you cannot pass just
870    // an arbitrary amount of data to the library.
871    // Instead we have to tell QT to just pass the data corresponding
872    // to one frame
873       
874    capabilities->flags |= codecWantsSpecialScaling;
875   
876    p->requestedBufferWidth = (**p->imageDescription).width;
877    p->requestedBufferHeight = (**p->imageDescription).height;
878   
879    // Indicate the pixel depth the component can use with the specified image
880    // normally should be capabilities->wantedPixelSize = (**p->imageDescription).depth;
881    // but we don't care since some DivX are so bugged that the depth information
882    // is not correct
883   
884    capabilities->wantedPixelSize = 0;
885   
886    // Type of pixels used in output
887    // If QuickTime got the y420 component it is cool
888    // since libavcodec ouputs y420
889    // If not we'll do some king of conversion to 2vuy
890   
891    HLock(glob->pixelTypes);
892    pos = *((OSType **)glob->pixelTypes);
893   
894    index = 0;
895       
896        if (!err) {
897        switch (glob->avContext->pix_fmt)
898        {
899                case PIX_FMT_BGR24:
900                        pos[index++] = k24RGBPixelFormat;
901                        break;
902                case PIX_FMT_RGB32:
903                        pos[index++] = k32ARGBPixelFormat;
904                        break;
905                case PIX_FMT_RGB24:
906                        pos[index++] = k24RGBPixelFormat;
907                        break;
908                case PIX_FMT_YUVA420P:
909                        pos[index++] = k4444YpCbCrA8PixelFormat;
910                        break;
911                case PIX_FMT_YUV420P:
912                default:
913                        if (glob->hasy420)
914                        {
915                                pos[index++] = 'y420';
916                        }
917                        else
918                        {
919                                pos[index++] = k2vuyPixelFormat;       
920                        }
921                        break;
922        }
923        }
924   
925    pos[index++] = 0;
926    HUnlock(glob->pixelTypes);
927       
928    p->wantedDestinationPixelTypes = (OSType **)glob->pixelTypes;
929   
930    // Specify the number of pixels the image must be extended in width and height if
931    // the component cannot accommodate the image at its given width and height
932    // It is not the case here
933   
934    capabilities->extendWidth = 0;
935    capabilities->extendHeight = 0;
936   
937        capabilities->flags |= codecCanAsync | codecCanAsyncWhen;
938       
939        FFusionDebugPrint("%p Preflight requesting colorspace '%s'. (error %d)\n", glob, FourCCString(pos[0]), err);
940       
941        Boolean keyExists = FALSE;
942        int loopFilterSkip = CFPreferencesGetAppIntegerValue(CFSTR("SkipLoopFilter"), PERIAN_PREF_DOMAIN, &keyExists);
943        if(keyExists)
944        {
945                enum AVDiscard loopFilterValue = AVDISCARD_DEFAULT;
946                switch (loopFilterSkip) {
947                        case 1:
948                                loopFilterValue = AVDISCARD_NONREF;
949                                break;
950                        case 2:
951                                loopFilterValue = AVDISCARD_BIDIR;
952                                break;
953                        case 3:
954                                loopFilterValue = AVDISCARD_NONKEY;
955                                break;
956                        case 4:
957                                loopFilterValue = AVDISCARD_ALL;
958                                break;
959                        default:
960                                break;
961                }
962                glob->avContext->skip_loop_filter = loopFilterValue;
963                FFusionDebugPrint("%p Preflight set skip loop filter to %d", glob, loopFilterValue);
964        }
965       
966    return err;
967}
968
969static int qtTypeForFrameInfo(int original, int fftype, int skippable)
970{
971        if(fftype == FF_I_TYPE)
972        {
973                if(!skippable)
974                        return kCodecFrameTypeKey;
975        }
976        else if(skippable && IsFrameDroppingEnabled())
977                return kCodecFrameTypeDroppableDifference;
978        else if(fftype != 0)
979                return kCodecFrameTypeDifference;       
980        return original;
981}
982
983//-----------------------------------------------------------------
984// ImageCodecBeginBand
985//-----------------------------------------------------------------
986// The ImageCodecBeginBand function allows your image decompressor
987// component to save information about a band before decompressing
988// it. This function is never called at interrupt time. The base
989// image decompressor preserves any changes your component makes to
990// any of the fields in the ImageSubCodecDecompressRecord or
991// CodecDecompressParams structures. If your component supports
992// asynchronous scheduled decompression, it may receive more than
993// one ImageCodecBeginBand call before receiving an ImageCodecDrawBand
994// call.
995//-----------------------------------------------------------------
996
997pascal ComponentResult FFusionCodecBeginBand(FFusionGlobals glob, CodecDecompressParams *p, ImageSubCodecDecompressRecord *drp, long flags)
998{       
999    long offsetH, offsetV;
1000    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1001        int redisplayFirstFrame = 0;
1002        int type = 0;
1003        int skippable = 0;
1004       
1005    //////
1006  /*  IBNibRef          nibRef;
1007    WindowRef           window;
1008    OSStatus            err;
1009    CFBundleRef         bundleRef;
1010    EventHandlerUPP     handlerUPP, handlerUPP2;
1011    EventTypeSpec       eventType;
1012    ControlID           controlID;
1013    ControlRef          theControl;
1014    KeyMap              currentKeyMap;
1015    int                 userPreference; */
1016    ///////
1017       
1018    offsetH = (long)(p->dstRect.left - p->dstPixMap.bounds.left) * (long)(p->dstPixMap.pixelSize >> 3);
1019    offsetV = (long)(p->dstRect.top - p->dstPixMap.bounds.top) * (long)drp->rowBytes;
1020   
1021    myDrp->width = (**p->imageDescription).width;
1022    myDrp->height = (**p->imageDescription).height;
1023    myDrp->depth = (**p->imageDescription).depth;
1024       
1025    myDrp->pixelFormat = p->dstPixMap.pixelFormat;
1026        myDrp->decoded = p->frameTime ? (0 != (p->frameTime->flags & icmFrameAlreadyDecoded)) : false;
1027        myDrp->frameData = NULL;
1028        myDrp->buffer = NULL;
1029       
1030        FFusionDebugPrint("%p BeginBand #%d. (%sdecoded, packed %d)\n", glob, p->frameNumber, not(myDrp->decoded), glob->packedType);
1031       
1032        if (!glob->avContext) {
1033                fprintf(stderr, "Perian Codec: QT tried to call BeginBand without preflighting!\n");
1034                return internalComponentErr;
1035        }
1036       
1037        if(myDrp->decoded)
1038        {
1039                int i;
1040                myDrp->frameNumber = p->frameNumber;
1041                for (i = 0; i < FFUSION_MAX_BUFFERS; i++) {
1042                        if (glob->buffers[i].retainCount && glob->buffers[i].frameNumber == myDrp->frameNumber) {
1043                                myDrp->buffer = retainBuffer(glob, &glob->buffers[i]);
1044                                break;
1045                        }
1046                }
1047                return noErr;
1048        }
1049       
1050        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && p->frameNumber != glob->begin.lastFrame + 1)
1051        {
1052                if(glob->decode.lastFrame < p->frameNumber && p->frameNumber < glob->begin.lastFrame + 1)
1053                {
1054                        /* We already began this sucker, but haven't decoded it yet, find the data */
1055                        FrameData *frameData = NULL;
1056                        frameData = FFusionDataFind(&glob->data, p->frameNumber);
1057                        if(frameData != NULL)
1058                        {
1059                                myDrp->frameData = frameData;
1060                                drp->frameType = qtTypeForFrameInfo(drp->frameType, myDrp->frameData->type, myDrp->frameData->skippabble);
1061                                myDrp->frameNumber = p->frameNumber;
1062                                myDrp->GOPStartFrameNumber = glob->begin.lastIFrame;
1063                                return noErr;
1064                        }
1065                }
1066                else
1067                {
1068                        /* Reset context, safe marking in such a case */
1069                        glob->begin.lastFrameType = FF_I_TYPE;
1070                        FFusionDataReadUnparsed(&(glob->data));
1071                        glob->begin.lastPFrameData = NULL;
1072                        redisplayFirstFrame = 1;
1073                }
1074        }
1075       
1076        if(glob->begin.parser != NULL)
1077        {
1078                int parsedBufSize;
1079                uint8_t *buffer = (uint8_t *)drp->codecData;
1080                int bufferSize = p->bufferSize;
1081               
1082                if(glob->data.unparsedFrames.dataSize != 0)
1083                {
1084                        buffer = glob->data.unparsedFrames.buffer;
1085                        bufferSize = glob->data.unparsedFrames.dataSize;
1086                }
1087               
1088                if(ffusionParse(glob->begin.parser, buffer, bufferSize, &parsedBufSize, &type, &skippable) == 0)
1089                {
1090                        /* parse failed */
1091                        myDrp->bufferSize = bufferSize;
1092                        if(glob->begin.futureType != 0)
1093                        {
1094                                /* Assume our previously decoded P frame */
1095                                type = glob->begin.futureType;
1096                                glob->begin.futureType = 0;
1097                                myDrp->frameData = glob->begin.lastPFrameData;
1098                        }
1099                        else
1100                        {
1101                                Codecprintf(glob->fileLog, "parse failed frame %d with size %d\n", p->frameNumber, bufferSize);
1102                                if(glob->data.unparsedFrames.dataSize != 0)
1103                                        Codecprintf(glob->fileLog, ", parser had extra data\n");                               
1104                        }
1105                }
1106                else if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER)
1107                {
1108                        if(type == FF_B_TYPE && glob->packedType == PACKED_ALL_IN_FIRST_FRAME && glob->begin.futureType == 0)
1109                                /* Badly framed.  We hit a B frame after it was supposed to be displayed, switch to delaying by a frame */
1110                                glob->packedType = PACKED_DELAY_BY_ONE_FRAME;
1111                        else if(glob->packedType == PACKED_DELAY_BY_ONE_FRAME && parsedBufSize < bufferSize - 16)
1112                                /* Seems to be switching back to packed in one frame; switch back*/
1113                                glob->packedType = PACKED_ALL_IN_FIRST_FRAME;
1114                       
1115                        myDrp->frameData = FFusionDataAppend(&(glob->data), buffer, parsedBufSize, type);
1116                        if(type != FF_I_TYPE)
1117                                myDrp->frameData->prereqFrame = glob->begin.lastPFrameData;
1118                        if(glob->packedType == PACKED_DELAY_BY_ONE_FRAME)
1119                        {
1120                                if(type != FF_B_TYPE)
1121                                {
1122                                        FrameData *nextPFrame = myDrp->frameData;
1123                                        FrameData *lastPFrame = glob->begin.lastPFrameData;
1124                                        if(lastPFrame != NULL)
1125                                                /* Mark the next P or I frame, predictive decoding */
1126                                                lastPFrame->nextFrame = nextPFrame;
1127                                        myDrp->frameData = lastPFrame;
1128                                        glob->begin.lastPFrameData = nextPFrame;
1129
1130                                        if(redisplayFirstFrame)
1131                                                myDrp->frameData = nextPFrame;
1132                                }
1133                               
1134                                int displayType = glob->begin.lastFrameType;
1135                                glob->begin.lastFrameType = type;
1136                                type = displayType;
1137                        }
1138                        else if(type != FF_B_TYPE)
1139                                glob->begin.lastPFrameData = myDrp->frameData;
1140
1141                        if(type == FF_I_TYPE && glob->packedType == PACKED_ALL_IN_FIRST_FRAME)
1142                                /* Wipe memory of past P frames */
1143                                glob->begin.futureType = 0;
1144                       
1145                        if(parsedBufSize < p->bufferSize)
1146                        {
1147                                int oldType = type;
1148                               
1149                                buffer += parsedBufSize;
1150                                bufferSize -= parsedBufSize;
1151                                int success = ffusionParse(glob->begin.parser, buffer, bufferSize, &parsedBufSize, &type, &skippable);
1152                                if(success && type == FF_B_TYPE)
1153                                {
1154                                        /* A B frame follows us, so setup the P frame for the future and set dependencies */
1155                                        glob->begin.futureType = oldType;
1156                                        if(glob->begin.lastPFrameData != NULL)
1157                                                /* Mark the next P or I frame, predictive decoding */
1158                                                glob->begin.lastPFrameData->nextFrame = myDrp->frameData;
1159                                        glob->begin.lastPFrameData = myDrp->frameData;
1160                                        myDrp->frameData = FFusionDataAppend(&(glob->data), buffer, parsedBufSize, type);
1161                                        myDrp->frameData->prereqFrame = glob->begin.lastPFrameData;
1162                                        buffer += parsedBufSize;
1163                                        bufferSize -= parsedBufSize;
1164                                }
1165                                if(bufferSize > 0)
1166                                        FFusionDataSetUnparsed(&(glob->data), buffer, bufferSize);
1167                                else
1168                                        FFusionDataReadUnparsed(&(glob->data));
1169                        }
1170                        else
1171                                FFusionDataReadUnparsed(&(glob->data));
1172                        myDrp->bufferSize = 0;
1173                }
1174                else
1175                {
1176                        myDrp->bufferSize = bufferSize;
1177                }
1178               
1179                drp->frameType = qtTypeForFrameInfo(drp->frameType, type, skippable);
1180                if(myDrp->frameData != NULL)
1181                {
1182                        myDrp->frameData->frameNumber = p->frameNumber;
1183                        myDrp->frameData->skippabble = skippable;
1184                }
1185        }
1186        else
1187                myDrp->bufferSize = p->bufferSize;
1188        glob->begin.lastFrame = p->frameNumber;
1189        if(drp->frameType == kCodecFrameTypeKey)
1190                glob->begin.lastIFrame = p->frameNumber;
1191        myDrp->frameNumber = p->frameNumber;
1192        myDrp->GOPStartFrameNumber = glob->begin.lastIFrame;
1193       
1194        glob->stats.type[drp->frameType].begin_calls++;
1195        RecomputeMaxCounts(glob);
1196        FFusionDebugPrint("%p BeginBand: frame #%d type %d. (%sskippable)\n", glob, myDrp->frameNumber, type, not(skippable));
1197       
1198    return noErr;
1199}
1200
1201static OSErr PrereqDecompress(FFusionGlobals glob, FrameData *prereq, AVCodecContext *context, ICMDataProcRecordPtr dataProc, long width, long height, AVFrame *picture)
1202{
1203        FFusionDebugPrint("%p prereq-decompressing frame #%d.\n", glob, prereq->frameNumber);
1204       
1205        FrameData *preprereq = FrameDataCheckPrereq(prereq);
1206        if(preprereq)
1207                PrereqDecompress(glob, preprereq, context, dataProc, width, height, picture);
1208       
1209        unsigned char *dataPtr = (unsigned char *)prereq->buffer;
1210        int dataSize = prereq->dataSize;
1211       
1212        OSErr err = FFusionDecompress(glob, context, dataPtr, dataProc, width, height, picture, dataSize);
1213       
1214        return err;
1215}
1216
1217pascal ComponentResult FFusionCodecDecodeBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, unsigned long flags)
1218{
1219        OSErr err = noErr;
1220        AVFrame tempFrame;
1221
1222    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1223       
1224        glob->stats.type[drp->frameType].decode_calls++;
1225        RecomputeMaxCounts(glob);
1226        FFusionDebugPrint("%p DecodeBand #%d qtType %d. (packed %d)\n", glob, myDrp->frameNumber, drp->frameType, glob->packedType);
1227
1228        avcodec_get_frame_defaults(&tempFrame);
1229       
1230        // QuickTime will drop H.264 frames when necessary if a sample dependency table exists
1231        // we don't want to flush buffers in that case.
1232        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && myDrp->frameNumber != glob->decode.lastFrame + 1)
1233        {
1234                /* Skipped some frames in here */
1235                FFusionDebugPrint("%p - frames skipped.\n", glob);
1236                if(drp->frameType == kCodecFrameTypeKey || myDrp->GOPStartFrameNumber > glob->decode.lastFrame || myDrp->frameNumber < glob->decode.lastFrame)
1237                {
1238                        /* If this is a key frame or the P frame before us is after the last frame (skip ahead), or we are before the last decoded frame (skip back) *
1239                         * then we are in a whole new GOP */
1240                        avcodec_flush_buffers(glob->avContext);
1241                }
1242        }
1243       
1244        if(myDrp->frameData && myDrp->frameData->decoded && glob->decode.futureBuffer != NULL)
1245        {
1246                myDrp->buffer = retainBuffer(glob, glob->decode.futureBuffer);
1247                myDrp->decoded = true;
1248#if 0   /* Need to make sure this frame's data is not eradicated during the decompress */
1249                FrameData *nextFrame = myDrp->frameData->nextFrame;
1250                if(nextFrame != NULL)
1251                {
1252                        FFusionDecompress(glob, glob->avContext, nextFrame->buffer, NULL, myDrp->width, myDrp->height, &tempFrame, nextFrame->dataSize);
1253                        if(tempFrame.data[0] != NULL)
1254                        {
1255                                glob->decode.futureBuffer = (FFusionBuffer *)tempFrame.opaque;
1256                                nextFrame->decoded = TRUE;
1257                        }
1258                }
1259                else
1260#endif
1261                        glob->decode.futureBuffer = NULL;
1262                FFusionDataMarkRead(myDrp->frameData);
1263                glob->decode.lastFrame = myDrp->frameNumber;
1264                return err;
1265        }
1266                       
1267        FrameData *frameData = NULL;
1268        unsigned char *dataPtr = NULL;
1269        unsigned int dataSize;
1270        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && myDrp->frameData != NULL && myDrp->frameData->decoded == 0)
1271        {
1272                /* Pull from our buffer */
1273                frameData = myDrp->frameData;
1274                FrameData *prereq = FrameDataCheckPrereq(frameData);
1275               
1276                if(prereq)
1277                {
1278                        err = PrereqDecompress(glob, prereq, glob->avContext, NULL, myDrp->width, myDrp->height, &tempFrame);
1279                        if(tempFrame.data[0] != NULL)
1280                        {
1281                                glob->decode.futureBuffer = (FFusionBuffer *)tempFrame.opaque;
1282                                prereq->decoded = TRUE;
1283                        }
1284                }
1285                dataPtr = (unsigned char *)frameData->buffer;
1286                dataSize = frameData->dataSize;
1287                frameData->decoded = TRUE;
1288        }
1289        else
1290        {
1291                /* data is already set up properly for us */
1292                dataSize = myDrp->bufferSize;
1293                dataPtr = FFusionCreateEntireDataBuffer(&(glob->data), (uint8_t *)drp->codecData, dataSize);
1294        }
1295        ICMDataProcRecordPtr dataProc = drp->dataProcRecord.dataProc ? &drp->dataProcRecord : NULL;
1296               
1297        avcodec_get_frame_defaults(&tempFrame);
1298        err = FFusionDecompress(glob, glob->avContext, dataPtr, dataProc, myDrp->width, myDrp->height, &tempFrame, dataSize);
1299                       
1300        if (glob->packedType == PACKED_QUICKTIME_KNOWS_ORDER) {
1301                myDrp->buffer = &glob->buffers[glob->lastAllocatedBuffer];
1302                myDrp->buffer->frameNumber = myDrp->frameNumber;
1303                retainBuffer(glob, myDrp->buffer);
1304                myDrp->buffer->returnedFrame = tempFrame;
1305                myDrp->decoded = true;
1306                glob->decode.lastFrame = myDrp->frameNumber;
1307                return err;
1308        }
1309        if(tempFrame.data[0] == NULL)
1310                myDrp->buffer = NULL;
1311        else
1312                myDrp->buffer = retainBuffer(glob, (FFusionBuffer *)tempFrame.opaque);
1313       
1314        if(tempFrame.pict_type == FF_I_TYPE)
1315                /* Wipe memory of past P frames */
1316                glob->decode.futureBuffer = NULL;
1317        glob->decode.lastFrame = myDrp->frameNumber;
1318        myDrp->decoded = true;
1319        if (myDrp->buffer) myDrp->buffer->returnedFrame = tempFrame;
1320       
1321        FFusionDataMarkRead(frameData);
1322       
1323        return err;
1324}
1325
1326//-----------------------------------------------------------------
1327// ImageCodecDrawBand
1328//-----------------------------------------------------------------
1329// The base image decompressor calls your image decompressor
1330// component's ImageCodecDrawBand function to decompress a band or
1331// frame. Your component must implement this function. If the
1332// ImageSubCodecDecompressRecord structure specifies a progress function
1333// or data-loading function, the base image decompressor will never call
1334// ImageCodecDrawBand at interrupt time. If the ImageSubCodecDecompressRecord
1335// structure specifies a progress function, the base image decompressor
1336// handles codecProgressOpen and codecProgressClose calls, and your image
1337// decompressor component must not implement these functions.
1338// If not, the base image decompressor may call the ImageCodecDrawBand
1339// function at interrupt time. When the base image decompressor calls your
1340// ImageCodecDrawBand function, your component must perform the decompression
1341// specified by the fields of the ImageSubCodecDecompressRecord structure.
1342// The structure includes any changes your component made to it when
1343// performing the ImageCodecBeginBand function. If your component supports
1344// asynchronous scheduled decompression, it may receive more than one
1345// ImageCodecBeginBand call before receiving an ImageCodecDrawBand call.
1346//-----------------------------------------------------------------
1347
1348pascal ComponentResult FFusionCodecDrawBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp)
1349{
1350    OSErr err = noErr;
1351    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1352        AVFrame *picture;
1353       
1354        glob->stats.type[drp->frameType].draw_calls++;
1355        RecomputeMaxCounts(glob);
1356        FFusionDebugPrint("%p DrawBand #%d. (%sdecoded)\n", glob, myDrp->frameNumber, not(myDrp->decoded));
1357       
1358        if(!myDrp->decoded) {
1359                err = FFusionCodecDecodeBand(glob, drp, 0);
1360
1361                if (err) goto err;
1362        }
1363       
1364        if (myDrp->buffer)
1365        {
1366                picture = myDrp->buffer->frame;
1367        }
1368        else
1369                picture = &glob->lastDisplayedFrame;
1370       
1371        if(!picture || picture->data[0] == 0)
1372        {
1373                if(glob->shouldUseReturnedFrame && myDrp->buffer->returnedFrame.data[0])
1374                        //Some decoders (vp3) keep their internal buffers in an unusable state
1375                        picture = &myDrp->buffer->returnedFrame;
1376                else if(glob->lastDisplayedFrame.data[0] != NULL)
1377                        //Display last frame
1378                        picture = &glob->lastDisplayedFrame;
1379                else {
1380                        //Display black (no frame decoded yet)
1381
1382                        if (!glob->colorConv.clear) {
1383                                err = ColorConversionFindFor(&glob->colorConv, glob->avContext->pix_fmt, NULL, myDrp->pixelFormat);
1384                               
1385                                if (err) goto err;
1386                        }
1387                       
1388                        glob->colorConv.clear((UInt8*)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height);
1389                        return noErr;
1390                }
1391        }
1392        else
1393        {
1394                if (myDrp->buffer)
1395                        glob->lastDisplayedFrame = *picture;
1396        }
1397       
1398        if (!glob->colorConv.convert) {
1399                err = ColorConversionFindFor(&glob->colorConv, glob->avContext->pix_fmt, picture, myDrp->pixelFormat);
1400               
1401                if (err) {
1402                        Codecprintf(glob->fileLog, "Unsupported conversion from pixel format %d to %s (%08x) buffer\n",
1403                                                glob->avContext->pix_fmt, FourCCString(myDrp->pixelFormat), myDrp->pixelFormat);
1404                        goto err;
1405                }
1406        }
1407       
1408        glob->colorConv.convert(picture, (UInt8*)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height);
1409       
1410err:
1411    return err;
1412}
1413
1414//-----------------------------------------------------------------
1415// ImageCodecEndBand
1416//-----------------------------------------------------------------
1417// The ImageCodecEndBand function notifies your image decompressor
1418// component that decompression of a band has finished or
1419// that it was terminated by the Image Compression Manager. Your
1420// image decompressor component is not required to implement the
1421// ImageCodecEndBand function. The base image decompressor may call
1422// the ImageCodecEndBand function at interrupt time.
1423// After your image decompressor component handles an ImageCodecEndBand
1424// call, it can perform any tasks that are required when decompression
1425// is finished, such as disposing of data structures that are no longer
1426// needed. Because this function can be called at interrupt time, your
1427// component cannot use this function to dispose of data structures;
1428// this must occur after handling the function. The value of the result
1429// parameter should be set to noErr if the band or frame was
1430// drawn successfully.
1431// If it is any other value, the band or frame was not drawn.
1432//-----------------------------------------------------------------
1433
1434pascal ComponentResult FFusionCodecEndBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, OSErr result, long flags)
1435{
1436        FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1437        glob->stats.type[drp->frameType].end_calls++;
1438        FFusionBuffer *buf = myDrp->buffer;
1439        if(buf)
1440                releaseBuffer(glob->avContext, buf);
1441       
1442        FFusionDebugPrint("%p EndBand #%d.\n", glob, myDrp->frameNumber);
1443       
1444    return noErr;
1445}
1446
1447//-----------------------------------------------------------------
1448// ImageCodecQueueStarting
1449//-----------------------------------------------------------------
1450// If your component supports asynchronous scheduled decompression,
1451// the base image decompressor calls your image decompressor
1452// component's ImageCodecQueueStarting function before decompressing
1453// the frames in the queue. Your component is not required to implement
1454// this function. It can implement the function if it needs to perform
1455// any tasks at this time, such as locking data structures.
1456// The base image decompressor never calls the ImageCodecQueueStarting
1457// function at interrupt time.
1458//-----------------------------------------------------------------
1459
1460pascal ComponentResult FFusionCodecQueueStarting(FFusionGlobals glob)
1461{       
1462    return noErr;
1463}
1464
1465//-----------------------------------------------------------------
1466// ImageCodecQueueStopping
1467//-----------------------------------------------------------------
1468// If your image decompressor component supports asynchronous scheduled
1469// decompression, the ImageCodecQueueStopping function notifies your
1470// component that the frames in the queue have been decompressed.
1471// Your component is not required to implement this function.
1472// After your image decompressor component handles an ImageCodecQueueStopping
1473// call, it can perform any tasks that are required when decompression
1474// of the frames is finished, such as disposing of data structures that
1475// are no longer needed.
1476// The base image decompressor never calls the ImageCodecQueueStopping
1477// function at interrupt time.
1478//-----------------------------------------------------------------
1479
1480pascal ComponentResult FFusionCodecQueueStopping(FFusionGlobals glob)
1481{       
1482    return noErr;
1483}
1484
1485//-----------------------------------------------------------------
1486// ImageCodecGetCompressedImageSize
1487//-----------------------------------------------------------------
1488// Your component receives the ImageCodecGetCompressedImageSize request
1489// whenever an application calls the ICM's GetCompressedImageSize function.
1490// You can use the ImageCodecGetCompressedImageSize function when you
1491// are extracting a single image from a sequence; therefore, you don't have
1492// an image description structure and don't know the exact size of one frame.
1493// In this case, the Image Compression Manager calls the component to determine
1494// the size of the data. Your component should return a long integer indicating
1495// the number of bytes of data in the compressed image. You may want to store
1496// the image size somewhere in the image description structure, so that you can
1497// respond to this request quickly. Only decompressors receive this request.
1498//-----------------------------------------------------------------
1499
1500pascal ComponentResult FFusionCodecGetCompressedImageSize(FFusionGlobals glob, ImageDescriptionHandle desc, Ptr data, long dataSize, ICMDataProcRecordPtr dataProc, long *size)
1501{
1502    ImageFramePtr framePtr = (ImageFramePtr)data;
1503       
1504    if (size == NULL) 
1505                return paramErr;
1506       
1507    *size = EndianU32_BtoN(framePtr->frameSize) + sizeof(ImageFrame);
1508       
1509    return noErr;
1510}
1511
1512//-----------------------------------------------------------------
1513// ImageCodecGetCodecInfo
1514//-----------------------------------------------------------------
1515// Your component receives the ImageCodecGetCodecInfo request whenever
1516// an application calls the Image Compression Manager's GetCodecInfo
1517// function.
1518// Your component should return a formatted compressor information
1519// structure defining its capabilities.
1520// Both compressors and decompressors may receive this request.
1521//-----------------------------------------------------------------
1522
1523pascal ComponentResult FFusionCodecGetCodecInfo(FFusionGlobals glob, CodecInfo *info)
1524{
1525    OSErr err = noErr;
1526       
1527    if (info == NULL) 
1528    {
1529        err = paramErr;
1530    }
1531    else 
1532    {
1533        CodecInfo **tempCodecInfo;
1534               
1535        switch (glob->componentType)
1536        {
1537            case 'MPG4':        // MS-MPEG4 v1
1538            case 'mpg4':
1539            case 'DIV1':
1540            case 'div1':
1541                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kDivX1CodecInfoResID, (Handle *)&tempCodecInfo);
1542                break;
1543               
1544            case 'MP42':        // MS-MPEG4 v2
1545            case 'mp42':
1546            case 'DIV2':
1547            case 'div2':
1548                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kDivX2CodecInfoResID, (Handle *)&tempCodecInfo);
1549                break;
1550               
1551            case 'div6':        // DivX 3
1552            case 'DIV6':
1553            case 'div5':
1554            case 'DIV5':
1555            case 'div4':
1556            case 'DIV4':
1557            case 'div3':
1558            case 'DIV3':
1559            case 'MP43':
1560            case 'mp43':
1561            case 'MPG3':
1562            case 'mpg3':
1563            case 'AP41':
1564            case 'COL0':
1565            case 'col0':
1566            case 'COL1':
1567            case 'col1':
1568                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kDivX3CodecInfoResID, (Handle *)&tempCodecInfo);
1569                break;
1570                               
1571            case 'divx':        // DivX 4
1572            case 'DIVX':
1573            case 'mp4s':
1574            case 'MP4S':
1575            case 'm4s2':
1576            case 'M4S2':
1577            case 0x04000000:
1578            case 'UMP4':
1579                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kDivX4CodecInfoResID, (Handle *)&tempCodecInfo);
1580                break;
1581                               
1582                        case 'IV31':    // Indeo 3
1583            case 'IV32':
1584                        case 'iv31':
1585            case 'iv32':
1586                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kIndeo3CodecInfoResID, (Handle *)&tempCodecInfo);
1587                break;
1588                               
1589                        case 'RT21':    // Indeo 2
1590                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kIndeo2CodecInfoResID, (Handle *)&tempCodecInfo);
1591                break;
1592               
1593            case 'DX50':
1594                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kDivX5CodecInfoResID, (Handle *)&tempCodecInfo);
1595                break;
1596               
1597            case 'XVID':        // XVID
1598            case 'xvid':
1599            case 'XviD':
1600            case 'XVIX':
1601            case 'BLZ0':
1602                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kXVIDCodecInfoResID, (Handle *)&tempCodecInfo);
1603                break;
1604               
1605            case '3IVD':        // 3ivx
1606            case '3ivd':
1607            case '3IV2':
1608            case '3iv2':
1609                err = GetComponentResource((Component)glob->self, codecInfoResourceType, k3ivxCodecInfoResID, (Handle *)&tempCodecInfo);
1610                break;
1611                               
1612                        case 'RMP4':    // Miscellaneous
1613                        case 'SEDG':
1614                        case 'WV1F':
1615                        case 'FMP4':
1616                        case 'SMP4':
1617                        case 'mp4v':
1618                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kMPEG4CodecInfoResID, (Handle *)&tempCodecInfo);
1619                                break;
1620                               
1621                        case 'H264':    // H.264
1622                        case 'h264':
1623                        case 'X264':
1624                        case 'x264':
1625                        case 'AVC1':
1626                        case 'avc1':
1627                        case 'DAVC':
1628                        case 'VSSH':
1629                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kH264CodecInfoResID, (Handle *)&tempCodecInfo);
1630                                break;
1631                               
1632                        case 'FLV1':
1633                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kFLV1CodecInfoResID, (Handle *)&tempCodecInfo);
1634                                break;
1635                               
1636                        case 'FSV1':
1637                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kFlashSVCodecInfoResID, (Handle *)&tempCodecInfo);
1638                                break;
1639                       
1640                        case 'VP60':
1641                        case 'VP61':
1642                        case 'VP62':
1643                        case 'VP6F':
1644                        case 'FLV4':
1645                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kVP6CodecInfoResID, (Handle *)&tempCodecInfo);
1646                                break;
1647                               
1648                        case 'I263':
1649                        case 'i263':
1650                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kI263CodecInfoResID, (Handle *)&tempCodecInfo);
1651                                break;
1652                               
1653                        case 'VP30':
1654                        case 'VP31':
1655                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kVP3CodecInfoResID, (Handle *)&tempCodecInfo);
1656                                break;
1657                               
1658                        case 'FFVH':
1659                        case 'HFYU':
1660                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kHuffYUVCodecInfoResID, (Handle *)&tempCodecInfo);
1661                                break;
1662                               
1663                        case 'MPEG':
1664                        case 'mpg1':
1665                        case 'mp1v':
1666                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kMPEG1CodecInfoResID, (Handle *)&tempCodecInfo);
1667                                break;
1668                               
1669                        case 'MPG2':
1670                        case 'mpg2':
1671                        case 'mp2v':
1672                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kMPEG2CodecInfoResID, (Handle *)&tempCodecInfo);
1673                                break;
1674                               
1675                        case 'FPS1':
1676                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kFRAPSCodecInfoResID, (Handle *)&tempCodecInfo);
1677                                break;
1678                               
1679                        case 'SNOW':
1680                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kSnowCodecInfoResID, (Handle *)&tempCodecInfo);
1681                                break;
1682
1683            case 'RJPG':
1684                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kNuvCodecInfoResID, (Handle *)&tempCodecInfo);
1685                break;
1686
1687            case 'tscc':
1688                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kTSCCCodecInfoResID, (Handle *)&tempCodecInfo);
1689                break;
1690                               
1691                        case 'ZMBV':
1692                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kZMBVCodecInfoResID, (Handle *)&tempCodecInfo);
1693                                break;
1694                               
1695                        case 'VP6A':
1696                                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kVP6ACodecInfoResID, (Handle *)&tempCodecInfo);
1697                                break;
1698                               
1699            default:    // should never happen but we have to handle the case
1700                err = GetComponentResource((Component)glob->self, codecInfoResourceType, kDivX4CodecInfoResID, (Handle *)&tempCodecInfo);
1701                               
1702        }
1703       
1704        if (err == noErr) 
1705        {
1706            *info = **tempCodecInfo;
1707           
1708            DisposeHandle((Handle)tempCodecInfo);
1709        }
1710    }
1711       
1712    return err;
1713}
1714
1715#define kSpoolChunkSize (16384)
1716#define kInfiniteDataSize (0x7fffffff)
1717
1718static int FFusionGetBuffer(AVCodecContext *s, AVFrame *pic)
1719{
1720        FFusionGlobals glob = s->opaque;
1721        int ret = avcodec_default_get_buffer(s, pic);
1722        int i;
1723       
1724        if (ret >= 0) {
1725                for (i = 0; i < FFUSION_MAX_BUFFERS; i++) {
1726                        if (!glob->buffers[i].retainCount) {
1727//                              FFusionDebugPrint("%p Starting Buffer %p.\n", glob, &glob->buffers[i]);
1728                                pic->opaque = &glob->buffers[i];
1729                                glob->buffers[i].frame = pic;
1730                                glob->buffers[i].retainCount = 1;
1731                                glob->buffers[i].ffmpegUsing = 1;
1732                                glob->lastAllocatedBuffer = i;
1733                                break;
1734                        }
1735                }
1736        }
1737       
1738        return ret;
1739}
1740
1741static void FFusionReleaseBuffer(AVCodecContext *s, AVFrame *pic)
1742{
1743//      FFusionGlobals glob = s->opaque;
1744        FFusionBuffer *buf = pic->opaque;
1745       
1746        if(buf->ffmpegUsing)
1747        {
1748                buf->ffmpegUsing = 0;
1749                releaseBuffer(s, buf);
1750        }
1751}
1752
1753static FFusionBuffer *retainBuffer(FFusionGlobals glob, FFusionBuffer *buf)
1754{
1755        buf->retainCount++;
1756//      FFusionDebugPrint("%p Retained Buffer %p #%d to %d.\n", glob, buf, buf->frameNumber, buf->retainCount);
1757        return buf;
1758}
1759
1760static void releaseBuffer(AVCodecContext *s, FFusionBuffer *buf)
1761{
1762        buf->retainCount--;
1763//      FFusionGlobals glob = (FFusionGlobals)s->opaque;
1764//      FFusionDebugPrint("%p Released Buffer %p #%d to %d.\n", glob, buf, buf->frameNumber, buf->retainCount);
1765        if(!buf->retainCount)
1766        {
1767                buf->returnedFrame.data[0] = NULL;
1768                avcodec_default_release_buffer(s, buf->frame);
1769        }
1770}
1771
1772//-----------------------------------------------------------------
1773// FFusionDecompress
1774//-----------------------------------------------------------------
1775// This function calls libavcodec to decompress one frame.
1776//-----------------------------------------------------------------
1777
1778OSErr FFusionDecompress(FFusionGlobals glob, AVCodecContext *context, UInt8 *dataPtr, ICMDataProcRecordPtr dataProc, long width, long height, AVFrame *picture, long length)
1779{
1780    OSErr err = noErr;
1781    int got_picture = false;
1782    int len = 0;
1783    long availableData = dataProc ? codecMinimumDataSize : kInfiniteDataSize;
1784       
1785        FFusionDebugPrint("%p Decompress %d bytes.\n", glob, length);
1786    picture->data[0] = 0;
1787       
1788    while (!got_picture && length != 0) 
1789    {
1790        if (availableData < kSpoolChunkSize) 
1791        {
1792            // get some more source data
1793           
1794            err = InvokeICMDataUPP((Ptr *)&dataPtr, length, dataProc->dataRefCon, dataProc->dataProc);
1795                       
1796            if (err == eofErr) err = noErr;
1797            if (err) return err;
1798                       
1799            availableData = codecMinimumDataSize;
1800        }
1801               
1802        len = avcodec_decode_video(context, picture, &got_picture, dataPtr, length);
1803               
1804        if (len < 0)
1805        {           
1806            got_picture = 0;
1807                        Codecprintf(glob->fileLog, "Error while decoding frame\n");
1808           
1809            return noErr;
1810        }
1811       
1812        availableData -= len;
1813        dataPtr += len;
1814                length -= len;
1815    }
1816    return err;
1817}
1818
1819static void SetupMultithreadedDecoding(AVCodecContext *s, enum CodecID codecID)
1820{
1821        int nthreads = 1;
1822        size_t len = 4;
1823       
1824    // multithreading is only effective for mpeg1/2 and h.264 with slices
1825    if (codecID != CODEC_ID_MPEG1VIDEO && codecID != CODEC_ID_MPEG2VIDEO && codecID != CODEC_ID_H264) return;
1826   
1827        // two threads on multicore, otherwise 1
1828        if (sysctlbyname("hw.activecpu", &nthreads, &len, NULL, 0) == -1) nthreads = 1;
1829        else nthreads = FFMIN(nthreads, 2);
1830       
1831        avcodec_thread_init(s, nthreads);
1832}
Note: See TracBrowser for help on using the repository browser.