

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no" lang="no">


<!-- Mirrored from kinodv.org/article/print/33/-1/12/ by HTTrack Website Copier/3.x [XR&CO'2014], Sat, 31 Dec 2022 22:20:33 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=iso-8859-1" /><!-- /Added by HTTrack -->
<head>
<title>Linux Digital Video - Kino Plugin HowTo</title>



<link rel="stylesheet" type="text/css" href="../../../../../sitedesign/linuxdv/style.css" />

<script language="JavaScript1.2">
<!--//

   function MM_swapImgRestore()
   {
      var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
   }

   function MM_preloadImages()
   {
      var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
      var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
      if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
   }

   function MM_findObj(n, d)
   {
      var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
      d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
      if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
      for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document); return x;
   }

   function MM_swapImage()
   {
      var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
      if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
   }

//-->
</script>

<meta name="author" content="eZ systems" />
<meta name="copyright" content="eZ systems &copy; 2001" />
<meta name="description" content="This document provides a brief HOWTO create new plug-ins to the Kino Magick sub-system." />
<meta name="keywords" content="IT, data, computer, web, internet, PC, network, server, programming, publishing, portal, intranet, e-commerce, e-trade, software, database, open source, unix, linux, apache, PHP, HTML, XML, MySQL, Skien, Grenland, Telemark, Norway" />


<body>

     

<table width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
	<td align="center">
	<h3>Found at: http://www.kinodv.org/article/print/33/-1/12/</h3>
	</td>
</tr>
</table>
<hr noshade="noshade" size="4" />

<img src="http://kinodv.org/images/path-arrow.gif" height="10" width="12" border="0" alt="">
<a class="path" href="../../../../archive/0/index.html">Top level</a>


<img src="http://kinodv.org/images/path-slash.gif" height="10" width="16" border="0" alt="">
<a class="path" href="../../../../archive/12/index.html">Developer Guide</a>



<hr noshade="noshade" size="4" />
<br />

<table width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
	<td>
	<p class="byline">Author: <a class="byline" href="../../../../author/view/4.html">Charles Yates</a></p>
	</td>
	<td align="right">
	<p class="byline">Publishing date: 03.09.2002 21:54</p>
	</td>
</tr>
</table>


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

<p>

<h3>INTRODUCTION</h3>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:<br>

<ul>
	
	<li>
	Importing from image files
	</li>
	<li>
	Applying video filters and transitions to users videos
	</li>
	<li>
	Applying audio effects, dubbing and mixing to users videos
	</li>
	<li>
	User customisation
	</li>
	<li>
	Integration with external audio and image libraries
	</li>
</ul>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.<br>
<br>
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.<br>
<br>

<h3>ROAD MAP</h3>The remainder of this document describes the following steps.<br>
<br>
<a href="#creating">Creating a new glade project</a><br/>
<a href="#customizing">Customising the Glade Generated files  </a><br/>
<a href="#defining">Defining the fx  </a><br/>
&nbsp;&nbsp;&nbsp;<a href="#imagecreate">Image Create  </a><br/>
&nbsp;&nbsp;&nbsp;<a href="#imagefilter">Image Filter</a><br/>
&nbsp;&nbsp;&nbsp;<a href="#imagetransition">Image Transition</a><br/>
&nbsp;&nbsp;&nbsp;<a href="#audiofilter">Audio Filter</a><br/>
&nbsp;&nbsp;&nbsp;<a href="#audiotransition">Audio Transition</a><br/>
<a href="#adding">Adding GUI Interaction</a><br/>
<a href="#communicating">Communicating the fx to kino</a><br/>
<a href="#compilation">Compilation and Installation</a><br/>
<a href="#distribution">Distribution </a><br/><br>
<a name="creating">
<h3>CREATING A NEW GLADE PROJECT</h3></a>The first step is to start glade and enter the Project Options dialog. The following modifications should be made in each of the tabs:<br>
<br>
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)<br>
<br>
C Options: Use all defaults except select 'Set Widget Names' and de-select 'Output main.c File'.<br>
<br>
Click on OK.<br>
<br>
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.<br>
<br>
Save and build the project.<br>
<br>
<a name="customizing">
<h3>CUSTOMISING THE GLADE GENERATED FILES</h3></a>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.<br>
<br>
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:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>AM_DISABLE_STATIC
AC_PROG_CXX
AM_PROG_LIBTOOL</pre>
	</td>
</tr>
</table><br>
The second file to edit is the src/Makefile.am.<br>
<br>
Add the following at the beginning of the file:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>KINO_INCLUDE = $(prefix)/include/kino
libdir = $(prefix)/lib/kino
</pre>
	</td>
</tr>
</table><br>
Add the kino include directory to the INCLUDES value:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>INCLUDES = \
	$(GNOME_INCLUDEDIR) \
	-I$(KINO_INCLUDE)
</pre>
	</td>
</tr>
</table><br>
Replace the initial entries of bin_PROGRAMS, mykinoplugin_SOURCES and mykinoplugin_LDADD with:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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)
</pre>
	</td>
</tr>
</table><br>
<a name="defining">
<h3>DEFINING THE FX</h3></a>We now need to create the SOURCES added to the Makefile.am.<br>
<br>
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 :-)).<br>
<br>
<br>
<a name="imagecreate"><b>Image Creators</b><br>
</a><br>
These allow you to write custom creators/importers of images.<br>
<br>
To define one of these, you need to:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>#include &lt;image_create.h&gt;</pre>
	</td>
</tr>
</table><br>
and implement a GDKImageCreate class:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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 );
}</pre>
	</td>
</tr>
</table><br>
<b>Notes:</b><br>

<ol>
	
	<li>
	The pixels array contains width * height * 3 bytes. Each pixel is represented by RGB triples.
	</li>
	<li>
	On the first call, the contents of pixels are undefined. On subsequent calls, it contains the previously created image.
	</li>
	<li>
	The number of times the CreateFrame method is called is determined by the GetNumberOfFrames method.
	</li>
	<li>
	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.
	</li>
	<li>
	See general notes on the 'Widget' methods below.
	</li>
</ol><a name="imagefilter"><b>Image Filters</b><br>
</a><br>
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).<br>
<br>
To define one of these, you need to:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>#include &lt;image_filters.h&gt;</pre>
	</td>
</tr>
</table><br>
and implement a GDKImageFilter class:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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 );
}</pre>
	</td>
</tr>
</table><br>
<b>Notes:</b><br>

<ol>
	
	<li>
	The pixels array contains width * height * 3 bytes. Each pixel is represented by RGB triples.
	</li>
	<li>
	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).
	</li>
	<li>
	See general notes on the 'Widget' methods below.
	</li>
</ol><a name="imagetransition"><b>Image Transition</b><br>
<br>
</a>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.<br>
<br>
To define one of these, you need to:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>#include &lt;image_transitions.h&gt; </pre>
	</td>
</tr>
</table><br>
and implement a GDKImageTransition class:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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 );
}
</pre>
	</td>
</tr>
</table><br>
<b>Notes:</b><br>

<ol>
	
	<li>
	The pixels array contains width * height * 3 bytes. Each pixel is represented by RGB triples. aframe is both input and output.
	</li>
	<li>
	The reverse argument is used to denote that the user has requested the reverse operation - it is your responsibility to accomodate this request.
	</li>
	<li>
	See general notes on the 'Widget' methods below.
	</li>
</ol><a name="audiofilter"><b>Audio Filters</b><br>
<br>
</a>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').<br>
<br>
To define one of these, you need to:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>#include &lt;audio_filters.h&gt; </pre>
	</td>
</tr>
</table><br>
and implement a GDKAudioFilter class:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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 );
}
</pre>
	</td>
</tr>
</table><br>
<b>Notes:</b><br>

<ol>
	
	<li>
	The io array of arrays is of [ channels ][ samples ] dimensions. 
	</li>
	<li>
	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). 
	</li>
	<li>
	See general notes on the 'Widget' methods below. 
	</li>
</ol>will add frequency to the filter in the next CVS update.<br>
<br>
<br>
<a name="audiotransition"><b>Audio Transitions</b><br>
<br>
</a>These allow you to write custom transitions for audio.<br>
<br>
To define one of these, you need to:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>#include &lt;audio_transitions.h&gt;</pre>
	</td>
</tr>
</table><br>
and implement a GDKAudioTransition class:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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 );
}</pre>
	</td>
</tr>
</table><br>
<b>Notes:</b><br>

<ol>
	
	<li>
	The aframe and bframe array of arrays are of [ channels ][ samples ] dimensions. aframe both input and output.
	</li>
	<li>
	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).
	</li>
	<li>
	See general notes on the 'Widget' methods below.
	</li>
</ol><a name="adding">
<h3>ADDING GUI INTERACTION</h3></a>Should you not need any GUI interaction, it is sufficient to define AttachWidgets, DetatchWidgets and InterpretWidgets as { }.<br>
<br>
If you do want them, then assuming you've defined a window in your glade project called 'window_mykinoplugin', the following is enough:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>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 ) )-&gt;child, GTK_WIDGET( bin ) );
        }

        void DetachWidgets( GtkBin *bin )
        {
             gtk_widget_reparent( ( GTK_BIN( bin ) )-&gt;child, GTK_WIDGET( window ) );
        }

        void InterpretWidgets( GtkBin *bin )
        {
              ... whatever you need to do ....
        }
}

</pre>
	</td>
</tr>
</table><br>
<b>Notes:</b><br>

<ol>
	
	<li>
	Attach is called when the user selects this effect for use
	</li>
	<li>
	Detach is called when the user de-selects this effect
	</li>
	<li>
	Interpret is called immediately before the first call to the main manipulation method.
	</li>
	<li>
	'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.
	</li>
</ol><a name="communicating">
<h3>COMMUNICATING THE FX TO KINO</h3></a>When the plug-in is loaded into kino, a single instance of each effect is added to the internal repositories.<br>
<br>
This is done via C function calls which return instances of each effect in your plug-in.<br>
<br>
So, to export an Image Filter, you would define a function as:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>extern &quot;C&quot; {

GDKImageFilter *GetImageFilter( int index )
{
    switch( index )
    {
        case 0: return new Whatever();
    }
    return NULL;
}

}

</pre>
	</td>
</tr>
</table><br>
Similarly, you would define ImageCreate, ImageTransition, AudioFilter and AudioTransition objects in the same way.<br>
<br>
<a name="compilation">
<h3>COMPILATION & INSTALLATION</h3></a>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.<br>
<br>
The first compilation (if you follow the methods above to use glade to create your auto files), needs you to run:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>./autogen.sh
./configure</pre>
	</td>
</tr>
</table><br>
NB: If you install kino with a non-default prefix, you will need to specify this on the ./configure step.<br>
<br>
Subsequent compilations should be handled correctly by:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>make</pre>
	</td>
</tr>
</table><br>
and installation should be:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>make install</pre>
	</td>
</tr>
</table><br>
<a name="distribution">
<h3>DISTRIBUTION</h3></a>Distributions can be created by running:<br>
<br>
<table width="100%" bgcolor="#eeeeee" >
<tr>
	<td>
	<pre>make distclean
cd ..
tar cvf mykinoplugin.tar mykinoplugin
gzip -9 mykinoplugin.tar</pre>
	</td>
</tr>
</table><br>
... or similar.<br>
<br>
If you wish to make them publicly available, upload them to this website.
</p>









<br clear="all" />

<div align="center">





     


<br /><br />


| <a class="path" href="../../../../view/33/1/12/index.html">Back to normal page view</a>
     


<!--
| <a class="path" href="/article/mailtofriend/33/1/12/">Send this article to a friend</a> |
-->
|
</div>

</body>

<!-- Mirrored from kinodv.org/article/print/33/-1/12/ by HTTrack Website Copier/3.x [XR&CO'2014], Sat, 31 Dec 2022 22:20:33 GMT -->
</html>
