source: trunk/FFusionCodec.c @ 1036

Revision 1036, 60.0 KB checked in by astrange, 6 years ago (diff)

Build system/logging:

  • Don't regenerate SubParsing?.m/ffmpeg universal libs if not needed
  • Print "Perian" instead of "Perian Codec"

Subtitles:

  • Rewrite SubSerializer?; much shorter and correct now (aside from line order).

(fixes many dropped lines in Live-eviL Captain Harlock and gg Sayonara Zetsubou Sensei)

  • Fix some bugs where line spans were rendered more than once with the wrong style.

(fixes transparency in Spice and Wolf 01 [ADTRW].mkv)

  • Ignore \blur properly

(fixes unstyled lines in [gg]_Goku_Sayonara_Zetsubou_Sensei_-_02_[D284BF24].mkv)

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