source: branches/perian-1.1/FFusionCodec.c @ 960

Revision 960, 60.6 KB checked in by astrange, 6 years ago (diff)

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