root/tags/perian-0.5/FFusionCodec.c

Revision 73, 51.4 kB (checked in by anonymous, 2 years ago)

Fix a small memory leak.

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 program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
17 //
18 // This program 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
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 //
27 //---------------------------------------------------------------------------
28 // Source Code
29 //---------------------------------------------------------------------------
30
31 #include <Carbon/Carbon.h>
32 #include <QuickTime/QuickTime.h>
33
34 #include "FFusionCodec.h"
35 #include "EI_Image.h"
36 #include "avcodec.h"
37 #include "postprocess.h"
38 #include "bswap.h"
39 #include "Codecprintf.h"
40
41 #ifdef __BIG_ENDIAN__
42 #define make_big_32(x) (x)
43 #else
44 #ifdef __LITTLE_ENDIAN__
45 #define make_big_32(x) bswap_32(x)
46 #else
47 #error Endian is unknown
48 #endif //Little
49 #endif //Big
50
51 void inline swapFrame(AVFrame * *a, AVFrame * *b)
52 {
53         AVFrame *t = *a;
54         *a = *b;
55         *b = t;
56 }
57
58 //---------------------------------------------------------------------------
59 // Types
60 //---------------------------------------------------------------------------
61
62 typedef struct
63 {
64     pp_mode_t                   *mode[PP_QUALITY_MAX+1];
65     pp_context_t                *context;
66     short                       goodness;
67     short                       level;
68 } PostProcParamRecord;
69
70 typedef struct
71 {
72     ComponentInstance           self;
73     ComponentInstance           delegateComponent;
74     ComponentInstance           target;
75     ImageCodecMPDrawBandUPP     drawBandUPP;
76     Handle                      pixelTypes;
77     AVCodec                     *avCodec;
78     AVCodecContext      *avContext;
79     AVFrame                     *picture;
80         AVFrame                 *futureFrame;
81         int                             lastFrameNumber;
82         uint64_t                lastFramePts;
83     OSType                      componentType;
84     char                        hasy420;
85     char                        alreadyDonePPPref;
86     PostProcParamRecord         postProcParams;
87         FILE                    *fileLog;
88         int                             futureFrameAvailable;
89         int                             delayedFrames;
90         AVFrame                 lastDisplayedFrame;
91 } FFusionGlobalsRecord, *FFusionGlobals;
92
93 typedef struct
94 {
95     long                        width;
96     long                        height;
97     long                        depth;
98     OSType                      pixelFormat;
99     long                        bufferSize;
100         int                             decoded;
101         long                    frameNumber;
102         int                             useFuture;
103 } FFusionDecompressRecord;
104
105
106 //---------------------------------------------------------------------------
107 // Prototypes of private subroutines
108 //---------------------------------------------------------------------------
109
110 static OSErr FFusionDecompress(AVCodecContext *context, UInt8 *dataPtr, ICMDataProcRecordPtr dataProc, long width, long height, AVFrame *picture, long length, int useFirstFrameHack);
111 static void FastY420(UInt8 *baseAddr, AVFrame *picture);
112 static void SlowY420(UInt8 *baseAddr, long rowBump, long width, long height, AVFrame *picture);
113 static void BGR24toRGB24(UInt8 *baseAddr, long rowBump, long width, long height, AVFrame *picture);
114
115 int GetPPUserPreference();
116 void SetPPUserPreference(int value);
117 pascal OSStatus HandlePPDialogWindowEvent(EventHandlerCallRef  nextHandler, EventRef theEvent, void* userData);
118 pascal OSStatus HandlePPDialogControlEvent(EventHandlerCallRef  nextHandler, EventRef theEvent, void* userData);
119 void ChangeHintText(int value, ControlRef staticTextField);
120
121 extern void initLib();
122
123 //---------------------------------------------------------------------------
124 // Component Dispatcher
125 //---------------------------------------------------------------------------
126
127 #define IMAGECODEC_BASENAME()           FFusionCodec
128 #define IMAGECODEC_GLOBALS()            FFusionGlobals storage
129
130 #define CALLCOMPONENT_BASENAME()        IMAGECODEC_BASENAME()
131 #define CALLCOMPONENT_GLOBALS()         IMAGECODEC_GLOBALS()
132
133 #define COMPONENT_UPP_PREFIX()          uppImageCodec
134 #define COMPONENT_DISPATCH_FILE         "FFusionCodecDispatch.h"
135 #define COMPONENT_SELECT_PREFIX()       kImageCodec
136
137 #define GET_DELEGATE_COMPONENT()        (storage->delegateComponent)
138
139 #include <QuickTime/ImageCodec.k.h>
140 #include <QuickTime/ComponentDispatchHelper.c>
141
142 //---------------------------------------------------------------------------
143 // Component Routines
144 //---------------------------------------------------------------------------
145
146 // -- This Image Decompressor Use the Base Image Decompressor Component --
147 //      The base image decompressor is an Apple-supplied component
148 //      that makes it easier for developers to create new decompressors.
149 //      The base image decompressor does most of the housekeeping and
150 //      interface functions required for a QuickTime decompressor component,
151 //      including scheduling for asynchronous decompression.
152
153 //-----------------------------------------------------------------
154 // Component Open Request - Required
155 //-----------------------------------------------------------------
156
157 pascal ComponentResult FFusionCodecOpen(FFusionGlobals glob, ComponentInstance self)
158 {
159     ComponentResult err;
160     ComponentDescription descout;
161     ComponentDescription cd;
162     Component c = 0;
163     long bitfield;
164        
165     cd.componentType = 'imdc';
166     cd.componentSubType = 'y420';
167     cd.componentManufacturer = 0;
168     cd.componentFlags = 0;
169     cd.componentFlagsMask = 0;
170    
171     GetComponentInfo((Component)self, &descout, 0, 0, 0);
172        
173     Codecprintf(NULL, "Opening component for type");
174     FourCCprintf(" ", descout.componentSubType);
175        
176     // Allocate memory for our globals, set them up and inform the component manager that we've done so
177        
178     glob = (FFusionGlobals)NewPtrClear(sizeof(FFusionGlobalsRecord));
179    
180     if (err = MemError())
181     {
182         Codecprintf(NULL, "Unable to allocate globals! Exiting.\n");           
183     }
184     else
185     {
186         SetComponentInstanceStorage(self, (Handle)glob);
187        
188         glob->self = self;
189         glob->target = self;
190         glob->drawBandUPP = NULL;
191         glob->pixelTypes = NewHandle(10 * sizeof(OSType));
192         glob->avCodec = 0;
193         glob->hasy420 = 0;
194                 glob->lastFrameNumber = 0;
195                 glob->lastFramePts = 0;
196         glob->alreadyDonePPPref = 0;
197         glob->componentType = descout.componentSubType;
198 #ifdef FILELOG
199                 glob->fileLog = fopen("/tmp/perian.log", "a");
200 #else
201                 glob->fileLog = NULL;
202 #endif
203                
204 //        c = FindNextComponent(c, &cd);
205                
206         if (c != 0)
207         {           
208             Gestalt(gestaltSystemVersion, &bitfield);
209            
210             if (bitfield >= 0x1010)
211             {
212                 Codecprintf(glob->fileLog, "Use speedy y420 component\n");
213                 glob->hasy420 = 1;
214             }
215         }
216         else
217         {
218             Codecprintf(glob->fileLog, "Use slow y420 component\n");
219         }
220                
221         // Open and target an instance of the base decompressor as we delegate
222         // most of our calls to the base decompressor instance
223        
224         err = OpenADefaultComponent(decompressorComponentType, kBaseCodecType, &glob->delegateComponent);
225         if (!err)
226         {
227             ComponentSetTarget(glob->delegateComponent, self);
228         }
229         else
230         {
231             Codecprintf(glob->fileLog, "Error opening the base image decompressor! Exiting.\n");
232         }
233     }
234    
235     return err;
236 }
237
238 //-----------------------------------------------------------------
239 // Component Close Request - Required
240 //-----------------------------------------------------------------
241
242 pascal ComponentResult FFusionCodecClose(FFusionGlobals glob, ComponentInstance self)
243 {
244     // Make sure to close the base component and dealocate our storage
245     int i;
246    
247     if (glob)
248     {
249         if (glob->delegateComponent)
250         {
251             CloseComponent(glob->delegateComponent);
252         }
253        
254         if (glob->drawBandUPP)
255         {
256             DisposeImageCodecMPDrawBandUPP(glob->drawBandUPP);
257         }
258        
259         if (glob->avCodec)
260         {
261             avcodec_close(glob->avContext);
262         }
263                
264         if (glob->picture)
265         {
266             av_free(glob->picture);
267         }
268                
269                 if (glob->futureFrame)
270                 {
271                         av_free(glob->futureFrame);
272                 }
273                
274         if (glob->avContext)
275         {
276             av_free(glob->avContext);
277         }
278                
279                 if (glob->pixelTypes)
280                 {
281                         DisposeHandle(glob->pixelTypes);
282                 }
283        
284         for (i=0; i<=PP_QUALITY_MAX; i++)
285         {
286             if (glob->postProcParams.mode[i])
287                 pp_free_mode(glob->postProcParams.mode[i]);
288         }
289                
290         if (glob->postProcParams.context)
291             pp_free_context(glob->postProcParams.context);
292                 if(glob->fileLog)
293                         fclose(glob->fileLog);
294                
295         DisposePtr((Ptr)glob);
296     }
297        
298     return noErr;
299 }
300
301 //-----------------------------------------------------------------
302 // Component Version Request - Required
303 //-----------------------------------------------------------------
304
305 pascal ComponentResult FFusionCodecVersion(FFusionGlobals glob)
306 {
307     return kFFusionCodecVersion;
308 }
309
310 //-----------------------------------------------------------------
311 // Component Target Request
312 //-----------------------------------------------------------------
313 // Allows another component to "target" you i.e., you call
314 // another component whenever you would call yourself (as a result
315 // of your component being used by another component)
316 //-----------------------------------------------------------------
317
318 pascal ComponentResult FFusionCodecTarget(FFusionGlobals glob, ComponentInstance target)
319 {
320     glob->target = target;
321        
322     return noErr;
323 }
324
325 //-----------------------------------------------------------------
326 // Component GetMPWorkFunction Request
327 //-----------------------------------------------------------------
328 // Allows your image decompressor component to perform asynchronous
329 // decompression in a single MP task by taking advantage of the
330 // Base Decompressor. If you implement this selector, your DrawBand
331 // function must be MP-safe. MP safety means not calling routines
332 // that may move or purge memory and not calling any routines which
333 // might cause 68K code to be executed. Ideally, your DrawBand
334 // function should not make any API calls whatsoever. Obviously
335 // don't implement this if you're building a 68k component.
336 //-----------------------------------------------------------------
337
338 pascal ComponentResult FFusionCodecGetMPWorkFunction(FFusionGlobals glob, ComponentMPWorkFunctionUPP *workFunction, void **refCon)
339 {
340         if (glob->drawBandUPP == NULL)
341                 glob->drawBandUPP = NewImageCodecMPDrawBandUPP((ImageCodecMPDrawBandProcPtr)FFusionCodecDrawBand);
342        
343         return ImageCodecGetBaseMPWorkFunction(glob->delegateComponent, workFunction, refCon, glob->drawBandUPP, glob);
344 }
345
346 //-----------------------------------------------------------------
347 // ImageCodecInitialize
348 //-----------------------------------------------------------------
349 // The first function call that your image decompressor component
350 // receives from the base image decompressor is always a call to
351 // ImageCodecInitialize . In response to this call, your image
352 // decompressor component returns an ImageSubCodecDecompressCapabilities
353 // structure that specifies its capabilities.
354 //-----------------------------------------------------------------
355
356 pascal ComponentResult FFusionCodecInitialize(FFusionGlobals glob, ImageSubCodecDecompressCapabilities *cap)
357 {
358        
359     // Secifies the size of the ImageSubCodecDecompressRecord structure
360     // and say we can support asyncronous decompression
361     // With the help of the base image decompressor, any image decompressor
362     // that uses only interrupt-safe calls for decompression operations can
363     // support asynchronous decompression.
364        
365     cap->decompressRecordSize = sizeof(FFusionDecompressRecord);
366     cap->canAsync = true;
367        
368         // QT 7
369         if(cap->recordSize > offsetof(ImageSubCodecDecompressCapabilities, baseCodecShouldCallDecodeBandForAllFrames))
370         {
371                 cap->subCodecIsMultiBufferAware = true;
372                 cap->subCodecSupportsOutOfOrderDisplayTimes = true;
373                 cap->baseCodecShouldCallDecodeBandForAllFrames = true;
374         }
375        
376     return noErr;
377 }
378
379 //-----------------------------------------------------------------
380 // ImageCodecPreflight
381 //-----------------------------------------------------------------
382 // The base image decompressor gets additional information about the
383 // capabilities of your image decompressor component by calling
384 // ImageCodecPreflight. The base image decompressor uses this
385 // information when responding to a call to the ImageCodecPredecompress
386 // function, which the ICM makes before decompressing an image. You
387 // are required only to provide values for the wantedDestinationPixelSize
388 // and wantedDestinationPixelTypes fields and can also modify other
389 // fields if necessary.
390 //-----------------------------------------------------------------
391
392 pascal ComponentResult FFusionCodecPreflight(FFusionGlobals glob, CodecDecompressParams *p)
393 {
394     OSType *pos;
395     int index, i;
396     CodecCapabilities *capabilities = p->capabilities;
397     long bitfield;
398     char altivec = 0;
399     Byte* myptr;
400        
401     // We first open libavcodec library and the codec corresponding
402     // to the fourCC if it has not been done before
403    
404     if (!glob->avCodec)
405     {
406                 initLib();
407                
408         switch (glob->componentType)
409         {
410             case 'MPG4':        // MS-MPEG4 v1
411             case 'mpg4':
412             case 'DIV1':
413             case 'div1':
414                 glob->avCodec = avcodec_find_decoder(CODEC_ID_MSMPEG4V1);
415                                 break;
416                                
417             case 'MP42':        // MS-MPEG4 v2
418             case 'mp42':
419             case 'DIV2':
420             case 'div2':
421                 glob->avCodec = avcodec_find_decoder(CODEC_ID_MSMPEG4V2);
422                                 break;
423                                
424             case 'div6':        // DivX 3
425             case 'DIV6':
426             case 'div5':
427             case 'DIV5':
428             case 'div4':
429             case 'DIV4':
430             case 'div3':
431             case 'DIV3':
432             case 'MP43':
433             case 'mp43':
434             case 'MPG3':
435             case 'mpg3':
436             case 'AP41':
437             case 'COL0':
438             case 'col0':
439             case 'COL1':
440             case 'col1':
441             case '3IVD':        // 3ivx
442             case '3ivd':
443                 glob->avCodec = avcodec_find_decoder(CODEC_ID_MSMPEG4V3);
444                                 break;
445                                
446             case 'divx':        // DivX 4
447             case 'DIVX':
448             case 'mp4s':
449             case 'MP4S':
450             case 'm4s2':
451             case 'M4S2':
452             case 0x04000000:
453             case 'UMP4':
454             case 'DX50':        // DivX 5
455             case 'XVID':        // XVID
456             case 'xvid':
457             case 'XviD':
458             case 'XVIX':
459             case 'BLZ0':
460             case '3IV2':        // 3ivx
461             case '3iv2':
462                         case 'RMP4':    // Miscellaneous
463                         case 'SEDG':
464                         case 'WV1F':
465                         case 'FMP4':
466                         case 'SMP4':
467                 glob->avCodec = avcodec_find_decoder(CODEC_ID_MPEG4);
468                                 break;
469                         case 'H264':    // H.264
470                         case 'h264':
471                         case 'X264':
472                         case 'x264':
473                         case 'DAVC':
474                         case 'VSSH':
475                                 glob->avCodec = avcodec_find_decoder(CODEC_ID_H264);
476                                 break;
477                         case 'FLV1':
478                                 glob->avCodec = avcodec_find_decoder(CODEC_ID_FLV1);
479                                 break;
480                         case 'FSV1':
481                                 glob->avCodec = avcodec_find_decoder(CODEC_ID_FLASHSV);
482                                 break;
483                         case 'VP62':
484                                 glob->avCodec = avcodec_find_decoder(CODEC_ID_VP6);
485                                 break;
486                         case 'VP6F':
487                                 glob->avCodec = avcodec_find_decoder(CODEC_ID_VP6F);
488                                 break;
489             default:
490                         Codecprintf(glob->fileLog, "Warning! Unknown codec type! Using MPEG4 by default.\n");
491                
492                 glob->avCodec = avcodec_find_decoder(CODEC_ID_MPEG4);
493         }
494        
495         // libavcodec version 0.4.6 and higher uses AVFrame instead of AVPicture
496         // It is better to handle the frame with a pointer and to use built-in
497         // allocation function
498        
499         glob->picture = avcodec_alloc_frame();
500                 glob->futureFrame = avcodec_alloc_frame();
501        
502         // we do the same for the AVCodecContext since all context values are
503         // correctly initialized when calling the alloc function
504        
505         glob->avContext = avcodec_alloc_context();
506                
507                 // Use low delay
508                 glob->avContext->flags |= CODEC_FLAG_LOW_DELAY;
509                
510         // Image size is mandatory for DivX-like codecs
511        
512         glob->avContext->width = (**p->imageDescription).width;
513         glob->avContext->height = (**p->imageDescription).height;
514                
515         // We also pass the FourCC since it allows the H263 hybrid decoder
516         // to make the difference between the various flavours of DivX
517        
518         myptr = (unsigned char *)&(glob->componentType);
519         glob->avContext->codec_tag = (myptr[3] << 24) + (myptr[2] << 16) + (myptr[1] << 8) + myptr[0];
520        
521         // Let's look for a CPU with AltiVec-like SMID unit
522        
523         Gestalt(gestaltPowerPCProcessorFeatures, &bitfield);
524         altivec = (bitfield & (1 << gestaltPowerPCHasVectorInstructions)) != 0;
525        
526                 // VP6 needs VP3 IDCT; Altivec IDCT doesn't work for now
527         if (altivec && glob->componentType != 'VP62' && glob->componentType != 'VP6F')
528         {
529             Codecprintf(glob->fileLog, "Altivec Acceleration enabled!\n");
530                        
531             glob->avContext->idct_algo = FF_IDCT_ALTIVEC;
532         }
533                
534         // Finally we open the avcodec
535        
536         if (avcodec_open(glob->avContext, glob->avCodec))
537         {
538             Codecprintf(glob->fileLog, "Error opening avcodec!\n");
539            
540             return -2;
541         }
542     }
543    
544     // Specify the minimum image band height supported by the component
545     // bandInc specifies a common factor of supported image band heights -
546     // if your component supports only image bands that are an even
547     // multiple of some number of pixels high report this common factor in bandInc
548    
549     capabilities->bandMin = (**p->imageDescription).height;
550     capabilities->bandInc = capabilities->bandMin;
551        
552     // libavcodec 0.4.x is no longer stream based i.e. you cannot pass just
553     // an arbitrary amount of data to the library.
554     // Instead we have to tell QT to just pass the data corresponding
555     // to one frame
556        
557     capabilities->flags |= codecWantsSpecialScaling;
558    
559     p->requestedBufferWidth = (**p->imageDescription).width;
560     p->requestedBufferHeight = (**p->imageDescription).height;
561    
562     // Indicate the pixel depth the component can use with the specified image
563     // normally should be capabilities->wantedPixelSize = (**p->imageDescription).depth;
564     // but we don't care since some DivX are so bugged that the depth information
565     // is not correct
566    
567     capabilities->wantedPixelSize = 0;
568    
569     // Type of pixels used in output
570     // If QuickTime got the y420 component it is cool
571     // since libavcodec ouputs y420
572     // If not we'll do some king of conversion to 2vuy
573    
574     HLock(glob->pixelTypes);
575     pos = *((OSType **)glob->pixelTypes);
576    
577     index = 0;
578        
579         switch (glob->avContext->pix_fmt)
580         {
581                 case PIX_FMT_BGR24:
582                         pos[index++] = k24RGBPixelFormat;
583                         break;
584                 case PIX_FMT_YUV420P:
585                 default:
586                         if (glob->hasy420)
587                         {
588                                 pos[index++] = 'y420';
589                         }
590                         else
591                         {
592                                 pos[index++] = k2vuyPixelFormat;       
593                         }
594                         break;
595         }
596    
597     pos[index++] = 0;
598     HUnlock(glob->pixelTypes);
599        
600     p->wantedDestinationPixelTypes = (OSType **)glob->pixelTypes;
601    
602     // Specify the number of pixels the image must be extended in width and height if
603     // the component cannot accommodate the image at its given width and height
604     // It is not the case here
605    
606     capabilities->extendWidth = 0;
607     capabilities->extendHeight = 0;
608    
609     // Post-processing
610    
611     glob->postProcParams.context = pp_get_context((**p->imageDescription).width, (**p->imageDescription).height, PP_FORMAT_420);
612    
613     for (i=0; i<=PP_QUALITY_MAX; i++)
614     {
615        
616         if (i <= 2)
617         {
618             glob->postProcParams.mode[i] = pp_get_mode_by_name_and_quality("h1,v1,dr"/*"al:f"*/, i);
619         }
620         else if (i <= 4)
621         {
622             glob->postProcParams.mode[i] = pp_get_mode_by_name_and_quality("hb,vb,dr,"/*"al:f"*/, i);
623         }
624         else
625         {
626             glob->postProcParams.mode[i] = pp_get_mode_by_name_and_quality("hb,vb,dr,""hb:c,vb:c,dr:c,"/*"al:f"*/, i);
627         }
628                
629         if (glob->postProcParams.mode[i] == NULL)
630         {
631             Codecprintf(glob->fileLog, "Error getting PP filter %d!\n", i);
632            
633             return -1;
634         }
635                
636         glob->postProcParams.goodness = 0;
637         glob->postProcParams.level = 0;//GetPPUserPreference();
638     }
639         capabilities->flags |= codecCanAsync | codecCanAsyncWhen;
640        
641    
642     return noErr;
643 }
644
645 //-----------------------------------------------------------------
646 // ImageCodecBeginBand
647 //-----------------------------------------------------------------
648 // The ImageCodecBeginBand function allows your image decompressor
649 // component to save information about a band before decompressing
650 // it. This function is never called at interrupt time. The base
651 // image decompressor preserves any changes your component makes to
652 // any of the fields in the ImageSubCodecDecompressRecord or
653 // CodecDecompressParams structures. If your component supports
654 // asynchronous scheduled decompression, it may receive more than
655 // one ImageCodecBeginBand call before receiving an ImageCodecDrawBand
656 // call.
657 //-----------------------------------------------------------------
658
659 pascal ComponentResult FFusionCodecBeginBand(FFusionGlobals glob, CodecDecompressParams *p, ImageSubCodecDecompressRecord *drp, long flags)
660 {       
661     long offsetH, offsetV;
662     FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
663        
664     //////
665     IBNibRef            nibRef;
666     WindowRef           window;
667     OSStatus            err;
668     CFBundleRef         bundleRef;
669     EventHandlerUPP     handlerUPP, handlerUPP2;
670     EventTypeSpec       eventType;
671     ControlID           controlID;
672     ControlRef          theControl;
673     KeyMap              currentKeyMap;
674     int                 userPreference;
675     ///////
676        
677     offsetH = (long)(p->dstRect.left - p->dstPixMap.bounds.left) * (long)(p->dstPixMap.pixelSize >> 3);
678     offsetV = (long)(p->dstRect.top - p->dstPixMap.bounds.top) * (long)drp->rowBytes;
679    
680     myDrp->width = (**p->imageDescription).width;
681     myDrp->height = (**p->imageDescription).height;
682     myDrp->depth = (**p->imageDescription).depth;
683     myDrp->bufferSize = p->bufferSize;                  // bufferSize is the data size of the current frame
684        
685     myDrp->pixelFormat = p->dstPixMap.pixelFormat;
686         myDrp->decoded = p->frameTime ? (0 != (p->frameTime->flags & icmFrameAlreadyDecoded)) : false;
687         myDrp->frameNumber = p->frameNumber - 1;
688        
689     if (p->conditionFlags & codecConditionFirstFrame)
690     {
691         GetKeys(currentKeyMap);
692        
693                 /*        if ((currentKeyMap[1] & kOptionKeyModifier) && !glob->alreadyDonePPPref)
694         {
695             glob->alreadyDonePPPref = 1;
696                        
697             bundleRef = CFBundleGetBundleWithIdentifier(CFSTR("net.aldorande.component.FFusion"));
698                        
699             if (bundleRef == NULL)
700                 printf("Cannot get main bundle reference\n");
701                        
702             err = CreateNibReferenceWithCFBundle(bundleRef, CFSTR("main"), &nibRef);
703            
704             if (err != noErr)
705                 printf("cannot create nib reference! %d\n", (int)err);
706            
707             if (nibRef != NULL)
708             {
709                 err = CreateWindowFromNib(nibRef, CFSTR("PostProcessing"), &window);
710                
711                 if (err != noErr)
712                     printf("cannot create window!\n");
713                
714                 DisposeNibReference(nibRef);
715                                
716                 if (window != NULL)
717                 {
718                     controlID.signature = 'post';
719                     controlID.id = 128;
720                    
721                     err = GetControlByID(window, &controlID, &theControl);
722                    
723                     if (err != noErr)
724                     {
725                         printf("Cannot get slider hint text control!\n");
726                     }
727                                        
728                     userPreference = GetPPUserPreference();
729                     ChangeHintText(userPreference, theControl);
730                    
731                     controlID.signature = 'post';
732                     controlID.id = 129;
733                    
734                     err = GetControlByID(window, &controlID, &theControl);
735                    
736                     if (err != noErr)
737                     {
738                         printf("Cannot get slider control!\n");
739                     }
740                                        
741                     SetControl32BitValue(theControl, userPreference);
742                                        
743                     ShowWindow(window);
744                    
745                     handlerUPP = NewEventHandlerUPP(HandlePPDialogWindowEvent);
746                    
747                     eventType.eventClass = kEventClassCommand;
748                     eventType.eventKind  = kEventCommandProcess;
749                    
750                     InstallWindowEventHandler(window, handlerUPP, 1, &eventType, window, NULL);
751                    
752                     handlerUPP2 = NewEventHandlerUPP(HandlePPDialogControlEvent);
753                    
754                     eventType.eventClass = kEventClassControl;
755                     eventType.eventKind = kEventControlTrack;
756                    
757                     InstallControlEventHandler(theControl, handlerUPP2, 1, &eventType, window, NULL);
758                 }
759             }
760         }*/
761     }
762    
763     /*if ((glob->postProcParams.level >= 0) && (GetPPUserPreference() > 0))
764     {
765         if (p->conditionFlags & codecConditionCatchUpDiff)
766         {
767             if (glob->postProcParams.level > 0)
768             {
769                 glob->postProcParams.level--;
770                
771                 printf("PP=%i -\n", glob->postProcParams.level);
772             }
773            
774             glob->postProcParams.goodness = 0;
775         }
776         else
777         {
778             if (++glob->postProcParams.goodness > 5)
779             {
780                 if (glob->postProcParams.level < PP_QUALITY_MAX + 1)
781                 {
782                     glob->postProcParams.level++;
783                    
784                     printf("PP=%i +\n", glob->postProcParams.level);
785                 }
786                
787                 glob->postProcParams.goodness = 0;
788             }
789         }
790     }*/
791        
792     return noErr;
793 }
794
795 pascal ComponentResult FFusionCodecDecodeBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, unsigned long flags)
796 {
797         OSErr err = noErr;
798         int useFirstFrameHack = 0;
799         AVFrame tempFrame;
800        
801     FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
802         if(myDrp->frameNumber != glob->lastFrameNumber + 1)
803         {
804                 avcodec_flush_buffers(glob->avContext);
805                 glob->futureFrameAvailable = false;
806                 glob->lastFramePts = 0;
807                 if(glob->delayedFrames != 0)
808                 {
809                         //Hack to force display of first frame
810                         glob->avContext->flags |= CODEC_FLAG_LOW_DELAY;
811                         useFirstFrameHack = 1;
812                 }
813         }
814         glob->lastFrameNumber = myDrp->frameNumber;
815        
816         unsigned char *dataPtr = (unsigned char *)drp->codecData;
817         ICMDataProcRecordPtr dataProc = drp->dataProcRecord.dataProc ? &drp->dataProcRecord : NULL;
818        
819         avcodec_get_frame_defaults(&tempFrame);
820         err = FFusionDecompress(glob->avContext, dataPtr, dataProc, myDrp->width, myDrp->height, &tempFrame, myDrp->bufferSize, useFirstFrameHack);
821         myDrp->useFuture = false;
822        
823         if(tempFrame.pts < glob->lastFramePts && glob->delayedFrames == 0)
824         {
825                 //Badly framed...  No choice but to delay frames by 1
826                 glob->delayedFrames = 1;
827                 swapFrame(&glob->picture, &glob->futureFrame);
828                 memcpy(glob->picture, &tempFrame, sizeof(AVFrame));
829         }
830         else if(glob->delayedFrames == 1)
831         {
832                 memcpy(glob->picture, &tempFrame, sizeof(AVFrame));
833                 if(tempFrame.pict_type == FF_I_TYPE)
834                 {
835                         glob->avContext->flags &= ~CODEC_FLAG_LOW_DELAY;
836                         avcodec_flush_buffers(glob->avContext);
837                         err = FFusionDecompress(glob->avContext, dataPtr, dataProc, myDrp->width, myDrp->height, glob->picture, myDrp->bufferSize, 1);
838                         glob->delayedFrames = 2;
839                 }
840                 else if(tempFrame.pict_type != FF_B_TYPE)
841                 {
842                         swapFrame(&glob->picture, &glob->futureFrame);
843                         glob->futureFrameAvailable = 1;
844                 }
845                 glob->lastFramePts = glob->picture->pts;
846         }
847         else
848         {
849                 memcpy(glob->picture, &tempFrame, sizeof(AVFrame));
850                 glob->lastFramePts = glob->picture->pts;       
851         }
852        
853         if(glob->picture->data[0] == NULL && glob->futureFrameAvailable)
854         {
855                 myDrp->useFuture = true;
856                 glob->futureFrameAvailable = false;
857                 glob->lastFramePts = glob->futureFrame->pts;
858         }
859         else if(glob->picture->pict_type == FF_P_TYPE && glob->delayedFrames == 0 && err == noErr)
860         {
861                 //Check to see if a B-Frame follows this
862                 unsigned char nullChars[8] = {0,0,0,0, 0,0,0,0};
863                 err = FFusionDecompress(glob->avContext, nullChars, NULL, myDrp->width, myDrp->height, glob->futureFrame, 8, 0);
864                 if(glob->futureFrame->data[0] != NULL)
865                 {
866                         //We found a B-frame in here
867                         AVFrame *tframe = glob->picture;
868                         glob->picture = glob->futureFrame;
869                         glob->futureFrame = tframe;
870                        
871                         glob->futureFrameAvailable = true;
872                         glob->lastFramePts = glob->picture->pts;
873                 }
874         }
875         myDrp->decoded = true;
876        
877         return err;
878 }
879
880 //-----------------------------------------------------------------
881 // ImageCodecDrawBand
882 //-----------------------------------------------------------------
883 // The base image decompressor calls your image decompressor
884 // component's ImageCodecDrawBand function to decompress a band or
885 // frame. Your component must implement this function. If the
886 // ImageSubCodecDecompressRecord structure specifies a progress function
887 // or data-loading function, the base image decompressor will never call
888 // ImageCodecDrawBand at interrupt time. If the ImageSubCodecDecompressRecord
889 // structure specifies a progress function, the base image decompressor
890 // handles codecProgressOpen and codecProgressClose calls, and your image
891 // decompressor component must not implement these functions.
892 // If not, the base image decompressor may call the ImageCodecDrawBand
893 // function at interrupt time. When the base image decompressor calls your
894 // ImageCodecDrawBand function, your component must perform the decompression
895 // specified by the fields of the ImageSubCodecDecompressRecord structure.
896 // The structure includes any changes your component made to it when
897 // performing the ImageCodecBeginBand function. If your component supports
898 // asynchronous scheduled decompression, it may receive more than one
899 // ImageCodecBeginBand call before receiving an ImageCodecDrawBand call.
900 //-----------------------------------------------------------------
901
902 pascal ComponentResult FFusionCodecDrawBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp)
903 {
904     OSErr err = noErr;
905     FFusionDecompressRecord *myDrp = (FFusionDecompressRecord *)drp->userDecompressRecord;
906     unsigned char *ppPage[3];
907     int ppStride[3];
908        
909         if(!myDrp->decoded)
910                 err = FFusionCodecDecodeBand(glob, drp, 0);
911        
912         AVFrame *picture = glob->picture;
913         if(myDrp->useFuture)
914                 picture = glob->futureFrame;
915        
916         if(picture->data[0] == 0)
917         {
918                 if(glob->lastDisplayedFrame.data[0] != NULL)
919                         //Display last frame
920                         picture = &(glob->lastDisplayedFrame);
921                 else
922                 {
923                         //Can't display anything so put up a black frame
924                         int i, j;
925                         Ptr addr = drp->baseAddr;
926                         for(i=0; i<myDrp->height; i++)
927                         {
928                                 for(j=0; j<myDrp->width*2; j+=2)
929                                 {
930                                         addr[j] = 0x80;
931                                         addr[j+1] = 0x10;
932                                         addr[j+2] = 0x80;
933                                         addr[j+3] = 0x10;
934                                 }
935                                 addr += drp->rowBytes;
936                         }
937                         return noErr;
938                 }
939         }
940         else
941                 memcpy(&(glob->lastDisplayedFrame), picture, sizeof(AVFrame));
942        
943         if (myDrp->pixelFormat == 'y420' && glob->avContext->pix_fmt == PIX_FMT_YUV420P)
944         {
945                 FastY420((UInt8 *)drp->baseAddr, picture);
946         }
947         else if (myDrp->pixelFormat == k2vuyPixelFormat && glob->avContext->pix_fmt == PIX_FMT_YUV420P)
948         {
949                 SlowY420((UInt8 *)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height, picture);
950         }
951         else if (myDrp->pixelFormat == k24RGBPixelFormat && glob->avContext->pix_fmt == PIX_FMT_BGR24)
952         {
953                 BGR24toRGB24((UInt8 *)drp->baseAddr, drp->rowBytes, myDrp->width, myDrp->height, picture);
954         }
955         else
956         {
957                 Codecprintf(glob->fileLog, "Unsupported conversion from PIX_FMT %d to %c%c%c%c (%08x) buffer\n",
958                                         glob->avContext->pix_fmt, myDrp->pixelFormat >> 24 & 0xff, myDrp->pixelFormat >> 16 & 0xff,
959                                         myDrp->pixelFormat >> 8 & 0xff, myDrp->pixelFormat & 0xff, myDrp->pixelFormat);
960         }
961        
962     if ((err == noErr) && (glob->postProcParams.level > 0))
963     {
964         ppPage[0] = picture->data[0];
965         ppPage[1] = picture->data[1];
966         ppPage[2] = picture->data[2];
967         ppStride[0] = picture->linesize[0];
968         ppStride[1] = picture->linesize[1];
969         ppStride[2] = picture->linesize[2];
970                
971         pp_postprocess(ppPage, ppStride,
972                        ppPage, ppStride,
973                        myDrp->width, myDrp->height,
974                        picture->qscale_table,
975                        picture->qstride,
976                        glob->postProcParams.mode[glob->postProcParams.level],
977                        glob->postProcParams.context,
978                        picture->pict_type);
979     }
980    
981     return err;
982 }
983
984 //-----------------------------------------------------------------
985 // ImageCodecEndBand
986 //-----------------------------------------------------------------
987 // The ImageCodecEndBand function notifies your image decompressor
988 // component that decompression of a band has finished or
989 // that it was terminated by the Image Compression Manager. Your
990 // image decompressor component is not required to implement the
991 // ImageCodecEndBand function. The base image decompressor may call
992 // the ImageCodecEndBand function at interrupt time.
993 // After your image decompressor component handles an ImageCodecEndBand
994 // call, it can perform any tasks that are required when decompression
995 // is finished, such as disposing of data structures that are no longer
996 // needed. Because this function can be called at interrupt time, your
997 // component cannot use this function to dispose of data structures;
998 // this must occur after handling the function. The value of the result
999 // parameter should be set to noErr if the band or frame was
1000 // drawn successfully.
1001 // If it is any other value, the band or frame was not drawn.
1002 //-----------------------------------------------------------------
1003
1004 pascal ComponentResult FFusionCodecEndBand(FFusionGlobals glob, ImageSubCodecDecompressRecord *drp, OSErr result, long flags)
1005 {
1006     return noErr;
1007 }
1008
1009