source: trunk/FFusionCodec.c @ 969

Revision 969, 60.9 KB checked in by astrange, 6 years ago (diff)

Replace trunk with 1.1 branch, keeping ffmpeg compatibility patches.
This will probably break local changes.

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