1= OFX Programming Guide : Basic Machinery
2Author:Bruno Nicoletti
32014-10-17
4:toc:
5:data-uri:
6:source-highlighter: coderay
7
8This is a guide to the basic machinery an OFX plugin uses to communicate with a host application, and goes into the fundamentals of the API.
9
10An example plugin will be used to illustrate how all the machinery works, and its source can be found in the pass:[C++]
11file `Guide/Code/Example1/basics.cpp`.
12This plugin is a 'no-op' image effect and does absolutely nothing to images, it is there purely to show you the basics of
13how a host and plugin work together. I'll embed snippets of the plugin, but with some comments and debug code stripped for
14clarity.
15
16An OFX plugin is a compiled dynamic library that an application can load on demand to add extra features to itself. A
17standardised API is used by a host and a plugin to communicate and do what is needed.
18
19OFX has an underlying plugin mechanism that could be used to
20create a wide variety of plugin APIs, but currently only one has been layered on top of the base plugin
21machinery, which is the OFX Image Effect API.
22
23The OFX API is specified using the `C` programming language purely by a set of header files, there are no libraries a plugin
24need to link against to make a plugin or host work.footnote:[Though there exist optional host and plugin support libraries that can be used to help you in your coding.]
25
26== Key Concepts and Terminology
27OFX has several key concepts and quite specific terminology, which definitely need defining.
28
29  * a `**host**` is an application than can load OFX plugins and provides an environment for plugins
30 to work in,
31  * a `**plugin**` provides a set of extra features to a host application,
32  * a `**binary**` is a dynamic library footnote:[which will be operating system specific] that contains one or more plugins,
33  * a `**suite**` is `C struct` containing a set of function pointers, which are named and versioned,
34Suites are the way a host allows a plugin to call functions within it and not have to link against anything,
35  * a `**property**` is a named object of a restricted set of `C` types, which is accessed via a property suite,
36  * a `**property set**` is a collection of properties,
37  * an `**action**` is a call into a plugin to do something,
38  * an `**API**` is a collection of suites, actions and properties that are used to do something useful, like process images. APIs are
39named and versioned.
40
41[[anchor-bootstrapper_functions]]
42== The Two Bootstrapper Functions
43To tell the host what it has inside it, a plugin binary needs to expose two functions to bootstrap the whole host/plugin communications process. These are...
44
45  * `int OfxGetNumberOfPlugins(void)`  - a function that returns the number of plugins within that binary,
46  * `OfxPlugin *OfxGetPlugin(int nth)` - a function that returns a `struct` that provides the information required by a host to bootstrap the plugin.
47
48The host should load the binary using the appropriate operating system calls, then search it for these two exposed symbols. It should then iterate over the number
49of advertised plugins and decide what to do with the plugins it finds.
50
51It should go without saying that a host should not hang onto the pointer returned by `OfxGetPlugin` after it unloads a binary, as the data will not be valid.
52It should also copy any strings out of the struct if it wants to keep them.
53
54From our example, we have the following...
55
56[source, c++]
57.basics.cpp
58----
59// how many plugins do we have in this binary?
60int OfxGetNumberOfPlugins(void)
61{
62  return 1;
63}
64
65// return the OfxPlugin struct for the nth plugin
66OfxPlugin * OfxGetPlugin(int nth)
67{
68  if(nth == 0)
69    return &effectPluginStruct;
70  return 0;
71}
72----
73
74== The OfxPluginStruct
75The `**OfxPluginStruct**` returned by `**OfxGetPlugin**` provides information about the implementation of a particular plugin. The definition found in the OFX
76headers is...
77
78[source, c++]
79.ofxCore.h
80----
81typedef struct OfxPlugin {
82  const char         *pluginApi;
83  int                 apiVersion;
84  const char         *pluginIdentifier;
85  unsigned int        pluginVersionMajor;
86  unsigned int        pluginVersionMinor;
87  void               (*setHost)(OfxHost *host);
88  OfxPluginEntryPoint *mainEntry;
89} OfxPlugin;
90----
91
92The fields in the struct give the host enough information to uniquely identify the plugin, what it does, and what version it is. These are...
93
94  * `**pluginAPI**` - the name of the API that this plugin satisfies, image effect plugins should set this to `kOfxImageEffectPluginApi`,
95  * `**apiVersion**` - the version of that API the plug-in was written to,
96  * `**pluginIdentifier**` - the unique name of the plug-in. Used only to disambiguate the plug-in from all other plug-ins, not necessarily for human eyes,
97  * `**pluginVersionMajor**` -  the major version of the plug-in, typically incremented when compatibility breaks,
98  * `**pluginVersionMinor**` -  the minor version of the plug-in, typically incremented when bugs and so on are fixed,
99  * `**setHost**` - a function used to set the OfxHost struct in the plugin,
100  * `**mainEntry**` - the function a host will use to send action requests to the plugin.
101
102Our example plugin's `OfxPlugin` struct looks like...
103
104[source, c++]
105.basics.cpp
106----
107static OfxPlugin effectPluginStruct =
108{
109  kOfxImageEffectPluginApi,
110  1,
111  "org.openeffects:BasicsExamplePlugin",
112  1,
113  0,
114  SetHostFunc,
115  MainEntryPoint
116};
117----
118
119Using this information a host application can grab a plugin struct then figure out if it supports the API at the given version.
120
121The `**pluginIdentifier**` is not meant to be the presented to the user, it is a purely a unique id for that plugin, _and any related
122versions_ of that plugin. Use this for serialisation etc... to identify the plugin. The domainname:pluginname nomenclature is suggested
123best practice for a unique id. For a user visible name, use the `**kOfxPropVersionLabel**` property
124
125Plugin versioning allows a plugin (as identified by the `**pluginIdentifier**` field) to be updated and redistributed
126multiple times, with the host knowing which is the most appropriate version to use.  It even allows old and new versions of the same
127plugin to be used simultaneously within a host application. There are more details on how to use the version numbers in the
128OFX Programming Reference.
129
130The `**setHost**` function is used by the host to give the plugin an `**OfxHost**` struct (see below), which is the bit
131that gives the plugin access to functions within the host application.
132
133Finally the `**mainEntry**` is the function called by the host to get the plugin to carry out actions. Via the property system
134it behaves as a generic function call, allowing arbitrary numbers of parameters to be passed to the plugin.
135
136== Suites
137A suite is simply a struct with a set of function pointers. Each suite is defined by a C struct
138definition in an OFX header file, as well a C literal string that names the
139suite. A host will pass a set of suites to a plugin, each suite having the set of function pointers
140filled appropriately.
141
142For example, look in the file ofxMemory.h for the suite used to perform memory allocation...
143
144[source, c++]
145.ofxMemory.h
146----
147#define kOfxMemorySuite "OfxMemorySuite"
148
149typedef struct OfxMemorySuiteV1 {
150  OfxStatus (*memoryAlloc)(void *handle,
151                           size_t nBytes,
152                           void **allocatedData);
153
154  OfxStatus (*memoryFree)(void *allocatedData);
155} OfxMemorySuiteV1;
156----
157
158Notice also, the version number built into the name of the memory suite. If we ever needed to change
159the memory suite for some reason, `OfxMemorySuiteV2` would be defined, with a new set of function
160pointers. The new suite could then live along side the old suite to provide backwards compatibility.
161
162Plugins have to ask for suites from the host by name with a specific version, how we do that
163is covered next.
164
165=== The OfxHost and Fetching Suites
166An instance of an `**OfxHost**` C struct is the thing that allows a plugin to get suites and provides information
167about a host application, it looks like...
168
169[source, c++]
170.ofxCore.h
171----
172typedef struct OfxHost {
173  OfxPropertySetHandle host;
174  void *(*fetchSuite)(OfxPropertySetHandle host, const char *suiteName, int suiteVersion);
175} OfxHost;
176----
177
178A plugin is given one of these by the host application via the `**OfxPlugin::setHost**` function it previously passed to the host.
179
180There are two members to an `**OfxHost**`, the first is a property set (more on properties in a moment) which describes what the host
181does and how it behaves.
182
183The second member is a function used to fetch suites from the host application. Going back to our example plugin, we have the following bits
184of code. For the moment ignore how and when the LoadAction is called, but notice what it does...
185
186[[LoadActionExample]]
187[source, c++]
188.basics.cpp
189----
190//  The anonymous namespace is used to hide symbols from export.
191namespace {
192  OfxHost               *gHost;
193  OfxPropertySuiteV1    *gPropertySuite = 0;
194  OfxImageEffectSuiteV1 *gImageEffectSuite = 0;
195
196  ////////////////////////////////////////////////////////////////////////////////
197  /// call back passed to the host in the OfxPlugin struct to set our host pointer
198  void SetHostFunc(OfxHost *hostStruct)
199  {
200    gHost = hostStruct;
201  }
202
203  ////////////////////////////////////////////////////////////////////////////////
204  /// the first action called
205  OfxStatus LoadAction(void)
206  {
207    gPropertySuite    = (OfxPropertySuiteV1 *) gHost->fetchSuite(gHost->host,
208                                                                 kOfxPropertySuite,
209                                                                 1);
210    gImageEffectSuite = (OfxImageEffectSuiteV1 *) gHost->fetchSuite(gHost->host,
211                                                                    kOfxImageEffectSuite,
212                                                                    1);
213
214    return kOfxStatOK;
215  }
216
217}
218----
219
220Notice that it is fetching two suites by name from the host. Firstly the all important kOfxPropertySuite
221and then the kOfxImageEffectSuite. It squirrels these away for later use in two global pointers. The
222plugin can then use the functions in the suites as and when needed.
223
224== Properties
225The main way plugins and hosts communicate is via the properties mechanism. A property is a named
226object inside a property set, which is a bit like a python dictionary. You use the property suite,
227defined in the header ofxProperty.h to access them.
228
229Properties can be of the following fundamental types...
230
231   * `**int**`
232   * `**double**`
233   * `**char pass:[*]**`
234   * `**void pass:[*] **`
235
236So for in our example we have....
237
238[source, c++]
239.basics.cpp
240----
241    OfxPropertySetHandle effectProps;
242    gImageEffectSuite->getPropertySet(effect, &effectProps);
243
244    gPropertySuite->propSetString(effectProps, kOfxPropLabel, 0, "OFX Basics Example");
245----
246
247Here the plugin is using the effect suite to get the property set on the effect.
248It is then setting the string property `**kOfxPropLabel**` to be "OFX Basics Example".
249There are corresponding calls for the other data types, and equivalent set calls. All pretty straight forwards.
250
251Notice the `**0**` passed as the third argument, which is an index. Properties can be multidimensional, for example
252the current pen position in a graphics viewport is a 2D integer property. You can get and set individual elements in a
253multidimensional property
254or you could use calls like `**OfxPropertySuiteV1::propSetIntN**` to set all values at once.
255Of course there exists 'N' calls for all types, as well as corresponding setting calls.
256
257The various OFX header files are littered with C macros that define the properties used by the API, what type they
258are, what property set they are on and whether you can read and/or write them. The OFX reference guide had all the
259properties listed by name and object they are on, as well as what they are for.
260
261By passing information via property sets, rather than fixed C structs, you gain a flexibility that allows for simple
262incremental additions to the API without breaking backwards compatibility and builds. It does come at a cost (being
263continual string look-up), but the flexibility it gives is worth it.
264
265NOTE: Plugins have to be very careful with scope of the pointer returned when you fetch a string property. The pointer will
266be guaranteed to be valid _only_ until the next call to an OFX suite function or until the action ends. If you want to use the
267string out of those scope you _must_ copy it.
268
269== Actions
270Actions are how a host tells a plugin what to do. The `**mainEntry**` function pointer in the `**OfxPlugin**` structure
271is the what accepts actions to do whatever is being requested.
272
273The function must conform to the following typedef...
274
275[source, c++]
276.ofxCore.h
277----
278typedef  OfxStatus (OfxPluginEntryPoint)(const char *action,
279                                         const void *handle,
280                                         OfxPropertySetHandle inArgs,
281                                         OfxPropertySetHandle outArgs);
282----
283
284Where...
285
286  * `action` is a C string that specifies what is to be done by the plugin, e.g. "OfxImageEffectActionRender" tells an image effect plugin to
287render a frame,
288  * `handle` is the thing that is being operated on, and needs to be downcast appropriately, what this is will depend on the action,
289  * `inArgs` is a well defined property set that are the arguments to the action,
290  * `outArgs` is a well defined property set where a plugin can return values as needed.
291
292The entry point will return an `OfxStatus` to tell the host what happened. A plugin is not obliged to trap all actions, just a certain subset,
293and if it doesn't need to trap the action, it can just return the status `**kOfxStatReplyDefault**` to have the host carry out the well defined
294default for that action.
295
296So looking at our example we can see its main entry point....
297
298[source, c++]
299.basics.cpp
300----
301  OfxStatus MainEntryPoint(const char *action,
302                           const void *handle,
303                           OfxPropertySetHandle inArgs,
304                           OfxPropertySetHandle outArgs)
305  {
306    // cast to appropriate type
307    OfxImageEffectHandle effect = (OfxImageEffectHandle) handle;
308
309    OfxStatus returnStatus = kOfxStatReplyDefault;
310
311    if(strcmp(action, kOfxActionLoad) == 0) {
312      returnStatus = LoadAction();
313    }
314    else if(strcmp(action, kOfxActionUnload) == 0) {
315      returnStatus = UnloadAction();
316    }
317    else if(strcmp(action, kOfxActionDescribe) == 0) {
318      returnStatus = DescribeAction(effect);
319    }
320    else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
321      returnStatus = DescribeInContextAction(effect, inArgs);
322    }
323    else if(strcmp(action, kOfxActionCreateInstance) == 0) {
324      returnStatus = CreateInstanceAction(effect);
325    }
326    else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
327      returnStatus = DestroyInstanceAction(effect);
328    }
329    else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
330      returnStatus = IsIdentityAction(effect, inArgs, outArgs);
331    }
332
333    return returnStatus;
334  }
335----
336
337You can see the plugin is trapping seven actions and is saying to do the default for the rest of the actions.
338
339In fact only four actions need to be trapped for an image effect plugin footnote:[kOfxLoadAction, kOfxActionDescribe, kOfxImageEffectActionDescribeInContext and one of kOfxImageEffectActionIsIdentity or kOfxImageEffectActionRender], but our machinery plugin is trapping more for illustrative purposes.
340
341What is on the property sets, and what the handle is depends on the action being called. Some actions have no arguments (eg: the kOfxLoadAction), while others have in and out arguments, e.g. the kOfxImageEffectActionIsIdentity.
342
343Actions give us a very flexible and expandable generic function calling mechanism. This means it is trivial to expand the API via adding extra
344properties or actions to the API without impacting existing plugins or applications.
345
346NOTE: For the main entry point on image effect plugins, the handle passed in will either be NULL or an `**OfxImageEffectHandle**`, which is just a blind pointer to host specific data that represents the plugin.
347
348== Basic Actions For Image Effect Plugins
349There are a set of actions called on a plugin that signal to the plugin what is going on and to get it to tell the host what the plugin does. These need
350to be called in a specific sequence to make it all work properly.
351
352=== The Load and Unload Actions
353The kOfxActionLoad is the very first action passed to a plugin. It will be called after the `setHost` callback has been used to pass the OfxHostStruct to the plugin. It is the point at which a plugin gets to create global structures that it will later be used across all instances. From our <<LoadActionExample, load action snippet>> above, you can see that the plugin is fetching two suites and caching the pointers away for later use.
354
355At some point the host application will want to unload the binary that the plugin is contained in, either when the host quits or the plugin is
356 no longer needed by the host application. The host needs to notify the plugin of this, as it may need to perform some clean up.
357The kOfxActionUnload action is sent to the plugin by the host to warn the plugin of it's imminent demise. After this action is called the host can no
358longer issue any actions to that plugin unless another kOfxActionLoad action is called. In our example plugin, the unload does nothing.
359
360NOTE: Hosts should always pair the kOfxActionLoad with a kOfxActionUnload, otherwise all sorts of badness can happen, including memory leaks,
361failing license checks and more. There is one excpetion to this, which is if a plugin encounters an error during the load action and returns
362an error state. In this case only, the plugin _must_ clean up
363before it returns, and , the balancing unload action is _not_ called. In all other circumstances where an error is
364returned by a plugin from any other action, the unload action will eventually be called.
365
366=== Describing Plugins To A Host
367Once a plugin has had kOfxActionLoad called on it, it will be asked to describe itself. This is done with the kOfxActionDescribe action.
368From our example plugin, here is the function called by our main entry point in response to the describe action.
369
370[source, c++]
371.basics.cpp
372----
373  OfxStatus DescribeAction(OfxImageEffectHandle descriptor)
374  {
375    // get the property set handle for the plugin
376    OfxPropertySetHandle effectProps;
377    gImageEffectSuite->getPropertySet(descriptor, &effectProps);
378
379    // set some labels and the group it belongs to
380    gPropertySuite->propSetString(effectProps,
381                                  kOfxPropLabel,
382                                  0,
383                                  "OFX Basics Example");
384    gPropertySuite->propSetString(effectProps,
385                                  kOfxImageEffectPluginPropGrouping,
386                                  0,
387                                  "OFX Example");
388
389    // define the image effects contexts we can be used in, in this case a simple filter
390    gPropertySuite->propSetString(effectProps,
391                                  kOfxImageEffectPropSupportedContexts,
392                                  0,
393                                  kOfxImageEffectContextFilter);
394
395    return kOfxStatOK;
396  }
397----
398
399You will see that it fetches a property set (via the image effect suite) and sets various properties on it. Specifically the label used
400in any user interface to name the plugin, and the group of plugins it belongs to. The grouping name allows a developer to ask the
401host to arrange all plugins with that group name into a single menu/container in the user interface.
402
403The final thing it sets is the single context it can be used in. Contexts are specific to image effect plugins, and they are there because a plugin can be used in many different ways.
404We call each way an image effect plugin can be used a context. In our example we are saying our
405plugin can behave as a filter only. A filter is simply an effect with one and only one input clip and one mandated output clip. This is typical
406of systems such as editors which can drop effects directly onto a clip in a time-line. For more complex systems, e.g. a node graph compositor,
407you might want to allow the same plugin to have more input clips and a richer parameter set, which we call the general context. A plugin can work
408one or more contexts, not all of which need be supported by a host.
409
410Because it can be used in different contexts, and will need to be described differently in each, an image effect plugin has a two tier description process.
411First kOfxActionDescribe is called to
412set attributes common to all the contexts the plugin can be used in, then the kOfxImageEffectActionDescribeInContext action is called, once for each
413context that the host wants to use the effect in.
414
415Again from our example plugin, here is how it responds to the describe in context action...
416
417NOTE: A plugin developer might package multiple plugins in a single binary and another multiple plugins into multiple binaries yet
418both expect them to show up in the same plugin group footnote:[as specified by **kOfxImageEffectPluginPropGrouping**] in the user interface.
419[source, c++]
420.basics.cpp
421----
422  OfxStatus
423  DescribeInContextAction(OfxImageEffectHandle descriptor, OfxPropertySetHandle inArgs)
424  {
425    // check state
426    ERROR_ABORT_IF(gDescribeCalled == false, "DescribeInContextAction called before DescribeAction");
427    gDescribeInContextCalled = true;
428
429    // get the context from the inArgs handle
430    char *context;
431    gPropertySuite->propGetString(inArgs, kOfxImageEffectPropContext, 0, &context);
432
433    ERROR_IF(strcmp(context, kOfxImageEffectContextFilter) != 0, "DescribeInContextAction called on unsupported contex %s", context);
434
435    OfxPropertySetHandle props;
436    // define the mandated single output clip
437    gImageEffectSuite->clipDefine(descriptor, "Output", &props);
438
439    // set the component types we can handle on out output
440    gPropertySuite->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
441    gPropertySuite->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
442
443    // define the mandated single source clip
444    gImageEffectSuite->clipDefine(descriptor, "Source", &props);
445
446    // set the component types we can handle on our main input
447    gPropertySuite->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
448    gPropertySuite->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
449
450    return kOfxStatOK;
451  }
452----
453In this case I've left the error check cluttering up the snippet so you can see how the `inArgs` property set is used to
454specify which context is currently being described. Our example then goes on define two image clips, the first used for
455output, and the second used for input. The API docs specify that a filter effect needs to specify both of these with
456exactly those names. Not also how the effect is setting a multidimensional property associated with each clip to
457specify what pixel types it supports on those clips.
458
459For more complex effects, these actions are the point where you specify parameters that the effect wants to use, and get to
460tweak a whole range of settings to say how the plugin behaves.
461
462=== Creating Instances
463So far a host knows what our plugin looks like and how it should behave, but it isn't using it to process pixels yet. At some point
464a user will click on a button in a UI and to say they want to use the plugin. To do that a host creates an __instance__ of the plugin.
465An instance represents a unique copy of the plugin and contains all the state needed for that. For example, a blur plugin may
466be instantiated many times in a compositing graph, each instance will have parameters set to a different value, and be connected to different
467input and output clips.
468
469A plugin developer may need to attach data to each plugin instance, typically to tie the plugin into their own image processing infrastructure.
470They get the chance to do that via the kOfxActionCreateInstance action. The host will call that action just after they have created and initialised
471their host-side data structures that represent the plugin. Our example plugin doesn't actually do anything on create instance, but it could choose
472to attached it's own data structures to the instance via the `kOfxPropInstanceData` property.
473
474A plugin will also want to destroy any of its own data structures when an instance is destroyed. It gets to do that in the kOfxActionDestroyInstance
475action.
476
477Our example plugin exercises both of those action just to illustrate what is going it. It simply places a string into the instance data property which
478it later fetches and destroys. In real plugins, this is typically a hook to deeper plugin side data structures.
479
480NOTE: Because a host might have asynchronous UI handling and multiple render threads on the same instance, it is suggested that a plugin that wants to write to the instance data after instance creation do so in a safe manner (e.g. by semaphore lock).
481
482[source, c++]
483.basics.cpp
484----
485  OfxStatus CreateInstanceAction(OfxImageEffectHandle instance)
486  {
487    OfxPropertySetHandle effectProps;
488    gImageEffectSuite->getPropertySet(instance, &effectProps);
489
490    // attach some instance data to the effect handle, it can be anything
491    char *myString = strdup("This is random instance data that could be anything you want.");
492
493    // set my private instance data
494    gPropertySuite->propSetPointer(effectProps,
495                                   kOfxPropInstanceData,
496                                   0,
497                                   (void *) myString);
498
499    return kOfxStatOK;
500  }
501
502  // instance destruction
503  OfxStatus DestroyInstanceAction(OfxImageEffectHandle instance)
504  {
505    OfxPropertySetHandle effectProps;
506    gImageEffectSuite->getPropertySet(instance, &effectProps);
507
508    // get my private instance data
509    char *myString = NULL;
510    gPropertySuite->propGetPointer(effectProps,
511                                   kOfxPropInstanceData,
512                                   0,
513                                   (void **) &myString);
514    ERROR_ABORT_IF(myString == NULL, "Instance data should not be null!");
515    free(myString);
516
517    return kOfxStatOK;
518  }
519----
520
521NOTE: kOfxActionDestroyInstance should always be called when an instance is destroyed, and furthermore all instances need to
522have had kOfxActionDestroyInstance called on them before kOfxActionUnload can be called.
523
524=== What About The Image Processing?
525This plugin is pretty much a 'hello world' OFX example, it doesn't actually process any images. Normally a host application would call
526the `**kOfxImageEffectActionRender**` action when it wants the plugin to render a frame. Our simple plugin gets around processing any images
527by trapping the `**kOfxImageEffectActionIsIdentity**` action. This action lets the plugin tell the host application that it currently does
528nothing to its inputs, for example a blur effect with the blur size of zero. In such a case the host can simply ignore the plugin and use
529its source images directly. And here is the code that does that...
530
531[source, c++]
532.basics.cpp
533----
534  OfxStatus IsIdentityAction( OfxImageEffectHandle instance,
535                              OfxPropertySetHandle inArgs,
536                              OfxPropertySetHandle outArgs)
537  {
538    // we set the name of the input clip to pull data from
539    gPropertySuite->propSetString(outArgs, kOfxPropName, 0, "Source");
540    return kOfxStatOK;
541  }
542----
543
544The plugin is telling the host to pass through an unprocessed image from an input clip, and because plugins can have more than one input
545it needs to tell the host which clip to use. It does that by setting the `kOfxPropName` property on the outargs. It also returns
546`**kOfxStatOK**` to indicate that it has trapped the action and that the plugin is currently doing nothing.
547
548Remember we said that each action has a well defined set of in and out arguments? In the case of the is identity action these are...
549
550.inArgs
551  * kOfxPropTime - the time at which to test for identity
552  * kOfxImageEffectPropFieldToRender - the field to test for identity
553  * kOfxImageEffectPropRenderWindow - the window to test for identity under
554  * kOfxImageEffectPropRenderScale - the scale factor being applied to the images being rendered
555
556.outArgs
557  * kOfxPropName this to the name of the clip that should be used if the effect is an identity transform, defaults to the empty string
558  * kOfxPropTime the time to use from the indicated source clip as an identity image (allowing time slips to happen), defaults to the value in kOfxPropTime in inArgs
559
560A proper plugin would examine the inArgs, its parameters and see if it is doing anything to its inputs. If it does need to process images
561it would return `**kOfxStatReplyDefault**` rather than `**kOfxStatOK**`.
562
563
564== Life Cycle of a Plugin
565
566Now we've outlined the basic actions and functions in a plugin, we should clearly specify the calling sequence. Failure to call them in the right
567sequence will lead to all sorts of undefined behaviour.
568
569Assuming the host has done nothing apart from load the dynamic library that contains plugins and has found the two <<anchor-bootstrapper_functions, boostrapping symbols>> in the plugin, the host
570should then...
571
572   - call `OfxGetNumberOfPlugins` to discover the number of plugins
573   - call `OfxGetPlugin` for each of the N plugins in the binary and decide if it can use them or not (by looking at APIs and versions)
574
575At this point the code in the binary should have done nothing apart from run those two functions. The host is free to unload the binary at this point without
576further interaction with the plugin.
577
578If the host decides it wants to use one of the plugins in the binary it must then...
579
580   * call the `setHost` function given to it __for that plugin__ and pass back an OfxHost struct which allows plugins to fetch suites appropriate for
581the API
582   * call the `kOfxActionLoad`
583     ** call `kOfxActionDescribe`
584     ** call `kOfxImageEffectActionDescribeInContext` for each context
585
586If the host wants to actually use a plugin, it creates whatever host side data structures are needed then...
587
588     ** calls kOfxActionCreateInstance
589
590When a host wants to get rid of an instance, before it destroys any of it's own data structures it...
591     ** calls kOfxActionDestroyInstance
592
593When the host wants to be done with the plugin, and before it dynamically unloads the binary it...
594   * calls `kOfxActionUnload`, all instances _must_ have been destroyed before this call.
595
596Once the final kOfxActionUnload has been called, even if it doesn't dynamically unload the binary, the host can no longer call the main entry point on that specific plugin until it once more calls kOfxActionLoad.
597
598=== Packaging A Plugin
599The compiled code for a plugin is contained in a dynamic library. Plugins are distributed as a directory structure that allows you to add icons and other resources you
600may need. There is more detailed information in the OFX Programming Reference Guide.
601
602== Summary
603This example has shown you the basics of the OFX plugin machinery, the main things it illustrated was...
604
605  - the <<anchor-bootstrapper_functions, two bootstrapper functions>> exposed by a plugin that start the plugin discovery process,
606  - the main entry point of a plugin is given <<Actions, actions>> by the host application to do things,
607  - the plugin gets <<Suites, suites>> from the host to gain access to functions in the host,
608  - <<Properties,property sets>> are the main way of passing data back and forth across the API,
609  - image effect plugins are <<Describing Plugins To A Host, described>> in a two step process,
610  - <<Creating Instances, instances are created>> when a host wants to use a plugin to do something,
611  - actions must be called in a <<Life Cycle of a Plugin, certain order>> for the API to work cleanly.