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