...But you don't want to go through the (sometimes painful) process of building the whole VLC. Well, you can build your own plugin separately. Here is how to do it (this tutorial is Windows centric because 1: I'm too lazy to launch my VM right now; 2:it's easy to do on Ubuntu for the linux trolls):
Ingredients
- The plugin headers. You can find them in C:\Program Files\VideoLAN\VLC\sdk\include\vlc\plugins on Windows.
- The libraries. Copy libvlc.dll and libvlccore.dll (you will find them in C:\Program Files\VideoLAN\VLC)
- A building environment (on Windows, use Mingw+MSYS)
- Some coffee
Recipe
At the time of writing, the wiki page wasn't really explicit, so I'll detail all the steps, for an example audio filter that switch the left and right audio streams (adapted from the trivial channel mixer plugin).
Let's begin by taking a look at what code you can find in a VLC plugin, like the trivial channel mixer plugin.
Preamble
First, the copyright and license:
/*****************************************************************************
* trivial.c : trivial channel mixer plug-in (drops unwanted channels)
*****************************************************************************
* Copyright (C) 2009 the VideoLAN team
* $Id: 3ecc0dd8363a50c40f7f123a9e2724a943c0c83c $
*
* Authors: Name <email address>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
That's not useful to run the plugin, but you'll have to add it when you send a patch to VideoLAN.
Next, the headers:
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_aout.h>
#include <vlc_filter.h>
the config.h file is generated from the configure step when you build the whole VLC. Each module must include at least vlc_common.h and vlc_plugin.h. The other headers included depend on the type of plugin you want to build (find it in the code of plugins from the category you want).
Note: you will probably need something more like the following for your audio plugin.
#define _(str) (str)
#define N_(str) (str)
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_messages.h>
#include <vlc_aout.h>
#include <vlc_filter.h>
#include <vlc_fourcc.h>
#include <vlc_block.h>
Don't hesitate to grep the include directory if you have some missing functions or unknown structures.
Module descriptor
static int Create ( vlc_object_t * );
static block_t *DoWork( filter_t *, block_t * );
vlc_module_begin ()
set_description( N_("Audio channel inverser") )
set_capability( "channel inverser", 1 )
set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_MISC )
set_callbacks( Create, NULL )
add_shortcut( "channel_inverser" )
vlc_module_end ()
First, you see the prototypes of functions used in this plugin. Create is used, well, to create the plugin, and DoWork will handle all the audio data.
Then, the part between vlc_module_begin and vlc_module_end is a set of macros used to declare the plugin structure. This part is used to define which type of module it will be. These macros create a function exported by the plugin and called when VLC looks for a suitable plugin.
If the module can be used, the core of VLC stores the callback (here, the Create function) and calls it later to initialize the plugin.
Create function
static int Create( vlc_object_t *p_this )
{
filter_t * p_filter = (filter_t *)p_this;
if ( (p_filter->fmt_in.audio.i_physical_channels
== p_filter->fmt_out.audio.i_physical_channels
&& p_filter->fmt_in.audio.i_original_channels
== p_filter->fmt_out.audio.i_original_channels)
|| p_filter->fmt_in.audio.i_format != p_filter->fmt_out.audio.i_format
|| p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate
|| (p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32
&& p_filter->fmt_in.audio.i_format != VLC_CODEC_FI32) )
{
return VLC_EGENERIC;
}
p_filter->pf_audio_filter = DoWork;
return VLC_SUCCESS;
}
The initialization function is used to set some configuration options, initialize memory structures, etc. Look at other modules to see how you can store variables, and how to create preferences variables.
Here, we verify that the number of channels, the format and the bitrate in the input and output are the same, and that the audio isn't stored in float numbers. If it's ok, we give to libvlc a pointer to the DoWork function, which will be called when audio data is available.
DoWork function
static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
{
int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
int i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
block_t *p_out_buf;
if( i_input_nb >= i_output_nb )
{
p_out_buf = p_in_buf; /* mix in place */
p_out_buf->i_buffer = p_in_buf->i_buffer / i_input_nb * i_output_nb;
}
else
{
p_out_buf = filter_NewAudioBuffer( p_filter,
p_in_buf->i_buffer / i_input_nb * i_output_nb );
if( !p_out_buf )
goto out;
p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
}
int32_t * p_dest = (int32_t *)p_out_buf->p_buffer;
const int32_t * p_src = (int32_t *)p_in_buf->p_buffer;
/* Reverse-stereo mode */
int i;
for ( i = p_in_buf->i_nb_samples; i--; )
{
*p_dest = p_src[1];
p_dest++;
*p_dest = p_src[0];
p_dest++;
p_src += 2;
}
out:
if( p_in_buf != p_out_buf )
block_Release( p_in_buf );
return p_out_buf;
}
The DoWork function manages the buffers and copy them from the input to the output.
Now in the oven
(No preheat please)
Here is the content of my Makefile:
all:
gcc -I/home/Geal/module/include -L/home/Geal/module/ -lvlccore -shared -std=gnu99 \
-DWIN32 -D__PLUGIN__ -DMODULE_STRING=\"channel_inverser\" module.c -o libchannel_inverser_plugin.dll
///
Adapt it to the name of your plugin, and to the path you use, or copy the one from the wiki. My Makefile only contains what is strictly necessary to build your plugin. Now:
Geal@chezmoi ~/module
$ make
///
Eat it while it's still hot
Now, you just need to copy your dll in the plugins directory of VLC media player, and try your plugin! I don't guarantee that it will work (more like I know that it doesn't work and I'm too lazy to fix it because I won't commit it), I just gave you the structure and the Makefile you need to be up and running. Note that you can use the following command line options to help in your development:
- -vvv: displays a LOT of debug messages
- --verbose-objects: helps you filter the messages (example: ./vlc -vvv --verbose-objects=-all,+direct3d to display only the messages related to the direct3d module)
Don't forget to send a patch to VideoLAN (subscribe to the vlc-devel mailing-list and attach it to a message). To integrate your module, please read the HACKING file at the root of the VLC source tree.
Now, show me your code!