source: trunk/FFusionCodec.c @ 1004

Revision 1004, 62.2 KB checked in by astrange, 5 years ago (diff)

Expose CODEC_FLAG2_FAST as "UseFastDecode?" in defaults.

This allows something like 25% faster h264 decode until filter_mb_fast is fixed.

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