1 /*
2 Software License :
3
4 Copyright (c) 2003, The Open Effects Association Ltd. All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 * Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14 * Neither the name The Open Effects Association Ltd, nor the names of its
15 contributors may be used to endorse or promote products derived from this
16 software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30
31 /*
32 Ofx Example plugin that shows how a plugin can manipulate pixel depths.
33
34 It is meant to illustrate certain features of the API, as opposed to being a perfectly
35 crafted piece of image processing software.
36
37 The main features are
38 - how to map pixel depths
39 */
40 #include <cstring>
41 #include <stdexcept>
42 #include <new>
43 #include "ofxImageEffect.h"
44 #include "ofxMemory.h"
45 #include "ofxMultiThread.h"
46
47 #include "../include/ofxUtilities.H" // example support utils
48
49 #if defined __APPLE__ || defined linux || defined __DragonFly__
50 # define EXPORT __attribute__((visibility("default")))
51 #elif defined _WIN32
52 # define EXPORT OfxExport
53 #else
54 # error Not building on your operating system quite yet
55 #endif
56
57 // Message id for the message posted when we don't have enough bits
58 #define kMessageNotEnoughBits "MessageIDNotEnoughBits"
59
Maximum(T a,T b)60 template <class T> inline T Maximum(T a, T b) {return a > b ? a : b;}
Minimum(T a,T b)61 template <class T> inline T Minimum(T a, T b) {return a < b ? a : b;}
62
63
64 static bool gSupportsBytes = false;
65 static bool gSupportsShorts = false;
66 static bool gSupportsFloats = false;
67 static int gDepthParamToBytes[3]; // maps the value of the bit depth param to a host supported bit depth
68
69 // pointers64 to various bits of the host
70 OfxHost *gHost;
71 OfxImageEffectSuiteV1 *gEffectHost = 0;
72 OfxPropertySuiteV1 *gPropHost = 0;
73 OfxParameterSuiteV1 *gParamHost = 0;
74 OfxMemorySuiteV1 *gMemoryHost = 0;
75 OfxMultiThreadSuiteV1 *gThreadHost = 0;
76 OfxMessageSuiteV1 *gMessageSuite = 0;
77 OfxInteractSuiteV1 *gInteractHost = 0;
78
79 // private instance data type
80 struct MyInstanceData {
81 // handles to the clips we deal with
82 OfxImageClipHandle sourceClip;
83 OfxImageClipHandle outputClip;
84
85 // handles to a our parameters
86 OfxParamHandle depthParam;
87 };
88
89
90 // Convinience wrapper to get private data
91 static MyInstanceData *
getMyInstanceData(OfxImageEffectHandle effect)92 getMyInstanceData(OfxImageEffectHandle effect)
93 {
94 MyInstanceData *myData = (MyInstanceData *) ofxuGetEffectInstanceData(effect);
95 return myData;
96 }
97
98
99 /** @brief Called at load */
100
101 // instance construction
102 static OfxStatus
createInstance(OfxImageEffectHandle effect)103 createInstance(OfxImageEffectHandle effect)
104 {
105 // get a pointer to the effect properties
106 OfxPropertySetHandle effectProps;
107 gEffectHost->getPropertySet(effect, &effectProps);
108
109 // get a pointer to the effect's parameter set
110 OfxParamSetHandle paramSet;
111 gEffectHost->getParamSet(effect, ¶mSet);
112
113 MyInstanceData *myData = new MyInstanceData;
114
115 // cache away param handles
116 gParamHost->paramGetHandle(paramSet, "depth", &myData->depthParam, 0);
117
118 // cache away clip handles
119 gEffectHost->clipGetHandle(effect, "Source", &myData->sourceClip, 0);
120 gEffectHost->clipGetHandle(effect, "Output", &myData->outputClip, 0);
121
122 ofxuSetEffectInstanceData(effect, (void *) myData);
123
124 return kOfxStatOK;
125 }
126
127 // instance destruction
128 static OfxStatus
destroyInstance(OfxImageEffectHandle effect)129 destroyInstance(OfxImageEffectHandle effect)
130 {
131 // get my instance data
132 MyInstanceData *myData = getMyInstanceData(effect);
133
134 // and delete it
135 if(myData)
136 delete myData;
137 return kOfxStatOK;
138 }
139
140 // are the settings of the effect performing an identity operation
141 static OfxStatus
isIdentity(OfxImageEffectHandle effect,OfxPropertySetHandle,OfxPropertySetHandle outArgs)142 isIdentity(OfxImageEffectHandle effect,
143 OfxPropertySetHandle /*inArgs*/,
144 OfxPropertySetHandle outArgs)
145 {
146 // retrieve any instance data associated with this effect
147 MyInstanceData *myData = getMyInstanceData(effect);
148
149 // get the render window and the time from the inArgs
150 //OfxTime time;
151 //OfxRectI renderWindow;
152
153 // get the src depth
154 int srcDepth = ofxuGetClipPixelDepth(myData->sourceClip);
155
156 // get the dst depth
157 int dstDepth = ofxuGetClipPixelDepth(myData->outputClip);
158
159 // if the depths are the same we have no work to do!
160 if(srcDepth == dstDepth) {
161 // set the property in the out args indicating which is the identity clip
162 gPropHost->propSetString(outArgs, kOfxPropName, 0, "Source");
163 return kOfxStatOK;
164 }
165
166 // In this case do the default, which in this case is to render
167 return kOfxStatReplyDefault;
168 }
169
170 ////////////////////////////////////////////////////////////////////////////////
171 // rendering routines
172 template <class T> inline T
Clamp(T v,int min,int max)173 Clamp(T v, int min, int max)
174 {
175 if(v < T(min)) return T(min);
176 if(v > T(max)) return T(max);
177 return v;
178 }
179
180 // look up a pixel in the image, does bounds checking to see if it is in the image rectangle
181 template <class PIX> inline PIX *
pixelAddress(PIX * img,OfxRectI rect,int x,int y,int bytesPerLine)182 pixelAddress(PIX *img, OfxRectI rect, int x, int y, int bytesPerLine)
183 {
184 if(x < rect.x1 || x >= rect.x2 || y < rect.y1 || y > rect.y2)
185 return 0;
186 PIX *pix = (PIX *) (((char *) img) + (y - rect.y1) * bytesPerLine);
187 pix += x - rect.x1;
188 return pix;
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////
192 // base class to process images with
193 class Processor {
194 protected :
195 OfxImageEffectHandle instance;
196 int nComponents;
197 void *srcV, *dstV;
198 OfxRectI srcRect, dstRect;
199 int srcBytesPerLine, dstBytesPerLine;
200 OfxRectI window;
201
202 public :
Processor(const Processor & p)203 Processor(const Processor &p)
204 : instance(p.instance)
205 , nComponents(p.nComponents)
206 , srcV(p.srcV)
207 , dstV(p.dstV)
208 , srcRect(p.srcRect)
209 , dstRect(p.dstRect)
210 , srcBytesPerLine(p.srcBytesPerLine)
211 , dstBytesPerLine(p.dstBytesPerLine)
212 , window(p.window)
213 {}
214
Processor(OfxImageEffectHandle inst,int nComps,void * src,OfxRectI sRect,int sBytesPerLine,void * dst,OfxRectI dRect,int dBytesPerLine,OfxRectI win)215 Processor(OfxImageEffectHandle inst, int nComps,
216 void *src, OfxRectI sRect, int sBytesPerLine,
217 void *dst, OfxRectI dRect, int dBytesPerLine,
218 OfxRectI win)
219 : instance(inst)
220 , nComponents(nComps)
221 , srcV(src)
222 , dstV(dst)
223 , srcRect(sRect)
224 , dstRect(dRect)
225 , srcBytesPerLine(sBytesPerLine)
226 , dstBytesPerLine(dBytesPerLine)
227 , window(win)
228 {}
229
230 static void multiThreadProcessing(unsigned int threadId, unsigned int nThreads, void *arg);
231 virtual void doProcessing(OfxRectI window);
232 void process(void);
233 };
234
235 // function call once for each thread by the host
236 void
multiThreadProcessing(unsigned int threadId,unsigned int nThreads,void * arg)237 Processor::multiThreadProcessing(unsigned int threadId, unsigned int nThreads, void *arg)
238 {
239 Processor *proc = (Processor *) arg;
240
241 // slice the y range into the number of threads it has
242 unsigned int dy = proc->window.y2 - proc->window.y1;
243 unsigned int y1 = proc->window.y1 + threadId * dy/nThreads;
244 unsigned int y2 = proc->window.y1 + Minimum((threadId + 1) * dy/nThreads, dy);
245
246 OfxRectI win = proc->window;
247 win.y1 = y1; win.y2 = y2;
248
249 // and render that thread on each
250 proc->doProcessing(win);
251 }
252
253 // function to kick off rendering across multiple CPUs
254 void
process(void)255 Processor::process(void)
256 {
257 unsigned int nThreads;
258 gThreadHost->multiThreadNumCPUs(&nThreads);
259 gThreadHost->multiThread(multiThreadProcessing, nThreads, (void *) this);
260 }
261
262 void
doProcessing(OfxRectI)263 Processor::doProcessing(OfxRectI /*window*/)
264 {
265 }
266
267 // template to do the RGBA processing
268 template <class SRCPIX, int kSrcMax, int srcIsFloat,
269 class DSTPIX, int kDstMax, int dstIsFloat>
270 class ProcessPix : public Processor {
271 public :
ProcessPix(const Processor & p)272 ProcessPix(const Processor &p)
273 : Processor(p)
274 {
275 process();
276 }
277
doProcessing(OfxRectI procWindow)278 void doProcessing(OfxRectI procWindow)
279 {
280 SRCPIX *src = (SRCPIX *) srcV;
281 DSTPIX *dst = (DSTPIX *) dstV;
282
283 float scaleF;
284 scaleF = float(kDstMax)/float(kSrcMax);
285
286 for(int y = procWindow.y1; y < procWindow.y2; y++) {
287 if(gEffectHost->abort(instance)) break;
288
289 DSTPIX *dstPix = pixelAddress(dst, dstRect, procWindow.x1, y, dstBytesPerLine);
290
291 for(int x = procWindow.x1; x < procWindow.x2; x++) {
292
293 // if a generator, we have no source
294 SRCPIX *srcPix = pixelAddress(src, srcRect, x, y, srcBytesPerLine);
295
296 // change my pixel depths
297 if(srcPix) {
298 for(int c = 0; c < nComponents; c++) {
299 if(dstIsFloat)
300 dstPix[c] = srcPix[c] * scaleF;
301 else if (srcIsFloat)
302 dstPix[c] = Clamp(srcPix[c] * scaleF, 0, kDstMax);
303 else
304 dstPix[c] = Clamp(srcPix[c] * kDstMax/kSrcMax, 0, kDstMax);
305 }
306 srcPix += nComponents;
307 }
308 else {
309 for(int c = 0; c < nComponents; c++)
310 dstPix[c] = 0;
311 }
312 dstPix += nComponents;
313 }
314 }
315 }
316
317 };
318
319 // the process code that the host sees
render(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle)320 static OfxStatus render(OfxImageEffectHandle effect,
321 OfxPropertySetHandle inArgs,
322 OfxPropertySetHandle /*outArgs*/)
323 {
324 // get the render window and the time from the inArgs
325 OfxTime time;
326 OfxRectI renderWindow;
327 OfxStatus status = kOfxStatOK;
328
329 gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
330 gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
331
332 // retrieve any instance data associated with this effect
333 MyInstanceData *myData = getMyInstanceData(effect);
334
335 // property handles and members of each image
336 // in reality, we would put this in a struct as the C++ support layer does
337 OfxPropertySetHandle sourceImg = NULL, outputImg = NULL;
338 int srcRowBytes, srcBitDepth, dstRowBytes, dstBitDepth;
339 bool srcIsAlpha, dstIsAlpha;
340 OfxRectI dstRect, srcRect;
341 void *src, *dst;
342
343 try {
344 outputImg = ofxuGetImage(myData->outputClip, time, dstRowBytes, dstBitDepth, dstIsAlpha, dstRect, dst);
345 if(outputImg == NULL) throw OfxuNoImageException();
346
347 sourceImg = ofxuGetImage(myData->sourceClip, time, srcRowBytes, srcBitDepth, srcIsAlpha, srcRect, src);
348 if(sourceImg == NULL) throw OfxuNoImageException();
349
350 int nComponents = dstIsAlpha ? 1 : 4;
351
352 // set up the processor that we pass to the individual constructors
353 Processor proc(effect, nComponents,
354 src, srcRect, srcRowBytes,
355 dst, dstRect, dstRowBytes,
356 renderWindow);
357
358 // now instantiate the templated processor depending on src and dest pixel types, 9 cases in all
359 switch(dstBitDepth) {
360 case 8 : {
361 switch(srcBitDepth) {
362 case 8 : {ProcessPix<unsigned char, 255, 0, unsigned char, 255, 0> pixProc(proc); break;}
363 case 16 : {ProcessPix<unsigned short, 65535, 0, unsigned char, 255, 0> pixProc(proc); break;}
364 case 32 : {ProcessPix<float, 1, 1, unsigned char, 255, 0> pixProc(proc); break;}
365 }
366 }
367 break;
368
369 case 16 : {
370 switch(srcBitDepth) {
371 case 8 : {ProcessPix<unsigned char, 255, 0, unsigned short, 65535, 0> pixProc(proc); break;}
372 case 16 : {ProcessPix<unsigned short, 65535, 0, unsigned short, 65535, 0> pixProc(proc); break;}
373 case 32 : {ProcessPix<float, 1, 1, unsigned short, 65535, 0> pixProc(proc); break;}
374 }
375 }
376 break;
377
378 case 32 : {
379 switch(srcBitDepth) {
380 case 8 : {ProcessPix<unsigned char, 255, 0, float, 1, 1> pixProc(proc); break;}
381 case 16 : {ProcessPix<unsigned short, 65535, 0, float, 1, 1> pixProc(proc); break;}
382 case 32 : {ProcessPix<float, 1, 1, float, 1, 1> pixProc(proc); break;}
383 }
384 }
385 break;
386 }
387 }
388 catch(OfxuNoImageException &ex) {
389 // if we were interrupted, the failed fetch is fine, just return kOfxStatOK
390 // otherwise, something wierd happened
391 if(!gEffectHost->abort(effect)) {
392 status = kOfxStatFailed;
393 }
394 }
395
396 // release the data pointers;
397 if(sourceImg)
398 gEffectHost->clipReleaseImage(sourceImg);
399 if(outputImg)
400 gEffectHost->clipReleaseImage(outputImg);
401
402 return status;
403 }
404
405 // Set our clip preferences
406 static OfxStatus
getClipPreferences(OfxImageEffectHandle effect,OfxPropertySetHandle,OfxPropertySetHandle outArgs)407 getClipPreferences(OfxImageEffectHandle effect,
408 OfxPropertySetHandle /*inArgs*/,
409 OfxPropertySetHandle outArgs)
410 {
411 // retrieve any instance data associated with this effect
412 MyInstanceData *myData = getMyInstanceData(effect);
413
414 // fetch the depth parameter value
415 int depthVal;
416 gParamHost->paramGetValue(myData->depthParam, &depthVal);
417
418 // and set the output depths based on that
419 switch(gDepthParamToBytes[depthVal]) {
420 // byte
421 case 8 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthByte); break;
422 // short
423 case 16 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthShort); break;
424 // float
425 case 32 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthFloat); break;
426 }
427
428 return kOfxStatOK;
429 }
430
431
432 // describe the plugin in context
433 static OfxStatus
describeInContext(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs)434 describeInContext(OfxImageEffectHandle effect, OfxPropertySetHandle inArgs)
435 {
436 // get the context from the inArgs handle
437 const char *context = NULL;
438 gPropHost->propGetString(inArgs, kOfxImageEffectPropContext, 0, &context);
439 //bool isGeneratorContext = strcmp(context, kOfxImageEffectContextGenerator) == 0;
440
441 OfxPropertySetHandle clipProps;
442 // define the single output clip in both contexts
443 gEffectHost->clipDefine(effect, "Output", &clipProps);
444
445 // set the component types we can handle on out output
446 gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
447 gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
448 gPropHost->propSetString(clipProps, kOfxImageClipPropFieldExtraction, 0, kOfxImageFieldSingle);
449
450 // define the single source clip in filter and general contexts
451 gEffectHost->clipDefine(effect, "Source", &clipProps);
452
453 // set the component types we can handle on our main input
454 gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
455 gPropHost->propSetString(clipProps, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
456 gPropHost->propSetString(clipProps, kOfxImageClipPropFieldExtraction, 0, kOfxImageFieldSingle);
457
458 ////////////////////////////////////////////////////////////////////////////////
459 // define the parameters for this context
460 OfxParamSetHandle paramSet;
461 gEffectHost->getParamSet(effect, ¶mSet);
462
463 //OfxParamHandle param;
464 OfxPropertySetHandle paramProps;
465
466 // single choice parameter
467 gParamHost->paramDefine(paramSet, kOfxParamTypeChoice, "depth", ¶mProps);
468 gPropHost->propSetString(paramProps, kOfxParamPropHint, 0, "What pixel depth to convert the image to");
469 gPropHost->propSetString(paramProps, kOfxPropLabel, 0, "Depth");
470
471 // set the options, depending on the bit depths the host supports
472 int i = 0;
473 if(gSupportsBytes) gPropHost->propSetString(paramProps, kOfxParamPropChoiceOption, i++, "Byte");
474 if(gSupportsShorts) gPropHost->propSetString(paramProps, kOfxParamPropChoiceOption, i++, "Short");
475 if(gSupportsFloats) gPropHost->propSetString(paramProps, kOfxParamPropChoiceOption, i++, "Float");
476
477 // we convert things to 8 bits by default
478 gPropHost->propSetInt(paramProps, kOfxParamPropDefault, 0, 0);
479
480 // say that the pixel depth affects the clip preferences
481 OfxPropertySetHandle effectProps;
482 gEffectHost->getPropertySet(effect, &effectProps);
483 gPropHost->propSetString(effectProps, kOfxImageEffectPropClipPreferencesSlaveParam, 0, "depth");
484
485 return kOfxStatOK;
486 }
487
488 ////////////////////////////////////////////////////////////////////////////////
489 // the plugin's description routine
490 static OfxStatus
describe(OfxImageEffectHandle effect)491 describe(OfxImageEffectHandle effect)
492 {
493 // first fetch the host APIs, this cannot be done before this call
494 OfxStatus stat;
495 if((stat = ofxuFetchHostSuites()) != kOfxStatOK)
496 return stat;
497
498 int hostSupportsMultipleDepths;
499 // record a few host features
500 gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsMultipleClipDepths, 0, &hostSupportsMultipleDepths);
501
502 // see how many bit depths the host supports, this affects our parameter values
503 int nHostDepths;
504 gPropHost->propGetDimension(gHost->host, kOfxImageEffectPropSupportedPixelDepths, &nHostDepths);
505
506 // If the host cannot support multiple bit depths on in and out clips or it only supports 1 bit depth
507 // we cant do any work, so refuse to load and explain why.
508 if(!hostSupportsMultipleDepths || nHostDepths == 1) {
509 // post a message
510 // - disabled, because posting a message within describe() crashes Nuke 6
511 //gMessageSuite->message(effect, kOfxMessageError, kMessageNotEnoughBits,
512 // "OFX GeneratorExample : cannot run on this application because the it does not allow effects to change the bit depth of images.");
513
514 // and refuse to load
515 // - disabled, because Nuke 6 still loads it - it's better to load it even if it's non-functional
516 //return kOfxStatErrMissingHostFeature;
517 }
518
519 // get the property handle for the plugin
520 OfxPropertySetHandle effectProps;
521 gEffectHost->getPropertySet(effect, &effectProps);
522
523 // We can render both fields in a fielded image in one hit as there is no animation and no spatially dependant parameters
524 gPropHost->propSetInt(effectProps, kOfxImageEffectPluginPropFieldRenderTwiceAlways, 0, 0);
525
526 // say we can support multiple pixel depths on in and out
527 gPropHost->propSetInt(effectProps, kOfxImageEffectPropSupportsMultipleClipDepths, 0, 1);
528
529 // set the bit depths the plugin can handle
530 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
531 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 1, kOfxBitDepthShort);
532 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 2, kOfxBitDepthFloat);
533
534 // figure which bit depths are supported
535 int i;
536 for(i = 0; i < nHostDepths; i++) {
537 const char *depthStr = NULL;
538 gPropHost->propGetString(gHost->host, kOfxImageEffectPropSupportedPixelDepths, i, &depthStr);
539 int nBits = ofxuMapPixelDepth(depthStr);
540 switch(nBits) {
541 case 8 : gSupportsBytes = true; break;
542 case 16 : gSupportsShorts = true; break;
543 case 32 : gSupportsFloats = true; break;
544 }
545 }
546
547 // now set a mapping from parameter value to bit depth
548 i = 0;
549 if(gSupportsBytes) gDepthParamToBytes[i++] = 8;
550 if(gSupportsShorts) gDepthParamToBytes[i++] = 16;
551 if(gSupportsFloats) gDepthParamToBytes[i++] = 32;
552
553 // set some labels and the group it belongs to
554 gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "OFX Depth Converter");
555 gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "OFX Example");
556
557 // define the contexts we can be used in
558 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextFilter);
559 gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 1, kOfxImageEffectContextGeneral);
560
561 return kOfxStatOK;
562 }
563
564 ////////////////////////////////////////////////////////////////////////////////
565 // The main function
566 static OfxStatus
pluginMain(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)567 pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs)
568 {
569 try {
570 // cast to appropriate type
571 OfxImageEffectHandle effect = (OfxImageEffectHandle ) handle;
572
573 if(strcmp(action, kOfxActionDescribe) == 0) {
574 return describe(effect);
575 }
576 else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
577 return describeInContext(effect, inArgs);
578 }
579 else if(strcmp(action, kOfxActionCreateInstance) == 0) {
580 return createInstance(effect);
581 }
582 else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
583 return destroyInstance(effect);
584 }
585 else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
586 return isIdentity(effect, inArgs, outArgs);
587 }
588 else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
589 return render(effect, inArgs, outArgs);
590 }
591 else if(strcmp(action, kOfxImageEffectActionGetClipPreferences) == 0) {
592 return getClipPreferences(effect, inArgs, outArgs);
593 }
594 } catch (std::bad_alloc) {
595 // catch memory
596 //std::cout << "OFX Plugin Memory error." << std::endl;
597 return kOfxStatErrMemory;
598 } catch ( const std::exception& e ) {
599 // standard exceptions
600 //std::cout << "OFX Plugin error: " << e.what() << std::endl;
601 return kOfxStatErrUnknown;
602 } catch (int err) {
603 // ho hum, gone wrong somehow
604 return err;
605 } catch ( ... ) {
606 // everything else
607 //std::cout << "OFX Plugin error" << std::endl;
608 return kOfxStatErrUnknown;
609 }
610
611 // other actions to take the default value
612 return kOfxStatReplyDefault;
613 }
614
615 // function to set the host structure
616 static void
setHostFunc(OfxHost * hostStruct)617 setHostFunc(OfxHost *hostStruct)
618 {
619 gHost = hostStruct;
620 }
621
622 ////////////////////////////////////////////////////////////////////////////////
623 // the plugin struct
624 static OfxPlugin basicPlugin =
625 {
626 kOfxImageEffectPluginApi,
627 1,
628 "uk.co.thefoundry.DepthConverterExample",
629 1,
630 0,
631 setHostFunc,
632 pluginMain
633 };
634
635 // the two mandated functions
636 EXPORT OfxPlugin *
OfxGetPlugin(int nth)637 OfxGetPlugin(int nth)
638 {
639 if(nth == 0)
640 return &basicPlugin;
641 return 0;
642 }
643
644 EXPORT int
OfxGetNumberOfPlugins(void)645 OfxGetNumberOfPlugins(void)
646 {
647 return 1;
648 }
649