source: trunk/FFusionCodec.c @ 1219

Revision 1219, 48.7 KB checked in by astrange, 4 years ago (diff)

Correct the placement of an avcodec_default_release_buffer call from r1065.

Fixes #439, no apparent new problems found in normal use.

Line 
1//---------------------------------------------------------------------------
2//FFusion
3//Alternative DivX Codec for MacOS X
4//version 2.2 (build 72)
5//by Jerome Cornet
6//Copyright 2002-2003 Jerome Cornet
7//parts by Dan Christiansen
8//Copyright 2003 Dan Christiansen
9//from DivOSX by Jamby
10//Copyright 2001-2002 Jamby
11//uses libavcodec from ffmpeg 0.4.6
12//
13//This library is free software; you can redistribute it and/or
14//modify it under the terms of the GNU Lesser General Public
15//License as published by the Free Software Foundation; either
16//version 2.1 of the License, or (at your option) any later version.
17//
18//This library is distributed in the hope that it will be useful,
19//but WITHOUT ANY WARRANTY; without even the implied warranty of
20//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21//Lesser General Public License for more details.
22//
23//You should have received a copy of the GNU Lesser General Public
24//License along with this library; if not, write to the Free Software
25//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26//
27//---------------------------------------------------------------------------
28// Source Code
29//---------------------------------------------------------------------------
30
31#include <Carbon/Carbon.h>
32#include <QuickTime/QuickTime.h>
33#include <Accelerate/Accelerate.h>
34#include <sys/sysctl.h>
35
36#include "PerianResourceIDs.h"
37#include "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#include "CodecIDs.h"
45
46//---------------------------------------------------------------------------
47// Types
48//---------------------------------------------------------------------------
49
50// 64 because that's 2 * ffmpeg's INTERNAL_BUFFER_SIZE and QT sometimes uses more than 32
51#define FFUSION_MAX_BUFFERS 64
52
53#define kNumPixelFormatsSupportedFFusion 1
54
55typedef struct
56{
57        AVFrame         *frame;
58        short           retainCount;
59        short           ffmpegUsing;
60        long            frameNumber;
61        AVFrame         returnedFrame;
62} FFusionBuffer;
63
64typedef enum
65{
66        PACKED_QUICKTIME_KNOWS_ORDER, /* This is for non-stupid container formats which actually know the difference between decode and display order */
67        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...*/
68        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.... */
69} FFusionPacked;
70
71/* Why do these small structs?  It makes the usage of these variables clearer, no other reason */
72
73/* globs used by the BeginBand routine */
74struct begin_glob
75{
76        FFusionParserContext    *parser;
77        long                    lastFrame;
78        long                    lastIFrame;
79        int                             lastFrameType;
80        int                             futureType;
81        FrameData               *lastPFrameData;
82};
83
84/* globs used by the DecodeBand routine */
85struct decode_glob
86{
87        long                    lastFrame;
88        FFusionBuffer   *futureBuffer;
89};
90
91struct per_frame_decode_stats
92{
93        unsigned                begin_calls;
94        unsigned                decode_calls;
95        unsigned                draw_calls;
96        unsigned                end_calls;
97};
98
99struct decode_stats
100{
101        struct per_frame_decode_stats type[4];
102        int             max_frames_begun;
103        int             max_frames_decoded;
104};
105
106typedef struct
107{
108    ComponentInstance           self;
109    ComponentInstance           delegateComponent;
110    ComponentInstance           target;
111    ImageCodecMPDrawBandUPP     drawBandUPP;
112    Handle                      pixelTypes;
113    AVCodec                     *avCodec;
114    AVCodecContext      *avContext;
115    OSType                      componentType;
116        FILE                    *fileLog;
117        AVFrame                 lastDisplayedFrame;
118        FFusionPacked   packedType;
119        FFusionBuffer   buffers[FFUSION_MAX_BUFFERS];   // the buffers which the codec has retained
120        int                             lastAllocatedBuffer;            // the index of the buffer which was last allocated
121                                                                                                // by the codec (and is the latest in decode order)     
122        int                             shouldUseReturnedFrame;
123        struct begin_glob       begin;
124        FFusionData             data;
125        struct decode_glob      decode;
126        struct decode_stats stats;
127        ColorConversionFuncs colorConv;
128} FFusionGlobalsRecord, *FFusionGlobals;
129
130typedef struct
131{
132    long                        width;
133    long                        height;
134    long                        depth;
135    OSType                      pixelFormat;
136        int                             decoded;
137        long                    frameNumber;
138        long                    GOPStartFrameNumber;
139        long                    bufferSize;
140        FFusionBuffer   *buffer;
141        FrameData               *frameData;
142} FFusionDecompressRecord;
143
144
145//---------------------------------------------------------------------------
146// Prototypes of private subroutines
147//---------------------------------------------------------------------------
148
149static OSErr FFusionDecompress(FFusionGlobals glob, AVCodecContext *context, UInt8 *dataPtr, long width, long height, AVFrame *picture, long length);
150static int FFusionGetBuffer(AVCodecContext *s, AVFrame *pic);
151static void FFusionReleaseBuffer(AVCodecContext *s, AVFrame *pic);
152static void releaseBuffer(AVCodecContext *s, FFusionBuffer *buf);
153static FFusionBuffer *retainBuffer(FFusionGlobals glob, FFusionBuffer *buf);
154
155int GetPPUserPreference();
156void SetPPUserPreference(int value);
157pascal OSStatus HandlePPDialogWindowEvent(EventHandlerCallRef  nextHandler, EventRef theEvent, void* userData);
158pascal OSStatus HandlePPDialogControlEvent(EventHandlerCallRef  nextHandler, EventRef theEvent, void* userData);
159void ChangeHintText(int value, ControlRef staticTextField);
160
161extern void init_FFmpeg();
162extern CFMutableStringRef CopyHomeDirectory();
163
164#define FFusionDebugPrint(x...) if (glob->fileLog) Codecprintf(glob->fileLog, x);
165#define not(x) ((x) ? "" : "not ")
166
167//---------------------------------------------------------------------------
168// Component Dispatcher
169//---------------------------------------------------------------------------
170
171#define IMAGECODEC_BASENAME()           FFusionCodec
172#define IMAGECODEC_GLOBALS()            FFusionGlobals storage
173
174#define CALLCOMPONENT_BASENAME()        IMAGECODEC_BASENAME()
175#define CALLCOMPONENT_GLOBALS()         IMAGECODEC_GLOBALS()
176
177#define COMPONENT_UPP_PREFIX()          uppImageCodec
178#define COMPONENT_DISPATCH_FILE         "FFusionCodecDispatch.h"
179#define COMPONENT_SELECT_PREFIX()       kImageCodec
180
181#define GET_DELEGATE_COMPONENT()        (storage->delegateComponent)
182
183#include <QuickTime/ImageCodec.k.h>
184#include <QuickTime/ComponentDispatchHelper.c>
185
186static void *launchUpdateChecker(void *args)
187{
188        FSRef *ref = (FSRef *)args;
189    LSOpenFSRef(ref, NULL);
190        free(ref);
191        return NULL;
192}
193
194Boolean FFusionAlreadyRanUpdateCheck = 0;
195
196void FFusionRunUpdateCheck()
197{
198        if (FFusionAlreadyRanUpdateCheck) return;
199
200    CFDateRef lastRunDate = CopyPreferencesValueTyped(CFSTR("NextRunDate"), CFDateGetTypeID());
201    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
202   
203        FFusionAlreadyRanUpdateCheck = 1;
204       
205        if (lastRunDate) {
206                Boolean exit = CFDateGetAbsoluteTime(lastRunDate) > now;
207                CFRelease(lastRunDate);
208                if (exit) return;
209        }
210   
211    //Two places to check, home dir and /
212   
213    CFMutableStringRef location = CopyHomeDirectory();
214    CFStringAppend(location, CFSTR("/Library/PreferencePanes/Perian.prefPane/Contents/Resources/PerianUpdateChecker.app"));
215   
216    char fileRep[1024];
217    FSRef *updateCheckRef = malloc(sizeof(FSRef));
218    Boolean doCheck = FALSE;
219   
220    if(CFStringGetFileSystemRepresentation(location, fileRep, 1024))
221        if(FSPathMakeRef((UInt8 *)fileRep, updateCheckRef, NULL) == noErr)
222            doCheck = TRUE;
223   
224    CFRelease(location);
225    if(doCheck == FALSE)
226    {
227        CFStringRef absLocation = CFSTR("/Library/PreferencePanes/Perian.prefPane/Contents/Resources/PerianUpdateChecker.app");
228        if(CFStringGetFileSystemRepresentation(absLocation, fileRep, 1024))
229            if(FSPathMakeRef((UInt8 *)fileRep, updateCheckRef, NULL) != noErr)
230                goto err;  //We have failed
231    }
232        pthread_t thread;
233        pthread_create(&thread, NULL, launchUpdateChecker, updateCheckRef);
234       
235        return;
236err:
237        free(updateCheckRef);
238}
239
240static void RecomputeMaxCounts(FFusionGlobals glob)
241{
242        int i;
243        unsigned begun = 0, decoded = 0, ended = 0, drawn = 0;
244       
245        for (i = 0; i < 4; i++) {
246                struct per_frame_decode_stats *f = &glob->stats.type[i];
247               
248                begun += f->begin_calls;
249                decoded += f->decode_calls;
250                drawn += f->draw_calls;
251                ended += f->end_calls;
252        }
253       
254        signed begin_diff = begun - ended, decode_diff = decoded - drawn;
255       
256        if (abs(begin_diff) > glob->stats.max_frames_begun) glob->stats.max_frames_begun = begin_diff;
257        if (abs(decode_diff) > glob->stats.max_frames_decoded) glob->stats.max_frames_decoded = decode_diff;
258}
259
260static void DumpFrameDropStats(FFusionGlobals glob)
261{
262        static const char types[4] = {'?', 'I', 'P', 'B'};
263        int i;
264       
265        if (!glob->fileLog || glob->decode.lastFrame == 0) return;
266       
267        Codecprintf(glob->fileLog, "%p frame drop stats\nType\t| BeginBand\t| DecodeBand\t| DrawBand\t| dropped before decode\t| dropped before draw\n", glob);
268       
269        for (i = 0; i < 4; i++) {
270                struct per_frame_decode_stats *f = &glob->stats.type[i];
271                               
272                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,
273                                        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.,
274                                        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.);
275        }
276}
277
278static enum PixelFormat FindPixFmtFromVideo(AVCodec *codec, AVCodecContext *avctx, Ptr data, int bufferSize)
279{
280    AVCodecContext tmpContext;
281    AVFrame tmpFrame;
282    int got_picture;
283    enum PixelFormat pix_fmt;
284   
285    avcodec_get_context_defaults2(&tmpContext, CODEC_TYPE_VIDEO);
286        avcodec_get_frame_defaults(&tmpFrame);
287    tmpContext.width = avctx->width;
288    tmpContext.height = avctx->height;
289        tmpContext.flags = avctx->flags;
290        tmpContext.bits_per_coded_sample = avctx->bits_per_coded_sample;
291    tmpContext.codec_tag = avctx->codec_tag;
292        tmpContext.codec_id  = avctx->codec_id;
293        tmpContext.extradata = avctx->extradata;
294        tmpContext.extradata_size = avctx->extradata_size;
295       
296    avcodec_open(&tmpContext, codec);
297        AVPacket pkt;
298        av_init_packet(&pkt);
299        pkt.data = (UInt8*)data;
300        pkt.size = bufferSize;
301    avcodec_decode_video2(&tmpContext, &tmpFrame, &got_picture, &pkt);
302    pix_fmt = tmpContext.pix_fmt;
303    avcodec_close(&tmpContext);
304   
305    return pix_fmt;
306}
307
308static void SetupMultithreadedDecoding(AVCodecContext *s, enum CodecID codecID)
309{
310        int nthreads = 1;
311        size_t len = 4;
312       
313    // multithreading is only effective for mpeg1/2 and h.264 with slices
314    if (codecID != CODEC_ID_MPEG1VIDEO && codecID != CODEC_ID_MPEG2VIDEO && codecID != CODEC_ID_H264) return;
315   
316        // two threads on multicore, otherwise 1
317        if (sysctlbyname("hw.activecpu", &nthreads, &len, NULL, 0) == -1) nthreads = 1;
318        else nthreads = FFMIN(nthreads, 2);
319       
320        avcodec_thread_init(s, nthreads);
321}
322
323static void SetSkipLoopFilter(FFusionGlobals glob, AVCodecContext *avctx)
324{
325        Boolean keyExists = FALSE;
326        int loopFilterSkip = CFPreferencesGetAppIntegerValue(CFSTR("SkipLoopFilter"), PERIAN_PREF_DOMAIN, &keyExists);
327        if(keyExists)
328        {
329                enum AVDiscard loopFilterValue = AVDISCARD_DEFAULT;
330                switch (loopFilterSkip) {
331                        case 1:
332                                loopFilterValue = AVDISCARD_NONREF;
333                                break;
334                        case 2:
335                                loopFilterValue = AVDISCARD_BIDIR;
336                                break;
337                        case 3:
338                                loopFilterValue = AVDISCARD_NONKEY;
339                                break;
340                        case 4:
341                                loopFilterValue = AVDISCARD_ALL;
342                                break;
343                        default:
344                                break;
345                }
346                avctx->skip_loop_filter = loopFilterValue;
347                FFusionDebugPrint("%p Preflight set skip loop filter to %d", glob, loopFilterValue);
348        }
349}
350
351static void swapFrame(AVFrame * *a, AVFrame * *b)
352{
353        AVFrame *t = *a;
354        *a = *b;
355        *b = t;
356}
357
358//---------------------------------------------------------------------------
359// Component Routines
360//---------------------------------------------------------------------------
361
362// -- This Image Decompressor Use the Base Image Decompressor Component --
363//      The base image decompressor is an Apple-supplied component
364//      that makes it easier for developers to create new decompressors.
365//      The base image decompressor does most of the housekeeping and
366//      interface functions required for a QuickTime decompressor component,
367//      including scheduling for asynchronous decompression.
368
369//-----------------------------------------------------------------
370// Component Open Request - Required
371//-----------------------------------------------------------------
372
373pascal ComponentResult FFusionCodecOpen(FFusionGlobals glob, ComponentInstance self)
374{
375    ComponentResult err;
376    ComponentDescription descout;
377   
378    GetComponentInfo((Component)self, &descout, 0, 0, 0);
379       
380  //  FourCCprintf("Opening component for type ", descout.componentSubType);
381    // Allocate memory for our globals, set them up and inform the component manager that we've done so
382       
383    glob = (FFusionGlobals)NewPtrClear(sizeof(FFusionGlobalsRecord));
384   
385    if (err = MemError())
386    {
387        Codecprintf(NULL, "Unable to allocate globals! Exiting.\n");           
388    }
389    else
390    {
391                CFStringRef pathToLogFile = CopyPreferencesValueTyped(CFSTR("DebugLogFile"), CFStringGetTypeID());
392                char path[PATH_MAX];
393        SetComponentInstanceStorage(self, (Handle)glob);
394
395        glob->self = self;
396        glob->target = self;
397        glob->drawBandUPP = NULL;
398        glob->pixelTypes = NewHandleClear((kNumPixelFormatsSupportedFFusion+1) * sizeof(OSType));
399        glob->avCodec = 0;
400        glob->componentType = descout.componentSubType;
401                glob->packedType = PACKED_ALL_IN_FIRST_FRAME;  //Unless we have reason to believe otherwise.
402                glob->data.frames = NULL;
403                glob->begin.parser = NULL;
404                if (pathToLogFile) {
405                        CFStringGetCString(pathToLogFile, path, PATH_MAX, kCFStringEncodingUTF8);
406                        CFRelease(pathToLogFile);
407                        glob->fileLog = fopen(path, "a");
408                }
409                glob->shouldUseReturnedFrame = 0;
410               
411        // Open and target an instance of the base decompressor as we delegate
412        // most of our calls to the base decompressor instance
413       
414        err = OpenADefaultComponent(decompressorComponentType, kBaseCodecType, &glob->delegateComponent);
415        if (!err)
416        {
417            ComponentSetTarget(glob->delegateComponent, self);
418        }
419        else
420        {
421            Codecprintf(glob->fileLog, "Error opening the base image decompressor! Exiting.\n");
422        }
423               
424                // we allocate some space for copying the frame data since we need some padding at the end
425                // for ffmpeg's optimized bitstream readers. Size doesn't really matter, it'll grow if need be
426                FFusionDataSetup(&(glob->data), 256, 1024*1024);
427        FFusionRunUpdateCheck();
428    }
429   
430    FFusionDebugPrint("%p opened for '%s'\n", glob, FourCCString(glob->componentType));
431    return err;
432}
433
434//-----------------------------------------------------------------
435// Component Close Request - Required
436//-----------------------------------------------------------------
437
438pascal ComponentResult FFusionCodecClose(FFusionGlobals glob, ComponentInstance self)
439{
440    FFusionDebugPrint("%p closed.\n", glob);
441        DumpFrameDropStats(glob);
442
443    // Make sure to close the base component and deallocate our storage
444    if (glob) 
445    {
446        if (glob->delegateComponent) 
447        {
448            CloseComponent(glob->delegateComponent);
449        }
450       
451        if (glob->drawBandUPP) 
452        {
453            DisposeImageCodecMPDrawBandUPP(glob->drawBandUPP);
454        }
455                               
456        if (glob->avContext)
457        {
458                        if (glob->avContext->extradata)
459                                free(glob->avContext->extradata);
460                                               
461                        if (glob->avContext->codec) avcodec_close(glob->avContext);
462            av_free(glob->avContext);
463        }
464               
465                if (glob->begin.parser)
466                {
467                        ffusionParserFree(glob->begin.parser);
468                }
469               
470                if (glob->pixelTypes)
471                {
472                        DisposeHandle(glob->pixelTypes);
473                }
474               
475                FFusionDataFree(&(glob->data));
476       
477                if(glob->fileLog)
478                        fclose(glob->fileLog);
479               
480        memset(glob, 0, sizeof(FFusionGlobalsRecord));
481        DisposePtr((Ptr)glob);
482    }
483       
484    return noErr;
485}
486
487//-----------------------------------------------------------------
488// Component Version Request - Required
489//-----------------------------------------------------------------
490
491pascal ComponentResult FFusionCodecVersion(FFusionGlobals glob)
492{
493    return kFFusionCodecVersion;
494}
495
496//-----------------------------------------------------------------
497// Component Target Request
498//-----------------------------------------------------------------
499// Allows another component to "target" you i.e., you call
500// another component whenever you would call yourself (as a result
501// of your component being used by another component)
502//-----------------------------------------------------------------
503
504pascal ComponentResult FFusionCodecTarget(FFusionGlobals glob, ComponentInstance target)
505{
506    glob->target = target;
507       
508    return noErr;
509}
510
511//-----------------------------------------------------------------
512// Component GetMPWorkFunction Request
513//-----------------------------------------------------------------
514// Allows your image decompressor component to perform asynchronous
515// decompression in a single MP task by taking advantage of the
516// Base Decompressor. If you implement this selector, your DrawBand
517// function must be MP-safe. MP safety means not calling routines
518// that may move or purge memory and not calling any routines which
519// might cause 68K code to be executed. Ideally, your DrawBand
520// function should not make any API calls whatsoever. Obviously
521// don't implement this if you're building a 68k component.
522//-----------------------------------------------------------------
523
524pascal ComponentResult FFusionCodecGetMPWorkFunction(FFusionGlobals glob, ComponentMPWorkFunctionUPP *workFunction, void **refCon)
525{
526        if (glob->drawBandUPP == NULL)
527                glob->drawBandUPP = NewImageCodecMPDrawBandUPP((ImageCodecMPDrawBandProcPtr)FFusionCodecDrawBand);
528       
529        return ImageCodecGetBaseMPWorkFunction(glob->delegateComponent, workFunction, refCon, glob->drawBandUPP, glob);
530}
531
532//-----------------------------------------------------------------
533// ImageCodecInitialize
534//-----------------------------------------------------------------
535// The first function call that your image decompressor component
536// receives from the base image decompressor is always a call to
537// ImageCodecInitialize . In response to this call, your image
538// decompressor component returns an ImageSubCodecDecompressCapabilities
539// structure that specifies its capabilities.
540//-----------------------------------------------------------------
541
542pascal ComponentResult FFusionCodecInitialize(FFusionGlobals glob, ImageSubCodecDecompressCapabilities *cap)
543{
544        Boolean doExperimentalFlags = CFPreferencesGetAppBooleanValue(CFSTR("ExperimentalQTFlags"), PERIAN_PREF_DOMAIN, NULL);
545       
546    // Secifies the size of the ImageSubCodecDecompressRecord structure
547    // and say we can support asyncronous decompression
548    // With the help of the base image decompressor, any image decompressor
549    // that uses only interrupt-safe calls for decompression operations can
550    // support asynchronous decompression.
551       
552    cap->decompressRecordSize = sizeof(FFusionDecompressRecord) + 12;
553    cap->canAsync = true;
554       
555        // QT 7
556        if(cap->recordSize > offsetof(ImageSubCodecDecompressCapabilities, baseCodecShouldCallDecodeBandForAllFrames))
557        {
558                cap->subCodecIsMultiBufferAware = true;
559                cap->subCodecSupportsOutOfOrderDisplayTimes = true;
560                cap->baseCodecShouldCallDecodeBandForAllFrames = true;
561                cap->subCodecSupportsScheduledBackwardsPlaybackWithDifferenceFrames = !doExperimentalFlags;
562                cap->subCodecSupportsDrawInDecodeOrder = doExperimentalFlags; 
563                cap->subCodecSupportsDecodeSmoothing = true; 
564        }
565       
566    return noErr;
567}
568
569static inline int shouldDecode(FFusionGlobals glob, enum CodecID codecID)
570{
571        FFusionDecodeAbilities decode = FFUSION_PREFER_DECODE;
572        if (glob->componentType == 'avc1')
573                decode = ffusionIsParsedVideoDecodable(glob->begin.parser);
574        if(decode > FFUSION_CANNOT_DECODE && 
575           (codecID == CODEC_ID_H264 || codecID == CODEC_ID_MPEG4) && CFPreferencesGetAppBooleanValue(CFSTR("PreferAppleCodecs"), PERIAN_PREF_DOMAIN, NULL))
576                decode = FFUSION_PREFER_NOT_DECODE;
577        if(decode > FFUSION_CANNOT_DECODE)
578                if(IsForcedDecodeEnabled())
579                        decode = FFUSION_PREFER_DECODE;
580        return decode > FFUSION_PREFER_NOT_DECODE;
581}
582
583//-----------------------------------------------------------------
584// ImageCodecPreflight
585//-----------------------------------------------------------------
586// The base image decompressor gets additional information about the
587// capabilities of your image decompressor component by calling
588// ImageCodecPreflight. The base image decompressor uses this
589// information when responding to a call to the ImageCodecPredecompress
590// function, which the ICM makes before decompressing an image. You
591// are required only to provide values for the wantedDestinationPixelSize
592// and wantedDestinationPixelTypes fields and can also modify other
593// fields if necessary.
594//-----------------------------------------------------------------
595
596pascal ComponentResult FFusionCodecPreflight(FFusionGlobals glob, CodecDecompressParams *p)
597{
598    OSType *pos;
599    int index;
600    CodecCapabilities *capabilities = p->capabilities;
601        long count = 0;
602        Handle imgDescExt;
603        OSErr err = noErr;
604       
605    // We first open libavcodec library and the codec corresponding
606    // to the fourCC if it has not been done before
607   
608        FFusionDebugPrint("%p Preflight called.\n", glob);
609        FFusionDebugPrint("%p Frame dropping is %senabled\n", glob, not(IsFrameDroppingEnabled()));
610       
611    if (!glob->avCodec)
612    {
613                init_FFmpeg();
614                initFFusionParsers();
615
616                OSType componentType = glob->componentType;
617                enum CodecID codecID = getCodecID(componentType);
618               
619                // official Apple/QT/ISO/etc fourccs are likely to have PTS vs DTS defined
620                // FIXME what this actually checks is whether the file has a 'ctts' atom, can we do that directly?
621                if(componentType == kMPEG4VisualCodecType || componentType == kH264CodecType ||
622                   componentType == kMPEG1VisualCodecType || componentType == kMPEG2VisualCodecType)
623                        glob->packedType = PACKED_QUICKTIME_KNOWS_ORDER;
624               
625                else if(componentType == 'VP30' || componentType == 'VP31')
626                        glob->shouldUseReturnedFrame = TRUE;
627
628                if(codecID == CODEC_ID_NONE)
629                {
630                        Codecprintf(glob->fileLog, "Warning! Unknown codec type! Using MPEG4 by default.\n");
631                        codecID = CODEC_ID_MPEG4;
632                }
633               
634                glob->avCodec = avcodec_find_decoder(codecID);
635//              if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER)
636                        glob->begin.parser = ffusionParserInit(codecID);
637               
638                if ((codecID == CODEC_ID_MPEG4 || codecID == CODEC_ID_H264) && !glob->begin.parser)
639                        Codecprintf(glob->fileLog, "This is a parseable format, but we couldn't open a parser!\n");
640               
641        // we do the same for the AVCodecContext since all context values are
642        // correctly initialized when calling the alloc function
643       
644        glob->avContext = avcodec_alloc_context2(CODEC_TYPE_VIDEO);
645               
646                // Use low delay
647                glob->avContext->flags |= CODEC_FLAG_LOW_DELAY;
648               
649        // Image size is mandatory for DivX-like codecs
650       
651        glob->avContext->width = (**p->imageDescription).width;
652        glob->avContext->height = (**p->imageDescription).height;
653                glob->avContext->bits_per_coded_sample = (**p->imageDescription).depth;
654               
655        // We also pass the FourCC since it allows the H263 hybrid decoder
656        // to make the difference between the various flavours of DivX
657        glob->avContext->codec_tag = Endian32_Swap(glob->componentType);
658                glob->avContext->codec_id  = codecID;
659       
660                // avc1 requires the avcC extension
661                if (glob->componentType == 'avc1') {
662                        count = isImageDescriptionExtensionPresent(p->imageDescription, 'avcC');
663                       
664                        if (count >= 1) {
665                                imgDescExt = NewHandle(0);
666                                GetImageDescriptionExtension(p->imageDescription, &imgDescExt, 'avcC', 1);
667                               
668                                glob->avContext->extradata = calloc(1, GetHandleSize(imgDescExt) + FF_INPUT_BUFFER_PADDING_SIZE);
669                                memcpy(glob->avContext->extradata, *imgDescExt, GetHandleSize(imgDescExt));
670                                glob->avContext->extradata_size = GetHandleSize(imgDescExt);
671                               
672                                DisposeHandle(imgDescExt);
673                        } else {
674                                count = isImageDescriptionExtensionPresent(p->imageDescription, 'strf');
675                               
676                                // avc1 in AVI, need to reorder frames
677                                if (count >= 1)
678                                        glob->packedType = PACKED_ALL_IN_FIRST_FRAME;
679                        }
680                } else if (glob->componentType == 'mp4v') {
681                        count = isImageDescriptionExtensionPresent(p->imageDescription, 'esds');
682                       
683                        if (count >= 1) {
684                                imgDescExt = NewHandle(0);
685                                GetImageDescriptionExtension(p->imageDescription, &imgDescExt, 'esds', 1);
686                               
687                                ReadESDSDescExt(imgDescExt, &glob->avContext->extradata, &glob->avContext->extradata_size);
688                               
689                                DisposeHandle(imgDescExt);
690                        }
691                } else {
692                        count = isImageDescriptionExtensionPresent(p->imageDescription, 'strf');
693                       
694                        if (count >= 1) {
695                                imgDescExt = NewHandle(0);
696                                GetImageDescriptionExtension(p->imageDescription, &imgDescExt, 'strf', 1);
697                               
698                                if (GetHandleSize(imgDescExt) - 40 > 0) {
699                                        glob->avContext->extradata = calloc(1, GetHandleSize(imgDescExt) - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
700                                        memcpy(glob->avContext->extradata, *imgDescExt + 40, GetHandleSize(imgDescExt) - 40);
701                                        glob->avContext->extradata_size = GetHandleSize(imgDescExt) - 40;
702                                }
703                                DisposeHandle(imgDescExt);
704                        }
705                }
706               
707                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);
708       
709                if(glob->avContext->extradata_size != 0 && glob->begin.parser != NULL)
710                        ffusionParseExtraData(glob->begin.parser, glob->avContext->extradata, glob->avContext->extradata_size);
711               
712                if (glob->fileLog)
713                        ffusionLogDebugInfo(glob->begin.parser, glob->fileLog);
714               
715                if (!shouldDecode(glob, codecID))
716                        err = featureUnsupported;
717               
718                // some hooks into ffmpeg's buffer allocation to get frames in
719                // decode order without delay more easily
720                glob->avContext->opaque = glob;
721                glob->avContext->get_buffer = FFusionGetBuffer;
722                glob->avContext->release_buffer = FFusionReleaseBuffer;
723               
724                // multi-slice decoding
725                SetupMultithreadedDecoding(glob->avContext, codecID);
726               
727                // deblock skipping for h264
728                SetSkipLoopFilter(glob, glob->avContext);
729               
730                //fast flag
731                if (CFPreferencesGetAppBooleanValue(CFSTR("UseFastDecode"), PERIAN_PREF_DOMAIN, NULL))
732                        glob->avContext->flags2 |= CODEC_FLAG2_FAST;
733               
734        // Finally we open the avcodec
735       
736        if (avcodec_open(glob->avContext, glob->avCodec))
737        {
738            Codecprintf(glob->fileLog, "Error opening avcodec!\n");
739           
740                        err = paramErr;
741        }
742               
743        // this format doesn't have enough information in its headers
744                // we have to decode the first frame
745                if (glob->avContext->pix_fmt == PIX_FMT_NONE && p->bufferSize && p->data)
746            glob->avContext->pix_fmt = FindPixFmtFromVideo(glob->avCodec, glob->avContext, p->data, p->bufferSize);
747    }
748   
749    // Specify the minimum image band height supported by the component
750    // bandInc specifies a common factor of supported image band heights -
751    // if your component supports only image bands that are an even
752    // multiple of some number of pixels high report this common factor in bandInc
753   
754    capabilities->bandMin = (**p->imageDescription).height;
755    capabilities->bandInc = capabilities->bandMin;
756       
757    // libavcodec 0.4.x is no longer stream based i.e. you cannot pass just
758    // an arbitrary amount of data to the library.
759    // Instead we have to tell QT to just pass the data corresponding
760    // to one frame
761       
762    capabilities->flags |= codecWantsSpecialScaling;
763   
764    p->requestedBufferWidth = (**p->imageDescription).width;
765    p->requestedBufferHeight = (**p->imageDescription).height;
766   
767    // Indicate the pixel depth the component can use with the specified image
768    // normally should be capabilities->wantedPixelSize = (**p->imageDescription).depth;
769    // but we don't care since some DivX are so bugged that the depth information
770    // is not correct
771   
772    capabilities->wantedPixelSize = 0;
773   
774    pos = *((OSType **)glob->pixelTypes);
775   
776    index = 0;
777       
778        if (!err) {
779                OSType qtPixFmt = ColorConversionDstForPixFmt(glob->avContext->pix_fmt);
780               
781                /*
782                 an error here means either
783                 1) a color converter for this format isn't implemented
784                 2) we know QT doesn't like this format and will give us argb 32bit instead
785                 
786                 in the case of 2 we have to special-case bail right here, since errors
787                 in BeginBand are ignored
788                 */
789                if (qtPixFmt)
790                        pos[index++] = qtPixFmt;
791                else
792                        err = featureUnsupported;
793        }
794       
795    p->wantedDestinationPixelTypes = (OSType **)glob->pixelTypes;
796   
797    // Specify the number of pixels the image must be extended in width and height if
798    // the component cannot accommodate the image at its given width and height
799    // It is not the case here
800   
801    capabilities->extendWidth = 0;
802    capabilities->extendHeight = 0;
803   
804        capabilities->flags |= codecCanAsync | codecCanAsyncWhen;
805       
806        FFusionDebugPrint("%p Preflight requesting colorspace '%s'. (error %d)\n", glob, FourCCString(pos[0]), err);
807       
808    return err;
809}
810
811static int qtTypeForFrameInfo(int original, int fftype, int skippable)
812{
813        if(fftype == FF_I_TYPE)
814        {
815                if(!skippable)
816                        return kCodecFrameTypeKey;
817        }
818        else if(skippable && IsFrameDroppingEnabled())
819                return kCodecFrameTypeDroppableDifference;
820        else if(fftype != 0)
821                return kCodecFrameTypeDifference;       
822        return original;
823}
824
825//-----------------------------------------------------------------
826// ImageCodecBeginBand
827//-----------------------------------------------------------------
828// The ImageCodecBeginBand function allows your image decompressor
829// component to save information about a band before decompressing
830// it. This function is never called at interrupt time. The base
831// image decompressor preserves any changes your component makes to
832// any of the fields in the ImageSubCodecDecompressRecord or
833// CodecDecompressParams structures. If your component supports
834// asynchronous scheduled decompression, it may receive more than
835// one ImageCodecBeginBand call before receiving an ImageCodecDrawBand
836// call.
837//-----------------------------------------------------------------
838
839pascal ComponentResult FFusionCodecBeginBand(FFusionGlobals glob, CodecDecompressParams *p, ImageSubCodecDecompressRecord *drp, long flags)
840{       
841    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
842        int redisplayFirstFrame = 0;
843        int type = 0;
844        int skippable = 0;
845       
846    //////
847  /*  IBNibRef          nibRef;
848    WindowRef           window;
849    OSStatus            err;
850    CFBundleRef         bundleRef;
851    EventHandlerUPP     handlerUPP, handlerUPP2;
852    EventTypeSpec       eventType;
853    ControlID           controlID;
854    ControlRef          theControl;
855    KeyMap              currentKeyMap;
856    int                 userPreference; */
857    ///////
858
859    myDrp->width = (**p->imageDescription).width;
860    myDrp->height = (**p->imageDescription).height;
861    myDrp->depth = (**p->imageDescription).depth;
862       
863    myDrp->pixelFormat = p->dstPixMap.pixelFormat;
864        myDrp->decoded = p->frameTime ? (0 != (p->frameTime->flags & icmFrameAlreadyDecoded)) : false;
865        myDrp->frameData = NULL;
866        myDrp->buffer = NULL;
867       
868        FFusionDebugPrint("%p BeginBand #%d. (%sdecoded, packed %d)\n", glob, p->frameNumber, not(myDrp->decoded), glob->packedType);
869       
870        if (!glob->avContext) {
871                Codecprintf(glob->fileLog, "Perian: QT tried to call BeginBand without preflighting!\n");
872                return internalComponentErr;
873        }
874       
875        if (p->frameNumber == 0 && myDrp->pixelFormat != ColorConversionDstForPixFmt(glob->avContext->pix_fmt)) {
876                Codecprintf(glob->fileLog, "QT gave us unwanted pixelFormat %s (%08x), this will not work\n", FourCCString(myDrp->pixelFormat), myDrp->pixelFormat);
877        }
878       
879        if(myDrp->decoded)
880        {
881                int i;
882                myDrp->frameNumber = p->frameNumber;
883                for (i = 0; i < FFUSION_MAX_BUFFERS; i++) {
884                        if (glob->buffers[i].retainCount && glob->buffers[i].frameNumber == myDrp->frameNumber) {
885                                myDrp->buffer = retainBuffer(glob, &glob->buffers[i]);
886                                break;
887                        }
888                }
889                return noErr;
890        }
891       
892        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && p->frameNumber != glob->begin.lastFrame + 1)
893        {
894                if(glob->decode.lastFrame < p->frameNumber && p->frameNumber < glob->begin.lastFrame + 1)
895                {
896                        /* We already began this sucker, but haven't decoded it yet, find the data */
897                        FrameData *frameData = NULL;
898                        frameData = FFusionDataFind(&glob->data, p->frameNumber);
899                        if(frameData != NULL)
900                        {
901                                myDrp->frameData = frameData;
902                                drp->frameType = qtTypeForFrameInfo(drp->frameType, myDrp->frameData->type, myDrp->frameData->skippabble);
903                                myDrp->frameNumber = p->frameNumber;
904                                myDrp->GOPStartFrameNumber = glob->begin.lastIFrame;
905                                return noErr;
906                        }
907                }
908                else
909                {
910                        /* Reset context, safe marking in such a case */
911                        glob->begin.lastFrameType = FF_I_TYPE;
912                        FFusionDataReadUnparsed(&(glob->data));
913                        glob->begin.lastPFrameData = NULL;
914                        redisplayFirstFrame = 1;
915                }
916        }
917       
918        if(glob->begin.parser != NULL)
919        {
920                int parsedBufSize;
921                uint8_t *buffer = (uint8_t *)drp->codecData;
922                int bufferSize = p->bufferSize;
923               
924                if(glob->data.unparsedFrames.dataSize != 0)
925                {
926                        buffer = glob->data.unparsedFrames.buffer;
927                        bufferSize = glob->data.unparsedFrames.dataSize;
928                }
929               
930                if(ffusionParse(glob->begin.parser, buffer, bufferSize, &parsedBufSize, &type, &skippable) == 0)
931                {
932                        /* parse failed */
933                        myDrp->bufferSize = bufferSize;
934                        if(glob->begin.futureType != 0)
935                        {
936                                /* Assume our previously decoded P frame */
937                                type = glob->begin.futureType;
938                                glob->begin.futureType = 0;
939                                myDrp->frameData = glob->begin.lastPFrameData;
940                        }
941                        else
942                        {
943                                Codecprintf(glob->fileLog, "parse failed frame %d with size %d\n", p->frameNumber, bufferSize);
944                                if(glob->data.unparsedFrames.dataSize != 0)
945                                        Codecprintf(glob->fileLog, ", parser had extra data\n");                               
946                        }
947                }
948                else if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER)
949                {
950                        if(type == FF_B_TYPE && glob->packedType == PACKED_ALL_IN_FIRST_FRAME && glob->begin.futureType == 0)
951                                /* Badly framed.  We hit a B frame after it was supposed to be displayed, switch to delaying by a frame */
952                                glob->packedType = PACKED_DELAY_BY_ONE_FRAME;
953                        else if(glob->packedType == PACKED_DELAY_BY_ONE_FRAME && parsedBufSize < bufferSize - 16)
954                                /* Seems to be switching back to packed in one frame; switch back*/
955                                glob->packedType = PACKED_ALL_IN_FIRST_FRAME;
956                       
957                        myDrp->frameData = FFusionDataAppend(&(glob->data), buffer, parsedBufSize, type);
958                        if(type != FF_I_TYPE)
959                                myDrp->frameData->prereqFrame = glob->begin.lastPFrameData;
960                        if(glob->packedType == PACKED_DELAY_BY_ONE_FRAME)
961                        {
962                                if(type != FF_B_TYPE)
963                                {
964                                        FrameData *nextPFrame = myDrp->frameData;
965                                        FrameData *lastPFrame = glob->begin.lastPFrameData;
966                                        if(lastPFrame != NULL)
967                                                /* Mark the next P or I frame, predictive decoding */
968                                                lastPFrame->nextFrame = nextPFrame;
969                                        myDrp->frameData = lastPFrame;
970                                        glob->begin.lastPFrameData = nextPFrame;
971
972                                        if(redisplayFirstFrame)
973                                                myDrp->frameData = nextPFrame;
974                                }
975                               
976                                int displayType = glob->begin.lastFrameType;
977                                glob->begin.lastFrameType = type;
978                                type = displayType;
979                        }
980                        else if(type != FF_B_TYPE)
981                                glob->begin.lastPFrameData = myDrp->frameData;
982
983                        if(type == FF_I_TYPE && glob->packedType == PACKED_ALL_IN_FIRST_FRAME)
984                                /* Wipe memory of past P frames */
985                                glob->begin.futureType = 0;
986                       
987                        if(parsedBufSize < p->bufferSize)
988                        {
989                                int oldType = type;
990                               
991                                buffer += parsedBufSize;
992                                bufferSize -= parsedBufSize;
993                                int success = ffusionParse(glob->begin.parser, buffer, bufferSize, &parsedBufSize, &type, &skippable);
994                                if(success && type == FF_B_TYPE)
995                                {
996                                        /* A B frame follows us, so setup the P frame for the future and set dependencies */
997                                        glob->begin.futureType = oldType;
998                                        if(glob->begin.lastPFrameData != NULL)
999                                                /* Mark the next P or I frame, predictive decoding */
1000                                                glob->begin.lastPFrameData->nextFrame = myDrp->frameData;
1001                                        glob->begin.lastPFrameData = myDrp->frameData;
1002                                        myDrp->frameData = FFusionDataAppend(&(glob->data), buffer, parsedBufSize, type);
1003                                        myDrp->frameData->prereqFrame = glob->begin.lastPFrameData;
1004                                        buffer += parsedBufSize;
1005                                        bufferSize -= parsedBufSize;
1006                                }
1007                                if(bufferSize > 0)
1008                                        FFusionDataSetUnparsed(&(glob->data), buffer, bufferSize);
1009                                else
1010                                        FFusionDataReadUnparsed(&(glob->data));
1011                        }
1012                        else
1013                                FFusionDataReadUnparsed(&(glob->data));
1014                        myDrp->bufferSize = 0;
1015                }
1016                else
1017                {
1018                        myDrp->bufferSize = bufferSize;
1019                }
1020               
1021                drp->frameType = qtTypeForFrameInfo(drp->frameType, type, skippable);
1022                if(myDrp->frameData != NULL)
1023                {
1024                        myDrp->frameData->frameNumber = p->frameNumber;
1025                        myDrp->frameData->skippabble = skippable;
1026                }
1027        }
1028        else
1029                myDrp->bufferSize = p->bufferSize;
1030        glob->begin.lastFrame = p->frameNumber;
1031        if(drp->frameType == kCodecFrameTypeKey)
1032                glob->begin.lastIFrame = p->frameNumber;
1033        myDrp->frameNumber = p->frameNumber;
1034        myDrp->GOPStartFrameNumber = glob->begin.lastIFrame;
1035       
1036        glob->stats.type[drp->frameType].begin_calls++;
1037        RecomputeMaxCounts(glob);
1038        FFusionDebugPrint("%p BeginBand: frame #%d type %d. (%sskippable)\n", glob, myDrp->frameNumber, type, not(skippable));
1039       
1040    return noErr;
1041}
1042
1043static OSErr PrereqDecompress(FFusionGlobals glob, FrameData *prereq, AVCodecContext *context, long width, long height, AVFrame *picture)
1044{
1045        FFusionDebugPrint("%p prereq-decompressing frame #%d.\n", glob, prereq->frameNumber);
1046       
1047        FrameData *preprereq = FrameDataCheckPrereq(prereq);
1048        if(preprereq)
1049                PrereqDecompress(glob, preprereq, context, width, height, picture);
1050       
1051        unsigned char *dataPtr = (unsigned char *)prereq->buffer;
1052        int dataSize = prereq->dataSize;
1053       
1054        OSErr err = FFusionDecompress(glob, context, dataPtr, width, height, picture, dataSize);
1055       
1056        return err;
1057}
1058
1059pascal ComponentResult FFusionCodecDecodeBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, unsigned long flags)
1060{
1061        OSErr err = noErr;
1062        AVFrame tempFrame;
1063
1064    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1065       
1066        glob->stats.type[drp->frameType].decode_calls++;
1067        RecomputeMaxCounts(glob);
1068        FFusionDebugPrint("%p DecodeBand #%d qtType %d. (packed %d)\n", glob, myDrp->frameNumber, drp->frameType, glob->packedType);
1069       
1070        // QuickTime will drop H.264 frames when necessary if a sample dependency table exists
1071        // we don't want to flush buffers in that case.
1072        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && myDrp->frameNumber != glob->decode.lastFrame + 1)
1073        {
1074                /* Skipped some frames in here */
1075                FFusionDebugPrint("%p - frames skipped.\n", glob);
1076                if(drp->frameType == kCodecFrameTypeKey || myDrp->GOPStartFrameNumber > glob->decode.lastFrame || myDrp->frameNumber < glob->decode.lastFrame)
1077                {
1078                        /* 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) *
1079                         * then we are in a whole new GOP */
1080                        avcodec_flush_buffers(glob->avContext);
1081                }
1082        }
1083       
1084        if(myDrp->frameData && myDrp->frameData->decoded && glob->decode.futureBuffer != NULL)
1085        {
1086                myDrp->buffer = retainBuffer(glob, glob->decode.futureBuffer);
1087                myDrp->decoded = true;
1088#if 0   /* Need to make sure this frame's data is not eradicated during the decompress */
1089                FrameData *nextFrame = myDrp->frameData->nextFrame;
1090                if(nextFrame != NULL)
1091                {
1092                        FFusionDecompress(glob, glob->avContext, nextFrame->buffer, NULL, myDrp->width, myDrp->height, &tempFrame, nextFrame->dataSize);
1093                        if(tempFrame.data[0] != NULL)
1094                        {
1095                                glob->decode.futureBuffer = (FFusionBuffer *)tempFrame.opaque;
1096                                nextFrame->decoded = TRUE;
1097                        }
1098                }
1099                else
1100#endif
1101                        glob->decode.futureBuffer = NULL;
1102                FFusionDataMarkRead(myDrp->frameData);
1103                glob->decode.lastFrame = myDrp->frameNumber;
1104                return err;
1105        }
1106                       
1107        FrameData *frameData = NULL;
1108        unsigned char *dataPtr = NULL;
1109        unsigned int dataSize;
1110        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && myDrp->frameData != NULL && myDrp->frameData->decoded == 0)
1111        {
1112                /* Pull from our buffer */
1113                frameData = myDrp->frameData;
1114                FrameData *prereq = FrameDataCheckPrereq(frameData);
1115               
1116                if(prereq)
1117                {
1118                        PrereqDecompress(glob, prereq, glob->avContext, myDrp->width, myDrp->height, &tempFrame);
1119                        if(tempFrame.data[0] != NULL)
1120                        {
1121                                glob->decode.futureBuffer = (FFusionBuffer *)tempFrame.opaque;
1122                                prereq->decoded = TRUE;
1123                        }
1124                }
1125                dataPtr = (unsigned char *)frameData->buffer;
1126                dataSize = frameData->dataSize;
1127                frameData->decoded = TRUE;
1128        }
1129        else
1130        {
1131                /* data is already set up properly for us */
1132                dataSize = myDrp->bufferSize;
1133                dataPtr = FFusionCreateEntireDataBuffer(&(glob->data), (uint8_t *)drp->codecData, dataSize);
1134        }
1135               
1136        err = FFusionDecompress(glob, glob->avContext, dataPtr, myDrp->width, myDrp->height, &tempFrame, dataSize);
1137                       
1138        if (glob->packedType == PACKED_QUICKTIME_KNOWS_ORDER) {
1139                myDrp->buffer = &glob->buffers[glob->lastAllocatedBuffer];
1140                myDrp->buffer->frameNumber = myDrp->frameNumber;
1141                retainBuffer(glob, myDrp->buffer);
1142                myDrp->buffer->returnedFrame = tempFrame;
1143                myDrp->decoded = true;
1144                glob->decode.lastFrame = myDrp->frameNumber;
1145                return err;
1146        }
1147        if(tempFrame.data[0] == NULL)
1148                myDrp->buffer = NULL;
1149        else
1150                myDrp->buffer = retainBuffer(glob, (FFusionBuffer *)tempFrame.opaque);
1151       
1152        if(tempFrame.pict_type == FF_I_TYPE)
1153                /* Wipe memory of past P frames */
1154                glob->decode.futureBuffer = NULL;
1155        glob->decode.lastFrame = myDrp->frameNumber;
1156        myDrp->decoded = true;
1157        if (myDrp->buffer) myDrp->buffer->returnedFrame = tempFrame;
1158       
1159        FFusionDataMarkRead(frameData);
1160       
1161        return err;
1162}
1163
1164//-----------------------------------------------------------------
1165// ImageCodecDrawBand
1166//-----------------------------------------------------------------
1167// The base image decompressor calls your image decompressor
1168// component's ImageCodecDrawBand function to decompress a band or
1169// frame. Your component must implement this function. If the
1170// ImageSubCodecDecompressRecord structure specifies a progress function
1171// or data-loading function, the base image decompressor will never call
1172// ImageCodecDrawBand at interrupt time. If the ImageSubCodecDecompressRecord
1173// structure specifies a progress function, the base image decompressor
1174// handles codecProgressOpen and codecProgressClose calls, and your image
1175// decompressor component must not implement these functions.
1176// If not, the base image decompressor may call the ImageCodecDrawBand
1177// function at interrupt time. When the base image decompressor calls your
1178// ImageCodecDrawBand function, your component must perform the decompression
1179// specified by the fields of the ImageSubCodecDecompressRecord structure.
1180// The structure includes any changes your component made to it when
1181// performing the ImageCodecBeginBand function. If your component supports
1182// asynchronous scheduled decompression, it may receive more than one
1183// ImageCodecBeginBand call before receiving an ImageCodecDrawBand call.
1184//-----------------------------------------------------------------
1185
1186pascal ComponentResult FFusionCodecDrawBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp)
1187{
1188    OSErr err = noErr;
1189    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1190        AVFrame *picture;
1191       
1192        glob->stats.type[drp->frameType].draw_calls++;
1193        RecomputeMaxCounts(glob);
1194        FFusionDebugPrint("%p DrawBand #%d. (%sdecoded)\n", glob, myDrp->frameNumber, not(myDrp->decoded));
1195       
1196        if(!myDrp->decoded) {
1197                err = FFusionCodecDecodeBand(glob, drp, 0);
1198
1199                if (err) goto err;
1200        }
1201       
1202        if (myDrp->buffer)
1203        {
1204                picture = myDrp->buffer->frame;
1205        }
1206        else
1207                picture = &glob->lastDisplayedFrame;
1208       
1209        if(!picture || picture->data[0] == 0)
1210        {
1211                if(glob->shouldUseReturnedFrame && myDrp->buffer->returnedFrame.data[0])
1212                        //Some decoders (vp3) keep their internal buffers in an unusable state
1213                        picture = &myDrp->buffer->returnedFrame;
1214                else if(glob->lastDisplayedFrame.data[0] != NULL)
1215                        //Display last frame
1216                        picture = &glob->lastDisplayedFrame;
1217                else {
1218                        //Display black (no frame decoded yet)
1219
1220                        if (!glob->colorConv.clear) {
1221                                err = ColorConversionFindFor(&glob->colorConv, glob->avContext->pix_fmt, NULL, myDrp->pixelFormat);
1222                                if (err) goto err;
1223                        }
1224                       
1225                        glob->colorConv.clear((UInt8*)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height);
1226                        return noErr;
1227                }
1228        }
1229        else
1230        {
1231                if (myDrp->buffer)
1232                        glob->lastDisplayedFrame = *picture;
1233        }
1234       
1235        if (!glob->colorConv.convert) {
1236                err = ColorConversionFindFor(&glob->colorConv, glob->avContext->pix_fmt, picture, myDrp->pixelFormat);
1237                if (err) goto err;
1238        }
1239       
1240        glob->colorConv.convert(picture, (UInt8*)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height);
1241       
1242err:
1243    return err;
1244}
1245
1246//-----------------------------------------------------------------
1247// ImageCodecEndBand
1248//-----------------------------------------------------------------
1249// The ImageCodecEndBand function notifies your image decompressor
1250// component that decompression of a band has finished or
1251// that it was terminated by the Image Compression Manager. Your
1252// image decompressor component is not required to implement the
1253// ImageCodecEndBand function. The base image decompressor may call
1254// the ImageCodecEndBand function at interrupt time.
1255// After your image decompressor component handles an ImageCodecEndBand
1256// call, it can perform any tasks that are required when decompression
1257// is finished, such as disposing of data structures that are no longer
1258// needed. Because this function can be called at interrupt time, your
1259// component cannot use this function to dispose of data structures;
1260// this must occur after handling the function. The value of the result
1261// parameter should be set to noErr if the band or frame was
1262// drawn successfully.
1263// If it is any other value, the band or frame was not drawn.
1264//-----------------------------------------------------------------
1265
1266pascal ComponentResult FFusionCodecEndBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, OSErr result, long flags)
1267{
1268        FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1269        glob->stats.type[drp->frameType].end_calls++;
1270        FFusionBuffer *buf = myDrp->buffer;
1271        if(buf && buf->frame)
1272                releaseBuffer(glob->avContext, buf);
1273       
1274        FFusionDebugPrint("%p EndBand #%d.\n", glob, myDrp->frameNumber);
1275       
1276    return noErr;
1277}
1278
1279// Gamma curve value for FFusion video.
1280ComponentResult FFusionCodecGetSourceDataGammaLevel(FFusionGlobals glob, Fixed *sourceDataGammaLevel)
1281{
1282        enum AVColorTransferCharacteristic color_trc = AVCOL_TRC_UNSPECIFIED;
1283        float gamma;
1284       
1285        if (glob->avContext)
1286                color_trc = glob->avContext->color_trc;
1287       
1288        switch (color_trc) {
1289                case AVCOL_TRC_GAMMA28:
1290                        gamma = 2.8;
1291                        break;
1292                case AVCOL_TRC_GAMMA22:
1293                        gamma = 2.2;
1294                        break;
1295                default: // absolutely everything in the world will reach here
1296                        gamma = 1/.45; // and GAMMA22 is probably a typo for this anyway
1297        }
1298       
1299        *sourceDataGammaLevel = FloatToFixed(gamma);
1300        return noErr;
1301}
1302
1303//-----------------------------------------------------------------
1304// ImageCodecGetCodecInfo
1305//-----------------------------------------------------------------
1306// Your component receives the ImageCodecGetCodecInfo request whenever
1307// an application calls the Image Compression Manager's GetCodecInfo
1308// function.
1309// Your component should return a formatted compressor information
1310// structure defining its capabilities.
1311// Both compressors and decompressors may receive this request.
1312//-----------------------------------------------------------------
1313
1314pascal ComponentResult FFusionCodecGetCodecInfo(FFusionGlobals glob, CodecInfo *info)
1315{
1316        return getPerianCodecInfo(glob->self, glob->componentType, info);
1317}
1318
1319static int FFusionGetBuffer(AVCodecContext *s, AVFrame *pic)
1320{
1321        FFusionGlobals glob = s->opaque;
1322        int ret = avcodec_default_get_buffer(s, pic);
1323        int i;
1324       
1325        if (ret >= 0) {
1326                for (i = 0; i < FFUSION_MAX_BUFFERS; i++) {
1327                        if (!glob->buffers[i].retainCount) {
1328//                              FFusionDebugPrint("%p Starting Buffer %p.\n", glob, &glob->buffers[i]);
1329                                pic->opaque = &glob->buffers[i];
1330                                glob->buffers[i].frame = pic;
1331                                glob->buffers[i].retainCount = 1;
1332                                glob->buffers[i].ffmpegUsing = 1;
1333                                glob->lastAllocatedBuffer = i;
1334                                break;
1335                        }
1336                }
1337        }
1338       
1339        return ret;
1340}
1341
1342static void FFusionReleaseBuffer(AVCodecContext *s, AVFrame *pic)
1343{
1344//      FFusionGlobals glob = s->opaque;
1345        FFusionBuffer *buf = pic->opaque;
1346       
1347        if(buf->ffmpegUsing)
1348        {
1349                buf->ffmpegUsing = 0;
1350                releaseBuffer(s, buf);
1351        }
1352}
1353
1354static FFusionBuffer *retainBuffer(FFusionGlobals glob, FFusionBuffer *buf)
1355{
1356        buf->retainCount++;
1357//      FFusionDebugPrint("%p Retained Buffer %p #%d to %d.\n", glob, buf, buf->frameNumber, buf->retainCount);
1358        return buf;
1359}
1360
1361static void releaseBuffer(AVCodecContext *s, FFusionBuffer *buf)
1362{
1363        buf->retainCount--;
1364//      FFusionGlobals glob = (FFusionGlobals)s->opaque;
1365//      FFusionDebugPrint("%p Released Buffer %p #%d to %d.\n", glob, buf, buf->frameNumber, buf->retainCount);
1366        if(!buf->retainCount && !buf->ffmpegUsing)
1367        {
1368                buf->returnedFrame.data[0] = NULL;
1369                avcodec_default_release_buffer(s, buf->frame);
1370        }
1371}
1372
1373//-----------------------------------------------------------------
1374// FFusionDecompress
1375//-----------------------------------------------------------------
1376// This function calls libavcodec to decompress one frame.
1377//-----------------------------------------------------------------
1378
1379OSErr FFusionDecompress(FFusionGlobals glob, AVCodecContext *context, UInt8 *dataPtr, long width, long height, AVFrame *picture, long length)
1380{
1381    OSErr err = noErr;
1382    int got_picture = false;
1383    int len = 0;
1384       
1385        FFusionDebugPrint("%p Decompress %d bytes.\n", glob, length);
1386    avcodec_get_frame_defaults(picture);
1387       
1388        AVPacket pkt;
1389        av_init_packet(&pkt);
1390        pkt.data = dataPtr;
1391        pkt.size = length;
1392        len = avcodec_decode_video2(context, picture, &got_picture, &pkt);
1393       
1394        if (len < 0)
1395        {           
1396                Codecprintf(glob->fileLog, "Error while decoding frame\n");
1397        } 
1398       
1399        return err;
1400}
Note: See TracBrowser for help on using the repository browser.