source: trunk/FFusionCodec.c @ 970

Revision 970, 61.1 KB checked in by gbooker, 6 years ago (diff)

Sanity check all pref types.
Fixes #385

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