1 /*
2 Software License :
3 
4 Copyright (c) 2014, 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   Author : Bruno Nicoletti (2014)
32 
33   This plugin will take you through the basics of defining and using
34   parameters as well as how to use instance data.
35 
36   The accompanying guide will explain what is happening in more detail.
37 */
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <math.h>
43 
44 #include <string>
45 #include <iostream>
46 
47 // the one OFX header we need, it includes the others necessary
48 #include "ofxImageEffect.h"
49 
50 #if defined __APPLE__ || defined linux || defined __DragonFly__
51 #  define EXPORT __attribute__((visibility("default")))
52 #elif defined _WIN32
53 #  define EXPORT OfxExport
54 #else
55 #  error Not building on your operating system quite yet
56 #endif
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 // macro to write a labelled message to stderr with
60 #ifdef _WIN32
61   #define DUMP(LABEL, MSG, ...)                                           \
62   {                                                                       \
63     fprintf(stderr, "%s%s:%d in %s ", LABEL, __FILE__, __LINE__, __FUNCTION__); \
64     fprintf(stderr, MSG, ##__VA_ARGS__);                                  \
65     fprintf(stderr, "\n");                                                \
66   }
67 #else
68   #define DUMP(LABEL, MSG, ...)                                           \
69   {                                                                       \
70     fprintf(stderr, "%s%s:%d in %s ", LABEL, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
71     fprintf(stderr, MSG, ##__VA_ARGS__);                                  \
72     fprintf(stderr, "\n");                                                \
73   }
74 #endif
75 
76 // macro to write a simple message, only works if 'VERBOSE' is #defined
77 //#define VERBOSE
78 #ifdef VERBOSE
79 #  define MESSAGE(MSG, ...) DUMP("", MSG, ##__VA_ARGS__)
80 #else
81 #  define MESSAGE(MSG, ...)
82 #endif
83 
84 // macro to dump errors to stderr if the given condition is true
85 #define ERROR_IF(CONDITION, MSG, ...) if(CONDITION) { DUMP("ERROR : ", MSG, ##__VA_ARGS__);}
86 
87 // macro to dump errors to stderr and abort if the given condition is true
88 #define ERROR_ABORT_IF(CONDITION, MSG, ...)     \
89 {                                               \
90   if(CONDITION) {                               \
91     DUMP("FATAL ERROR : ", MSG, ##__VA_ARGS__); \
92     abort();                                    \
93   }                                             \
94 }
95 
96 // name of our two params
97 #define GAIN_PARAM_NAME "gain"
98 #define APPLY_TO_ALPHA_PARAM_NAME "applyToAlpha"
99 
100 // anonymous namespace to hide our symbols in
101 namespace {
102   ////////////////////////////////////////////////////////////////////////////////
103   // set of suite pointers provided by the host
104   OfxHost               *gHost;
105   OfxPropertySuiteV1    *gPropertySuite    = 0;
106   OfxImageEffectSuiteV1 *gImageEffectSuite = 0;
107   OfxParameterSuiteV1   *gParameterSuite   = 0;
108 
109   ////////////////////////////////////////////////////////////////////////////////
110   // our instance data, where we are caching away clip and param handles
111   struct MyInstanceData {
112     // handles to the clips we deal with
113     OfxImageClipHandle sourceClip;
114     OfxImageClipHandle outputClip;
115 
116     // handles to a our parameters
117     OfxParamHandle gainParam;
118     OfxParamHandle applyToAlphaParam;
119   };
120 
121   ////////////////////////////////////////////////////////////////////////////////
122   // get my instance data from a property set handle
FetchInstanceData(OfxPropertySetHandle effectProps)123   MyInstanceData *FetchInstanceData(OfxPropertySetHandle effectProps)
124   {
125     MyInstanceData *myData = 0;
126     gPropertySuite->propGetPointer(effectProps,
127                                    kOfxPropInstanceData,
128                                    0,
129                                    (void **) &myData);
130     return myData;
131   }
132 
133   ////////////////////////////////////////////////////////////////////////////////
134   // get my instance data
FetchInstanceData(OfxImageEffectHandle effect)135   MyInstanceData *FetchInstanceData(OfxImageEffectHandle effect)
136   {
137     // get the property handle for the plugin
138     OfxPropertySetHandle effectProps;
139     gImageEffectSuite->getPropertySet(effect, &effectProps);
140 
141     // and get the instance data out of that
142     return FetchInstanceData(effectProps);
143   }
144 
145   ////////////////////////////////////////////////////////////////////////////////
146   // get the named suite and put it in the given pointer, with error checking
147   template <class SUITE>
FetchSuite(SUITE * & suite,const char * suiteName,int suiteVersion)148   void FetchSuite(SUITE *& suite, const char *suiteName, int suiteVersion)
149   {
150     suite = (SUITE *) gHost->fetchSuite(gHost->host, suiteName, suiteVersion);
151     if(!suite) {
152       ERROR_ABORT_IF(suite == NULL,
153                      "Failed to fetch %s verison %d from the host.",
154                      suiteName,
155                      suiteVersion);
156     }
157   }
158 
159   ////////////////////////////////////////////////////////////////////////////////
160   // The first _action_ called after the binary is loaded (three boot strapper functions will be howeever)
LoadAction(void)161   OfxStatus LoadAction(void)
162   {
163     // fetch our three suites
164     FetchSuite(gPropertySuite,    kOfxPropertySuite,    1);
165     FetchSuite(gImageEffectSuite, kOfxImageEffectSuite, 1);
166     FetchSuite(gParameterSuite,   kOfxParameterSuite,   1);
167 
168     return kOfxStatOK;
169   }
170 
171   ////////////////////////////////////////////////////////////////////////////////
172   // the plugin's basic description routine
DescribeAction(OfxImageEffectHandle descriptor)173   OfxStatus DescribeAction(OfxImageEffectHandle descriptor)
174   {
175     // get the property set handle for the plugin
176     OfxPropertySetHandle effectProps;
177     gImageEffectSuite->getPropertySet(descriptor, &effectProps);
178 
179     // set some labels and the group it belongs to
180     gPropertySuite->propSetString(effectProps,
181                                   kOfxPropLabel,
182                                   0,
183                                   "OFX Gain Example");
184     gPropertySuite->propSetString(effectProps,
185                                   kOfxImageEffectPluginPropGrouping,
186                                   0,
187                                   "OFX Example");
188 
189     // define the image effects contexts we can be used in, in this case a simple filter
190     gPropertySuite->propSetString(effectProps,
191                                   kOfxImageEffectPropSupportedContexts,
192                                   0,
193                                   kOfxImageEffectContextFilter);
194 
195     // set the bit depths the plugin can handle
196     gPropertySuite->propSetString(effectProps,
197                                   kOfxImageEffectPropSupportedPixelDepths,
198                                   0,
199                                   kOfxBitDepthFloat);
200     gPropertySuite->propSetString(effectProps,
201                                   kOfxImageEffectPropSupportedPixelDepths,
202                                   1,
203                                   kOfxBitDepthShort);
204     gPropertySuite->propSetString(effectProps,
205                                   kOfxImageEffectPropSupportedPixelDepths,
206                                   2,
207                                   kOfxBitDepthByte);
208 
209     // say that a single instance of this plugin can be rendered in multiple threads
210     gPropertySuite->propSetString(effectProps,
211                                   kOfxImageEffectPluginRenderThreadSafety,
212                                   0,
213                                   kOfxImageEffectRenderFullySafe);
214 
215     // say that the host should manage SMP threading over a single frame
216     gPropertySuite->propSetInt(effectProps,
217                                kOfxImageEffectPluginPropHostFrameThreading,
218                                0,
219                                1);
220 
221 
222     return kOfxStatOK;
223   }
224 
225   ////////////////////////////////////////////////////////////////////////////////
226   //  describe the plugin in context
227   OfxStatus
DescribeInContextAction(OfxImageEffectHandle descriptor,OfxPropertySetHandle)228   DescribeInContextAction(OfxImageEffectHandle descriptor,
229                           OfxPropertySetHandle /*inArgs*/)
230   {
231     OfxPropertySetHandle props;
232     // define the mandated single output clip
233     gImageEffectSuite->clipDefine(descriptor, "Output", &props);
234 
235     // set the component types we can handle on out output
236     gPropertySuite->propSetString(props,
237                                   kOfxImageEffectPropSupportedComponents,
238                                   0,
239                                   kOfxImageComponentRGBA);
240     gPropertySuite->propSetString(props,
241                                   kOfxImageEffectPropSupportedComponents,
242                                   1,
243                                   kOfxImageComponentAlpha);
244     gPropertySuite->propSetString(props,
245                                   kOfxImageEffectPropSupportedComponents,
246                                   2,
247                                   kOfxImageComponentRGB);
248 
249     // define the mandated single source clip
250     gImageEffectSuite->clipDefine(descriptor, "Source", &props);
251 
252     // set the component types we can handle on our main input
253     gPropertySuite->propSetString(props,
254                                   kOfxImageEffectPropSupportedComponents,
255                                   0,
256                                   kOfxImageComponentRGBA);
257     gPropertySuite->propSetString(props,
258                                   kOfxImageEffectPropSupportedComponents,
259                                   1,
260                                   kOfxImageComponentAlpha);
261     gPropertySuite->propSetString(props,
262                                   kOfxImageEffectPropSupportedComponents,
263                                   2,
264                                   kOfxImageComponentRGB);
265 
266     // first get the handle to the parameter set
267     OfxParamSetHandle paramSet;
268     gImageEffectSuite->getParamSet(descriptor, &paramSet);
269 
270     // properties on our parameter
271     OfxPropertySetHandle paramProps;
272 
273     // now define a 'gain' parameter and set its properties
274     gParameterSuite->paramDefine(paramSet,
275                                  kOfxParamTypeDouble,
276                                  GAIN_PARAM_NAME,
277                                  &paramProps);
278     gPropertySuite->propSetString(paramProps,
279                                   kOfxParamPropDoubleType,
280                                   0,
281                                   kOfxParamDoubleTypeScale);
282     gPropertySuite->propSetDouble(paramProps,
283                                   kOfxParamPropDefault,
284                                   0,
285                                   1.0);
286     gPropertySuite->propSetDouble(paramProps,
287                                   kOfxParamPropMin,
288                                   0,
289                                   0.0);
290     gPropertySuite->propSetDouble(paramProps,
291                                   kOfxParamPropDisplayMin,
292                                   0,
293                                   0.0);
294     gPropertySuite->propSetDouble(paramProps,
295                                   kOfxParamPropDisplayMax,
296                                   0,
297                                   10.0);
298     gPropertySuite->propSetString(paramProps,
299                                   kOfxPropLabel,
300                                   0,
301                                   "Gain");
302     gPropertySuite->propSetString(paramProps,
303                                   kOfxParamPropHint,
304                                   0,
305                                   "How much to multiply the image by.");
306 
307     // and define the 'applyToAlpha' parameters and set its properties
308     gParameterSuite->paramDefine(paramSet,
309                                  kOfxParamTypeBoolean,
310                                  APPLY_TO_ALPHA_PARAM_NAME,
311                                  &paramProps);
312     gPropertySuite->propSetInt(paramProps,
313                                kOfxParamPropDefault,
314                                0,
315                                0);
316     gPropertySuite->propSetString(paramProps,
317                                   kOfxParamPropHint,
318                                   0,
319                                   "Whether to apply the gain value to alpha as well.");
320     gPropertySuite->propSetString(paramProps,
321                                   kOfxPropLabel,
322                                   0,
323                                   "Apply To Alpha");
324 
325     return kOfxStatOK;
326   }
327 
328   ////////////////////////////////////////////////////////////////////////////////
329   /// instance construction
CreateInstanceAction(OfxImageEffectHandle instance)330   OfxStatus CreateInstanceAction( OfxImageEffectHandle instance)
331   {
332     OfxPropertySetHandle effectProps;
333     gImageEffectSuite->getPropertySet(instance, &effectProps);
334 
335     // To avoid continual lookup, put our handles into our instance
336     // data, those handles are guaranteed to be valid for the duration
337     // of the instance.
338     MyInstanceData *myData = new MyInstanceData;
339 
340     // Set my private instance data
341     gPropertySuite->propSetPointer(effectProps, kOfxPropInstanceData, 0, (void *) myData);
342 
343     // Cache the source and output clip handles
344     gImageEffectSuite->clipGetHandle(instance, "Source", &myData->sourceClip, 0);
345     gImageEffectSuite->clipGetHandle(instance, "Output", &myData->outputClip, 0);
346 
347     // Cache away the param handles
348     OfxParamSetHandle paramSet;
349     gImageEffectSuite->getParamSet(instance, &paramSet);
350     gParameterSuite->paramGetHandle(paramSet,
351                                     GAIN_PARAM_NAME,
352                                     &myData->gainParam,
353                                     0);
354     gParameterSuite->paramGetHandle(paramSet,
355                                     APPLY_TO_ALPHA_PARAM_NAME,
356                                     &myData->applyToAlphaParam,
357                                     0);
358 
359     return kOfxStatOK;
360   }
361 
362   ////////////////////////////////////////////////////////////////////////////////
363   // instance destruction
DestroyInstanceAction(OfxImageEffectHandle instance)364   OfxStatus DestroyInstanceAction( OfxImageEffectHandle instance)
365   {
366     // get my instance data
367     MyInstanceData *myData = FetchInstanceData(instance);
368     delete myData;
369 
370     return kOfxStatOK;
371   }
372 
373   ////////////////////////////////////////////////////////////////////////////////
374   // Look up a pixel in the image. returns null if the pixel was not
375   // in the bounds of the image
376   template <class T>
pixelAddress(int x,int y,void * baseAddress,OfxRectI bounds,int rowBytes,int nCompsPerPixel)377   static inline T * pixelAddress(int x, int y,
378                                  void *baseAddress,
379                                  OfxRectI bounds,
380                                  int rowBytes,
381                                  int nCompsPerPixel)
382   {
383     // Inside the bounds of this image?
384     if(x < bounds.x1 || x >= bounds.x2 || y < bounds.y1 || y >= bounds.y2)
385       return NULL;
386 
387     // turn image plane coordinates into offsets from the bottom left
388     int yOffset = y - bounds.y1;
389     int xOffset = x - bounds.x1;
390 
391     // Find the start of our row, using byte arithmetic
392     void *rowStartAsVoid = reinterpret_cast<char *>(baseAddress) + yOffset * rowBytes;
393 
394     // turn the row start into a pointer to our data type
395     T *rowStart = reinterpret_cast<T *>(rowStartAsVoid);
396 
397     // finally find the position of the first component of column
398     return rowStart + (xOffset * nCompsPerPixel);
399   }
400 
401   ////////////////////////////////////////////////////////////////////////////////
402   // iterate over our pixels and process them
403   template <class T, int MAX>
PixelProcessing(double gain,bool applyToAlpha,OfxImageEffectHandle instance,OfxPropertySetHandle sourceImg,OfxPropertySetHandle outputImg,OfxRectI renderWindow,int nComps)404   void PixelProcessing(double gain,
405                        bool applyToAlpha,
406                        OfxImageEffectHandle instance,
407                        OfxPropertySetHandle sourceImg,
408                        OfxPropertySetHandle outputImg,
409                        OfxRectI renderWindow,
410                        int nComps)
411   {
412     // fetch output image info from the property handle
413     int dstRowBytes;
414     OfxRectI dstBounds;
415     void *dstPtr = NULL;
416     gPropertySuite->propGetInt(outputImg, kOfxImagePropRowBytes, 0, &dstRowBytes);
417     gPropertySuite->propGetIntN(outputImg, kOfxImagePropBounds, 4, &dstBounds.x1);
418     gPropertySuite->propGetPointer(outputImg, kOfxImagePropData, 0, &dstPtr);
419 
420     if(dstPtr == NULL) {
421       throw "Bad destination pointer";
422     }
423 
424     // fetch input image info from the property handle
425     int srcRowBytes;
426     OfxRectI srcBounds;
427     void *srcPtr = NULL;
428     gPropertySuite->propGetInt(sourceImg, kOfxImagePropRowBytes, 0, &srcRowBytes);
429     gPropertySuite->propGetIntN(sourceImg, kOfxImagePropBounds, 4, &srcBounds.x1);
430     gPropertySuite->propGetPointer(sourceImg, kOfxImagePropData, 0, &srcPtr);
431 
432     if(srcPtr == NULL) {
433       throw "Bad source pointer";
434     }
435 
436     // and do some processing
437     for(int y = renderWindow.y1; y < renderWindow.y2; y++) {
438       if(y % 20 == 0 && gImageEffectSuite->abort(instance)) break;
439 
440       // get the row start for the output image
441       T *dstPix = pixelAddress<T>(renderWindow.x1, y,
442                                   dstPtr,
443                                   dstBounds,
444                                   dstRowBytes,
445                                   nComps);
446 
447       for(int x = renderWindow.x1; x < renderWindow.x2; x++) {
448 
449         // get the source pixel
450         T *srcPix = pixelAddress<T>(x, y,
451                                     srcPtr,
452                                     srcBounds,
453                                     srcRowBytes,
454                                     nComps);
455 
456         if(srcPix) {
457           // we have one, iterate each component in the pixels
458           for(int i = 0; i < nComps; ++i) {
459             if(i != 3 || applyToAlpha) {
460               // multiply our source component by our gain value
461               double value = *srcPix * gain;
462 
463               // if it has gone out of legal bounds, clamp it
464               if(MAX != 1) {  // we let floating point pixels over and underflow
465                 value = value < 0 ? 0 : (value > MAX ? MAX : value);
466               }
467               *dstPix = T(value);
468             }
469             else {
470               *dstPix = *srcPix;
471             }
472             // increment to next component
473             ++dstPix; ++srcPix;
474           }
475         }
476         else {
477           // we don't have a pixel in the source image, set output to zero
478           for(int i = 0; i < nComps; ++i) {
479             *dstPix = 0;
480             ++dstPix;
481           }
482         }
483       }
484     }
485   }
486 
487 
488   ////////////////////////////////////////////////////////////////////////////////
489   // Render an output image
RenderAction(OfxImageEffectHandle instance,OfxPropertySetHandle inArgs,OfxPropertySetHandle)490   OfxStatus RenderAction( OfxImageEffectHandle instance,
491                           OfxPropertySetHandle inArgs,
492                           OfxPropertySetHandle /*outArgs*/)
493   {
494     // get the render window and the time from the inArgs
495     OfxTime time;
496     OfxRectI renderWindow;
497     OfxStatus status = kOfxStatOK;
498 
499     gPropertySuite->propGetDouble(inArgs, kOfxPropTime, 0, &time);
500     gPropertySuite->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
501 
502     // get our instance data which has out clip and param handles
503     MyInstanceData *myData = FetchInstanceData(instance);
504 
505     // get our param values
506     double gain = 1.0;
507     int applyToAlpha = 0;
508     gParameterSuite->paramGetValueAtTime(myData->gainParam, time, &gain);
509     gParameterSuite->paramGetValueAtTime(myData->applyToAlphaParam, time, &applyToAlpha);
510 
511 
512     // the property sets holding our images
513     OfxPropertySetHandle outputImg = NULL, sourceImg = NULL;
514     try {
515       // fetch image to render into from that clip
516       OfxPropertySetHandle outputImg;
517       if(gImageEffectSuite->clipGetImage(myData->outputClip, time, NULL, &outputImg) != kOfxStatOK) {
518         throw " no output image!";
519       }
520 
521       // fetch image at render time from that clip
522       if (gImageEffectSuite->clipGetImage(myData->sourceClip, time, NULL, &sourceImg) != kOfxStatOK) {
523         throw " no source image!";
524       }
525 
526       // figure out the data types
527       const char *cstr;
528       gPropertySuite->propGetString(outputImg, kOfxImageEffectPropComponents, 0, &cstr);
529       std::string components = cstr;
530 
531       // how many components per pixel?
532       int nComps = 0;
533       if(components == kOfxImageComponentRGBA) {
534         nComps = 4;
535       }
536       else if(components == kOfxImageComponentRGB) {
537         nComps = 3;
538       }
539       else if(components == kOfxImageComponentAlpha) {
540         nComps = 1;
541       }
542       else {
543         throw " bad pixel type!";
544       }
545 
546       // now do our render depending on the data type
547       gPropertySuite->propGetString(outputImg, kOfxImageEffectPropPixelDepth, 0, &cstr);
548       std::string dataType = cstr;
549 
550       if(dataType == kOfxBitDepthByte) {
551         PixelProcessing<unsigned char, 255>(gain, applyToAlpha != 0,
552                                             instance, sourceImg, outputImg, renderWindow, nComps);
553       }
554       else if(dataType == kOfxBitDepthShort) {
555         PixelProcessing<unsigned short, 65535>(gain, applyToAlpha != 0,
556                                                instance, sourceImg, outputImg, renderWindow, nComps);
557       }
558       else if (dataType == kOfxBitDepthFloat) {
559         PixelProcessing<float, 1>(gain, applyToAlpha != 0,
560                                   instance, sourceImg, outputImg, renderWindow, nComps);
561       }
562       else {
563         throw " bad data type!";
564       }
565 
566     }
567     catch(const char *errStr ) {
568       bool isAborting = gImageEffectSuite->abort(instance);
569 
570       // if we were interrupted, the failed fetch is fine, just return kOfxStatOK
571       // otherwise, something wierd happened
572       if(!isAborting) {
573         status = kOfxStatFailed;
574       }
575       ERROR_IF(!isAborting, " Rendering failed because %s", errStr);
576 
577     }
578 
579     if(sourceImg)
580       gImageEffectSuite->clipReleaseImage(sourceImg);
581     if(outputImg)
582       gImageEffectSuite->clipReleaseImage(outputImg);
583 
584     // all was well
585     return status;
586   }
587 
588   // are the settings of the effect making it redundant and so not do anything to the image data
IsIdentityAction(OfxImageEffectHandle instance,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)589   OfxStatus IsIdentityAction( OfxImageEffectHandle instance,
590                               OfxPropertySetHandle inArgs,
591                               OfxPropertySetHandle outArgs)
592   {
593     MyInstanceData *myData = FetchInstanceData(instance);
594 
595     double time;
596     gPropertySuite->propGetDouble(inArgs, kOfxPropTime, 0, &time);
597 
598     double gain = 1.0;
599     gParameterSuite->paramGetValueAtTime(myData->gainParam, time, &gain);
600 
601     // if the gain value is 1.0 (or nearly so) say we aren't doing anything
602     if(fabs(gain - 1.0) < 0.000000001) {
603       // we set the name of the input clip to pull default images from
604       gPropertySuite->propSetString(outArgs, kOfxPropName, 0, "Source");
605       // and say we trapped the action and we are at the identity
606       return kOfxStatOK;
607     }
608 
609     // say we aren't at the identity
610     return kOfxStatReplyDefault;
611   }
612 
613   ////////////////////////////////////////////////////////////////////////////////
614   // Call back passed to the host in the OfxPlugin struct to set our host pointer
615   //
616   // This must be called AFTER both OfxGetNumberOfPlugins and OfxGetPlugin, but
617   // before the pluginMain entry point is ever touched.
SetHostFunc(OfxHost * hostStruct)618   void SetHostFunc(OfxHost *hostStruct)
619   {
620     gHost = hostStruct;
621   }
622 
623   ////////////////////////////////////////////////////////////////////////////////
624   // The main entry point function, the host calls this to get the plugin to do things.
MainEntryPoint(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)625   OfxStatus MainEntryPoint(const char *action, const void *handle, OfxPropertySetHandle inArgs,  OfxPropertySetHandle outArgs)
626   {
627     MESSAGE(": START action is : %s \n", action );
628     // cast to appropriate type
629     OfxImageEffectHandle effect = (OfxImageEffectHandle) handle;
630 
631     OfxStatus returnStatus = kOfxStatReplyDefault;
632 
633     if(strcmp(action, kOfxActionLoad) == 0) {
634       // The very first action called on a plugin.
635       returnStatus = LoadAction();
636     }
637     else if(strcmp(action, kOfxActionDescribe) == 0) {
638       // the first action called to describe what the plugin does
639       returnStatus = DescribeAction(effect);
640     }
641     else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
642       // the second action called to describe what the plugin does in a specific context
643       returnStatus = DescribeInContextAction(effect, inArgs);
644     }
645     else if(strcmp(action, kOfxActionCreateInstance) == 0) {
646       // the action called when an instance of a plugin is created
647       returnStatus = CreateInstanceAction(effect);
648     }
649     else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
650       // the action called when an instance of a plugin is destroyed
651       returnStatus = DestroyInstanceAction(effect);
652     }
653     else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
654       // Check to see if our param settings cause nothing to happen
655       returnStatus = IsIdentityAction(effect, inArgs, outArgs);
656     }
657     else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
658       // action called to render a frame
659       returnStatus = RenderAction(effect, inArgs, outArgs);
660     }
661 
662     MESSAGE(": END action is : %s \n", action );
663     /// other actions to take the default value
664     return returnStatus;
665   }
666 
667 } // end of anonymous namespace
668 
669 
670 ////////////////////////////////////////////////////////////////////////////////
671 // The plugin struct passed back to the host application to initiate bootstrapping\
672 // of plugin communications
673 static OfxPlugin effectPluginStruct =
674 {
675   kOfxImageEffectPluginApi,                // The API this plugin satisfies.
676   1,                                       // The version of the API it satisifes.
677   "org.openeffects:GainExamplePlugin",     // The unique ID of this plugin.
678   1,                                       // The major version number of this plugin.
679   0,                                       // The minor version number of this plugin.
680   SetHostFunc,                             // Function used to pass back to the plugin the OFXHost struct.
681   MainEntryPoint                           // The main entry point to the plugin where all actions are passed to.
682 };
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 // The first of the two functions that a host application will look for
686 // after loading the binary, this function returns the number of plugins within
687 // this binary.
688 //
689 // This will be the first function called by the host.
OfxGetNumberOfPlugins(void)690 EXPORT int OfxGetNumberOfPlugins(void)
691 {
692   return 1;
693 }
694 
695 ////////////////////////////////////////////////////////////////////////////////
696 // The second of the two functions that a host application will look for
697 // after loading the binary, this function returns the 'nth' plugin declared in
698 // this binary.
699 //
700 // This will be called multiple times by the host, once for each plugin present.
OfxGetPlugin(int nth)701 EXPORT OfxPlugin * OfxGetPlugin(int nth)
702 {
703   if(nth == 0)
704     return &effectPluginStruct;
705   return 0;
706 }
707