source: trunk/FFusionCodec.c @ 916

Revision 916, 58.9 KB checked in by astrange, 6 years ago (diff)

Parse the first frame in Preflight if we need to find the pix_fmt from it.
Closes #347

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