source: trunk/FFusionCodec.c @ 1039

Revision 1039, 59.1 KB checked in by astrange, 6 years ago (diff)
  • Remove fast y420 path that never worked.
  • Merge code dealing with ff->qt pixel format conversions.
  • Add RGB16 LE -> RGB16 BE conversion.

(fixes mphq sample V-codecs/tscc/TI_1_Einfuehrung.avi)

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