source: trunk/FFusionCodec.c @ 1223

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

Don't consider MPEG-4 N-VOPs to be a parse error.

Fixes some false warnings and corruption in some divx/xvid files.
Closes #302.

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                int skipped;
924               
925                if(glob->data.unparsedFrames.dataSize != 0)
926                {
927                        buffer = glob->data.unparsedFrames.buffer;
928                        bufferSize = glob->data.unparsedFrames.dataSize;
929                }
930               
931                if(ffusionParse(glob->begin.parser, buffer, bufferSize, &parsedBufSize, &type, &skippable, &skipped) == 0 && (!skipped || glob->begin.futureType))
932                {
933                        /* parse failed */
934                        myDrp->bufferSize = bufferSize;
935                        if(glob->begin.futureType != 0)
936                        {
937                                /* Assume our previously decoded P frame */
938                                type = glob->begin.futureType;
939                                glob->begin.futureType = 0;
940                                myDrp->frameData = glob->begin.lastPFrameData;
941                        }
942                        else
943                        {
944                                Codecprintf(glob->fileLog, "parse failed frame %d with size %d\n", p->frameNumber, bufferSize);
945                                if(glob->data.unparsedFrames.dataSize != 0)
946                                        Codecprintf(glob->fileLog, ", parser had extra data\n");                               
947                        }
948                }
949                else if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER)
950                {
951                        if(type == FF_B_TYPE && glob->packedType == PACKED_ALL_IN_FIRST_FRAME && glob->begin.futureType == 0)
952                                /* Badly framed.  We hit a B frame after it was supposed to be displayed, switch to delaying by a frame */
953                                glob->packedType = PACKED_DELAY_BY_ONE_FRAME;
954                        else if(glob->packedType == PACKED_DELAY_BY_ONE_FRAME && parsedBufSize < bufferSize - 16)
955                                /* Seems to be switching back to packed in one frame; switch back*/
956                                glob->packedType = PACKED_ALL_IN_FIRST_FRAME;
957                       
958                        myDrp->frameData = FFusionDataAppend(&(glob->data), buffer, parsedBufSize, type);
959                        if(type != FF_I_TYPE)
960                                myDrp->frameData->prereqFrame = glob->begin.lastPFrameData;
961                        if(glob->packedType == PACKED_DELAY_BY_ONE_FRAME)
962                        {
963                                if(type != FF_B_TYPE)
964                                {
965                                        FrameData *nextPFrame = myDrp->frameData;
966                                        FrameData *lastPFrame = glob->begin.lastPFrameData;
967                                        if(lastPFrame != NULL)
968                                                /* Mark the next P or I frame, predictive decoding */
969                                                lastPFrame->nextFrame = nextPFrame;
970                                        myDrp->frameData = lastPFrame;
971                                        glob->begin.lastPFrameData = nextPFrame;
972
973                                        if(redisplayFirstFrame)
974                                                myDrp->frameData = nextPFrame;
975                                }
976                               
977                                int displayType = glob->begin.lastFrameType;
978                                glob->begin.lastFrameType = type;
979                                type = displayType;
980                        }
981                        else if(type != FF_B_TYPE)
982                                glob->begin.lastPFrameData = myDrp->frameData;
983
984                        if(type == FF_I_TYPE && glob->packedType == PACKED_ALL_IN_FIRST_FRAME)
985                                /* Wipe memory of past P frames */
986                                glob->begin.futureType = 0;
987                       
988                        if(parsedBufSize < p->bufferSize)
989                        {
990                                int oldType = type;
991                               
992                                buffer += parsedBufSize;
993                                bufferSize -= parsedBufSize;
994                                int success = ffusionParse(glob->begin.parser, buffer, bufferSize, &parsedBufSize, &type, &skippable, &skipped);
995                                if(success && type == FF_B_TYPE)
996                                {
997                                        /* A B frame follows us, so setup the P frame for the future and set dependencies */
998                                        glob->begin.futureType = oldType;
999                                        if(glob->begin.lastPFrameData != NULL)
1000                                                /* Mark the next P or I frame, predictive decoding */
1001                                                glob->begin.lastPFrameData->nextFrame = myDrp->frameData;
1002                                        glob->begin.lastPFrameData = myDrp->frameData;
1003                                        myDrp->frameData = FFusionDataAppend(&(glob->data), buffer, parsedBufSize, type);
1004                                        myDrp->frameData->prereqFrame = glob->begin.lastPFrameData;
1005                                        buffer += parsedBufSize;
1006                                        bufferSize -= parsedBufSize;
1007                                }
1008                                if(bufferSize > 0)
1009                                        FFusionDataSetUnparsed(&(glob->data), buffer, bufferSize);
1010                                else
1011                                        FFusionDataReadUnparsed(&(glob->data));
1012                        }
1013                        else
1014                                FFusionDataReadUnparsed(&(glob->data));
1015                        myDrp->bufferSize = 0;
1016                }
1017                else
1018                {
1019                        myDrp->bufferSize = bufferSize;
1020                }
1021               
1022                drp->frameType = qtTypeForFrameInfo(drp->frameType, type, skippable);
1023                if(myDrp->frameData != NULL)
1024                {
1025                        myDrp->frameData->frameNumber = p->frameNumber;
1026                        myDrp->frameData->skippabble = skippable;
1027                }
1028        }
1029        else
1030                myDrp->bufferSize = p->bufferSize;
1031        glob->begin.lastFrame = p->frameNumber;
1032        if(drp->frameType == kCodecFrameTypeKey)
1033                glob->begin.lastIFrame = p->frameNumber;
1034        myDrp->frameNumber = p->frameNumber;
1035        myDrp->GOPStartFrameNumber = glob->begin.lastIFrame;
1036       
1037        glob->stats.type[drp->frameType].begin_calls++;
1038        RecomputeMaxCounts(glob);
1039        FFusionDebugPrint("%p BeginBand: frame #%d type %d. (%sskippable)\n", glob, myDrp->frameNumber, type, not(skippable));
1040       
1041    return noErr;
1042}
1043
1044static OSErr PrereqDecompress(FFusionGlobals glob, FrameData *prereq, AVCodecContext *context, long width, long height, AVFrame *picture)
1045{
1046        FFusionDebugPrint("%p prereq-decompressing frame #%d.\n", glob, prereq->frameNumber);
1047       
1048        FrameData *preprereq = FrameDataCheckPrereq(prereq);
1049        if(preprereq)
1050                PrereqDecompress(glob, preprereq, context, width, height, picture);
1051       
1052        unsigned char *dataPtr = (unsigned char *)prereq->buffer;
1053        int dataSize = prereq->dataSize;
1054       
1055        OSErr err = FFusionDecompress(glob, context, dataPtr, width, height, picture, dataSize);
1056       
1057        return err;
1058}
1059
1060pascal ComponentResult FFusionCodecDecodeBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, unsigned long flags)
1061{
1062        OSErr err = noErr;
1063        AVFrame tempFrame;
1064
1065    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1066       
1067        glob->stats.type[drp->frameType].decode_calls++;
1068        RecomputeMaxCounts(glob);
1069        FFusionDebugPrint("%p DecodeBand #%d qtType %d. (packed %d)\n", glob, myDrp->frameNumber, drp->frameType, glob->packedType);
1070       
1071        // QuickTime will drop H.264 frames when necessary if a sample dependency table exists
1072        // we don't want to flush buffers in that case.
1073        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && myDrp->frameNumber != glob->decode.lastFrame + 1)
1074        {
1075                /* Skipped some frames in here */
1076                FFusionDebugPrint("%p - frames skipped.\n", glob);
1077                if(drp->frameType == kCodecFrameTypeKey || myDrp->GOPStartFrameNumber > glob->decode.lastFrame || myDrp->frameNumber < glob->decode.lastFrame)
1078                {
1079                        /* 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) *
1080                         * then we are in a whole new GOP */
1081                        avcodec_flush_buffers(glob->avContext);
1082                }
1083        }
1084       
1085        if(myDrp->frameData && myDrp->frameData->decoded && glob->decode.futureBuffer != NULL)
1086        {
1087                myDrp->buffer = retainBuffer(glob, glob->decode.futureBuffer);
1088                myDrp->decoded = true;
1089#if 0   /* Need to make sure this frame's data is not eradicated during the decompress */
1090                FrameData *nextFrame = myDrp->frameData->nextFrame;
1091                if(nextFrame != NULL)
1092                {
1093                        FFusionDecompress(glob, glob->avContext, nextFrame->buffer, NULL, myDrp->width, myDrp->height, &tempFrame, nextFrame->dataSize);
1094                        if(tempFrame.data[0] != NULL)
1095                        {
1096                                glob->decode.futureBuffer = (FFusionBuffer *)tempFrame.opaque;
1097                                nextFrame->decoded = TRUE;
1098                        }
1099                }
1100                else
1101#endif
1102                        glob->decode.futureBuffer = NULL;
1103                FFusionDataMarkRead(myDrp->frameData);
1104                glob->decode.lastFrame = myDrp->frameNumber;
1105                return err;
1106        }
1107                       
1108        FrameData *frameData = NULL;
1109        unsigned char *dataPtr = NULL;
1110        unsigned int dataSize;
1111        if(glob->packedType != PACKED_QUICKTIME_KNOWS_ORDER && myDrp->frameData != NULL && myDrp->frameData->decoded == 0)
1112        {
1113                /* Pull from our buffer */
1114                frameData = myDrp->frameData;
1115                FrameData *prereq = FrameDataCheckPrereq(frameData);
1116               
1117                if(prereq)
1118                {
1119                        PrereqDecompress(glob, prereq, glob->avContext, myDrp->width, myDrp->height, &tempFrame);
1120                        if(tempFrame.data[0] != NULL)
1121                        {
1122                                glob->decode.futureBuffer = (FFusionBuffer *)tempFrame.opaque;
1123                                prereq->decoded = TRUE;
1124                        }
1125                }
1126                dataPtr = (unsigned char *)frameData->buffer;
1127                dataSize = frameData->dataSize;
1128                frameData->decoded = TRUE;
1129        }
1130        else
1131        {
1132                /* data is already set up properly for us */
1133                dataSize = myDrp->bufferSize;
1134                dataPtr = FFusionCreateEntireDataBuffer(&(glob->data), (uint8_t *)drp->codecData, dataSize);
1135        }
1136               
1137        err = FFusionDecompress(glob, glob->avContext, dataPtr, myDrp->width, myDrp->height, &tempFrame, dataSize);
1138                       
1139        if (glob->packedType == PACKED_QUICKTIME_KNOWS_ORDER) {
1140                myDrp->buffer = &glob->buffers[glob->lastAllocatedBuffer];
1141                myDrp->buffer->frameNumber = myDrp->frameNumber;
1142                retainBuffer(glob, myDrp->buffer);
1143                myDrp->buffer->returnedFrame = tempFrame;
1144                myDrp->decoded = true;
1145                glob->decode.lastFrame = myDrp->frameNumber;
1146                return err;
1147        }
1148        if(tempFrame.data[0] == NULL)
1149                myDrp->buffer = NULL;
1150        else
1151                myDrp->buffer = retainBuffer(glob, (FFusionBuffer *)tempFrame.opaque);
1152       
1153        if(tempFrame.pict_type == FF_I_TYPE)
1154                /* Wipe memory of past P frames */
1155                glob->decode.futureBuffer = NULL;
1156        glob->decode.lastFrame = myDrp->frameNumber;
1157        myDrp->decoded = true;
1158        if (myDrp->buffer) myDrp->buffer->returnedFrame = tempFrame;
1159       
1160        FFusionDataMarkRead(frameData);
1161       
1162        return err;
1163}
1164
1165//-----------------------------------------------------------------
1166// ImageCodecDrawBand
1167//-----------------------------------------------------------------
1168// The base image decompressor calls your image decompressor
1169// component's ImageCodecDrawBand function to decompress a band or
1170// frame. Your component must implement this function. If the
1171// ImageSubCodecDecompressRecord structure specifies a progress function
1172// or data-loading function, the base image decompressor will never call
1173// ImageCodecDrawBand at interrupt time. If the ImageSubCodecDecompressRecord
1174// structure specifies a progress function, the base image decompressor
1175// handles codecProgressOpen and codecProgressClose calls, and your image
1176// decompressor component must not implement these functions.
1177// If not, the base image decompressor may call the ImageCodecDrawBand
1178// function at interrupt time. When the base image decompressor calls your
1179// ImageCodecDrawBand function, your component must perform the decompression
1180// specified by the fields of the ImageSubCodecDecompressRecord structure.
1181// The structure includes any changes your component made to it when
1182// performing the ImageCodecBeginBand function. If your component supports
1183// asynchronous scheduled decompression, it may receive more than one
1184// ImageCodecBeginBand call before receiving an ImageCodecDrawBand call.
1185//-----------------------------------------------------------------
1186
1187pascal ComponentResult FFusionCodecDrawBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp)
1188{
1189    OSErr err = noErr;
1190    FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1191        AVFrame *picture;
1192       
1193        glob->stats.type[drp->frameType].draw_calls++;
1194        RecomputeMaxCounts(glob);
1195        FFusionDebugPrint("%p DrawBand #%d. (%sdecoded)\n", glob, myDrp->frameNumber, not(myDrp->decoded));
1196       
1197        if(!myDrp->decoded) {
1198                err = FFusionCodecDecodeBand(glob, drp, 0);
1199
1200                if (err) goto err;
1201        }
1202       
1203        if (myDrp->buffer)
1204        {
1205                picture = myDrp->buffer->frame;
1206        }
1207        else
1208                picture = &glob->lastDisplayedFrame;
1209       
1210        if(!picture || picture->data[0] == 0)
1211        {
1212                if(glob->shouldUseReturnedFrame && myDrp->buffer->returnedFrame.data[0])
1213                        //Some decoders (vp3) keep their internal buffers in an unusable state
1214                        picture = &myDrp->buffer->returnedFrame;
1215                else if(glob->lastDisplayedFrame.data[0] != NULL)
1216                        //Display last frame
1217                        picture = &glob->lastDisplayedFrame;
1218                else {
1219                        //Display black (no frame decoded yet)
1220
1221                        if (!glob->colorConv.clear) {
1222                                err = ColorConversionFindFor(&glob->colorConv, glob->avContext->pix_fmt, NULL, myDrp->pixelFormat);
1223                                if (err) goto err;
1224                        }
1225                       
1226                        glob->colorConv.clear((UInt8*)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height);
1227                        return noErr;
1228                }
1229        }
1230        else
1231        {
1232                if (myDrp->buffer)
1233                        glob->lastDisplayedFrame = *picture;
1234        }
1235       
1236        if (!glob->colorConv.convert) {
1237                err = ColorConversionFindFor(&glob->colorConv, glob->avContext->pix_fmt, picture, myDrp->pixelFormat);
1238                if (err) goto err;
1239        }
1240       
1241        glob->colorConv.convert(picture, (UInt8*)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height);
1242       
1243err:
1244    return err;
1245}
1246
1247//-----------------------------------------------------------------
1248// ImageCodecEndBand
1249//-----------------------------------------------------------------
1250// The ImageCodecEndBand function notifies your image decompressor
1251// component that decompression of a band has finished or
1252// that it was terminated by the Image Compression Manager. Your
1253// image decompressor component is not required to implement the
1254// ImageCodecEndBand function. The base image decompressor may call
1255// the ImageCodecEndBand function at interrupt time.
1256// After your image decompressor component handles an ImageCodecEndBand
1257// call, it can perform any tasks that are required when decompression
1258// is finished, such as disposing of data structures that are no longer
1259// needed. Because this function can be called at interrupt time, your
1260// component cannot use this function to dispose of data structures;
1261// this must occur after handling the function. The value of the result
1262// parameter should be set to noErr if the band or frame was
1263// drawn successfully.
1264// If it is any other value, the band or frame was not drawn.
1265//-----------------------------------------------------------------
1266
1267pascal ComponentResult FFusionCodecEndBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, OSErr result, long flags)
1268{
1269        FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
1270        glob->stats.type[drp->frameType].end_calls++;
1271        FFusionBuffer *buf = myDrp->buffer;
1272        if(buf && buf->frame)
1273                releaseBuffer(glob->avContext, buf);
1274       
1275        FFusionDebugPrint("%p EndBand #%d.\n", glob, myDrp->frameNumber);
1276       
1277    return noErr;
1278}
1279
1280// Gamma curve value for FFusion video.
1281ComponentResult FFusionCodecGetSourceDataGammaLevel(FFusionGlobals glob, Fixed *sourceDataGammaLevel)
1282{
1283        enum AVColorTransferCharacteristic color_trc = AVCOL_TRC_UNSPECIFIED;
1284        float gamma;
1285       
1286        if (glob->avContext)
1287                color_trc = glob->avContext->color_trc;
1288       
1289        switch (color_trc) {
1290                case AVCOL_TRC_GAMMA28:
1291                        gamma = 2.8;
1292                        break;
1293                case AVCOL_TRC_GAMMA22:
1294                        gamma = 2.2;
1295                        break;
1296                default: // absolutely everything in the world will reach here
1297                        gamma = 1/.45; // and GAMMA22 is probably a typo for this anyway
1298        }
1299       
1300        *sourceDataGammaLevel = FloatToFixed(gamma);
1301        return noErr;
1302}
1303
1304//-----------------------------------------------------------------
1305// ImageCodecGetCodecInfo
1306//-----------------------------------------------------------------
1307// Your component receives the ImageCodecGetCodecInfo request whenever
1308// an application calls the Image Compression Manager's GetCodecInfo
1309// function.
1310// Your component should return a formatted compressor information
1311// structure defining its capabilities.
1312// Both compressors and decompressors may receive this request.
1313//-----------------------------------------------------------------
1314
1315pascal ComponentResult FFusionCodecGetCodecInfo(FFusionGlobals glob, CodecInfo *info)
1316{
1317        return getPerianCodecInfo(glob->self, glob->componentType, info);
1318}
1319
1320static int FFusionGetBuffer(AVCodecContext *s, AVFrame *pic)
1321{
1322        FFusionGlobals glob = s->opaque;
1323        int ret = avcodec_default_get_buffer(s, pic);
1324        int i;
1325       
1326        if (ret >= 0) {
1327                for (i = 0; i < FFUSION_MAX_BUFFERS; i++) {
1328                        if (!glob->buffers[i].retainCount) {
1329//                              FFusionDebugPrint("%p Starting Buffer %p.\n", glob, &glob->buffers[i]);
1330                                pic->opaque = &glob->buffers[i];
1331                                glob->buffers[i].frame = pic;
1332                                glob->buffers[i].retainCount = 1;
1333                                glob->buffers[i].ffmpegUsing = 1;
1334                                glob->lastAllocatedBuffer = i;
1335                                break;
1336                        }
1337                }
1338        }
1339       
1340        return ret;
1341}
1342
1343static void FFusionReleaseBuffer(AVCodecContext *s, AVFrame *pic)
1344{
1345//      FFusionGlobals glob = s->opaque;
1346        FFusionBuffer *buf = pic->opaque;
1347       
1348        if(buf->ffmpegUsing)
1349        {
1350                buf->ffmpegUsing = 0;
1351                releaseBuffer(s, buf);
1352        }
1353}
1354
1355static FFusionBuffer *retainBuffer(FFusionGlobals glob, FFusionBuffer *buf)
1356{
1357        buf->retainCount++;
1358//      FFusionDebugPrint("%p Retained Buffer %p #%d to %d.\n", glob, buf, buf->frameNumber, buf->retainCount);
1359        return buf;
1360}
1361
1362static void releaseBuffer(AVCodecContext *s, FFusionBuffer *buf)
1363{
1364        buf->retainCount--;
1365//      FFusionGlobals glob = (FFusionGlobals)s->opaque;
1366//      FFusionDebugPrint("%p Released Buffer %p #%d to %d.\n", glob, buf, buf->frameNumber, buf->retainCount);
1367        if(!buf->retainCount && !buf->ffmpegUsing)
1368        {
1369                buf->returnedFrame.data[0] = NULL;
1370                avcodec_default_release_buffer(s, buf->frame);
1371        }
1372}
1373
1374//-----------------------------------------------------------------
1375// FFusionDecompress
1376//-----------------------------------------------------------------
1377// This function calls libavcodec to decompress one frame.
1378//-----------------------------------------------------------------
1379
1380OSErr FFusionDecompress(FFusionGlobals glob, AVCodecContext *context, UInt8 *dataPtr, long width, long height, AVFrame *picture, long length)
1381{
1382    OSErr err = noErr;
1383    int got_picture = false;
1384    int len = 0;
1385       
1386        FFusionDebugPrint("%p Decompress %d bytes.\n", glob, length);
1387    avcodec_get_frame_defaults(picture);
1388       
1389        AVPacket pkt;
1390        av_init_packet(&pkt);
1391        pkt.data = dataPtr;
1392        pkt.size = length;
1393        len = avcodec_decode_video2(context, picture, &got_picture, &pkt);
1394       
1395        if (len < 0)
1396        {           
1397                Codecprintf(glob->fileLog, "Error while decoding frame\n");
1398        } 
1399       
1400        return err;
1401}
Note: See TracBrowser for help on using the repository browser.