Found at: http://www.kinodv.org/article/print/33/-1/12/


Top level Developer Guide

This document provides a brief HOWTO create new plug-ins to the Kino Magick sub-system.

INTRODUCTION

The plug-in mechanism, like the entirety of the Magick implementation, is seen as a strategic short-term mechanism to provide Kino with often requested functionality such as:
As a strategic solution, no guarantee is made on the longer term viability in subsequent Kino releases. This applies to both the internally provided fx and any plug-ins developed.

The remainder of this document provides a brief description of how new plug-ins are created. It assumes a basic knowledge of C++ and a knowledge of glade and the GTK libraries is beneficial. This document assumes the use of glade, though it's not strictly necessary.

ROAD MAP

The remainder of this document describes the following steps.

Creating a new glade project
Customising the Glade Generated files
Defining the fx
   Image Create
   Image Filter
   Image Transition
   Audio Filter
   Audio Transition
Adding GUI Interaction
Communicating the fx to kino
Compilation and Installation
Distribution

CREATING A NEW GLADE PROJECT

The first step is to start glade and enter the Project Options dialog. The following modifications should be made in each of the tabs:

General: Use all defaults, but change the project directory - note that it is sufficient to change the directory only (/home/user/mykinoplugin would create a new directory called mykinoplugin in your home directory, with a glade project called mykinoplugin.glade)

C Options: Use all defaults except select 'Set Widget Names' and de-select 'Output main.c File'.

Click on OK.

If the effects you wish to add require user interaction, then you can create a new window and add any widgets that are required. If you don't need any then, you don't need to even create a window.

Save and build the project.

CUSTOMISING THE GLADE GENERATED FILES

By default, glade assumes that you are generating an application. In the case of a kino plug-in, we are creating a shared object, so we need to change a few settings to reflect this.

The first file to edit is the configure.in file (located in your project directory). After the line 'AM_CONFIG_HEADER(config.h)' add the following:

AM_DISABLE_STATIC
AC_PROG_CXX
AM_PROG_LIBTOOL

The second file to edit is the src/Makefile.am.

Add the following at the beginning of the file:

KINO_INCLUDE = $(prefix)/include/kino
libdir = $(prefix)/lib/kino

Add the kino include directory to the INCLUDES value:

INCLUDES = \
	$(GNOME_INCLUDEDIR) \
	-I$(KINO_INCLUDE)

Replace the initial entries of bin_PROGRAMS, mykinoplugin_SOURCES and mykinoplugin_LDADD with:

lib_LTLIBRARIES = libmykinoplugin.la

libmykinoplugin_la_SOURCES = \
	support.c support.h \
	interface.c interface.h \
	callbacks.c callbacks.h \
	mykinoplugin.cc {+ any additional defined}

libmykinoplugin_la_LIBADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS)

DEFINING THE FX

We now need to create the SOURCES added to the Makefile.am.

Kino currently provides 5 possible types of plug-in. An individual plug-in project may define any number of each, or indeed none of any (though why you would do that escapes me :-)).


Image Creators

These allow you to write custom creators/importers of images.

To define one of these, you need to:

#include <image_create.h>

and implement a GDKImageCreate class:

class MyPlugin : public GDKImageCreate
{
    public:
        char *GetDescription( ) const;
        void CreateFrame( uint8_t *pixels, int width, int height,
                double position, double delta_frame );
        int GetNumberOfFrames( );
        void AttachWidgets( GtkBin *bin );
        void DetachWidgets( GtkBin *bin );
        void InterpretWidgets( GtkBin *bin );
}

Notes:
  1. The pixels array contains width * height * 3 bytes. Each pixel is represented by RGB triples.
  2. On the first call, the contents of pixels are undefined. On subsequent calls, it contains the previously created image.
  3. The number of times the CreateFrame method is called is determined by the GetNumberOfFrames method.
  4. The first call is always denoted by a position of 0.0 and the last is normally 1.0 (unless the 'GetNumberOfFrames' returned 1 on the previous call.
  5. See general notes on the 'Widget' methods below.
Image Filters

These allow you to write custom filters to image. A filter allows you to alter the input frames in some way (such as 'convert to black and white', or add a 'ripple' etc).

To define one of these, you need to:

#include <image_filters.h>

and implement a GDKImageFilter class:

class MyPlugin : public GDKImageFilter
{
    public:
        char *GetDescription( ) const;
        void FilterFrame( uint8_t *pixels, int width, int height,
                double position, double delta_frame );
        void AttachWidgets( GtkBin *bin );
        void DetachWidgets( GtkBin *bin );
        void InterpretWidgets( GtkBin *bin );
}

Notes:
  1. The pixels array contains width * height * 3 bytes. Each pixel is represented by RGB triples.
  2. The first call is always denoted by a position of 0.0 and the last is normally 1.0 (unless the number of frames being input is 1).
  3. See general notes on the 'Widget' methods below.
Image Transition

These allow you to write custom image transitions. A transition is basically any effect which merges two sequences of images to create a third one which replaces the two.

To define one of these, you need to:

#include <image_transitions.h> 

and implement a GDKImageTransition class:

class MyPlugin : public GDKImageTransition
{
    public:
        char *GetDescription( ) const;
        void GetFrame( uint8_t *aframe, uint8_t *bframe, int width, int height,
                double position, double delta_frame, bool reverse );
        void AttachWidgets( GtkBin *bin );
        void DetachWidgets( GtkBin *bin );
        void InterpretWidgets( GtkBin *bin );
}

Notes:
  1. The pixels array contains width * height * 3 bytes. Each pixel is represented by RGB triples. aframe is both input and output.
  2. The reverse argument is used to denote that the user has requested the reverse operation - it is your responsibility to accomodate this request.
  3. See general notes on the 'Widget' methods below.
Audio Filters

These allow you to write custom filters to audio. A filter allows you to alter the input frames in some way (such as 'fade in', 'fade out').

To define one of these, you need to:

#include <audio_filters.h> 

and implement a GDKAudioFilter class:

class MyPlugin : public GDKAudioFilter
{
    public:
        char *GetDescription( ) const;
        void GetFrame( int16_t **io, int frequency,
                int channels, int samples, double position, double delta_frame );
        void AttachWidgets( GtkBin *bin );
        void DetachWidgets( GtkBin *bin );
        void InterpretWidgets( GtkBin *bin );
}

Notes:
  1. The io array of arrays is of [ channels ][ samples ] dimensions.
  2. The first call is always denoted by a position of 0.0 and the last is normally 1.0 (unless the number of frames being input is 1).
  3. See general notes on the 'Widget' methods below.
will add frequency to the filter in the next CVS update.


Audio Transitions

These allow you to write custom transitions for audio.

To define one of these, you need to:

#include <audio_transitions.h>

and implement a GDKAudioTransition class:

class MyPlugin : public GDKAudioTransition
{
    public:
        char *GetDescription( ) const;
        void GetFrame( int16_t **aframe, int16_t **bframe, int frequency,
                int channels, int samples, double position, double delta_frame );
        void AttachWidgets( GtkBin *bin );
        void DetachWidgets( GtkBin *bin );
        void InterpretWidgets( GtkBin *bin );
}

Notes:
  1. The aframe and bframe array of arrays are of [ channels ][ samples ] dimensions. aframe both input and output.
  2. The first call is always denoted by a position of 0.0 and the last is normally 1.0 (unless the number of frames being input is 1).
  3. See general notes on the 'Widget' methods below.

ADDING GUI INTERACTION

Should you not need any GUI interaction, it is sufficient to define AttachWidgets, DetatchWidgets and InterpretWidgets as { }.

If you do want them, then assuming you've defined a window in your glade project called 'window_mykinoplugin', the following is enough:

class Whatever : public GDK...
{
    private:
        GtkWidget *window;
        ... any vars used to hold ui obtained values ...

    public:
        Whatever()
        {
            window = create_window_mykinoplugin();
        }

        virtual ~Whatever()
        {
             gtk_widget_destroy( window );
        }

        .... image/audio manipulation as above...

        void AttachWidgets( GtkBin *bin )
        {
             gtk_widget_reparent( ( GTK_BIN( window ) )->child, GTK_WIDGET( bin ) );
        }

        void DetachWidgets( GtkBin *bin )
        {
             gtk_widget_reparent( ( GTK_BIN( bin ) )->child, GTK_WIDGET( window ) );
        }

        void InterpretWidgets( GtkBin *bin )
        {
              ... whatever you need to do ....
        }
}


Notes:
  1. Attach is called when the user selects this effect for use
  2. Detach is called when the user de-selects this effect
  3. Interpret is called immediately before the first call to the main manipulation method.
  4. 'const char *' errors can be thrown from any method to feedback error conditions to the user - they will be presented in a modal dialog and will terminate the processing.

COMMUNICATING THE FX TO KINO

When the plug-in is loaded into kino, a single instance of each effect is added to the internal repositories.

This is done via C function calls which return instances of each effect in your plug-in.

So, to export an Image Filter, you would define a function as:

extern "C" {

GDKImageFilter *GetImageFilter( int index )
{
    switch( index )
    {
        case 0: return new Whatever();
    }
    return NULL;
}

}


Similarly, you would define ImageCreate, ImageTransition, AudioFilter and AudioTransition objects in the same way.

COMPILATION & INSTALLATION

In order to use your plug-in, it must be installed in the kino lib directory. Plug-ins are currently picked up on kino start up.

The first compilation (if you follow the methods above to use glade to create your auto files), needs you to run:

./autogen.sh
./configure

NB: If you install kino with a non-default prefix, you will need to specify this on the ./configure step.

Subsequent compilations should be handled correctly by:

make

and installation should be:

make install

DISTRIBUTION

Distributions can be created by running:

make distclean
cd ..
tar cvf mykinoplugin.tar mykinoplugin
gzip -9 mykinoplugin.tar

... or similar.

If you wish to make them publicly available, upload them to this website.




| Back to normal page view |