source: trunk/FFusionCodec.c @ 1379

Revision 1379, 48.4 KB checked in by astrange, 4 years ago (diff)

Enable fftheora video decoder to fix Theora-in-MKV

This is easier than figuring out why XiphQT doesn't work.

As a side effect, delete half of MatroskaCodecIDs.cpp.
FFusionCodecPreflight() is approaching needing refactoring too.

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