source: trunk/FFusionCodec.c @ 1108

Revision 1108, 59.6 KB checked in by gbooker, 5 years ago (diff)

New system for defining resources. Hopefully this makes more sense

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