Plugins Development Documentation

©2001, Georges-Edouard Berenger, berenger@francenet.fr
Hamburg, October 7th, 2001.

What is this document?

The Plugins API have been developed with two concurrent goals in mind:

Organization

Four classes are defined and documented separately: There is one more class which host developers will want to know about: Remains the simple function:

extern "C" status_t _EXPORT GetVideoPlugins(TList & plugin_list, VideoPluginsHost * host, image_id id);

It is the entry point the host application will be looking for when it tries to load a plugin. This function should first make sure that the host application is recent enough with this code:

status_t GetVideoPlugins(TList & plugin_list, VideoPluginsHost * host, image_id id)
{
	status_t compatible = host->APIVersionCompatible();
	if (compatible != B_OK)
		return compatible;

	// The version is compatible, now instanciate the VideoPluginType object:
	plugin_list.AddItem(new MyPluginType(host, id));
	return B_OK;
}
...where MyPluginType is the type of plugin you define. You may very well add several different types of plugins as done in this example:
	plugin_list.AddItem(new SharpenPluginType(host, id));
	plugin_list.AddItem(new BlurPluginType(host, id));
Note that the first lines never change in your code, and if ever you update the shared plugins files, then you will automatically update the test.

More about plugin properties

The biggest difficulty about those APIs is to define the abilities of your plugins properly. There are non-obvious design choices which are discussed here.

Each VideoPluginType class (instanciated only once) defines what are called vertices, which can each be seen as a path from one bitmap format to an other one, with respect to certain properties. Each VideoPluginType must define one or more vertices, as necessary, but those vertices must remains absolutely constant during the entire life of the plugin. It is allowed that this list changes each time the VideoPluginType object is created, for instance to match the abilities of the video card in use, as demonstrated by the "Overlayer" sample plugin.

In other words, GetVerticesProperties must always return the same values. The structures which describes the vertices may not change or disappear during the live of the VideoPluginType object.

The properties of a vertice are defined as follows:

typedef struct {
	color_space	in_cspace;
	color_space	out_cspace;
	float		quality;
	uint32		flags;
	int32		future[4];
} vertice_properties;
in_cspace is the color space of the bitmap to be filtered. There is no restriction on this format as long as you know how to handle it. out_cspace is the color space of the result bitmap. There is no restriction on this format as long as you know how to handle it as well! It may be different than the format of the bitmap filtered. Therefore, you can very well make a converter plugin which will convert B_RGB32 bitmaps into B_RGB16 ones, and vice versa.

You may also choose to accept any color space for a vertice using ANY_COLOR_SPACE, with the following restrictions:
If you wish to use ANY_COLOR_SPACE,
then you MUST use it for both in_cspace & out_cspace.

in_cspace and out_cspace will ALWAYS be equal.

In other words, you can not use ANY_COLOR_SPACE to describe a filter which would make any kind of format conversion. If you wish to make such a format converter, then you must enumerate each supported format conversion, one after the other.

The reason behind this limitation is that it would increase greatly the complexity of the path finding algorithm and the handling of intermediate bitmaps. A great deal of the complexity comes from other features such as overlay support and support for bitmaps to which you may attach views.

For each vertice, you must set at least one of the four flags VAPI_PROCESS_TO_DISTINCT, VAPI_PROCESS_TO_OVERLAY, VAPI_PROCESS_IN_PLACE, VAPI_PROCESS_OVERLAY_IN_PLACE for each vertice, but you may define more than one. Those flags describes if your plugin can write in an overlay or not, and if your plugin may accept that the output bitmap is the same as the input bitmap. Note that the different vertices of a plugin may each set those flags as they wish, regardless of the other vertices.

Precisely:

When ApplyEffect(BBitmap * frame_in, BBitmap * frame_out, int64 frame_count, bool skipped_frames) is called, it receives a pointer to the incoming and to the outgoing bitmaps.

The bitmaps on which processing is done are handled entirely by the PluginsHandler class. It is the responsibility of this class to always provide bitmap(s) which respect the properties of the vertice used. Here is how the effective mode is chosen:

If the plugin needs to use BView methods to draw in the bitmap (VAPI_BVIEW_DRAWING), then it will receive a bitmap with a view attached. Otherwise...
If the plugin accepts to process overlays in place (VAPI_PROCESS_OVERLAY_IN_PLACE), and the previous plugin (if any) accepts to write in an overlay, and if all the plugins after this plugin accept to work on an overlay in place, then the plugin will receive an overlay, and the output bitmap will also be that overlay. Otherwise...
If the plugin accepts to write in an overlay (VAPI_PROCESS_TO_OVERLAY), and if the plugins after it can work on the overlay in place, then it will get a regular bitmap as input, and will be given an overlay as output. Of course, the video card has to support overlays! Otherwise...
If the plugin accepts to modify manually a single bitmap (VAPI_PROCESS_IN_PLACE), then it will get a single bitmap for input and output. Otherwise...
If the plugin accepts to work on different "normal" bitmaps (VAPI_PROCESS_TO_DISTINCT), then it will get two distinct bitmaps.

If none of the situations above arise, that means that the path selected wasn't valid. This obviously shouldn't ever happen!
This might happen nevertheless either because a plugin has inconsistent flags, or because the algorithm breaks at some level... Use debug outputs to find out what is going on! Very careful choice of the flags is essential. The example plugins show how to use those flags properly in different situations.

You can get the system to break if for instance your plugin requires to write and/or process an overlay: if no overlay is available, then the system won't be able to find any solution! Therefore, plugins should always support either VAPI_PROCESS_TO_DISTINCT or VAPI_PROCESS_IN_PLACE.

As a general rule, you will probably never need to use VAPI_PROCESS_OVERLAY_IN_PLACE. Modifying an overlay is not a good idea because you will create ugly visible flicker effects. Remember that an overlay is essentially a way to clip a section of video memory over a part of your screen where a specific color is used. Users will be able to see the modifications you are doing to this memory in real time.

Also, your plugin may want to use the BView APIs to draw. For that, use the VAPI_BVIEW_DRAWING flag which will automatically set the VAPI_PROCESS_IN_PLACE flag. BView method allow you only to work in the given bitmap, therefore you can't use the VAPI_PROCESS_TO_DISTINCT or VAPI_PROCESS_TO_OVERLAY. You should also not use the VAPI_PROCESS_OVERLAY_IN_PLACE together with VAPI_BVIEW_DRAWING, for it is not supported at least by some video cards.

Getting ready for work

Plugin developers will need to get the latest version of their host application with the corresponding files: They will link their plugins against the host application and the necessary system libraries (libbe.so, etc.).

Host application developers will need to get the latest version of the following files:

The latest version of those files are available in the stampTV source code package available on BeBits.