| 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 |
|---|