source: trunk/FFusionCodec.c @ 1069

Revision 1069, 59.5 KB checked in by astrange, 6 years ago (diff)

Fix Indeo.

  • Add missing codec ID mapping (from Madd_the_sane)
  • Add missing color conversion (inefficient and with bad code duplication)

Closes #53

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