source: trunk/FFusionCodec.c @ 1371

Revision 1371, 48.4 KB checked in by astrange, 3 years ago (diff)

FFusion: Pass AVFrame to release_buffer

AVFrames can be copied, in which case using opaque->frame released the wrong
copy of the frame. This caused vp3 to crash on the second frame.

Refs #499

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