source: trunk/FFusionCodec.c @ 1152

Revision 1152, 56.8 KB checked in by astrange, 5 years ago (diff)

Fix being able to decode anything at all.

It didn't set codec_tag and codec_id before
avcodec_open, which is checked now.

(although it makes no sense to check this, maybe
it'll be reverted)

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