Move src/control/ to lib/
authorRémi Denis-Courmont <remi@remlab.net>
Tue, 30 Aug 2011 20:40:14 +0000 (23:40 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Tue, 30 Aug 2011 20:40:34 +0000 (23:40 +0300)
58 files changed:
Makefile.am
bin/Makefile.am
configure.ac
include/vlc/libvlc_events.h
lib/audio.c [new file with mode: 0644]
lib/core.c [new file with mode: 0644]
lib/error.c [new file with mode: 0644]
lib/event.c [new file with mode: 0644]
lib/event_async.c [new file with mode: 0644]
lib/event_internal.h [new file with mode: 0644]
lib/libvlc.pc.in [new file with mode: 0644]
lib/libvlc.sym [new file with mode: 0644]
lib/libvlc_internal.h [new file with mode: 0644]
lib/log.c [new file with mode: 0644]
lib/media.c [new file with mode: 0644]
lib/media_discoverer.c [new file with mode: 0644]
lib/media_internal.h [new file with mode: 0644]
lib/media_library.c [new file with mode: 0644]
lib/media_list.c [new file with mode: 0644]
lib/media_list_internal.h [new file with mode: 0644]
lib/media_list_path.h [new file with mode: 0644]
lib/media_list_player.c [new file with mode: 0644]
lib/media_player.c [new file with mode: 0644]
lib/media_player_internal.h [new file with mode: 0644]
lib/playlist.c [new file with mode: 0644]
lib/video.c [new file with mode: 0644]
lib/vlm.c [new file with mode: 0644]
modules/gui/qt4/qt4.cpp
po/POTFILES.in
src/Makefile.am
src/control/audio.c [deleted file]
src/control/core.c [deleted file]
src/control/error.c [deleted file]
src/control/event.c [deleted file]
src/control/event_async.c [deleted file]
src/control/event_internal.h [deleted file]
src/control/libvlc_internal.h [deleted file]
src/control/log.c [deleted file]
src/control/media.c [deleted file]
src/control/media_discoverer.c [deleted file]
src/control/media_internal.h [deleted file]
src/control/media_library.c [deleted file]
src/control/media_list.c [deleted file]
src/control/media_list_internal.h [deleted file]
src/control/media_list_path.h [deleted file]
src/control/media_list_player.c [deleted file]
src/control/media_player.c [deleted file]
src/control/media_player_internal.h [deleted file]
src/control/playlist.c [deleted file]
src/control/video.c [deleted file]
src/control/vlm.c [deleted file]
src/interface/interface.c
src/libvlc.c
src/libvlc.pc.in [deleted file]
src/libvlc.sym [deleted file]
src/misc/exit.c
test/libvlc/media_list_player.c
test/src/misc/variables.c

index b5de587..a415dd1 100644 (file)
@@ -7,10 +7,8 @@
 # which have makefiles with distribution information.
 #  - src (libvlc) is nedeed by modules
 #  - libs/* are needed by modules
-DIST_SUBDIRS = \
-       m4 compat doc po share src \
-       bin modules test
-SUBDIRS = compat doc po share src
+DIST_SUBDIRS = m4 compat doc po share src modules lib bin test
+SUBDIRS = compat doc po share src lib
 if BUILD_VLC
 SUBDIRS += bin
 endif
@@ -347,8 +345,11 @@ MAINTAINERCLEANFILES = ChangeLog
 libcompat:
        cd compat && $(MAKE) $(AM_MAKEFLAGS)
 
-libvlc: libcompat
-       cd src && $(MAKE) $(AM_MAKEFLAGS) libvlc.la
+libvlccore: libcompat
+       cd src && $(MAKE) $(AM_MAKEFLAGS) libvlccore.la
+
+libvlc: libvlccore
+       cd lib && $(MAKE) $(AM_MAKEFLAGS) libvlc.la
 
 core: libvlc vlc$(EXEEXT)
        cd bin && $(MAKE) $(AM_MAKEFLAGS) vlc$(EXEEXT) vlc-static$(EXEEXT)
index 85b8a8b..7c40a97 100644 (file)
@@ -31,7 +31,6 @@ endif
 vlc_wrapper_SOURCES = rootwrap.c
 vlc_wrapper_LDADD = $(SOCKET_LIBS)
 
-vlc_DEPENDENCIES = ../src/libvlc.sym
 vlc_LDFLAGS = $(LDFLAGS_vlc)
 vlc_LDADD = ../src/libvlc.la ../src/libvlccore.la $(LIBS_vlc)
 
@@ -46,7 +45,7 @@ vlc_static_LDFLAGS = $(vlc_LDFLAGS)
 
 if HAVE_WIN32
 vlc_LDADD += -lwininet vlc_win32_rc.$(OBJEXT)
-vlc_DEPENDENCIES += vlc_win32_rc.$(OBJEXT)
+vlc_DEPENDENCIES = vlc_win32_rc.$(OBJEXT)
 else
 vlc_LDADD += $(LIBDL)
 vlc_static_LDFLAGS += -no-install -static
index 781db98..bcd74f4 100644 (file)
@@ -4266,6 +4266,7 @@ AC_CONFIG_FILES([
   compat/Makefile
   src/Makefile
   src/test/Makefile
+  lib/Makefile
   bin/Makefile
   test/Makefile
   modules/access/Makefile
index ec2f984..7b29541 100644 (file)
@@ -45,7 +45,7 @@ extern "C" {
 enum libvlc_event_e {
     /* Append new event types at the end of a category.
      * Do not remove, insert or re-order any entry.
-     * Keep this in sync with src/control/event.c:libvlc_event_type_name(). */
+     * Keep this in sync with lib/event.c:libvlc_event_type_name(). */
     libvlc_MediaMetaChanged=0,
     libvlc_MediaSubItemAdded,
     libvlc_MediaDurationChanged,
diff --git a/lib/audio.c b/lib/audio.c
new file mode 100644 (file)
index 0000000..c7d1ba1
--- /dev/null
@@ -0,0 +1,519 @@
+/*****************************************************************************
+ * libvlc_audio.c: New libvlc audio control API
+ *****************************************************************************
+ * Copyright (C) 2006 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Filippo Carone <filippo@carone.org>
+ *          Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_player.h>
+
+#include <vlc_common.h>
+#include <vlc_input.h>
+#include <vlc_aout_intf.h>
+#include <vlc_aout.h>
+#include <vlc_modules.h>
+
+#include "libvlc_internal.h"
+#include "media_player_internal.h"
+
+/*
+ * Remember to release the returned audio_output_t since it is locked at
+ * the end of this function.
+ */
+static audio_output_t *GetAOut( libvlc_media_player_t *mp )
+{
+    assert( mp != NULL );
+
+    input_thread_t *p_input = libvlc_get_input_thread( mp );
+    if( p_input == NULL )
+        return NULL;
+
+    audio_output_t * p_aout = input_GetAout( p_input );
+    vlc_object_release( p_input );
+    if( p_aout == NULL )
+        libvlc_printerr( "No active audio output" );
+    return p_aout;
+}
+
+/*****************************************
+ * Get the list of available audio outputs
+ *****************************************/
+libvlc_audio_output_t *
+        libvlc_audio_output_list_get( libvlc_instance_t *p_instance )
+{
+    VLC_UNUSED( p_instance );
+    libvlc_audio_output_t *p_list = NULL,
+                          *p_actual = NULL,
+                          *p_previous = NULL;
+    module_t **module_list = module_list_get( NULL );
+
+    for (size_t i = 0; module_list[i]; i++)
+    {
+        module_t *p_module = module_list[i];
+
+        if( module_provides( p_module, "audio output" ) )
+        {
+            if( p_actual == NULL)
+            {
+                p_actual = ( libvlc_audio_output_t * )
+                    malloc( sizeof( libvlc_audio_output_t ) );
+                if( p_actual == NULL )
+                {
+                    libvlc_printerr( "Not enough memory" );
+                    libvlc_audio_output_list_release( p_list );
+                    module_list_free( module_list );
+                    return NULL;
+                }
+                if( p_list == NULL )
+                {
+                    p_list = p_actual;
+                    p_previous = p_actual;
+                }
+            }
+            p_actual->psz_name = strdup( module_get_object( p_module ) );
+            p_actual->psz_description = strdup( module_get_name( p_module, true )  );
+            p_actual->p_next = NULL;
+            if( p_previous != p_actual ) /* not first item */
+                p_previous->p_next = p_actual;
+            p_previous = p_actual;
+            p_actual = p_actual->p_next;
+        }
+    }
+
+    module_list_free( module_list );
+
+    return p_list;
+}
+
+/********************************************
+ * Free the list of available audio outputs
+ ***********************************************/
+void libvlc_audio_output_list_release( libvlc_audio_output_t *p_list )
+{
+    libvlc_audio_output_t *p_actual, *p_before;
+    p_actual = p_list;
+
+    while ( p_actual )
+    {
+        free( p_actual->psz_name );
+        free( p_actual->psz_description );
+        p_before = p_actual;
+        p_actual = p_before->p_next;
+        free( p_before );
+    }
+}
+
+
+/***********************
+ * Set the audio output.
+ ***********************/
+int libvlc_audio_output_set( libvlc_media_player_t *mp, const char *psz_name )
+{
+    char *value;
+
+    if( !module_exists( psz_name )
+     || asprintf( &value, "%s,none", psz_name ) == -1 )
+        return -1;
+    var_SetString( mp, "aout", value );
+    free( value );
+    return 0;
+}
+
+/****************************
+ * Get count of devices.
+ *****************************/
+int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
+                                      const char *psz_audio_output )
+{
+    char *psz_config_name;
+    if( !psz_audio_output )
+        return 0;
+    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
+        return 0;
+
+    module_config_t *p_module_config = config_FindConfig(
+        VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
+
+    if( p_module_config && p_module_config->pf_update_list )
+    {
+        vlc_value_t val;
+        val.psz_string = strdup( p_module_config->value.psz );
+
+        p_module_config->pf_update_list(
+            VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
+        free( val.psz_string );
+        free( psz_config_name );
+
+        return p_module_config->i_list;
+    }
+
+    free( psz_config_name );
+    return 0;
+}
+
+/********************************
+ * Get long name of device
+ *********************************/
+char * libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
+                                            const char *psz_audio_output,
+                                            int i_device )
+{
+    char *psz_config_name;
+    if( !psz_audio_output )
+        return NULL;
+    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
+        return NULL;
+
+    module_config_t *p_module_config = config_FindConfig(
+        VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
+
+    if( p_module_config )
+    {
+        // refresh if there arent devices
+        if( p_module_config->i_list < 2 && p_module_config->pf_update_list )
+        {
+            vlc_value_t val;
+            val.psz_string = strdup( p_module_config->value.psz );
+
+            p_module_config->pf_update_list(
+                VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
+            free( val.psz_string );
+        }
+
+        if( i_device >= 0 && i_device < p_module_config->i_list )
+        {
+            free( psz_config_name );
+
+            if( p_module_config->ppsz_list_text[i_device] )
+                return strdup( p_module_config->ppsz_list_text[i_device] );
+            else
+                return strdup( p_module_config->ppsz_list[i_device] );
+        }
+    }
+
+    free( psz_config_name );
+    return NULL;
+}
+
+/********************************
+ * Get id name of device
+ *********************************/
+char * libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
+                                      const char *psz_audio_output,
+                                      int i_device )
+{
+    char *psz_config_name;
+    if( !psz_audio_output )
+        return NULL;
+    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1)
+        return NULL;
+
+    module_config_t *p_module_config = config_FindConfig(
+        VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
+
+    if( p_module_config )
+    {
+        // refresh if there arent devices
+        if( p_module_config->i_list < 2 && p_module_config->pf_update_list )
+        {
+            vlc_value_t val;
+            val.psz_string = strdup( p_module_config->value.psz );
+
+            p_module_config->pf_update_list(
+                VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
+            free( val.psz_string );
+        }
+
+        if( i_device >= 0 && i_device < p_module_config->i_list )
+        {
+            free( psz_config_name );
+            return strdup( p_module_config->ppsz_list[i_device] );
+        }
+    }
+
+    free( psz_config_name );
+    return NULL;
+}
+
+/*****************************
+ * Set device for using
+ *****************************/
+void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
+                                     const char *psz_audio_output,
+                                     const char *psz_device_id )
+{
+    char *psz_config_name;
+    if( !psz_audio_output || !psz_device_id )
+        return;
+    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
+        return;
+    if( !var_Type( mp, psz_config_name ) )
+        /* Don't recreate the same variable over and over and over... */
+        var_Create( mp, psz_config_name, VLC_VAR_STRING );
+    var_SetString( mp, psz_config_name, psz_device_id );
+    free( psz_config_name );
+}
+
+/*****************************************************************************
+ * libvlc_audio_output_get_device_type : Get the current audio device type
+ *****************************************************************************/
+int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
+{
+    audio_output_t *p_aout = GetAOut( mp );
+    if( p_aout )
+    {
+        int i_device_type = var_GetInteger( p_aout, "audio-device" );
+        vlc_object_release( p_aout );
+        return i_device_type;
+    }
+    return libvlc_AudioOutputDevice_Error;
+}
+
+/*****************************************************************************
+ * libvlc_audio_output_set_device_type : Set the audio device type
+ *****************************************************************************/
+void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
+                                          int device_type )
+{
+    audio_output_t *p_aout = GetAOut( mp );
+    if( !p_aout )
+        return;
+    if( var_SetInteger( p_aout, "audio-device", device_type ) < 0 )
+        libvlc_printerr( "Error setting audio device" );
+    vlc_object_release( p_aout );
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_mute : Get the volume state, true if muted
+ *****************************************************************************/
+void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
+{
+    aout_ToggleMute( mp, NULL );
+}
+
+int libvlc_audio_get_mute( libvlc_media_player_t *mp )
+{
+    return aout_IsMuted( VLC_OBJECT(mp) );
+}
+
+void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
+{
+    aout_SetMute( VLC_OBJECT(mp), NULL, !!mute );
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_volume : Get the current volume
+ *****************************************************************************/
+int libvlc_audio_get_volume( libvlc_media_player_t *mp )
+{
+    unsigned volume = aout_VolumeGet( mp );
+
+    return (volume * 100 + AOUT_VOLUME_DEFAULT / 2) / AOUT_VOLUME_DEFAULT;
+}
+
+
+/*****************************************************************************
+ * libvlc_audio_set_volume : Set the current volume
+ *****************************************************************************/
+int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
+{
+    volume = (volume * AOUT_VOLUME_DEFAULT + 50) / 100;
+    if (volume < 0 || volume > AOUT_VOLUME_MAX)
+    {
+        libvlc_printerr( "Volume out of range" );
+        return -1;
+    }
+    aout_VolumeSet (mp, volume);
+    return 0;
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_track_count : Get the number of available audio tracks
+ *****************************************************************************/
+int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    int i_track_count;
+
+    if( !p_input_thread )
+        return -1;
+
+    i_track_count = var_CountChoices( p_input_thread, "audio-es" );
+
+    vlc_object_release( p_input_thread );
+    return i_track_count;
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_track_description : Get the description of available audio tracks
+ *****************************************************************************/
+libvlc_track_description_t *
+        libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
+{
+    return libvlc_get_track_description( p_mi, "audio-es" );
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_track : Get the current audio track
+ *****************************************************************************/
+int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    vlc_value_t val_list;
+    vlc_value_t val;
+    int i_track = -1;
+    int i;
+
+    if( !p_input_thread )
+        return -1;
+
+    if( var_Get( p_input_thread, "audio-es", &val ) < 0 )
+    {
+        vlc_object_release( p_input_thread );
+        libvlc_printerr( "Audio track information not found" );
+        return -1;
+    }
+
+    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        if( val_list.p_list->p_values[i].i_int == val.i_int )
+        {
+            i_track = i;
+            break;
+        }
+    }
+    var_FreeList( &val_list, NULL );
+    vlc_object_release( p_input_thread );
+    return i_track;
+}
+
+/*****************************************************************************
+ * libvlc_audio_set_track : Set the current audio track
+ *****************************************************************************/
+int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    vlc_value_t val_list;
+    vlc_value_t newval;
+    int i_ret;
+
+    if( !p_input_thread )
+        return -1;
+
+    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    if( (i_track < 0) || (i_track > val_list.p_list->i_count) )
+    {
+        libvlc_printerr( "Audio track out of range" );
+        i_ret = -1;
+        goto end;
+    }
+
+    newval = val_list.p_list->p_values[i_track];
+    i_ret = var_Set( p_input_thread, "audio-es", newval );
+    if( i_ret < 0 )
+    {
+        libvlc_printerr( "Audio track out of range" ); /* Race... */
+        i_ret = -1;
+        goto end;
+    }
+    i_ret = 0;
+
+end:
+    var_FreeList( &val_list, NULL );
+    vlc_object_release( p_input_thread );
+    return i_ret;
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_channel : Get the current audio channel
+ *****************************************************************************/
+int libvlc_audio_get_channel( libvlc_media_player_t *mp )
+{
+    audio_output_t *p_aout = GetAOut( mp );
+    if( !p_aout )
+        return 0;
+
+    int val = var_GetInteger( p_aout, "audio-channels" );
+    vlc_object_release( p_aout );
+    return val;
+}
+
+/*****************************************************************************
+ * libvlc_audio_set_channel : Set the current audio channel
+ *****************************************************************************/
+int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
+{
+    audio_output_t *p_aout = GetAOut( mp );
+    int ret = 0;
+
+    if( !p_aout )
+        return -1;
+
+    if( var_SetInteger( p_aout, "audio-channels", channel ) < 0 )
+    {
+        libvlc_printerr( "Audio channel out of range" );
+        ret = -1;
+    }
+    vlc_object_release( p_aout );
+    return ret;
+}
+
+/*****************************************************************************
+ * libvlc_audio_get_delay : Get the current audio delay
+ *****************************************************************************/
+int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
+    int64_t val = 0;
+    if( p_input_thread != NULL )
+    {
+      val = var_GetTime( p_input_thread, "audio-delay" );
+      vlc_object_release( p_input_thread );
+    }
+    return val;
+}
+
+/*****************************************************************************
+ * libvlc_audio_set_delay : Set the current audio delay
+ *****************************************************************************/
+int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
+    int ret = 0;
+    if( p_input_thread != NULL )
+    {
+      var_SetTime( p_input_thread, "audio-delay", i_delay );
+      vlc_object_release( p_input_thread );
+    }
+    else
+    {
+      ret = -1;
+    }
+    return ret;
+}
diff --git a/lib/core.c b/lib/core.c
new file mode 100644 (file)
index 0000000..6e88b94
--- /dev/null
@@ -0,0 +1,258 @@
+/*****************************************************************************
+ * core.c: Core libvlc new API functions : initialization
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "libvlc_internal.h"
+#include <vlc_modules.h>
+#include <vlc/libvlc.h>
+
+#include <vlc_interface.h>
+#include <vlc_vlm.h>
+
+#include <stdarg.h>
+#include <limits.h>
+#include <assert.h>
+
+static const char nomemstr[] = "Insufficient memory";
+
+libvlc_instance_t * libvlc_new( int argc, const char *const *argv )
+{
+    libvlc_instance_t *p_new = malloc (sizeof (*p_new));
+    if (unlikely(p_new == NULL))
+        return NULL;
+
+    libvlc_init_threads ();
+
+    const char *my_argv[argc + 2];
+    my_argv[0] = "libvlc"; /* dummy arg0, skipped by getopt() et al */
+    for( int i = 0; i < argc; i++ )
+         my_argv[i + 1] = argv[i];
+    my_argv[argc + 1] = NULL; /* C calling conventions require a NULL */
+
+    libvlc_int_t *p_libvlc_int = libvlc_InternalCreate();
+    if (unlikely (p_libvlc_int == NULL))
+        goto error;
+
+    if (libvlc_InternalInit( p_libvlc_int, argc + 1, my_argv ))
+    {
+        libvlc_InternalDestroy( p_libvlc_int );
+        goto error;
+    }
+
+    p_new->p_libvlc_int = p_libvlc_int;
+    p_new->libvlc_vlm.p_vlm = NULL;
+    p_new->libvlc_vlm.p_event_manager = NULL;
+    p_new->libvlc_vlm.pf_release = NULL;
+    p_new->ref_count = 1;
+    p_new->p_callback_list = NULL;
+    vlc_mutex_init(&p_new->instance_lock);
+    var_Create( p_libvlc_int, "http-user-agent",
+                VLC_VAR_STRING|VLC_VAR_DOINHERIT );
+    return p_new;
+
+error:
+    libvlc_deinit_threads ();
+    free (p_new);
+    return NULL;
+}
+
+void libvlc_retain( libvlc_instance_t *p_instance )
+{
+    assert( p_instance != NULL );
+    assert( p_instance->ref_count < UINT_MAX );
+
+    vlc_mutex_lock( &p_instance->instance_lock );
+    p_instance->ref_count++;
+    vlc_mutex_unlock( &p_instance->instance_lock );
+}
+
+void libvlc_release( libvlc_instance_t *p_instance )
+{
+    vlc_mutex_t *lock = &p_instance->instance_lock;
+    int refs;
+
+    vlc_mutex_lock( lock );
+    assert( p_instance->ref_count > 0 );
+    refs = --p_instance->ref_count;
+    vlc_mutex_unlock( lock );
+
+    if( refs == 0 )
+    {
+        vlc_mutex_destroy( lock );
+        if( p_instance->libvlc_vlm.pf_release )
+            p_instance->libvlc_vlm.pf_release( p_instance );
+        libvlc_InternalCleanup( p_instance->p_libvlc_int );
+        libvlc_InternalDestroy( p_instance->p_libvlc_int );
+        free( p_instance );
+        libvlc_deinit_threads ();
+    }
+}
+
+int libvlc_add_intf( libvlc_instance_t *p_i, const char *name )
+{
+    if( libvlc_InternalAddIntf( p_i->p_libvlc_int, name ))
+    {
+        if( name )
+        {
+            libvlc_printerr("interface \"%s\" initialization failed",
+                name );
+        }
+        else
+        {
+            libvlc_printerr("default interface initialization failed");
+        }
+        return -1;
+    }
+    return 0;
+}
+
+void libvlc_set_exit_handler( libvlc_instance_t *p_i, void (*cb) (void *),
+                              void *data )
+{
+    libvlc_int_t *p_libvlc = p_i->p_libvlc_int;
+    libvlc_SetExitHandler( p_libvlc, cb, data );
+}
+
+void libvlc_wait( libvlc_instance_t *p_i )
+{
+    libvlc_int_t *p_libvlc = p_i->p_libvlc_int;
+    libvlc_InternalWait( p_libvlc );
+}
+
+void libvlc_set_user_agent (libvlc_instance_t *p_i,
+                            const char *name, const char *http)
+{
+    libvlc_int_t *p_libvlc = p_i->p_libvlc_int;
+    char *str;
+
+    var_SetString (p_libvlc, "user-agent", name);
+    if ((http != NULL)
+     && (asprintf (&str, "%s LibVLC/"PACKAGE_VERSION, http) != -1))
+    {
+        var_SetString (p_libvlc, "http-user-agent", str);
+        free (str);
+    }
+}
+
+const char * libvlc_get_version(void)
+{
+    return VERSION_MESSAGE;
+}
+
+const char * libvlc_get_compiler(void)
+{
+    return VLC_Compiler();
+}
+
+const char * libvlc_get_changeset(void)
+{
+    extern const char psz_vlc_changeset[];
+    return psz_vlc_changeset;
+}
+
+void libvlc_free( void *ptr )
+{
+    free( ptr );
+}
+
+static libvlc_module_description_t *module_description_list_get(
+                libvlc_instance_t *p_instance, const char *capability )
+{
+    VLC_UNUSED( p_instance );
+    libvlc_module_description_t *p_list = NULL,
+                          *p_actual = NULL,
+                          *p_previous = NULL;
+    module_t **module_list = module_list_get( NULL );
+
+    for (size_t i = 0; module_list[i]; i++)
+    {
+        module_t *p_module = module_list[i];
+
+        if ( !module_provides( p_module, capability ) )
+            continue;
+
+        p_actual = ( libvlc_module_description_t * ) malloc( sizeof( libvlc_module_description_t ) );
+        if ( p_actual == NULL )
+        {
+            libvlc_printerr( "Not enough memory" );
+            libvlc_module_description_list_release( p_list );
+            module_list_free( module_list );
+            return NULL;
+        }
+
+        if ( p_list == NULL )
+            p_list = p_actual;
+
+        const char* name = module_get_object( p_module );
+        const char* shortname = module_get_name( p_module, false );
+        const char* longname = module_get_name( p_module, true );
+        const char* help = module_get_help( p_module );
+        p_actual->psz_name = name ? strdup( name ) : NULL;
+        p_actual->psz_shortname = shortname ? strdup( shortname ) : NULL;
+        p_actual->psz_longname = longname ? strdup( longname ) : NULL;
+        p_actual->psz_help = help ? strdup( help ) : NULL;
+
+        p_actual->p_next = NULL;
+        if ( p_previous )
+            p_previous->p_next = p_actual;
+        p_previous = p_actual;
+    }
+
+    module_list_free( module_list );
+    return p_list;
+}
+
+void libvlc_module_description_list_release( libvlc_module_description_t *p_list )
+{
+    libvlc_module_description_t *p_actual, *p_before;
+    p_actual = p_list;
+
+    while ( p_actual )
+    {
+        free( p_actual->psz_name );
+        free( p_actual->psz_shortname );
+        free( p_actual->psz_longname );
+        free( p_actual->psz_help );
+        p_before = p_actual;
+        p_actual = p_before->p_next;
+        free( p_before );
+    }
+}
+
+libvlc_module_description_t *libvlc_audio_filter_list_get( libvlc_instance_t *p_instance )
+{
+    return module_description_list_get( p_instance, "audio filter" );
+}
+
+libvlc_module_description_t *libvlc_video_filter_list_get( libvlc_instance_t *p_instance )
+{
+    return module_description_list_get( p_instance, "video filter2" );
+}
+
+int64_t libvlc_clock(void)
+{
+    return mdate();
+}
diff --git a/lib/error.c b/lib/error.c
new file mode 100644 (file)
index 0000000..e3f7051
--- /dev/null
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * error.c: Error handling for libvlc
+ *****************************************************************************
+ * Copyright (C) 2009 Rémi Denis-Courmont
+ *
+ * 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.
+ *****************************************************************************/
+
+#include "libvlc_internal.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+#include <vlc/libvlc.h>
+
+
+static const char oom[] = "Out of memory";
+/* TODO: use only one thread-specific key for whole libvlc */
+static vlc_threadvar_t context;
+
+static void libvlc_setup_threads (bool init)
+{
+    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+    static uintptr_t refs = 0;
+
+    vlc_mutex_lock (&lock);
+    if (init)
+    {
+        if (refs++ == 0)
+            vlc_threadvar_create (&context, free);
+    }
+    else
+    {
+        assert (refs > 0);
+        if (--refs == 0)
+            vlc_threadvar_delete (&context);
+    }
+    vlc_mutex_unlock (&lock);
+}
+
+void libvlc_init_threads (void)
+{
+    libvlc_setup_threads (true);
+}
+
+void libvlc_deinit_threads (void)
+{
+    libvlc_setup_threads (false);
+}
+
+static char *get_error (void)
+{
+    return vlc_threadvar_get (context);
+}
+
+static void free_error (void)
+{
+    char *msg = get_error ();
+    if (msg != oom)
+        free (msg);
+}
+
+/**
+ * Gets a human-readable error message for the last LibVLC error in the calling
+ * thread. The resulting string is valid until another error occurs (at least
+ * until the next LibVLC call).
+ *
+ * @return NULL if there was no error, a nul-terminated string otherwise.
+ */
+const char *libvlc_errmsg (void)
+{
+    return get_error ();
+}
+
+/**
+ * Clears the LibVLC error status for the current thread. This is optional.
+ * By default, the error status is automatically overridden when a new error
+ * occurs, and destroyed when the thread exits.
+ */
+void libvlc_clearerr (void)
+{
+    free_error ();
+    vlc_threadvar_set (context, NULL);
+}
+
+/**
+ * Sets the LibVLC error status and message for the current thread.
+ * Any previous error is overridden.
+ * @return a nul terminated string (always)
+ */
+const char *libvlc_vprinterr (const char *fmt, va_list ap)
+{
+    char *msg;
+
+    assert (fmt != NULL);
+    if (vasprintf (&msg, fmt, ap) == -1)
+        msg = (char *)oom;
+
+    free_error ();
+    vlc_threadvar_set (context, msg);
+    return msg;
+}
+
+/**
+ * Sets the LibVLC error status and message for the current thread.
+ * Any previous error is overridden.
+ * @return a nul terminated string (always)
+ */
+const char *libvlc_printerr (const char *fmt, ...)
+{
+    va_list ap;
+    const char *msg;
+
+    va_start (ap, fmt);
+    msg = libvlc_vprinterr (fmt, ap);
+    va_end (ap);
+    return msg;
+}
+
diff --git a/lib/event.c b/lib/event.c
new file mode 100644 (file)
index 0000000..2ce0a23
--- /dev/null
@@ -0,0 +1,450 @@
+/*****************************************************************************
+ * event.c: New libvlc event control API
+ *****************************************************************************
+ * Copyright (C) 2007-2010 the VideoLAN team
+ * $Id $
+ *
+ * Authors: Filippo Carone <filippo@carone.org>
+ *          Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define  LIBVLC_EVENT_TYPES_KEEP_DEFINE
+#include <vlc/libvlc.h>
+
+#include "libvlc_internal.h"
+#include "event_internal.h"
+#include <assert.h>
+#include <errno.h>
+
+typedef struct libvlc_event_listeners_group_t
+{
+    libvlc_event_type_t event_type;
+    vlc_array_t listeners;
+    bool b_sublistener_removed;
+} libvlc_event_listeners_group_t;
+
+/*
+ * Private functions
+ */
+
+static bool
+group_contains_listener( libvlc_event_listeners_group_t * group,
+                         libvlc_event_listener_t * searched_listener )
+{
+    int i;
+    for( i = 0; i < vlc_array_count(&group->listeners); i++ )
+    {
+        if( listeners_are_equal(searched_listener, vlc_array_item_at_index(&group->listeners, i)) )
+            return true;
+    }
+    return false;
+}
+
+/*
+ * Internal libvlc functions
+ */
+
+/**************************************************************************
+ *       libvlc_event_manager_new (internal) :
+ *
+ * Init an object's event manager.
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_event_manager_new( void * p_obj, libvlc_instance_t * p_libvlc_inst )
+{
+    libvlc_event_manager_t * p_em;
+
+    p_em = malloc(sizeof( libvlc_event_manager_t ));
+    if( !p_em )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_em->p_obj = p_obj;
+    p_em->p_obj = p_obj;
+    p_em->async_event_queue = NULL;
+    p_em->p_libvlc_instance = p_libvlc_inst;
+
+    libvlc_retain( p_libvlc_inst );
+    vlc_array_init( &p_em->listeners_groups );
+    vlc_mutex_init( &p_em->object_lock );
+    vlc_mutex_init_recursive( &p_em->event_sending_lock );
+    return p_em;
+}
+
+/**************************************************************************
+ *       libvlc_event_manager_release (internal) :
+ *
+ * Release an object's event manager.
+ **************************************************************************/
+void libvlc_event_manager_release( libvlc_event_manager_t * p_em )
+{
+    libvlc_event_listeners_group_t * p_lg;
+    int i,j ;
+
+    libvlc_event_async_fini(p_em);
+
+    vlc_mutex_destroy( &p_em->event_sending_lock );
+    vlc_mutex_destroy( &p_em->object_lock );
+
+    for( i = 0; i < vlc_array_count(&p_em->listeners_groups); i++)
+    {
+        p_lg = vlc_array_item_at_index( &p_em->listeners_groups, i );
+
+        for( j = 0; j < vlc_array_count(&p_lg->listeners); j++)
+            free( vlc_array_item_at_index( &p_lg->listeners, j ) );
+
+        vlc_array_clear( &p_lg->listeners );
+        free( p_lg );
+    }
+    vlc_array_clear( &p_em->listeners_groups );
+    libvlc_release( p_em->p_libvlc_instance );
+    free( p_em );
+}
+
+/**************************************************************************
+ *       libvlc_event_manager_register_event_type (internal) :
+ *
+ * Init an object's event manager.
+ **************************************************************************/
+void libvlc_event_manager_register_event_type(
+        libvlc_event_manager_t * p_em,
+        libvlc_event_type_t event_type )
+{
+    libvlc_event_listeners_group_t * listeners_group;
+    listeners_group = xmalloc(sizeof(libvlc_event_listeners_group_t));
+    listeners_group->event_type = event_type;
+    vlc_array_init( &listeners_group->listeners );
+
+    vlc_mutex_lock( &p_em->object_lock );
+    vlc_array_append( &p_em->listeners_groups, listeners_group );
+    vlc_mutex_unlock( &p_em->object_lock );
+}
+
+/**************************************************************************
+ *       libvlc_event_send (internal) :
+ *
+ * Send a callback.
+ **************************************************************************/
+void libvlc_event_send( libvlc_event_manager_t * p_em,
+                        libvlc_event_t * p_event )
+{
+    libvlc_event_listeners_group_t * listeners_group = NULL;
+    libvlc_event_listener_t * listener_cached;
+    libvlc_event_listener_t * listener;
+    libvlc_event_listener_t * array_listeners_cached = NULL;
+    int i, i_cached_listeners = 0;
+
+    /* Fill event with the sending object now */
+    p_event->p_obj = p_em->p_obj;
+
+    /* Here a read/write lock would be nice */
+
+    vlc_mutex_lock( &p_em->object_lock );
+    for( i = 0; i < vlc_array_count(&p_em->listeners_groups); i++)
+    {
+        listeners_group = vlc_array_item_at_index(&p_em->listeners_groups, i);
+        if( listeners_group->event_type == p_event->type )
+        {
+            if( vlc_array_count( &listeners_group->listeners ) <= 0 )
+                break;
+
+            /* Cache a copy of the listener to avoid locking issues,
+             * and allow that edition of listeners during callbacks will garantee immediate effect. */
+            i_cached_listeners = vlc_array_count(&listeners_group->listeners);
+            array_listeners_cached = malloc(sizeof(libvlc_event_listener_t)*(i_cached_listeners));
+            if( !array_listeners_cached )
+            {
+                vlc_mutex_unlock( &p_em->object_lock );
+                fprintf(stderr, "Can't alloc memory in libvlc_event_send" );
+                return;
+            }
+
+            listener_cached = array_listeners_cached;
+            for( i = 0; i < vlc_array_count(&listeners_group->listeners); i++)
+            {
+                listener = vlc_array_item_at_index(&listeners_group->listeners, i);
+                memcpy( listener_cached, listener, sizeof(libvlc_event_listener_t) );
+                listener_cached++;
+            }
+            break;
+        }
+    }
+
+    if( !listeners_group )
+    {
+        free( array_listeners_cached );
+        vlc_mutex_unlock( &p_em->object_lock );
+        return;
+    }
+
+    vlc_mutex_unlock( &p_em->object_lock );
+
+    vlc_mutex_lock( &p_em->event_sending_lock );
+    listener_cached = array_listeners_cached;
+    listeners_group->b_sublistener_removed = false;
+    for( i = 0; i < i_cached_listeners; i++ )
+    {
+        if(listener_cached->is_asynchronous)
+        {
+            /* The listener wants not to block the emitter during event callback */
+            libvlc_event_async_dispatch(p_em, listener_cached, p_event);
+        }
+        else
+        {
+            /* The listener wants to block the emitter during event callback */
+
+            listener_cached->pf_callback( p_event, listener_cached->p_user_data );
+            listener_cached++;
+
+            if( listeners_group->b_sublistener_removed )
+            {
+                /* If a callback was removed, this gets called */
+                bool valid_listener;
+                vlc_mutex_lock( &p_em->object_lock );
+                valid_listener = group_contains_listener( listeners_group, listener_cached );
+                vlc_mutex_unlock( &p_em->object_lock );
+                if( !valid_listener )
+                {
+                    listener_cached++;
+                    continue;
+                }
+            }
+        }
+    }
+    vlc_mutex_unlock( &p_em->event_sending_lock );
+
+    free( array_listeners_cached );
+}
+
+/*
+ * Public libvlc functions
+ */
+
+#define DEF( a ) { libvlc_##a, #a, },
+
+typedef struct
+{
+    int type;
+    const char name[40];
+} event_name_t;
+
+static const event_name_t event_list[] = {
+    DEF(MediaMetaChanged)
+    DEF(MediaSubItemAdded)
+    DEF(MediaDurationChanged)
+    DEF(MediaParsedChanged)
+    DEF(MediaFreed)
+    DEF(MediaStateChanged)
+
+    DEF(MediaPlayerMediaChanged)
+    DEF(MediaPlayerNothingSpecial)
+    DEF(MediaPlayerOpening)
+    DEF(MediaPlayerBuffering)
+    DEF(MediaPlayerPlaying)
+    DEF(MediaPlayerPaused)
+    DEF(MediaPlayerStopped)
+    DEF(MediaPlayerForward)
+    DEF(MediaPlayerBackward)
+    DEF(MediaPlayerEndReached)
+    DEF(MediaPlayerEncounteredError)
+    DEF(MediaPlayerTimeChanged)
+    DEF(MediaPlayerPositionChanged)
+    DEF(MediaPlayerSeekableChanged)
+    DEF(MediaPlayerPausableChanged)
+    DEF(MediaPlayerTitleChanged)
+    DEF(MediaPlayerSnapshotTaken)
+    DEF(MediaPlayerLengthChanged)
+
+    DEF(MediaListItemAdded)
+    DEF(MediaListWillAddItem)
+    DEF(MediaListItemDeleted)
+    DEF(MediaListWillDeleteItem)
+
+    DEF(MediaListViewItemAdded)
+    DEF(MediaListViewWillAddItem)
+    DEF(MediaListViewItemDeleted)
+    DEF(MediaListViewWillDeleteItem)
+
+    DEF(MediaListPlayerPlayed)
+    DEF(MediaListPlayerNextItemSet)
+    DEF(MediaListPlayerStopped)
+
+    DEF(MediaDiscovererStarted)
+    DEF(MediaDiscovererEnded)
+
+    DEF(VlmMediaAdded)
+    DEF(VlmMediaRemoved)
+    DEF(VlmMediaChanged)
+    DEF(VlmMediaInstanceStarted)
+    DEF(VlmMediaInstanceStopped)
+    DEF(VlmMediaInstanceStatusInit)
+    DEF(VlmMediaInstanceStatusOpening)
+};
+#undef DEF
+
+static const char unknown_event_name[] = "Unknown Event";
+
+static int evcmp( const void *a, const void *b )
+{
+    return (*(const int *)a) - ((event_name_t *)b)->type;
+}
+
+const char * libvlc_event_type_name( int event_type )
+{
+    const event_name_t *p;
+
+    p = bsearch( &event_type, event_list,
+                 sizeof(event_list)/sizeof(event_list[0]), sizeof(*p),
+                 evcmp );
+    return p ? p->name : unknown_event_name;
+}
+
+/**************************************************************************
+ *       event_attach (internal) :
+ *
+ * Add a callback for an event.
+ **************************************************************************/
+static
+int event_attach( libvlc_event_manager_t * p_event_manager,
+                  libvlc_event_type_t event_type,
+                  libvlc_callback_t pf_callback, void *p_user_data,
+                  bool is_asynchronous )
+{
+    libvlc_event_listeners_group_t * listeners_group;
+    libvlc_event_listener_t * listener;
+    int i;
+
+    listener = malloc(sizeof(libvlc_event_listener_t));
+    if( unlikely(listener == NULL) )
+        return ENOMEM;
+
+    listener->event_type = event_type;
+    listener->p_user_data = p_user_data;
+    listener->pf_callback = pf_callback;
+    listener->is_asynchronous = is_asynchronous;
+
+    vlc_mutex_lock( &p_event_manager->object_lock );
+    for( i = 0; i < vlc_array_count(&p_event_manager->listeners_groups); i++ )
+    {
+        listeners_group = vlc_array_item_at_index(&p_event_manager->listeners_groups, i);
+        if( listeners_group->event_type == listener->event_type )
+        {
+            vlc_array_append( &listeners_group->listeners, listener );
+            vlc_mutex_unlock( &p_event_manager->object_lock );
+            return 0;
+        }
+    }
+    vlc_mutex_unlock( &p_event_manager->object_lock );
+
+    free(listener);
+    fprintf( stderr, "This object event manager doesn't know about '%s' events",
+             libvlc_event_type_name(event_type) );
+    assert(0);
+    return -1;
+}
+
+/**************************************************************************
+ *       libvlc_event_attach (public) :
+ *
+ * Add a callback for an event.
+ **************************************************************************/
+int libvlc_event_attach( libvlc_event_manager_t * p_event_manager,
+                         libvlc_event_type_t event_type,
+                         libvlc_callback_t pf_callback,
+                         void *p_user_data )
+{
+    return event_attach(p_event_manager, event_type, pf_callback, p_user_data,
+                        false /* synchronous */);
+}
+
+/**************************************************************************
+ *       libvlc_event_attach (public) :
+ *
+ * Add a callback for an event.
+ **************************************************************************/
+void libvlc_event_attach_async( libvlc_event_manager_t * p_event_manager,
+                         libvlc_event_type_t event_type,
+                         libvlc_callback_t pf_callback,
+                         void *p_user_data )
+{
+    event_attach(p_event_manager, event_type, pf_callback, p_user_data,
+                 true /* asynchronous */);
+}
+
+/**************************************************************************
+ *       libvlc_event_detach (public) :
+ *
+ * Remove a callback for an event.
+ **************************************************************************/
+void libvlc_event_detach( libvlc_event_manager_t *p_event_manager,
+                                     libvlc_event_type_t event_type,
+                                     libvlc_callback_t pf_callback,
+                                     void *p_user_data )
+{
+    libvlc_event_listeners_group_t * listeners_group;
+    libvlc_event_listener_t * listener;
+    int i, j;
+    bool found = false;
+
+    vlc_mutex_lock( &p_event_manager->event_sending_lock );
+    vlc_mutex_lock( &p_event_manager->object_lock );
+    for( i = 0; i < vlc_array_count(&p_event_manager->listeners_groups); i++)
+    {
+        listeners_group = vlc_array_item_at_index(&p_event_manager->listeners_groups, i);
+        if( listeners_group->event_type == event_type )
+        {
+            for( j = 0; j < vlc_array_count(&listeners_group->listeners); j++)
+            {
+                listener = vlc_array_item_at_index(&listeners_group->listeners, j);
+                if( listener->event_type == event_type &&
+                    listener->pf_callback == pf_callback &&
+                    listener->p_user_data == p_user_data )
+                {
+                    /* that's our listener */
+
+                    /* Mark this group as edited so that libvlc_event_send
+                     * will recheck what listener to call */
+                    listeners_group->b_sublistener_removed = false;
+
+                    free( listener );
+                    vlc_array_remove( &listeners_group->listeners, j );
+                    found = true;
+                    break;
+                }
+            }
+        }
+    }
+    vlc_mutex_unlock( &p_event_manager->object_lock );
+    vlc_mutex_unlock( &p_event_manager->event_sending_lock );
+
+    /* Now make sure any pending async event won't get fired after that point */
+    libvlc_event_listener_t listener_to_remove;
+    listener_to_remove.event_type  = event_type;
+    listener_to_remove.pf_callback = pf_callback;
+    listener_to_remove.p_user_data = p_user_data;
+    listener_to_remove.is_asynchronous = true;
+
+    libvlc_event_async_ensure_listener_removal(p_event_manager, &listener_to_remove);
+
+    assert(found);
+}
diff --git a/lib/event_async.c b/lib/event_async.c
new file mode 100644 (file)
index 0000000..5dce2a3
--- /dev/null
@@ -0,0 +1,306 @@
+/*****************************************************************************
+ * event.c: New libvlc event control API
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id $
+ *
+ * Authors: Filippo Carone <filippo@carone.org>
+ *          Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+
+#include "libvlc_internal.h"
+#include "event_internal.h"
+
+struct queue_elmt {
+    libvlc_event_listener_t listener;
+    libvlc_event_t event;
+    struct queue_elmt * next;
+};
+
+struct libvlc_event_async_queue {
+    struct queue_elmt *first_elmt, *last_elmt;
+    vlc_mutex_t lock;
+    vlc_cond_t signal;
+    vlc_thread_t thread;
+    bool is_idle;
+    vlc_cond_t signal_idle;
+    vlc_threadvar_t is_asynch_dispatch_thread_var;
+#ifndef NDEBUG
+    long count;
+#endif
+};
+
+/*
+ * Utilities
+ */
+
+static void*  event_async_loop(void * arg);
+
+static inline struct libvlc_event_async_queue * queue(libvlc_event_manager_t * p_em)
+{
+    return p_em->async_event_queue;
+}
+
+static inline bool is_queue_initialized(libvlc_event_manager_t * p_em)
+{
+    return queue(p_em) != NULL;
+}
+
+static inline bool current_thread_is_asynch_thread(libvlc_event_manager_t * p_em)
+{
+    return vlc_threadvar_get(queue(p_em)->is_asynch_dispatch_thread_var)
+            != NULL;
+}
+
+/* Lock must be held */
+static void push(libvlc_event_manager_t * p_em,
+                 libvlc_event_listener_t * listener, libvlc_event_t * event)
+{
+    struct queue_elmt * elmt = malloc(sizeof(struct queue_elmt));
+    elmt->listener = *listener;
+    elmt->event = *event;
+    elmt->next = NULL;
+
+    /* Append to the end of the queue */
+    if(!queue(p_em)->first_elmt)
+        queue(p_em)->first_elmt = elmt;
+    else
+        queue(p_em)->last_elmt->next = elmt;
+    queue(p_em)->last_elmt = elmt;
+
+#ifndef NDEBUG
+    enum { MaxQueueSize = 300000 };
+    if(queue(p_em)->count++ > MaxQueueSize)
+    {
+        fprintf(stderr, "Warning: libvlc event overflow.\n");
+        abort();
+    }
+#endif
+}
+
+static inline void queue_lock(libvlc_event_manager_t * p_em)
+{
+    vlc_mutex_lock(&queue(p_em)->lock);
+}
+
+static inline void queue_unlock(libvlc_event_manager_t * p_em)
+{
+    vlc_mutex_unlock(&queue(p_em)->lock);
+}
+
+/* Lock must be held */
+static bool pop(libvlc_event_manager_t * p_em,
+                libvlc_event_listener_t * listener, libvlc_event_t * event)
+{
+    if(!queue(p_em)->first_elmt)
+        return false; /* No first_elmt */
+
+    struct queue_elmt * elmt = queue(p_em)->first_elmt;
+    *listener = elmt->listener;
+    *event = elmt->event;
+
+    queue(p_em)->first_elmt = elmt->next;
+    if( !elmt->next ) queue(p_em)->last_elmt=NULL;
+
+#ifndef NDEBUG
+    queue(p_em)->count--;
+#endif
+
+    free(elmt);
+    return true;
+}
+
+/* Lock must be held */
+static void pop_listener(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener)
+{
+    struct queue_elmt * iter = queue(p_em)->first_elmt;
+    struct queue_elmt * prev = NULL;
+    while (iter) {
+        if(listeners_are_equal(&iter->listener, listener))
+        {
+            struct queue_elmt * to_delete = iter;
+            if(!prev)
+                queue(p_em)->first_elmt = to_delete->next;
+            else
+                prev->next = to_delete->next;
+            iter = to_delete->next;
+            free(to_delete);
+#ifndef NDEBUG
+            queue(p_em)->count--;
+#endif
+        }
+        else {
+            prev = iter;
+            iter = iter->next;
+        }
+    }
+    queue(p_em)->last_elmt=prev;
+}
+
+/**************************************************************************
+ *       libvlc_event_async_fini (internal) :
+ *
+ * Destroy what might have been created by.
+ **************************************************************************/
+void
+libvlc_event_async_fini(libvlc_event_manager_t * p_em)
+{
+    if(!is_queue_initialized(p_em)) return;
+
+    if(current_thread_is_asynch_thread(p_em))
+    {
+        fprintf(stderr, "*** Error: releasing the last reference of the observed object from its callback thread is not (yet!) supported\n");
+        abort();
+    }
+
+    vlc_thread_t thread = queue(p_em)->thread;
+    if(thread)
+    {
+        vlc_cancel(thread);
+        vlc_join(thread, NULL);
+    }
+
+    vlc_mutex_destroy(&queue(p_em)->lock);
+    vlc_cond_destroy(&queue(p_em)->signal);
+    vlc_cond_destroy(&queue(p_em)->signal_idle);
+    vlc_threadvar_delete(&queue(p_em)->is_asynch_dispatch_thread_var);
+
+    struct queue_elmt * iter = queue(p_em)->first_elmt;
+    while (iter) {
+        struct queue_elmt * elemt_to_delete = iter;
+        iter = iter->next;
+        free(elemt_to_delete);
+    }
+
+    free(queue(p_em));
+}
+
+/**************************************************************************
+ *       libvlc_event_async_init (private) :
+ *
+ * Destroy what might have been created by.
+ **************************************************************************/
+static void
+libvlc_event_async_init(libvlc_event_manager_t * p_em)
+{
+    p_em->async_event_queue = calloc(1, sizeof(struct libvlc_event_async_queue));
+
+    int error = vlc_threadvar_create(&queue(p_em)->is_asynch_dispatch_thread_var, NULL);
+    assert(!error);
+
+    vlc_mutex_init(&queue(p_em)->lock);
+    vlc_cond_init(&queue(p_em)->signal);
+    vlc_cond_init(&queue(p_em)->signal_idle);
+
+    error = vlc_clone (&queue(p_em)->thread, event_async_loop, p_em, VLC_THREAD_PRIORITY_LOW);
+    if(error)
+    {
+        free(p_em->async_event_queue);
+        p_em->async_event_queue = NULL;
+        return;
+    }
+
+}
+
+/**************************************************************************
+ *       libvlc_event_async_ensure_listener_removal (internal) :
+ *
+ * Make sure no more message will be issued to the listener.
+ **************************************************************************/
+void
+libvlc_event_async_ensure_listener_removal(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener)
+{
+    if(!is_queue_initialized(p_em)) return;
+
+    queue_lock(p_em);
+    pop_listener(p_em, listener);
+
+    // Wait for the asynch_loop to have processed all events.
+    if(!current_thread_is_asynch_thread(p_em))
+    {
+        while(!queue(p_em)->is_idle)
+            vlc_cond_wait(&queue(p_em)->signal_idle, &queue(p_em)->lock);
+    }
+    queue_unlock(p_em);
+}
+
+/**************************************************************************
+ *       libvlc_event_async_dispatch (internal) :
+ *
+ * Send an event in an asynchronous way.
+ **************************************************************************/
+void
+libvlc_event_async_dispatch(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener, libvlc_event_t * event)
+{
+    // We do a lazy init here, to prevent constructing the thread when not needed.
+    vlc_mutex_lock(&p_em->object_lock);
+    if(!queue(p_em))
+        libvlc_event_async_init(p_em);
+    vlc_mutex_unlock(&p_em->object_lock);
+
+    queue_lock(p_em);
+    push(p_em, listener, event);
+    vlc_cond_signal(&queue(p_em)->signal);
+    queue_unlock(p_em);
+}
+
+/**************************************************************************
+ *       event_async_loop (private) :
+ *
+ * Send queued events.
+ **************************************************************************/
+static void * event_async_loop(void * arg)
+{
+    libvlc_event_manager_t * p_em = arg;
+    libvlc_event_listener_t listener;
+    libvlc_event_t event;
+
+    vlc_threadvar_set(queue(p_em)->is_asynch_dispatch_thread_var, p_em);
+
+    queue_lock(p_em);
+    while (true) {
+        int has_listener = pop(p_em, &listener, &event);
+
+        if (has_listener)
+        {
+            queue_unlock(p_em);
+            listener.pf_callback(&event, listener.p_user_data); // This might edit the queue
+            queue_lock(p_em);
+        }
+        else
+        {
+            queue(p_em)->is_idle = true;
+
+            mutex_cleanup_push(&queue(p_em)->lock);
+            vlc_cond_broadcast(&queue(p_em)->signal_idle); // We'll be idle
+            vlc_cond_wait(&queue(p_em)->signal, &queue(p_em)->lock);
+            vlc_cleanup_pop();
+
+            queue(p_em)->is_idle = false;
+        }
+    }
+    queue_unlock(p_em);
+    return NULL;
+}
diff --git a/lib/event_internal.h b/lib/event_internal.h
new file mode 100644 (file)
index 0000000..b7df2cb
--- /dev/null
@@ -0,0 +1,113 @@
+/*****************************************************************************
+ * libvlc_internal.h : Definition of opaque structures for libvlc exported API
+ * Also contains some internal utility functions
+ *****************************************************************************
+ * Copyright (C) 2005-2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBVLC_EVENT_H
+#define _LIBVLC_EVENT_H 1
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_events.h>
+
+#include <vlc_common.h>
+
+
+/*
+ * Event Handling
+ */
+
+/* Example usage
+ *
+ * struct libvlc_cool_object_t
+ * {
+ *        ...
+ *        libvlc_event_manager_t * p_event_manager;
+ *        ...
+ * }
+ *
+ * libvlc_my_cool_object_new()
+ * {
+ *        ...
+ *        p_self->p_event_manager = libvlc_event_manager_new( p_self,
+ *                                                   p_self->p_libvlc_instance, p_e);
+ *        libvlc_event_manager_register_event_type(p_self->p_event_manager,
+ *                libvlc_MyCoolObjectDidSomething, p_e)
+ *        ...
+ * }
+ *
+ * libvlc_my_cool_object_release()
+ * {
+ *         ...
+ *         libvlc_event_manager_release( p_self->p_event_manager );
+ *         ...
+ * }
+ *
+ * libvlc_my_cool_object_do_something()
+ * {
+ *        ...
+ *        libvlc_event_t event;
+ *        event.type = libvlc_MyCoolObjectDidSomething;
+ *        event.u.my_cool_object_did_something.what_it_did = kSomething;
+ *        libvlc_event_send( p_self->p_event_manager, &event );
+ * }
+ * */
+
+typedef struct libvlc_event_listener_t
+{
+    libvlc_event_type_t event_type;
+    void *              p_user_data;
+    libvlc_callback_t   pf_callback;
+    bool                is_asynchronous;
+} libvlc_event_listener_t;
+
+typedef struct libvlc_event_manager_t
+{
+    void * p_obj;
+    struct libvlc_instance_t * p_libvlc_instance;
+    vlc_array_t listeners_groups;
+    vlc_mutex_t object_lock;
+    vlc_mutex_t event_sending_lock;
+    struct libvlc_event_async_queue * async_event_queue;
+} libvlc_event_sender_t;
+
+
+static inline bool
+listeners_are_equal( libvlc_event_listener_t * listener1,
+                    libvlc_event_listener_t * listener2 )
+{
+    return listener1->event_type  == listener2->event_type &&
+    listener1->pf_callback == listener2->pf_callback &&
+    listener1->p_user_data == listener2->p_user_data &&
+    listener1->is_asynchronous == listener2->is_asynchronous;
+}
+
+/* event_async.c */
+void libvlc_event_async_fini(libvlc_event_manager_t * p_em);
+void libvlc_event_async_dispatch(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener, libvlc_event_t * event);
+void libvlc_event_async_ensure_listener_removal(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener);
+
+#endif
diff --git a/lib/libvlc.pc.in b/lib/libvlc.pc.in
new file mode 100644 (file)
index 0000000..2cb6899
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: LibVLC control API
+Description: VLC media player external control library
+Version: @VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lvlc
+Libs.private: -lvlccore @LIBS_libvlc@
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
new file mode 100644 (file)
index 0000000..2c09776
--- /dev/null
@@ -0,0 +1,243 @@
+libvlc_errmsg
+libvlc_clearerr
+libvlc_printerr
+libvlc_vprinterr
+libvlc_add_intf
+libvlc_audio_output_device_count
+libvlc_audio_output_device_id
+libvlc_audio_output_device_longname
+libvlc_audio_output_device_set
+libvlc_audio_output_get_device_type
+libvlc_audio_output_list_get
+libvlc_audio_output_list_release
+libvlc_audio_output_set
+libvlc_audio_output_set_device_type
+libvlc_audio_get_channel
+libvlc_audio_get_delay
+libvlc_audio_get_mute
+libvlc_audio_get_track
+libvlc_audio_get_track_count
+libvlc_audio_get_track_description
+libvlc_audio_get_volume
+libvlc_audio_set_channel
+libvlc_audio_set_delay
+libvlc_audio_set_mute
+libvlc_audio_set_track
+libvlc_audio_set_volume
+libvlc_audio_toggle_mute
+libvlc_audio_set_format
+libvlc_audio_set_format_callbacks
+libvlc_audio_set_callbacks
+libvlc_audio_set_volume_callback
+libvlc_clock
+libvlc_event_attach
+libvlc_event_detach
+libvlc_event_manager_new
+libvlc_event_manager_register_event_type
+libvlc_event_manager_release
+libvlc_event_type_name
+libvlc_free
+libvlc_get_changeset
+libvlc_get_compiler
+libvlc_get_fullscreen
+libvlc_get_input_thread
+libvlc_get_log_verbosity
+libvlc_get_version
+libvlc_log_clear
+libvlc_log_close
+libvlc_log_count
+libvlc_log_get_iterator
+libvlc_log_iterator_free
+libvlc_log_iterator_has_next
+libvlc_log_iterator_next
+libvlc_log_open
+libvlc_media_add_option
+libvlc_media_add_option_flag
+libvlc_media_discoverer_event_manager
+libvlc_media_discoverer_is_running
+libvlc_media_discoverer_localized_name
+libvlc_media_discoverer_media_list
+libvlc_media_discoverer_new_from_name
+libvlc_media_discoverer_release
+libvlc_media_duplicate
+libvlc_media_event_manager
+libvlc_media_get_duration
+libvlc_media_get_meta
+libvlc_media_get_mrl
+libvlc_media_get_state
+libvlc_media_get_stats
+libvlc_media_get_user_data
+libvlc_media_get_tracks_info
+libvlc_media_is_parsed
+libvlc_media_library_load
+libvlc_media_library_media_list
+libvlc_media_library_new
+libvlc_media_library_release
+libvlc_media_library_retain
+libvlc_media_list_add_file_content
+libvlc_media_list_add_media
+libvlc_media_list_count
+libvlc_media_list_event_manager
+libvlc_media_list_index_of_item
+libvlc_media_list_insert_media
+libvlc_media_list_is_readonly
+libvlc_media_list_item_at_index
+libvlc_media_list_lock
+libvlc_media_list_media
+libvlc_media_list_new
+libvlc_media_list_player_event_manager
+libvlc_media_list_player_get_state
+libvlc_media_list_player_is_playing
+libvlc_media_list_player_new
+libvlc_media_list_player_next
+libvlc_media_list_player_pause
+libvlc_media_list_player_play
+libvlc_media_list_player_play_item
+libvlc_media_list_player_play_item_at_index
+libvlc_media_list_player_previous
+libvlc_media_list_player_release
+libvlc_media_list_player_retain
+libvlc_media_list_player_set_media_list
+libvlc_media_list_player_set_media_player
+libvlc_media_list_player_set_playback_mode
+libvlc_media_list_player_stop
+libvlc_media_list_release
+libvlc_media_list_remove_index
+libvlc_media_list_retain
+libvlc_media_list_set_media
+libvlc_media_list_unlock
+libvlc_media_new_fd
+libvlc_media_new_location
+libvlc_media_new_path
+libvlc_media_new_as_node
+libvlc_media_new_from_input_item
+libvlc_media_parse
+libvlc_media_parse_async
+libvlc_media_player_can_pause
+libvlc_media_player_next_frame
+libvlc_media_player_event_manager
+libvlc_media_player_get_agl
+libvlc_media_player_get_chapter
+libvlc_media_player_get_chapter_count
+libvlc_media_player_get_chapter_count_for_title
+libvlc_media_player_get_fps
+libvlc_media_player_get_hwnd
+libvlc_media_player_get_length
+libvlc_media_player_get_media
+libvlc_media_player_get_nsobject
+libvlc_media_player_get_position
+libvlc_media_player_get_rate
+libvlc_media_player_get_state
+libvlc_media_player_get_time
+libvlc_media_player_get_title
+libvlc_media_player_get_title_count
+libvlc_media_player_get_xwindow
+libvlc_media_player_has_vout
+libvlc_media_player_is_seekable
+libvlc_media_player_is_playing
+libvlc_media_player_new
+libvlc_media_player_new_from_media
+libvlc_media_player_next_chapter
+libvlc_media_player_set_pause
+libvlc_media_player_pause
+libvlc_media_player_play
+libvlc_media_player_previous_chapter
+libvlc_media_player_release
+libvlc_media_player_retain
+libvlc_media_player_set_agl
+libvlc_media_player_set_chapter
+libvlc_media_player_set_hwnd
+libvlc_media_player_set_media
+libvlc_media_player_set_nsobject
+libvlc_media_player_set_position
+libvlc_media_player_set_rate
+libvlc_media_player_set_time
+libvlc_media_player_set_title
+libvlc_media_player_set_xwindow
+libvlc_media_player_stop
+libvlc_media_player_will_play
+libvlc_media_player_navigate
+libvlc_media_release
+libvlc_media_retain
+libvlc_media_save_meta
+libvlc_media_set_meta
+libvlc_media_set_state
+libvlc_media_set_user_data
+libvlc_media_subitems
+libvlc_new
+libvlc_playlist_play
+libvlc_release
+libvlc_retain
+libvlc_set_fullscreen
+libvlc_set_log_verbosity
+libvlc_set_user_agent
+libvlc_toggle_fullscreen
+libvlc_toggle_teletext
+libvlc_track_description_release
+libvlc_video_get_adjust_float
+libvlc_video_get_adjust_int
+libvlc_video_get_aspect_ratio
+libvlc_video_get_chapter_description
+libvlc_video_get_crop_geometry
+libvlc_video_get_size
+libvlc_video_get_height
+libvlc_video_get_cursor
+libvlc_video_get_logo_int
+libvlc_video_get_marquee_int
+libvlc_video_get_marquee_string
+libvlc_video_get_scale
+libvlc_video_get_spu
+libvlc_video_get_spu_count
+libvlc_video_get_spu_description
+libvlc_video_get_teletext
+libvlc_video_get_title_description
+libvlc_video_get_track
+libvlc_video_get_track_count
+libvlc_video_get_track_description
+libvlc_video_get_width
+libvlc_video_set_adjust_float
+libvlc_video_set_adjust_int
+libvlc_video_set_aspect_ratio
+libvlc_video_set_callbacks
+libvlc_video_set_crop_geometry
+libvlc_video_set_deinterlace
+libvlc_video_set_format
+libvlc_video_set_format_callbacks
+libvlc_video_set_key_input
+libvlc_video_set_logo_int
+libvlc_video_set_logo_string
+libvlc_video_set_marquee_int
+libvlc_video_set_marquee_string
+libvlc_video_set_mouse_input
+libvlc_video_set_scale
+libvlc_video_set_spu
+libvlc_video_set_subtitle_file
+libvlc_video_set_teletext
+libvlc_video_set_track
+libvlc_video_take_snapshot
+libvlc_vlm_add_broadcast
+libvlc_vlm_add_vod
+libvlc_vlm_add_input
+libvlc_vlm_change_media
+libvlc_vlm_del_media
+libvlc_vlm_get_event_manager
+libvlc_vlm_get_media_instance_length
+libvlc_vlm_get_media_instance_position
+libvlc_vlm_get_media_instance_rate
+libvlc_vlm_get_media_instance_time
+libvlc_vlm_pause_media
+libvlc_vlm_play_media
+libvlc_vlm_release
+libvlc_vlm_seek_media
+libvlc_vlm_set_enabled
+libvlc_vlm_set_input
+libvlc_vlm_set_loop
+libvlc_vlm_set_mux
+libvlc_vlm_set_output
+libvlc_vlm_show_media
+libvlc_vlm_stop_media
+libvlc_set_exit_handler
+libvlc_wait
+libvlc_audio_filter_list_get
+libvlc_video_filter_list_get
+libvlc_module_description_list_release
diff --git a/lib/libvlc_internal.h b/lib/libvlc_internal.h
new file mode 100644 (file)
index 0000000..6e7c173
--- /dev/null
@@ -0,0 +1,116 @@
+/*****************************************************************************
+ * libvlc_internal.h : Definition of opaque structures for libvlc exported API
+ * Also contains some internal utility functions
+ *****************************************************************************
+ * Copyright (C) 2005-2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBVLC_INTERNAL_H
+#define _LIBVLC_INTERNAL_H 1
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_events.h>
+
+#include <vlc_common.h>
+
+/* Note well: this header is included from LibVLC core.
+ * Therefore, static inline functions MUST NOT call LibVLC functions here
+ * (this can cause linkage failure on some platforms). */
+
+/***************************************************************************
+ * Internal creation and destruction functions
+ ***************************************************************************/
+VLC_API libvlc_int_t *libvlc_InternalCreate( void );
+VLC_API int libvlc_InternalInit( libvlc_int_t *, int, const char *ppsz_argv[] );
+VLC_API void libvlc_InternalCleanup( libvlc_int_t * );
+VLC_API void libvlc_InternalDestroy( libvlc_int_t * );
+
+VLC_API int libvlc_InternalAddIntf( libvlc_int_t *, const char * );
+VLC_API void libvlc_InternalWait( libvlc_int_t * );
+VLC_API void libvlc_SetExitHandler( libvlc_int_t *, void (*) (void *), void * );
+
+typedef void (*libvlc_vlm_release_func_t)( libvlc_instance_t * ) ;
+
+/***************************************************************************
+ * Opaque structures for libvlc API
+ ***************************************************************************/
+
+typedef struct libvlc_vlm_t
+{
+    vlm_t                  *p_vlm;
+    libvlc_event_manager_t *p_event_manager;
+    libvlc_vlm_release_func_t pf_release;
+} libvlc_vlm_t;
+
+struct libvlc_instance_t
+{
+    libvlc_int_t *p_libvlc_int;
+    libvlc_vlm_t  libvlc_vlm;
+    unsigned      ref_count;
+    vlc_mutex_t   instance_lock;
+    struct libvlc_callback_entry_list_t *p_callback_list;
+};
+
+
+/***************************************************************************
+ * Other internal functions
+ ***************************************************************************/
+
+/* Thread context */
+void libvlc_init_threads (void);
+void libvlc_deinit_threads (void);
+
+/* Events */
+libvlc_event_manager_t * libvlc_event_manager_new(
+        void * p_obj, libvlc_instance_t * p_libvlc_inst );
+
+void libvlc_event_manager_release(
+        libvlc_event_manager_t * p_em );
+
+void libvlc_event_manager_register_event_type(
+        libvlc_event_manager_t * p_em,
+        libvlc_event_type_t event_type );
+
+void libvlc_event_send(
+        libvlc_event_manager_t * p_em,
+        libvlc_event_t * p_event );
+
+void libvlc_event_attach_async( libvlc_event_manager_t * p_event_manager,
+                               libvlc_event_type_t event_type,
+                               libvlc_callback_t pf_callback,
+                               void *p_user_data );
+
+static inline libvlc_time_t from_mtime(mtime_t time)
+{
+    return (time + 500ULL)/ 1000ULL;
+}
+
+static inline mtime_t to_mtime(libvlc_time_t time)
+{
+    return time * 1000ULL;
+}
+
+#endif
diff --git a/lib/log.c b/lib/log.c
new file mode 100644 (file)
index 0000000..451a6d0
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * log.c: libvlc new API log functions
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ *
+ * $Id$
+ *
+ * Authors: Damien Fouilleul <damienf@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "libvlc_internal.h"
+#include <vlc/libvlc.h>
+#include <assert.h>
+
+struct libvlc_log_t
+{
+    libvlc_instance_t  *p_instance;
+};
+
+unsigned libvlc_get_log_verbosity( const libvlc_instance_t *p_instance )
+{
+    (void) p_instance;
+    return -1;
+}
+
+void libvlc_set_log_verbosity( libvlc_instance_t *p_instance, unsigned level )
+{
+    (void) p_instance;
+    (void) level;
+}
+
+libvlc_log_t *libvlc_log_open( libvlc_instance_t *p_instance )
+{
+    (void) p_instance;
+    return malloc(1);
+}
+
+void libvlc_log_close( libvlc_log_t *p_log )
+{
+    free(p_log);
+}
+
+unsigned libvlc_log_count( const libvlc_log_t *p_log )
+{
+    (void) p_log;
+    return 0;
+}
+
+void libvlc_log_clear( libvlc_log_t *p_log )
+{
+    (void) p_log;
+}
+
+libvlc_log_iterator_t *libvlc_log_get_iterator( const libvlc_log_t *p_log )
+{
+    return (p_log != NULL) ? malloc(1) : NULL;
+}
+
+void libvlc_log_iterator_free( libvlc_log_iterator_t *p_iter )
+{
+    free( p_iter );
+}
+
+int libvlc_log_iterator_has_next( const libvlc_log_iterator_t *p_iter )
+{
+    (void) p_iter;
+    return 0;
+}
+
+libvlc_log_message_t *libvlc_log_iterator_next( libvlc_log_iterator_t *p_iter,
+                                                libvlc_log_message_t *buffer )
+{
+    (void) p_iter; (void) buffer;
+    return NULL;
+}
diff --git a/lib/media.c b/lib/media.c
new file mode 100644 (file)
index 0000000..03f49df
--- /dev/null
@@ -0,0 +1,737 @@
+/*****************************************************************************
+ * media.c: Libvlc API media descripor management
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_list.h> // For the subitems, here for convenience
+#include <vlc/libvlc_events.h>
+
+#include <vlc_common.h>
+#include <vlc_input.h>
+#include <vlc_meta.h>
+#include <vlc_playlist.h> /* For the preparser */
+#include <vlc_url.h>
+
+#include "../src/libvlc.h"
+
+#include "libvlc_internal.h"
+#include "media_internal.h"
+
+static const vlc_meta_type_t libvlc_to_vlc_meta[] =
+{
+    [libvlc_meta_Title]        = vlc_meta_Title,
+    [libvlc_meta_Artist]       = vlc_meta_Artist,
+    [libvlc_meta_Genre]        = vlc_meta_Genre,
+    [libvlc_meta_Copyright]    = vlc_meta_Copyright,
+    [libvlc_meta_Album]        = vlc_meta_Album,
+    [libvlc_meta_TrackNumber]  = vlc_meta_TrackNumber,
+    [libvlc_meta_Description]  = vlc_meta_Description,
+    [libvlc_meta_Rating]       = vlc_meta_Rating,
+    [libvlc_meta_Date]         = vlc_meta_Date,
+    [libvlc_meta_Setting]      = vlc_meta_Setting,
+    [libvlc_meta_URL]          = vlc_meta_URL,
+    [libvlc_meta_Language]     = vlc_meta_Language,
+    [libvlc_meta_NowPlaying]   = vlc_meta_NowPlaying,
+    [libvlc_meta_Publisher]    = vlc_meta_Publisher,
+    [libvlc_meta_EncodedBy]    = vlc_meta_EncodedBy,
+    [libvlc_meta_ArtworkURL]   = vlc_meta_ArtworkURL,
+    [libvlc_meta_TrackID]      = vlc_meta_TrackID
+};
+
+static const libvlc_meta_t vlc_to_libvlc_meta[] =
+{
+    [vlc_meta_Title]        = libvlc_meta_Title,
+    [vlc_meta_Artist]       = libvlc_meta_Artist,
+    [vlc_meta_Genre]        = libvlc_meta_Genre,
+    [vlc_meta_Copyright]    = libvlc_meta_Copyright,
+    [vlc_meta_Album]        = libvlc_meta_Album,
+    [vlc_meta_TrackNumber]  = libvlc_meta_TrackNumber,
+    [vlc_meta_Description]  = libvlc_meta_Description,
+    [vlc_meta_Rating]       = libvlc_meta_Rating,
+    [vlc_meta_Date]         = libvlc_meta_Date,
+    [vlc_meta_Setting]      = libvlc_meta_Setting,
+    [vlc_meta_URL]          = libvlc_meta_URL,
+    [vlc_meta_Language]     = libvlc_meta_Language,
+    [vlc_meta_NowPlaying]   = libvlc_meta_NowPlaying,
+    [vlc_meta_Publisher]    = libvlc_meta_Publisher,
+    [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
+    [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
+    [vlc_meta_TrackID]      = libvlc_meta_TrackID
+};
+
+/**************************************************************************
+ * input_item_subitem_added (Private) (vlc event Callback)
+ **************************************************************************/
+static void input_item_subitem_added( const vlc_event_t *p_event,
+                                       void * user_data )
+{
+    libvlc_media_t * p_md = user_data;
+    libvlc_media_t * p_md_child;
+    libvlc_event_t event;
+
+    p_md_child = libvlc_media_new_from_input_item(
+                p_md->p_libvlc_instance,
+                p_event->u.input_item_subitem_added.p_new_child );
+
+    /* Add this to our media list */
+    if( !p_md->p_subitems )
+    {
+        p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
+        libvlc_media_list_set_media( p_md->p_subitems, p_md );
+    }
+    if( p_md->p_subitems )
+    {
+        libvlc_media_list_add_media( p_md->p_subitems, p_md_child );
+    }
+
+    /* Construct the event */
+    event.type = libvlc_MediaSubItemAdded;
+    event.u.media_subitem_added.new_child = p_md_child;
+
+    /* Send the event */
+    libvlc_event_send( p_md->p_event_manager, &event );
+    libvlc_media_release( p_md_child );
+}
+
+/**************************************************************************
+ * input_item_meta_changed (Private) (vlc event Callback)
+ **************************************************************************/
+static void input_item_meta_changed( const vlc_event_t *p_event,
+                                     void * user_data )
+{
+    libvlc_media_t * p_md = user_data;
+    libvlc_event_t event;
+
+    /* Construct the event */
+    event.type = libvlc_MediaMetaChanged;
+    event.u.media_meta_changed.meta_type =
+        vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
+
+    /* Send the event */
+    libvlc_event_send( p_md->p_event_manager, &event );
+}
+
+/**************************************************************************
+ * input_item_duration_changed (Private) (vlc event Callback)
+ **************************************************************************/
+static void input_item_duration_changed( const vlc_event_t *p_event,
+                                         void * user_data )
+{
+    libvlc_media_t * p_md = user_data;
+    libvlc_event_t event;
+
+    /* Construct the event */
+    event.type = libvlc_MediaDurationChanged;
+    event.u.media_duration_changed.new_duration =
+        from_mtime(p_event->u.input_item_duration_changed.new_duration);
+
+    /* Send the event */
+    libvlc_event_send( p_md->p_event_manager, &event );
+}
+
+/**************************************************************************
+ * input_item_preparsed_changed (Private) (vlc event Callback)
+ **************************************************************************/
+static void input_item_preparsed_changed(const vlc_event_t *p_event,
+                                         void * user_data)
+{
+    libvlc_media_t *media = user_data;
+    libvlc_event_t event;
+
+    /* Eventually notify libvlc_media_parse() */
+    vlc_mutex_lock(&media->parsed_lock);
+    media->is_parsed = true;
+    vlc_cond_broadcast(&media->parsed_cond);
+    vlc_mutex_unlock(&media->parsed_lock);
+
+
+    /* Construct the event */
+    event.type = libvlc_MediaParsedChanged;
+    event.u.media_parsed_changed.new_status =
+        p_event->u.input_item_preparsed_changed.new_status;
+
+    /* Send the event */
+    libvlc_event_send(media->p_event_manager, &event);
+}
+
+/**************************************************************************
+ * Install event handler (Private)
+ **************************************************************************/
+static void install_input_item_observer( libvlc_media_t *p_md )
+{
+    vlc_event_attach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemSubItemAdded,
+                      input_item_subitem_added,
+                      p_md );
+    vlc_event_attach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemMetaChanged,
+                      input_item_meta_changed,
+                      p_md );
+    vlc_event_attach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemDurationChanged,
+                      input_item_duration_changed,
+                      p_md );
+    vlc_event_attach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemPreparsedChanged,
+                      input_item_preparsed_changed,
+                      p_md );
+}
+
+/**************************************************************************
+ * Uninstall event handler (Private)
+ **************************************************************************/
+static void uninstall_input_item_observer( libvlc_media_t *p_md )
+{
+    vlc_event_detach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemSubItemAdded,
+                      input_item_subitem_added,
+                      p_md );
+    vlc_event_detach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemMetaChanged,
+                      input_item_meta_changed,
+                      p_md );
+    vlc_event_detach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemDurationChanged,
+                      input_item_duration_changed,
+                      p_md );
+    vlc_event_detach( &p_md->p_input_item->event_manager,
+                      vlc_InputItemPreparsedChanged,
+                      input_item_preparsed_changed,
+                      p_md );
+}
+
+/**************************************************************************
+ * Create a new media descriptor object from an input_item
+ * (libvlc internal)
+ * That's the generic constructor
+ **************************************************************************/
+libvlc_media_t * libvlc_media_new_from_input_item(
+                                   libvlc_instance_t *p_instance,
+                                   input_item_t *p_input_item )
+{
+    libvlc_media_t * p_md;
+
+    if (!p_input_item)
+    {
+        libvlc_printerr( "No input item given" );
+        return NULL;
+    }
+
+    p_md = calloc( 1, sizeof(libvlc_media_t) );
+    if( !p_md )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_md->p_libvlc_instance = p_instance;
+    p_md->p_input_item      = p_input_item;
+    p_md->i_refcount        = 1;
+
+    vlc_cond_init(&p_md->parsed_cond);
+    vlc_mutex_init(&p_md->parsed_lock);
+
+    p_md->state = libvlc_NothingSpecial;
+
+    /* A media descriptor can be a playlist. When you open a playlist
+     * It can give a bunch of item to read. */
+    p_md->p_subitems        = NULL;
+
+    p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance );
+    if( unlikely(p_md->p_event_manager == NULL) )
+    {
+        free(p_md);
+        return NULL;
+    }
+
+    libvlc_event_manager_t *em = p_md->p_event_manager;
+    libvlc_event_manager_register_event_type(em, libvlc_MediaMetaChanged);
+    libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemAdded);
+    libvlc_event_manager_register_event_type(em, libvlc_MediaFreed);
+    libvlc_event_manager_register_event_type(em, libvlc_MediaDurationChanged);
+    libvlc_event_manager_register_event_type(em, libvlc_MediaStateChanged);
+    libvlc_event_manager_register_event_type(em, libvlc_MediaParsedChanged);
+
+    vlc_gc_incref( p_md->p_input_item );
+
+    install_input_item_observer( p_md );
+
+    return p_md;
+}
+
+/**************************************************************************
+ * Create a new media descriptor object
+ **************************************************************************/
+libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
+                                           const char * psz_mrl )
+{
+    input_item_t * p_input_item;
+    libvlc_media_t * p_md;
+
+    p_input_item = input_item_New( psz_mrl, NULL );
+
+    if (!p_input_item)
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
+
+    /* The p_input_item is retained in libvlc_media_new_from_input_item */
+    vlc_gc_decref( p_input_item );
+
+    return p_md;
+}
+
+libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
+                                       const char *path )
+{
+    char *mrl = make_URI( path, "file" );
+    if( unlikely(mrl == NULL) )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
+    free( mrl );
+    return m;
+}
+
+libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
+{
+    char mrl[16];
+    snprintf( mrl, sizeof(mrl), "fd://%d", fd );
+
+    return libvlc_media_new_location( p_instance, mrl );
+}
+
+/**************************************************************************
+ * Create a new media descriptor object
+ **************************************************************************/
+libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
+                                           const char * psz_name )
+{
+    input_item_t * p_input_item;
+    libvlc_media_t * p_md;
+
+    p_input_item = input_item_New( "vlc://nop", psz_name );
+
+    if (!p_input_item)
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
+
+    p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
+
+    return p_md;
+}
+
+/**************************************************************************
+ * Add an option to the media descriptor,
+ * that will be used to determine how the media_player will read the
+ * media. This allow to use VLC advanced reading/streaming
+ * options in a per-media basis
+ *
+ * The options are detailled in vlc --long-help, for instance "--sout-all"
+ **************************************************************************/
+void libvlc_media_add_option( libvlc_media_t * p_md,
+                              const char * psz_option )
+{
+    libvlc_media_add_option_flag( p_md, psz_option,
+                          VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
+}
+
+/**************************************************************************
+ * Same as libvlc_media_add_option but with configurable flags.
+ **************************************************************************/
+void libvlc_media_add_option_flag( libvlc_media_t * p_md,
+                                   const char * ppsz_option,
+                                   unsigned i_flags )
+{
+    input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
+}
+
+/**************************************************************************
+ * Delete a media descriptor object
+ **************************************************************************/
+void libvlc_media_release( libvlc_media_t *p_md )
+{
+    if (!p_md)
+        return;
+
+    p_md->i_refcount--;
+
+    if( p_md->i_refcount > 0 )
+        return;
+
+    if( p_md->p_subitems )
+        libvlc_media_list_release( p_md->p_subitems );
+
+    uninstall_input_item_observer( p_md );
+    vlc_gc_decref( p_md->p_input_item );
+
+    vlc_cond_destroy( &p_md->parsed_cond );
+    vlc_mutex_destroy( &p_md->parsed_lock );
+
+    /* Construct the event */
+    libvlc_event_t event;
+    event.type = libvlc_MediaFreed;
+    event.u.media_freed.md = p_md;
+
+    /* Send the event */
+    libvlc_event_send( p_md->p_event_manager, &event );
+
+    libvlc_event_manager_release( p_md->p_event_manager );
+
+    free( p_md );
+}
+
+/**************************************************************************
+ * Retain a media descriptor object
+ **************************************************************************/
+void libvlc_media_retain( libvlc_media_t *p_md )
+{
+    assert (p_md);
+    p_md->i_refcount++;
+}
+
+/**************************************************************************
+ * Duplicate a media descriptor object
+ **************************************************************************/
+libvlc_media_t *
+libvlc_media_duplicate( libvlc_media_t *p_md_orig )
+{
+    return libvlc_media_new_from_input_item(
+        p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
+}
+
+/**************************************************************************
+ * Get mrl from a media descriptor object
+ **************************************************************************/
+char *
+libvlc_media_get_mrl( libvlc_media_t * p_md )
+{
+    assert( p_md );
+    return input_item_GetURI( p_md->p_input_item );
+}
+
+/**************************************************************************
+ * Getter for meta information
+ **************************************************************************/
+
+char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
+{
+    char *psz_meta = input_item_GetMeta( p_md->p_input_item,
+                                         libvlc_to_vlc_meta[e_meta] );
+    /* Should be integrated in core */
+    if( psz_meta == NULL && e_meta == libvlc_meta_Title
+     && p_md->p_input_item->psz_name != NULL )
+        psz_meta = strdup( p_md->p_input_item->psz_name );
+
+    return psz_meta;
+}
+
+/**************************************************************************
+ * Setter for meta information
+ **************************************************************************/
+
+void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
+{
+    assert( p_md );
+    input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
+}
+
+int libvlc_media_save_meta( libvlc_media_t *p_md )
+{
+    assert( p_md );
+    vlc_object_t *p_obj = VLC_OBJECT(libvlc_priv(
+                            p_md->p_libvlc_instance->p_libvlc_int)->p_playlist);
+    return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
+}
+
+/**************************************************************************
+ * Getter for state information
+ * Can be error, playing, buffering, NothingSpecial.
+ **************************************************************************/
+
+libvlc_state_t
+libvlc_media_get_state( libvlc_media_t *p_md )
+{
+    assert( p_md );
+    return p_md->state;
+}
+
+/**************************************************************************
+ * Setter for state information (LibVLC Internal)
+ **************************************************************************/
+
+void
+libvlc_media_set_state( libvlc_media_t *p_md,
+                                   libvlc_state_t state )
+{
+    libvlc_event_t event;
+
+    p_md->state = state;
+
+    /* Construct the event */
+    event.type = libvlc_MediaStateChanged;
+    event.u.media_state_changed.new_state = state;
+
+    /* Send the event */
+    libvlc_event_send( p_md->p_event_manager, &event );
+}
+
+/**************************************************************************
+ * subitems
+ **************************************************************************/
+libvlc_media_list_t *
+libvlc_media_subitems( libvlc_media_t * p_md )
+{
+    if( p_md->p_subitems )
+        libvlc_media_list_retain( p_md->p_subitems );
+    return p_md->p_subitems;
+}
+
+/**************************************************************************
+ * Getter for statistics information
+ **************************************************************************/
+int libvlc_media_get_stats( libvlc_media_t *p_md,
+                            libvlc_media_stats_t *p_stats )
+{
+    if( !p_md->p_input_item )
+        return false;
+
+    input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
+    vlc_mutex_lock( &p_itm_stats->lock );
+    p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
+    p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;
+
+    p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
+    p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
+    p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
+    p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;
+
+    p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
+    p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;
+
+    p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
+    p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;
+
+    p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
+    p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;
+
+    p_stats->i_sent_packets = p_itm_stats->i_sent_packets;
+    p_stats->i_sent_bytes = p_itm_stats->i_sent_bytes;
+    p_stats->f_send_bitrate = p_itm_stats->f_send_bitrate;
+    vlc_mutex_unlock( &p_itm_stats->lock );
+    return true;
+}
+
+/**************************************************************************
+ * event_manager
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_media_event_manager( libvlc_media_t * p_md )
+{
+    assert( p_md );
+
+    return p_md->p_event_manager;
+}
+
+/**************************************************************************
+ * Get duration of media object (in ms)
+ **************************************************************************/
+int64_t
+libvlc_media_get_duration( libvlc_media_t * p_md )
+{
+    assert( p_md );
+
+    if( !p_md->p_input_item )
+    {
+        libvlc_printerr( "No input item" );
+        return -1;
+    }
+
+    if (!input_item_IsPreparsed( p_md->p_input_item ))
+        return -1;
+
+    return from_mtime(input_item_GetDuration( p_md->p_input_item ));
+}
+
+static int media_parse(libvlc_media_t *media)
+{
+    /* TODO: fetcher and parser independent of playlist */
+    playlist_t *playlist =
+        libvlc_priv (media->p_libvlc_instance->p_libvlc_int)->p_playlist;
+
+    /* TODO: Fetch art on need basis. But how not to break compatibility? */
+    playlist_AskForArtEnqueue(playlist, media->p_input_item );
+    return playlist_PreparseEnqueue(playlist, media->p_input_item);
+}
+
+/**************************************************************************
+ * Parse the media and wait.
+ **************************************************************************/
+void
+libvlc_media_parse(libvlc_media_t *media)
+{
+    vlc_mutex_lock(&media->parsed_lock);
+    if (!media->has_asked_preparse)
+    {
+        media->has_asked_preparse = true;
+        vlc_mutex_unlock(&media->parsed_lock);
+
+        if (media_parse(media))
+            /* Parse failed: do not wait! */
+            return;
+        vlc_mutex_lock(&media->parsed_lock);
+    }
+
+    while (!media->is_parsed)
+        vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
+    vlc_mutex_unlock(&media->parsed_lock);
+}
+
+/**************************************************************************
+ * Parse the media but do not wait.
+ **************************************************************************/
+void
+libvlc_media_parse_async(libvlc_media_t *media)
+{
+    bool needed;
+
+    vlc_mutex_lock(&media->parsed_lock);
+    needed = !media->has_asked_preparse;
+    media->has_asked_preparse = true;
+    vlc_mutex_unlock(&media->parsed_lock);
+
+    if (needed)
+        media_parse(media);
+}
+
+/**************************************************************************
+ * Get parsed status for media object.
+ **************************************************************************/
+int
+libvlc_media_is_parsed(libvlc_media_t *media)
+{
+    bool parsed;
+
+    vlc_mutex_lock(&media->parsed_lock);
+    parsed = media->is_parsed;
+    vlc_mutex_unlock(&media->parsed_lock);
+    return parsed;
+}
+
+/**************************************************************************
+ * Sets media descriptor's user_data. user_data is specialized data
+ * accessed by the host application, VLC.framework uses it as a pointer to
+ * an native object that references a libvlc_media_t pointer
+ **************************************************************************/
+void
+libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
+{
+    assert( p_md );
+    p_md->p_user_data = p_new_user_data;
+}
+
+/**************************************************************************
+ * Get media descriptor's user_data. user_data is specialized data
+ * accessed by the host application, VLC.framework uses it as a pointer to
+ * an native object that references a libvlc_media_t pointer
+ **************************************************************************/
+void *
+libvlc_media_get_user_data( libvlc_media_t * p_md )
+{
+    assert( p_md );
+    return p_md->p_user_data;
+}
+
+/**************************************************************************
+ * Get media descriptor's elementary streams description
+ **************************************************************************/
+int
+libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
+{
+    assert( p_md );
+
+    input_item_t *p_input_item = p_md->p_input_item;
+    vlc_mutex_lock( &p_input_item->lock );
+
+    const int i_es = p_input_item->i_es;
+    *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
+
+    if( !*pp_es ) /* no ES, or OOM */
+    {
+        vlc_mutex_unlock( &p_input_item->lock );
+        return 0;
+    }
+
+    /* Fill array */
+    for( int i = 0; i < i_es; i++ )
+    {
+        libvlc_media_track_info_t *p_mes = *pp_es+i;
+        const es_format_t *p_es = p_input_item->es[i];
+
+        p_mes->i_codec = p_es->i_codec;
+        p_mes->i_id = p_es->i_id;
+
+        p_mes->i_profile = p_es->i_profile;
+        p_mes->i_level = p_es->i_level;
+
+        switch(p_es->i_cat)
+        {
+        case UNKNOWN_ES:
+        default:
+            p_mes->i_type = libvlc_track_unknown;
+            break;
+        case VIDEO_ES:
+            p_mes->i_type = libvlc_track_video;
+            p_mes->u.video.i_height = p_es->video.i_height;
+            p_mes->u.video.i_width = p_es->video.i_width;
+            break;
+        case AUDIO_ES:
+            p_mes->i_type = libvlc_track_audio;
+            p_mes->u.audio.i_channels = p_es->audio.i_channels;
+            p_mes->u.audio.i_rate = p_es->audio.i_rate;
+            break;
+        case SPU_ES:
+            p_mes->i_type = libvlc_track_text;
+            break;
+        }
+    }
+
+    vlc_mutex_unlock( &p_input_item->lock );
+    return i_es;
+}
diff --git a/lib/media_discoverer.c b/lib/media_discoverer.c
new file mode 100644 (file)
index 0000000..c4163b3
--- /dev/null
@@ -0,0 +1,325 @@
+/*****************************************************************************
+ * media_discoverer.c: libvlc new API media discoverer functions
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_list.h>
+#include <vlc/libvlc_media_discoverer.h>
+#include <vlc/libvlc_events.h>
+
+#include <vlc_services_discovery.h>
+
+#include "libvlc_internal.h"
+#include "media_internal.h" // libvlc_media_new_from_input_item()
+#include "media_list_internal.h" // _libvlc_media_list_add_media()
+
+struct libvlc_media_discoverer_t
+{
+    libvlc_event_manager_t * p_event_manager;
+    libvlc_instance_t *      p_libvlc_instance;
+    services_discovery_t *   p_sd;
+    libvlc_media_list_t *    p_mlist;
+    bool                     running;
+    vlc_dictionary_t         catname_to_submedialist;
+};
+
+/*
+ * Private functions
+ */
+
+/**************************************************************************
+ *       services_discovery_item_added (Private) (VLC event callback)
+ **************************************************************************/
+
+static void services_discovery_item_added( const vlc_event_t * p_event,
+                                           void * user_data )
+{
+    input_item_t * p_item = p_event->u.services_discovery_item_added.p_new_item;
+    const char * psz_cat = p_event->u.services_discovery_item_added.psz_category;
+    libvlc_media_t * p_md;
+    libvlc_media_discoverer_t * p_mdis = user_data;
+    libvlc_media_list_t * p_mlist = p_mdis->p_mlist;
+
+    p_md = libvlc_media_new_from_input_item( p_mdis->p_libvlc_instance,
+                                             p_item );
+
+    /* If we have a category, that mean we have to group the items having
+     * that category in a media_list. */
+    if( psz_cat )
+    {
+        p_mlist = vlc_dictionary_value_for_key( &p_mdis->catname_to_submedialist, psz_cat );
+
+        if( p_mlist == kVLCDictionaryNotFound )
+        {
+            libvlc_media_t * p_catmd;
+            p_catmd = libvlc_media_new_as_node( p_mdis->p_libvlc_instance, psz_cat );
+            p_mlist = libvlc_media_subitems( p_catmd );
+            p_mlist->b_read_only = true;
+
+            /* Insert the newly created mlist in our dictionary */
+            vlc_dictionary_insert( &p_mdis->catname_to_submedialist, psz_cat, p_mlist );
+
+            /* Insert the md into the root list */
+            libvlc_media_list_lock( p_mdis->p_mlist );
+            _libvlc_media_list_add_media( p_mdis->p_mlist, p_catmd );
+            libvlc_media_list_unlock( p_mdis->p_mlist );
+
+            /* We don't release the mlist cause the dictionary
+             * doesn't retain the object. But we release the md. */
+            libvlc_media_release( p_catmd );
+        }
+    }
+
+    libvlc_media_list_lock( p_mlist );
+    _libvlc_media_list_add_media( p_mlist, p_md );
+    libvlc_media_list_unlock( p_mlist );
+
+    libvlc_media_release( p_md );
+}
+
+/**************************************************************************
+ *       services_discovery_item_removed (Private) (VLC event callback)
+ **************************************************************************/
+
+static void services_discovery_item_removed( const vlc_event_t * p_event,
+                                             void * user_data )
+{
+    input_item_t * p_item = p_event->u.services_discovery_item_added.p_new_item;
+    libvlc_media_t * p_md;
+    libvlc_media_discoverer_t * p_mdis = user_data;
+
+    int i, count = libvlc_media_list_count( p_mdis->p_mlist );
+    libvlc_media_list_lock( p_mdis->p_mlist );
+    for( i = 0; i < count; i++ )
+    {
+        p_md = libvlc_media_list_item_at_index( p_mdis->p_mlist, i );
+        if( p_md->p_input_item == p_item )
+        {
+            _libvlc_media_list_remove_index( p_mdis->p_mlist, i );
+            break;
+        }
+    }
+    libvlc_media_list_unlock( p_mdis->p_mlist );
+}
+
+/**************************************************************************
+ *       services_discovery_started (Private) (VLC event callback)
+ **************************************************************************/
+
+static void services_discovery_started( const vlc_event_t * p_event,
+                                        void * user_data )
+{
+    VLC_UNUSED(p_event);
+    libvlc_media_discoverer_t * p_mdis = user_data;
+    libvlc_event_t event;
+    p_mdis->running = true;
+    event.type = libvlc_MediaDiscovererStarted;
+    libvlc_event_send( p_mdis->p_event_manager, &event );
+}
+
+/**************************************************************************
+ *       services_discovery_ended (Private) (VLC event callback)
+ **************************************************************************/
+
+static void services_discovery_ended( const vlc_event_t * p_event,
+                                      void * user_data )
+{
+    VLC_UNUSED(p_event);
+    libvlc_media_discoverer_t * p_mdis = user_data;
+    libvlc_event_t event;
+    p_mdis->running = false;
+    event.type = libvlc_MediaDiscovererEnded;
+    libvlc_event_send( p_mdis->p_event_manager, &event );
+}
+
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *       new (Public)
+ *
+ * Init an object.
+ **************************************************************************/
+libvlc_media_discoverer_t *
+libvlc_media_discoverer_new_from_name( libvlc_instance_t * p_inst,
+                                       const char * psz_name )
+{
+    libvlc_media_discoverer_t * p_mdis;
+
+    p_mdis = malloc(sizeof(libvlc_media_discoverer_t));
+    if( unlikely(!p_mdis) )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_mdis->p_libvlc_instance = p_inst;
+    p_mdis->p_mlist = libvlc_media_list_new( p_inst );
+    p_mdis->p_mlist->b_read_only = true;
+    p_mdis->running = false;
+
+    vlc_dictionary_init( &p_mdis->catname_to_submedialist, 0 );
+
+    p_mdis->p_event_manager = libvlc_event_manager_new( p_mdis, p_inst );
+    if( unlikely(p_mdis->p_event_manager == NULL) )
+    {
+        free( p_mdis );
+        return NULL;
+    }
+
+    libvlc_event_manager_register_event_type( p_mdis->p_event_manager,
+            libvlc_MediaDiscovererStarted );
+    libvlc_event_manager_register_event_type( p_mdis->p_event_manager,
+            libvlc_MediaDiscovererEnded );
+
+    p_mdis->p_sd = vlc_sd_Create( (vlc_object_t*)p_inst->p_libvlc_int,
+                                  psz_name );
+    if( unlikely(p_mdis->p_sd == NULL) )
+    {
+        libvlc_printerr( "%s: no such discovery module found", psz_name );
+        libvlc_media_list_release( p_mdis->p_mlist );
+        libvlc_event_manager_release( p_mdis->p_event_manager );
+        free( p_mdis );
+        return NULL;
+    }
+
+    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
+                      vlc_ServicesDiscoveryItemAdded,
+                      services_discovery_item_added,
+                      p_mdis );
+    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
+                      vlc_ServicesDiscoveryItemRemoved,
+                      services_discovery_item_removed,
+                      p_mdis );
+    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
+                      vlc_ServicesDiscoveryStarted,
+                      services_discovery_started,
+                      p_mdis );
+    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
+                      vlc_ServicesDiscoveryEnded,
+                      services_discovery_ended,
+                      p_mdis );
+
+    /* Here we go */
+    if( !vlc_sd_Start( p_mdis->p_sd ) )
+    {
+        libvlc_printerr( "%s: internal module error",
+                         p_mdis->p_sd->psz_name );
+        libvlc_media_list_release( p_mdis->p_mlist );
+        libvlc_event_manager_release( p_mdis->p_event_manager );
+        free( p_mdis );
+        return NULL;
+    }
+
+    return p_mdis;
+}
+
+/**************************************************************************
+ * release (Public)
+ **************************************************************************/
+void
+libvlc_media_discoverer_release( libvlc_media_discoverer_t * p_mdis )
+{
+    int i;
+
+    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
+                     vlc_ServicesDiscoveryItemAdded,
+                     services_discovery_item_added,
+                     p_mdis );
+    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
+                     vlc_ServicesDiscoveryItemRemoved,
+                     services_discovery_item_removed,
+                     p_mdis );
+    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
+                     vlc_ServicesDiscoveryStarted,
+                     services_discovery_started,
+                     p_mdis );
+    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
+                     vlc_ServicesDiscoveryEnded,
+                     services_discovery_ended,
+                     p_mdis );
+
+    libvlc_media_list_release( p_mdis->p_mlist );
+
+    vlc_sd_StopAndDestroy( p_mdis->p_sd );
+
+    /* Free catname_to_submedialist and all the mlist */
+    char ** all_keys = vlc_dictionary_all_keys( &p_mdis->catname_to_submedialist );
+    for( i = 0; all_keys[i]; i++ )
+    {
+        libvlc_media_list_t * p_catmlist = vlc_dictionary_value_for_key( &p_mdis->catname_to_submedialist, all_keys[i] );
+        libvlc_media_list_release( p_catmlist );
+        free( all_keys[i] );
+    }
+    free( all_keys );
+
+    vlc_dictionary_clear( &p_mdis->catname_to_submedialist, NULL, NULL );
+    libvlc_event_manager_release( p_mdis->p_event_manager );
+
+    free( p_mdis );
+}
+
+/**************************************************************************
+ * localized_name (Public)
+ **************************************************************************/
+char *
+libvlc_media_discoverer_localized_name( libvlc_media_discoverer_t * p_mdis )
+{
+    return services_discovery_GetLocalizedName( p_mdis->p_sd );
+}
+
+/**************************************************************************
+ * media_list (Public)
+ **************************************************************************/
+libvlc_media_list_t *
+libvlc_media_discoverer_media_list( libvlc_media_discoverer_t * p_mdis )
+{
+    libvlc_media_list_retain( p_mdis->p_mlist );
+    return p_mdis->p_mlist;
+}
+
+/**************************************************************************
+ * event_manager (Public)
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_media_discoverer_event_manager( libvlc_media_discoverer_t * p_mdis )
+{
+    return p_mdis->p_event_manager;
+}
+
+
+/**************************************************************************
+ * running (Public)
+ **************************************************************************/
+int
+libvlc_media_discoverer_is_running( libvlc_media_discoverer_t * p_mdis )
+{
+    return p_mdis->running;
+}
diff --git a/lib/media_internal.h b/lib/media_internal.h
new file mode 100644 (file)
index 0000000..c74c7d0
--- /dev/null
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * libvlc_internal.h : Definition of opaque structures for libvlc exported API
+ * Also contains some internal utility functions
+ *****************************************************************************
+ * Copyright (C) 2005-2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBVLC_MEDIA_INTERNAL_H
+#define _LIBVLC_MEDIA_INTERNAL_H 1
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+
+#include <vlc_common.h>
+#include <vlc_input.h>
+
+struct libvlc_media_t
+{
+    libvlc_event_manager_t * p_event_manager;
+    input_item_t      *p_input_item;
+    int                i_refcount;
+    libvlc_instance_t *p_libvlc_instance;
+    libvlc_state_t     state;
+    VLC_FORWARD_DECLARE_OBJECT(libvlc_media_list_t*) p_subitems; /* A media descriptor can have Sub items. This is the only dependancy we really have on media_list */
+    void *p_user_data;
+
+    vlc_cond_t parsed_cond;
+    vlc_mutex_t parsed_lock;
+
+    bool is_parsed;
+    bool has_asked_preparse;
+};
+
+/* Media Descriptor */
+libvlc_media_t * libvlc_media_new_from_input_item(
+        libvlc_instance_t *, input_item_t * );
+
+void libvlc_media_set_state( libvlc_media_t *, libvlc_state_t );
+
+#endif
diff --git a/lib/media_library.c b/lib/media_library.c
new file mode 100644 (file)
index 0000000..e23bbf6
--- /dev/null
@@ -0,0 +1,149 @@
+/*****************************************************************************
+ * tree.c: libvlc tags tree functions
+ * Create a tree of the 'tags' of a media_list's medias.
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_list.h>
+#include <vlc/libvlc_media_library.h>
+#include <vlc/libvlc_events.h>
+
+#include <vlc_common.h>
+
+#include "libvlc_internal.h"
+
+struct libvlc_media_library_t
+{
+    libvlc_event_manager_t * p_event_manager;
+    libvlc_instance_t *      p_libvlc_instance;
+    int                      i_refcount;
+    libvlc_media_list_t *    p_mlist;
+};
+
+
+/*
+ * Private functions
+ */
+
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *       new (Public)
+ **************************************************************************/
+libvlc_media_library_t *
+libvlc_media_library_new( libvlc_instance_t * p_inst )
+{
+    libvlc_media_library_t * p_mlib;
+
+    p_mlib = malloc(sizeof(libvlc_media_library_t));
+
+    if( !p_mlib )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_mlib->p_libvlc_instance = p_inst;
+    p_mlib->i_refcount = 1;
+    p_mlib->p_mlist = NULL;
+
+    p_mlib->p_event_manager = libvlc_event_manager_new( p_mlib, p_inst );
+    if( unlikely(p_mlib->p_event_manager == NULL) )
+    {
+        free(p_mlib);
+        return NULL;
+    }
+
+    return p_mlib;
+}
+
+/**************************************************************************
+ *       release (Public)
+ **************************************************************************/
+void libvlc_media_library_release( libvlc_media_library_t * p_mlib )
+{
+    p_mlib->i_refcount--;
+
+    if( p_mlib->i_refcount > 0 )
+        return;
+
+    libvlc_event_manager_release( p_mlib->p_event_manager );
+    free( p_mlib );
+}
+
+/**************************************************************************
+ *       retain (Public)
+ **************************************************************************/
+void libvlc_media_library_retain( libvlc_media_library_t * p_mlib )
+{
+    p_mlib->i_refcount++;
+}
+
+/**************************************************************************
+ *       load (Public)
+ *
+ * It doesn't yet load the playlists
+ **************************************************************************/
+int libvlc_media_library_load( libvlc_media_library_t * p_mlib )
+{
+    char *psz_datadir = config_GetUserDir( VLC_DATA_DIR );
+    char * psz_uri;
+
+    if( psz_datadir == NULL
+     || asprintf( &psz_uri, "file/xspf-open://%s" DIR_SEP "ml.xsp",
+                  psz_datadir ) == -1 )
+        psz_uri = NULL;
+    free( psz_datadir );
+
+    if( psz_uri == NULL )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return -1;
+    }
+
+    if( p_mlib->p_mlist )
+        libvlc_media_list_release( p_mlib->p_mlist );
+
+    p_mlib->p_mlist = libvlc_media_list_new( p_mlib->p_libvlc_instance );
+
+    int ret = libvlc_media_list_add_file_content( p_mlib->p_mlist, psz_uri );
+    free( psz_uri );
+    return ret;
+}
+
+/**************************************************************************
+ *        media_list (Public)
+ **************************************************************************/
+libvlc_media_list_t *
+libvlc_media_library_media_list( libvlc_media_library_t * p_mlib )
+{
+    if( p_mlib->p_mlist )
+        libvlc_media_list_retain( p_mlib->p_mlist );
+    return p_mlib->p_mlist;
+}
diff --git a/lib/media_list.c b/lib/media_list.c
new file mode 100644 (file)
index 0000000..0691a2c
--- /dev/null
@@ -0,0 +1,503 @@
+/*****************************************************************************
+ * media_list.c: libvlc new API media list functions
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_list.h>
+#include <vlc/libvlc_events.h>
+
+#include <vlc_common.h>
+#include <vlc_input.h>
+
+#include "libvlc_internal.h"
+#include "media_internal.h" // libvlc_media_new_from_input_item()
+#include "media_list_internal.h"
+
+typedef enum EventPlaceInTime {
+    EventWillHappen,
+    EventDidHappen
+} EventPlaceInTime;
+
+//#define DEBUG_MEDIA_LIST
+
+#ifdef DEBUG_MEDIA_LIST
+# define trace( fmt, ... ) printf( "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
+#else
+# define trace( ... )
+#endif
+
+/*
+ * Private functions
+ */
+
+
+
+/**************************************************************************
+ *       notify_item_addition (private)
+ *
+ * Do the appropriate action when an item is deleted.
+ **************************************************************************/
+static void
+notify_item_addition( libvlc_media_list_t * p_mlist,
+                      libvlc_media_t * p_md,
+                      int index,
+                      EventPlaceInTime event_status )
+{
+    libvlc_event_t event;
+
+    /* Construct the event */
+    if( event_status == EventDidHappen )
+    {
+        trace("item was added at index %d\n", index);
+        event.type = libvlc_MediaListItemAdded;
+        event.u.media_list_item_added.item = p_md;
+        event.u.media_list_item_added.index = index;
+    }
+    else /* if( event_status == EventWillHappen ) */
+    {
+        event.type = libvlc_MediaListWillAddItem;
+        event.u.media_list_will_add_item.item = p_md;
+        event.u.media_list_will_add_item.index = index;
+    }
+
+    /* Send the event */
+    libvlc_event_send( p_mlist->p_event_manager, &event );
+}
+
+/**************************************************************************
+ *       notify_item_deletion (private)
+ *
+ * Do the appropriate action when an item is added.
+ **************************************************************************/
+static void
+notify_item_deletion( libvlc_media_list_t * p_mlist,
+                      libvlc_media_t * p_md,
+                      int index,
+                      EventPlaceInTime event_status )
+{
+    libvlc_event_t event;
+
+    /* Construct the event */
+    if( event_status == EventDidHappen )
+    {
+        trace("item at index %d was deleted\n", index);
+        event.type = libvlc_MediaListItemDeleted;
+        event.u.media_list_item_deleted.item = p_md;
+        event.u.media_list_item_deleted.index = index;
+    }
+    else /* if( event_status == EventWillHappen ) */
+    {
+        event.type = libvlc_MediaListWillDeleteItem;
+        event.u.media_list_will_delete_item.item = p_md;
+        event.u.media_list_will_delete_item.index = index;
+    }
+
+    /* Send the event */
+    libvlc_event_send( p_mlist->p_event_manager, &event );
+}
+
+/**************************************************************************
+ *       static mlist_is_writable (private)
+ **************************************************************************/
+static inline
+bool mlist_is_writable( libvlc_media_list_t *p_mlist )
+{
+    if( !p_mlist||p_mlist->b_read_only )
+    {
+        /* We are read-only from user side */
+        libvlc_printerr( "Attempt to write a read-only media list" );
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *       libvlc_media_list_new (Public)
+ *
+ * Init an object.
+ **************************************************************************/
+libvlc_media_list_t *
+libvlc_media_list_new( libvlc_instance_t * p_inst )
+{
+    libvlc_media_list_t * p_mlist;
+
+    p_mlist = malloc(sizeof(libvlc_media_list_t));
+    if( unlikely(p_mlist == NULL) )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return NULL;
+    }
+
+    p_mlist->p_libvlc_instance = p_inst;
+    p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist, p_inst );
+    if( unlikely(p_mlist->p_event_manager == NULL) )
+    {
+        free(p_mlist);
+        return NULL;
+    }
+
+    /* Code for that one should be handled in flat_media_list.c */
+    p_mlist->p_flat_mlist = NULL;
+    p_mlist->b_read_only = false;
+
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListItemAdded );
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListWillAddItem );
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListItemDeleted );
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListWillDeleteItem );
+
+    vlc_mutex_init( &p_mlist->object_lock );
+    vlc_mutex_init( &p_mlist->refcount_lock ); // FIXME: spinlock?
+
+    vlc_array_init( &p_mlist->items );
+    assert( p_mlist->items.i_count == 0 );
+    p_mlist->i_refcount = 1;
+    p_mlist->p_md = NULL;
+
+    return p_mlist;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_release (Public)
+ *
+ * Release an object.
+ **************************************************************************/
+void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
+{
+    libvlc_media_t * p_md;
+    int i;
+
+    vlc_mutex_lock( &p_mlist->refcount_lock );
+    p_mlist->i_refcount--;
+    if( p_mlist->i_refcount > 0 )
+    {
+        vlc_mutex_unlock( &p_mlist->refcount_lock );
+        return;
+    }
+    vlc_mutex_unlock( &p_mlist->refcount_lock );
+
+    /* Refcount null, time to free */
+
+    libvlc_event_manager_release( p_mlist->p_event_manager );
+
+    libvlc_media_release( p_mlist->p_md );
+
+    for ( i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
+    {
+        p_md = vlc_array_item_at_index( &p_mlist->items, i );
+        libvlc_media_release( p_md );
+    }
+
+    vlc_mutex_destroy( &p_mlist->object_lock );
+    vlc_array_clear( &p_mlist->items );
+
+    free( p_mlist );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_retain (Public)
+ *
+ * Increase an object refcount.
+ **************************************************************************/
+void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
+{
+    vlc_mutex_lock( &p_mlist->refcount_lock );
+    p_mlist->i_refcount++;
+    vlc_mutex_unlock( &p_mlist->refcount_lock );
+}
+
+
+/**************************************************************************
+ *       add_file_content (Public)
+ **************************************************************************/
+int
+libvlc_media_list_add_file_content( libvlc_media_list_t * p_mlist,
+                                    const char * psz_uri )
+{
+    input_item_t * p_input_item;
+    libvlc_media_t * p_md;
+
+    p_input_item = input_item_NewExt( psz_uri,
+                                         _("Media Library"), 0, NULL, 0, -1 );
+
+    if( !p_input_item )
+    {
+        libvlc_printerr( "Not enough memory" );
+        return -1;
+    }
+
+    p_md = libvlc_media_new_from_input_item( p_mlist->p_libvlc_instance,
+                                             p_input_item );
+    if( !p_md )
+    {
+        vlc_gc_decref( p_input_item );
+        return -1;
+    }
+
+    if( libvlc_media_list_add_media( p_mlist, p_md ) )
+    {
+#warning Missing error handling!
+        /* printerr and leaks */
+        return -1;
+    }
+
+    input_Read( p_mlist->p_libvlc_instance->p_libvlc_int, p_input_item );
+    return 0;
+}
+
+/**************************************************************************
+ *       set_media (Public)
+ **************************************************************************/
+void libvlc_media_list_set_media( libvlc_media_list_t * p_mlist,
+                                  libvlc_media_t * p_md )
+
+{
+    vlc_mutex_lock( &p_mlist->object_lock );
+    libvlc_media_release( p_mlist->p_md );
+    libvlc_media_retain( p_md );
+    p_mlist->p_md = p_md;
+    vlc_mutex_unlock( &p_mlist->object_lock );
+}
+
+/**************************************************************************
+ *       media (Public)
+ *
+ * If this media_list comes is a media's subitems,
+ * This holds the corresponding media.
+ * This md is also seen as the information holder for the media_list.
+ * Indeed a media_list can have meta information through this
+ * media.
+ **************************************************************************/
+libvlc_media_t *
+libvlc_media_list_media( libvlc_media_list_t * p_mlist )
+{
+    libvlc_media_t *p_md;
+
+    vlc_mutex_lock( &p_mlist->object_lock );
+    p_md = p_mlist->p_md;
+    if( p_md )
+        libvlc_media_retain( p_md );
+    vlc_mutex_unlock( &p_mlist->object_lock );
+
+    return p_md;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_count (Public)
+ *
+ * Lock should be held when entering.
+ **************************************************************************/
+int libvlc_media_list_count( libvlc_media_list_t * p_mlist )
+{
+    return vlc_array_count( &p_mlist->items );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_add_media (Public)
+ *
+ * Lock should be held when entering.
+ **************************************************************************/
+int libvlc_media_list_add_media( libvlc_media_list_t * p_mlist,
+                                 libvlc_media_t * p_md )
+{
+    if( !mlist_is_writable(p_mlist) )
+        return -1;
+    _libvlc_media_list_add_media( p_mlist, p_md );
+    return 0;
+}
+
+/* LibVLC internal version */
+void _libvlc_media_list_add_media( libvlc_media_list_t * p_mlist,
+                                   libvlc_media_t * p_md )
+{
+    libvlc_media_retain( p_md );
+
+    notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items ),
+                          EventWillHappen );
+    vlc_array_append( &p_mlist->items, p_md );
+    notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items )-1,
+                          EventDidHappen );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_insert_media (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+int libvlc_media_list_insert_media( libvlc_media_list_t * p_mlist,
+                                    libvlc_media_t * p_md,
+                                    int index )
+{
+    if( !mlist_is_writable(p_mlist) )
+        return -1;
+    _libvlc_media_list_insert_media( p_mlist, p_md, index );
+    return 0;
+}
+
+/* LibVLC internal version */
+void _libvlc_media_list_insert_media(
+                                   libvlc_media_list_t * p_mlist,
+                                   libvlc_media_t * p_md,
+                                   int index )
+{
+    libvlc_media_retain( p_md );
+
+    notify_item_addition( p_mlist, p_md, index, EventWillHappen );
+    vlc_array_insert( &p_mlist->items, p_md, index );
+    notify_item_addition( p_mlist, p_md, index, EventDidHappen );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_remove_index (Public)
+ *
+ * Lock should be held when entering.
+ **************************************************************************/
+int libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
+                                     int index )
+{
+    if( !mlist_is_writable(p_mlist) )
+        return -1;
+    return _libvlc_media_list_remove_index( p_mlist, index );
+}
+
+/* LibVLC internal version */
+int _libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
+                                     int index )
+{
+    libvlc_media_t * p_md;
+
+    if( index < 0 || index >= vlc_array_count( &p_mlist->items ))
+    {
+        libvlc_printerr( "Index out of bounds" );
+        return -1;
+    }
+
+    p_md = vlc_array_item_at_index( &p_mlist->items, index );
+
+    notify_item_deletion( p_mlist, p_md, index, EventWillHappen );
+    vlc_array_remove( &p_mlist->items, index );
+    notify_item_deletion( p_mlist, p_md, index, EventDidHappen );
+
+    libvlc_media_release( p_md );
+    return 0;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_item_at_index (Public)
+ *
+ * Lock should be held when entering.
+ **************************************************************************/
+libvlc_media_t *
+libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
+                                 int index )
+{
+    libvlc_media_t * p_md;
+
+    if( index < 0 || index >= vlc_array_count( &p_mlist->items ))
+    {
+        libvlc_printerr( "Index out of bounds" );
+        return NULL;
+    }
+
+    p_md = vlc_array_item_at_index( &p_mlist->items, index );
+    libvlc_media_retain( p_md );
+    return p_md;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_index_of_item (Public)
+ *
+ * Lock should be held when entering.
+ * Warning: this function returns the first matching item.
+ **************************************************************************/
+int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
+                                     libvlc_media_t * p_searched_md )
+{
+    libvlc_media_t * p_md;
+    int i;
+    for ( i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
+    {
+        p_md = vlc_array_item_at_index( &p_mlist->items, i );
+        if( p_searched_md == p_md )
+            return i;
+    }
+    libvlc_printerr( "Media not found" );
+    return -1;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_is_readonly (Public)
+ *
+ * This indicates if this media list is read-only from a user point of view
+ **************************************************************************/
+int libvlc_media_list_is_readonly( libvlc_media_list_t * p_mlist )
+{
+    return p_mlist->b_read_only;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_lock (Public)
+ *
+ * The lock must be held in access operations. It is never used in the
+ * Public method.
+ **************************************************************************/
+void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
+{
+    vlc_mutex_lock( &p_mlist->object_lock );
+}
+
+
+/**************************************************************************
+ *       libvlc_media_list_unlock (Public)
+ *
+ * The lock must be held in access operations
+ **************************************************************************/
+void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
+{
+    vlc_mutex_unlock( &p_mlist->object_lock );
+}
+
+
+/**************************************************************************
+ *       libvlc_media_list_p_event_manager (Public)
+ *
+ * The p_event_manager is immutable, so you don't have to hold the lock
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist )
+{
+    return p_mlist->p_event_manager;
+}
diff --git a/lib/media_list_internal.h b/lib/media_list_internal.h
new file mode 100644 (file)
index 0000000..72e1e7e
--- /dev/null
@@ -0,0 +1,70 @@
+/*****************************************************************************
+ * libvlc_internal.h : Definition of opaque structures for libvlc exported API
+ * Also contains some internal utility functions
+ *****************************************************************************
+ * Copyright (C) 2005-2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBVLC_MEDIA_LIST_INTERNAL_H
+#define _LIBVLC_MEDIA_LIST_INTERNAL_H 1
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/vlc.h>
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc_media.h>
+
+#include <vlc_common.h>
+
+struct libvlc_media_list_t
+{
+    libvlc_event_manager_t *    p_event_manager;
+    libvlc_instance_t *         p_libvlc_instance;
+    int                         i_refcount;
+    vlc_mutex_t                 object_lock;
+    vlc_mutex_t                 refcount_lock;
+    libvlc_media_t * p_md; /* The media from which the
+                                       * mlist comes, if any. */
+    vlc_array_t                items;
+
+    /* Other way to see that media list */
+    /* Used in flat_media_list.c */
+    libvlc_media_list_t *       p_flat_mlist;
+
+    /* This indicates if this media list is read-only
+     * from a user point of view */
+    bool                  b_read_only;
+};
+
+/* Media List */
+void _libvlc_media_list_add_media(
+        libvlc_media_list_t * p_mlist,
+        libvlc_media_t * p_md );
+
+void _libvlc_media_list_insert_media(
+        libvlc_media_list_t * p_mlist,
+        libvlc_media_t * p_md, int index );
+
+int _libvlc_media_list_remove_index(
+        libvlc_media_list_t * p_mlist, int index );
+
+#endif
diff --git a/lib/media_list_path.h b/lib/media_list_path.h
new file mode 100644 (file)
index 0000000..f356506
--- /dev/null
@@ -0,0 +1,245 @@
+/*****************************************************************************
+ * media_list_path.h : Some inlined function that allows media_list_path
+ * manipulation. This is internal and used only by media_list_player.
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ * $Id $
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBVLC_MEDIA_LIST_PATH_H
+#define _LIBVLC_MEDIA_LIST_PATH_H 1
+
+typedef int * libvlc_media_list_path_t; /* (Media List Player Internal) */
+
+/**************************************************************************
+ *       path_dump (Media List Player Internal)
+ **************************************************************************/
+static inline void libvlc_media_list_path_dump( const libvlc_media_list_path_t path )
+{
+    if(!path)
+    {
+        printf("NULL path\n");
+        return;
+    }
+
+    int i;
+    for(i = 0; path[i] != -1; i++)
+        printf("%s%d", i > 0 ? "/" : "", path[i]);
+    printf("\n");
+}
+
+/**************************************************************************
+ *       path_empty (Media List Player Internal)
+ **************************************************************************/
+static inline libvlc_media_list_path_t libvlc_media_list_path_empty( void )
+{
+    libvlc_media_list_path_t ret = xmalloc(sizeof(int));
+    ret[0] = -1;
+    return ret;
+}
+
+/**************************************************************************
+ *       path_with_root_index (Media List Player Internal)
+ **************************************************************************/
+static inline libvlc_media_list_path_t libvlc_media_list_path_with_root_index( int index )
+{
+    libvlc_media_list_path_t ret = xmalloc(sizeof(int)*2);
+    ret[0] = index;
+    ret[1] = -1;
+    return ret;
+}
+
+/**************************************************************************
+ *       path_depth (Media List Player Internal)
+ **************************************************************************/
+static inline int libvlc_media_list_path_depth( const libvlc_media_list_path_t path )
+{
+    int i;
+    for( i = 0; path[i] != -1; i++ );
+    return i;
+}
+
+/**************************************************************************
+ *       path_append (Media List Player Internal)
+ **************************************************************************/
+static inline void libvlc_media_list_path_append( libvlc_media_list_path_t * p_path, int index )
+{
+    int old_depth = libvlc_media_list_path_depth( *p_path );
+    *p_path = xrealloc( *p_path, sizeof(int)*(old_depth+2));
+    *p_path[old_depth] = index;
+    *p_path[old_depth+1] = -1;
+}
+
+/**************************************************************************
+ *       path_copy_by_appending (Media List Player Internal)
+ **************************************************************************/
+static inline libvlc_media_list_path_t libvlc_media_list_path_copy_by_appending( const libvlc_media_list_path_t path, int index )
+{
+    libvlc_media_list_path_t ret;
+    int old_depth = libvlc_media_list_path_depth( path );
+    ret = xmalloc( sizeof(int) * (old_depth + 2) );
+    memcpy( ret, path, sizeof(int) * old_depth );
+    ret[old_depth] = index;
+    ret[old_depth+1] = -1;
+    return ret;
+}
+
+/**************************************************************************
+ *       path_copy (Media List Player Internal)
+ **************************************************************************/
+static inline libvlc_media_list_path_t libvlc_media_list_path_copy( const libvlc_media_list_path_t path )
+{
+    libvlc_media_list_path_t ret;
+    int depth = libvlc_media_list_path_depth( path );
+    ret = xmalloc( sizeof(int)*(depth+1) );
+    memcpy( ret, path, sizeof(int)*(depth+1) );
+    return ret;
+}
+
+/**************************************************************************
+ *       get_path_rec (Media List Player Internal)
+ **************************************************************************/
+static libvlc_media_list_path_t
+get_path_rec( const libvlc_media_list_path_t path, libvlc_media_list_t * p_current_mlist, libvlc_media_t * p_searched_md )
+{
+    int i, count;
+    count = libvlc_media_list_count( p_current_mlist );
+    for( i = 0; i < count; i++ )
+    {
+        libvlc_media_t * p_md = libvlc_media_list_item_at_index( p_current_mlist, i );
+
+        if( p_md == p_searched_md )
+            return libvlc_media_list_path_copy_by_appending( path, i ); /* Found! */
+
+        libvlc_media_list_t * p_subitems = libvlc_media_subitems( p_md );
+        libvlc_media_release( p_md );
+        if( p_subitems )
+        {
+            libvlc_media_list_path_t new_path = libvlc_media_list_path_copy_by_appending( path, i );
+            libvlc_media_list_lock( p_subitems );
+            libvlc_media_list_path_t ret = get_path_rec( new_path, p_subitems, p_searched_md );
+            libvlc_media_list_unlock( p_subitems );
+            free( new_path );
+            libvlc_media_list_release( p_subitems );
+            if( ret )
+                return ret; /* Found in sublist! */
+        }
+    }
+    return NULL;
+}
+
+/**************************************************************************
+ *       path_of_item (Media List Player Internal)
+ **************************************************************************/
+static inline libvlc_media_list_path_t libvlc_media_list_path_of_item( libvlc_media_list_t * p_mlist, libvlc_media_t * p_md )
+{
+    libvlc_media_list_path_t path = libvlc_media_list_path_empty();
+    libvlc_media_list_path_t ret;
+    ret = get_path_rec( path, p_mlist, p_md );
+    free( path );
+    return ret;
+}
+
+/**************************************************************************
+ *       item_at_path (Media List Player Internal)
+ **************************************************************************/
+static libvlc_media_t *
+libvlc_media_list_item_at_path( libvlc_media_list_t * p_mlist, const libvlc_media_list_path_t path )
+{
+    libvlc_media_list_t * p_current_mlist = p_mlist;
+    libvlc_media_t * p_md = NULL;
+    int i;
+    for( i = 0; path[i] != -1; i++ )
+    {
+        p_md = libvlc_media_list_item_at_index( p_current_mlist, path[i] );
+
+        if( p_current_mlist != p_mlist )
+            libvlc_media_list_release( p_current_mlist );
+
+        if( path[i+1] == -1 )
+            return p_md;
+
+        p_current_mlist = libvlc_media_subitems( p_md );
+        libvlc_media_release( p_md );
+        if( !p_current_mlist )
+            return NULL;
+
+        /* Fetch next one */
+    }
+    /* Not found, shouldn't happen if the p_path is not empty */
+    if( p_current_mlist != p_mlist )
+        libvlc_media_list_release( p_current_mlist );
+    return NULL;
+}
+
+/**************************************************************************
+ *       parentlist_at_path (Media List Player Internal)
+ **************************************************************************/
+static libvlc_media_list_t *
+libvlc_media_list_parentlist_at_path( libvlc_media_list_t * p_mlist, const libvlc_media_list_path_t path )
+{
+    libvlc_media_list_t * p_current_mlist = p_mlist;
+    libvlc_media_t * p_md = NULL;
+    int i;
+    for( i = 0; path[i] != -1; i++ )
+    {
+        if( p_current_mlist != p_mlist )
+            libvlc_media_list_release( p_current_mlist );
+
+        if( path[i+1] == -1 )
+        {
+            libvlc_media_list_retain(p_current_mlist);
+            return p_current_mlist;
+        }
+
+        p_md = libvlc_media_list_item_at_index( p_current_mlist, path[i] );
+
+        p_current_mlist = libvlc_media_subitems( p_md );
+        libvlc_media_release( p_md );
+        if( !p_current_mlist )
+            return NULL;
+
+        /* Fetch next one */
+    }
+    /* Not found, shouldn't happen if the p_path is not empty */
+    if( p_current_mlist != p_mlist )
+        libvlc_media_list_release( p_current_mlist );
+    return NULL;
+}
+
+/**************************************************************************
+ *       sublist_at_path (Media List Player Internal)
+ **************************************************************************/
+static libvlc_media_list_t *
+libvlc_media_list_sublist_at_path( libvlc_media_list_t * p_mlist, const libvlc_media_list_path_t path )
+{
+    libvlc_media_list_t * ret;
+    libvlc_media_t * p_md = libvlc_media_list_item_at_path( p_mlist, path );
+    if( !p_md )
+        return NULL;
+    ret = libvlc_media_subitems( p_md );
+    libvlc_media_release( p_md );
+    return ret;
+}
+
+#endif
diff --git a/lib/media_list_player.c b/lib/media_list_player.c
new file mode 100644 (file)
index 0000000..343866b
--- /dev/null
@@ -0,0 +1,821 @@
+/*****************************************************************************
+ * media_list_player.c: libvlc new API media_list player functions
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_list.h>
+#include <vlc/libvlc_media_player.h>
+#include <vlc/libvlc_media_list_player.h>
+#include <vlc/libvlc_events.h>
+#include <assert.h>
+
+#include "libvlc_internal.h"
+
+#include "media_internal.h" // Abuse, could and should be removed
+#include "media_list_path.h"
+
+//#define DEBUG_MEDIA_LIST_PLAYER
+
+/* This is a very dummy implementation of playlist on top of
+ * media_list and media_player.
+ *
+ * All this code is doing is simply computing the next item
+ * of a tree of media_list (see get_next_index()), and play
+ * the next item when the current is over. This is happening
+ * via the event callback media_player_reached_end().
+ *
+ * This is thread safe, and we use a two keys (locks) scheme
+ * to discriminate between callbacks and regular uses.
+ */
+
+struct libvlc_media_list_player_t
+{
+    libvlc_event_manager_t *    p_event_manager;
+    libvlc_instance_t *         p_libvlc_instance;
+    int                         i_refcount;
+    /* Protect access to this structure. */
+    vlc_mutex_t                 object_lock;
+    /* Protect access to this structure and from callback execution. */
+    vlc_mutex_t                 mp_callback_lock;
+    /* Indicate to media player callbacks that they are cancelled. */
+    bool                        are_mp_callback_cancelled;
+    libvlc_media_list_path_t    current_playing_item_path;
+    libvlc_media_t *            p_current_playing_item;
+    libvlc_media_list_t *       p_mlist;
+    libvlc_media_player_t *     p_mi;
+    libvlc_playback_mode_t      e_playback_mode;
+};
+
+/* This is not yet exported by libvlccore */
+static inline void vlc_assert_locked(vlc_mutex_t *mutex)
+{
+    VLC_UNUSED(mutex);
+}
+
+/*
+ * Forward declaration
+ */
+
+static
+int set_relative_playlist_position_and_play(libvlc_media_list_player_t *p_mlp,
+                                            int i_relative_position);
+static void stop(libvlc_media_list_player_t * p_mlp);
+
+/*
+ * Private functions
+ */
+
+/**************************************************************************
+ * Shortcuts
+ **************************************************************************/
+static inline void lock(libvlc_media_list_player_t * p_mlp)
+{
+    // Obtain an access to this structure
+    vlc_mutex_lock(&p_mlp->object_lock);
+
+    // Make sure no callback will occurs at the same time
+    vlc_mutex_lock(&p_mlp->mp_callback_lock);
+}
+
+static inline void unlock(libvlc_media_list_player_t * p_mlp)
+{
+    vlc_mutex_unlock(&p_mlp->mp_callback_lock);
+    vlc_mutex_unlock(&p_mlp->object_lock);
+}
+
+static inline void assert_locked(libvlc_media_list_player_t * p_mlp)
+{
+    vlc_assert_locked(&p_mlp->mp_callback_lock);
+}
+
+static inline libvlc_event_manager_t * mlist_em(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+    return libvlc_media_list_event_manager(p_mlp->p_mlist);
+}
+
+static inline libvlc_event_manager_t * mplayer_em(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+    return libvlc_media_player_event_manager(p_mlp->p_mi);
+}
+
+/**************************************************************************
+ *       get_next_path (private)
+ *
+ *  Returns the path to the next item in the list.
+ *  If looping is specified and the current item is the last list item in
+ *  the list it will return the first item in the list.
+ **************************************************************************/
+static libvlc_media_list_path_t
+get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
+{
+    assert_locked(p_mlp);
+
+    /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
+    libvlc_media_list_path_t ret;
+    libvlc_media_list_t * p_parent_of_playing_item;
+    libvlc_media_list_t * p_sublist_of_playing_item;
+
+    if (!p_mlp->current_playing_item_path)
+    {
+        if (!libvlc_media_list_count(p_mlp->p_mlist))
+            return NULL;
+        return libvlc_media_list_path_with_root_index(0);
+    }
+
+    p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
+                            p_mlp->p_mlist,
+                            p_mlp->current_playing_item_path);
+
+    /* If item just gained a sublist just play it */
+    if (p_sublist_of_playing_item)
+    {
+        libvlc_media_list_release(p_sublist_of_playing_item);
+        return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
+    }
+
+    /* Try to catch parent element */
+    p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
+                            p_mlp->current_playing_item_path);
+
+    int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
+    if (depth < 1 || !p_parent_of_playing_item)
+        return NULL;
+
+    ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
+    ret[depth - 1]++; /* set to next element */
+
+    /* If this goes beyond the end of the list */
+    while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
+    {
+        depth--;
+        if (depth <= 0)
+        {
+            if(b_loop)
+            {
+                ret[0] = 0;
+                ret[1] = -1;
+                break;
+            }
+            else
+            {
+                free(ret);
+                libvlc_media_list_release(p_parent_of_playing_item);
+                return NULL;
+            }
+        }
+        ret[depth] = -1;
+        ret[depth-1]++;
+        p_parent_of_playing_item  = libvlc_media_list_parentlist_at_path(
+                                        p_mlp->p_mlist,
+                                        ret);
+    }
+
+    libvlc_media_list_release(p_parent_of_playing_item);
+    return ret;
+}
+
+/**************************************************************************
+ *       find_last_item (private)
+ *
+ *  Returns the path of the last descendant of a given item path.
+ *  Note: Due to the recursive nature of the function and the need to free
+ *        media list paths, paths passed in may be freed if they are replaced.
+          Recommended usage is to set return value to the same path that was
+          passed to the function (i.e. item = find_last_item(list, item); )
+ **************************************************************************/
+static libvlc_media_list_path_t
+find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
+{
+    libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
+    libvlc_media_list_path_t last_item_path = current_item;
+
+    if(p_sublist)
+    {
+        int i_count = libvlc_media_list_count(p_sublist);
+        if(i_count > 0)
+        {
+            /* Add the last sublist item to the path. */
+            last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
+            free(current_item);
+            /* Check that sublist item for more descendants. */
+            last_item_path = find_last_item(p_mlist, last_item_path);
+        }
+
+        libvlc_media_list_release(p_sublist);
+    }
+
+    return last_item_path;
+}
+
+/**************************************************************************
+ *       get_previous_path (private)
+ *
+ *  Returns the path to the preceding item in the list.
+ *  If looping is specified and the current item is the first list item in
+ *  the list it will return the last descendant of the last item in the list.
+ **************************************************************************/
+static libvlc_media_list_path_t
+get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
+{
+    assert_locked(p_mlp);
+
+    /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
+    libvlc_media_list_path_t ret;
+    libvlc_media_list_t * p_parent_of_playing_item;
+
+    if (!p_mlp->current_playing_item_path)
+    {
+        if (!libvlc_media_list_count(p_mlp->p_mlist))
+            return NULL;
+        return libvlc_media_list_path_with_root_index(0);
+    }
+
+    /* Try to catch parent element */
+    p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
+                                            p_mlp->p_mlist,
+                                            p_mlp->current_playing_item_path);
+
+    int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
+    if (depth < 1 || !p_parent_of_playing_item)
+        return NULL;
+
+    /* Set the return path to the current path */
+    ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
+
+    /* Change the return path to the previous list entry */
+    ret[depth - 1]--; /* set to previous element */
+    ret[depth] = -1;
+
+    /* Is the return path is beyond the start of the current list? */
+    if(ret[depth - 1] < 0)
+    {
+        /* Move to parent of current item */
+        depth--;
+
+        /* Are we at the root level of the tree? */
+        if (depth <= 0)
+        {
+            // Is looping enabled?
+            if(b_loop)
+            {
+                int i_count = libvlc_media_list_count(p_parent_of_playing_item);
+
+                /* Set current play item to the last element in the list */
+                ret[0] = i_count - 1;
+                ret[1] = -1;
+
+                /* Set the return path to the last descendant item of the current item */
+                ret = find_last_item(p_mlp->p_mlist, ret);
+            }
+            else
+            {
+                /* No looping so return empty path. */
+                free(ret);
+                ret = NULL;
+            }
+        }
+        else
+        {
+            /* This is the case of moving backward from the beginning of the
+            *  subitem list to its parent item.
+            *  This ensures that current path is properly terminated to
+            *  use that parent.
+            */
+            ret[depth] = -1;
+        }
+    }
+    else
+    {
+        ret = find_last_item(p_mlp->p_mlist, ret);
+    }
+
+    libvlc_media_list_release(p_parent_of_playing_item);
+    return ret;
+}
+
+/**************************************************************************
+ *       media_player_reached_end (private) (Event Callback)
+ **************************************************************************/
+static void
+media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
+{
+    VLC_UNUSED(p_event);
+    libvlc_media_list_player_t * p_mlp = p_user_data;
+
+    vlc_mutex_lock(&p_mlp->mp_callback_lock);
+    if (!p_mlp->are_mp_callback_cancelled)
+        set_relative_playlist_position_and_play(p_mlp, 1);
+    vlc_mutex_unlock(&p_mlp->mp_callback_lock);
+}
+
+/**************************************************************************
+ *       playlist_item_deleted (private) (Event Callback)
+ **************************************************************************/
+static void
+mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
+{
+    // Nothing to do. For now.
+    (void)p_event; (void)p_user_data;
+}
+
+
+/**************************************************************************
+ * install_playlist_observer (private)
+ **************************************************************************/
+static void
+install_playlist_observer(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+    libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
+}
+
+/**************************************************************************
+ * uninstall_playlist_observer (private)
+ **************************************************************************/
+static void
+uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+    if (!p_mlp->p_mlist) return;
+    libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
+}
+
+/**************************************************************************
+ * install_media_player_observer (private)
+ **************************************************************************/
+static void
+install_media_player_observer(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+    libvlc_event_attach_async(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
+}
+
+
+/**************************************************************************
+ *       uninstall_media_player_observer (private)
+ **************************************************************************/
+static void
+uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+    if (!p_mlp->p_mi) return;
+
+    // From now on, media_player callback won't be relevant.
+    p_mlp->are_mp_callback_cancelled = true;
+
+    // Allow callbacks to run, because detach() will wait until all callbacks are processed.
+    // This is safe because only callbacks are allowed, and there execution will be cancelled.
+    vlc_mutex_unlock(&p_mlp->mp_callback_lock);
+    libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
+
+    // Now, lock back the callback lock. No more callback will be present from this point.
+    vlc_mutex_lock(&p_mlp->mp_callback_lock);
+    p_mlp->are_mp_callback_cancelled = false;
+
+    // What is here is safe, because we guarantee that we won't be able to anything concurrently,
+    // - except (cancelled) callbacks - thanks to the object_lock.
+}
+
+/**************************************************************************
+ *       set_current_playing_item (private)
+ *
+ * Playlist lock should be held
+ **************************************************************************/
+static void
+set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
+{
+    assert_locked(p_mlp);
+
+    /* First, save the new path that we are going to play */
+    if (p_mlp->current_playing_item_path != path)
+    {
+        free(p_mlp->current_playing_item_path);
+        p_mlp->current_playing_item_path = path;
+    }
+
+    if (!path)
+        return;
+
+    libvlc_media_t * p_md;
+    p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
+    if (!p_md)
+        return;
+
+    /* Make sure media_player_reached_end() won't get called */
+    uninstall_media_player_observer(p_mlp);
+
+    /* Create a new media_player if there is none */
+    if (!p_mlp->p_mi)
+        p_mlp->p_mi = libvlc_media_player_new_from_media(p_md);
+
+    libvlc_media_player_set_media(p_mlp->p_mi, p_md);
+
+    install_media_player_observer(p_mlp);
+    libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
+}
+
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *         new (Public)
+ **************************************************************************/
+libvlc_media_list_player_t *
+libvlc_media_list_player_new(libvlc_instance_t * p_instance)
+{
+    libvlc_media_list_player_t * p_mlp;
+    p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
+    if (unlikely(p_mlp == NULL))
+    {
+        libvlc_printerr("Not enough memory");
+        return NULL;
+    }
+
+    p_mlp->p_event_manager = libvlc_event_manager_new(p_mlp, p_instance);
+    if (unlikely(p_mlp->p_event_manager == NULL))
+    {
+        free (p_mlp);
+        return NULL;
+    }
+
+    libvlc_retain(p_instance);
+    p_mlp->p_libvlc_instance = p_instance;
+    p_mlp->i_refcount = 1;
+    vlc_mutex_init(&p_mlp->object_lock);
+    vlc_mutex_init(&p_mlp->mp_callback_lock);
+    libvlc_event_manager_register_event_type(p_mlp->p_event_manager, libvlc_MediaListPlayerNextItemSet);
+    p_mlp->e_playback_mode = libvlc_playback_mode_default;
+
+    return p_mlp;
+}
+
+/**************************************************************************
+ *         release (Public)
+ **************************************************************************/
+void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
+{
+    if (!p_mlp)
+        return;
+
+    lock(p_mlp);
+    p_mlp->i_refcount--;
+    if (p_mlp->i_refcount > 0)
+    {
+        unlock(p_mlp);
+        return;
+    }
+
+    assert(p_mlp->i_refcount == 0);
+
+    /* Keep the lock(), because the uninstall functions
+     * check for it. That's convenient. */
+
+    if (p_mlp->p_mi)
+    {
+        uninstall_media_player_observer(p_mlp);
+        libvlc_media_player_release(p_mlp->p_mi);
+    }
+    if (p_mlp->p_mlist)
+    {
+        uninstall_playlist_observer(p_mlp);
+        libvlc_media_list_release(p_mlp->p_mlist);
+    }
+
+    unlock(p_mlp);
+    vlc_mutex_destroy(&p_mlp->object_lock);
+    vlc_mutex_destroy(&p_mlp->mp_callback_lock);
+
+    libvlc_event_manager_release(p_mlp->p_event_manager);
+
+    free(p_mlp->current_playing_item_path);
+    libvlc_release(p_mlp->p_libvlc_instance);
+    free(p_mlp);
+}
+
+/**************************************************************************
+ *        retain (Public)
+ **************************************************************************/
+void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
+{
+    if (!p_mlp)
+        return;
+
+    lock(p_mlp);
+    p_mlp->i_refcount++;
+    unlock(p_mlp);
+}
+
+/**************************************************************************
+ *        event_manager (Public)
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
+{
+    return p_mlp->p_event_manager;
+}
+
+/**************************************************************************
+ *        set_media_player (Public)
+ **************************************************************************/
+void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
+{
+    lock(p_mlp);
+
+    if (p_mlp->p_mi)
+    {
+        uninstall_media_player_observer(p_mlp);
+        libvlc_media_player_release(p_mlp->p_mi);
+    }
+    libvlc_media_player_retain(p_mi);
+    p_mlp->p_mi = p_mi;
+
+    install_media_player_observer(p_mlp);
+
+    unlock(p_mlp);
+}
+
+/**************************************************************************
+ *       set_media_list (Public)
+ **************************************************************************/
+void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
+{
+    assert (p_mlist);
+
+    lock(p_mlp);
+    if (p_mlp->p_mlist)
+    {
+        uninstall_playlist_observer(p_mlp);
+        libvlc_media_list_release(p_mlp->p_mlist);
+    }
+    libvlc_media_list_retain(p_mlist);
+    p_mlp->p_mlist = p_mlist;
+
+    install_playlist_observer(p_mlp);
+
+    unlock(p_mlp);
+}
+
+/**************************************************************************
+ *        Play (Public)
+ **************************************************************************/
+void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
+{
+    lock(p_mlp);
+    if (!p_mlp->current_playing_item_path)
+    {
+        set_relative_playlist_position_and_play(p_mlp, 1);
+        unlock(p_mlp);
+        return; /* Will set to play */
+    }
+    libvlc_media_player_play(p_mlp->p_mi);
+    unlock(p_mlp);
+}
+
+
+/**************************************************************************
+ *        Pause (Public)
+ **************************************************************************/
+void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
+{
+    lock(p_mlp);
+    if (!p_mlp->p_mi)
+    {
+        unlock(p_mlp);
+        return;
+    }
+    libvlc_media_player_pause(p_mlp->p_mi);
+    unlock(p_mlp);
+}
+
+/**************************************************************************
+ *        is_playing (Public)
+ **************************************************************************/
+int
+libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
+{
+    if (!p_mlp->p_mi)
+    {
+        return libvlc_NothingSpecial;
+    }
+    libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
+    return (state == libvlc_Opening) || (state == libvlc_Buffering) ||
+           (state == libvlc_Playing);
+}
+
+/**************************************************************************
+ *        State (Public)
+ **************************************************************************/
+libvlc_state_t
+libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
+{
+    if (!p_mlp->p_mi)
+        return libvlc_Ended;
+    return libvlc_media_player_get_state(p_mlp->p_mi);
+}
+
+/**************************************************************************
+ *        Play item at index (Public)
+ **************************************************************************/
+int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
+{
+    lock(p_mlp);
+    set_current_playing_item(p_mlp, libvlc_media_list_path_with_root_index(i_index));
+    libvlc_media_player_play(p_mlp->p_mi);
+    unlock(p_mlp);
+
+    /* Send the next item event */
+    libvlc_event_t event;
+    event.type = libvlc_MediaListPlayerNextItemSet;
+    libvlc_event_send(p_mlp->p_event_manager, &event);
+    return 0;
+}
+
+/**************************************************************************
+ *        Play item (Public)
+ **************************************************************************/
+int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
+{
+    lock(p_mlp);
+    libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
+    if (!path)
+    {
+        libvlc_printerr("Item not found in media list");
+        unlock(p_mlp);
+        return -1;
+    }
+
+    set_current_playing_item(p_mlp, path);
+    libvlc_media_player_play(p_mlp->p_mi);
+    unlock(p_mlp);
+    return 0;
+}
+
+/**************************************************************************
+ *       Stop (Private)
+ *
+ * Lock must be held.
+ **************************************************************************/
+static void stop(libvlc_media_list_player_t * p_mlp)
+{
+    assert_locked(p_mlp);
+
+    if (p_mlp->p_mi)
+    {
+        /* We are not interested in getting media stop event now */
+        uninstall_media_player_observer(p_mlp);
+        libvlc_media_player_stop(p_mlp->p_mi);
+        install_media_player_observer(p_mlp);
+    }
+
+    free(p_mlp->current_playing_item_path);
+    p_mlp->current_playing_item_path = NULL;
+}
+
+/**************************************************************************
+ *       Stop (Public)
+ **************************************************************************/
+void libvlc_media_list_player_stop(libvlc_media_list_player_t * p_mlp)
+{
+    lock(p_mlp);
+    stop(p_mlp);
+    unlock(p_mlp);
+}
+
+/**************************************************************************
+ *       Set relative playlist position and play (Private)
+ *
+ * Sets the currently played item to the given relative play item position
+ * (based on the currently playing item) and then begins the new item playback.
+ * Lock must be held.
+ **************************************************************************/
+static int set_relative_playlist_position_and_play(
+                                      libvlc_media_list_player_t * p_mlp,
+                                      int i_relative_position)
+{
+    assert_locked(p_mlp);
+
+    if (!p_mlp->p_mlist)
+    {
+        libvlc_printerr("No media list");
+        return -1;
+    }
+
+    libvlc_media_list_lock(p_mlp->p_mlist);
+
+    libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
+
+    if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
+    {
+        bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
+
+        if(i_relative_position > 0)
+        {
+            do
+            {
+                path = get_next_path(p_mlp, b_loop);
+                set_current_playing_item(p_mlp, path);
+                --i_relative_position;
+            }
+            while(i_relative_position > 0);
+        }
+        else if(i_relative_position < 0)
+        {
+            do
+            {
+                path = get_previous_path(p_mlp, b_loop);
+                set_current_playing_item(p_mlp, path);
+                ++i_relative_position;
+            }
+            while (i_relative_position < 0);
+        }
+    }
+    else
+    {
+        set_current_playing_item(p_mlp, path);
+    }
+
+#ifdef DEBUG_MEDIA_LIST_PLAYER
+    printf("Playing:");
+    libvlc_media_list_path_dump(path);
+#endif
+
+    if (!path)
+    {
+        libvlc_media_list_unlock(p_mlp->p_mlist);
+        return -1;
+    }
+
+    libvlc_media_player_play(p_mlp->p_mi);
+
+    libvlc_media_list_unlock(p_mlp->p_mlist);
+
+    /* Send the next item event */
+    libvlc_event_t event;
+    event.type = libvlc_MediaListPlayerNextItemSet;
+    libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
+    event.u.media_list_player_next_item_set.item = p_md;
+    libvlc_event_send(p_mlp->p_event_manager, &event);
+    libvlc_media_release(p_md);
+    return 0;
+}
+
+/**************************************************************************
+ *       Next (Public)
+ **************************************************************************/
+int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
+{
+    lock(p_mlp);
+    int failure = set_relative_playlist_position_and_play(p_mlp, 1);
+    unlock(p_mlp);
+    return failure;
+}
+
+/**************************************************************************
+ *       Previous (Public)
+ **************************************************************************/
+int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
+{
+    lock(p_mlp);
+    int failure = set_relative_playlist_position_and_play(p_mlp, -1);
+    unlock(p_mlp);
+    return failure;
+}
+
+/**************************************************************************
+ *       Set Playback Mode (Public)
+ **************************************************************************/
+void libvlc_media_list_player_set_playback_mode(
+                                            libvlc_media_list_player_t * p_mlp,
+                                            libvlc_playback_mode_t e_mode )
+{
+    lock(p_mlp);
+    p_mlp->e_playback_mode = e_mode;
+    unlock(p_mlp);
+}
diff --git a/lib/media_player.c b/lib/media_player.c
new file mode 100644 (file)
index 0000000..4b40730
--- /dev/null
@@ -0,0 +1,1384 @@
+/*****************************************************************************
+ * media_player.c: Libvlc API Media Instance management functions
+ *****************************************************************************
+ * Copyright (C) 2005-2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_events.h>
+
+#include <vlc_demux.h>
+#include <vlc_input.h>
+#include <vlc_vout.h>
+#include <vlc_keys.h>
+
+#include "libvlc_internal.h"
+#include "media_internal.h" // libvlc_media_set_state()
+#include "media_player_internal.h"
+
+/*
+ * mapping of libvlc_navigate_mode_t to vlc_action_t
+ */
+static const vlc_action_t libvlc_navigate_to_action[] =
+{
+    ACTIONID_NAV_ACTIVATE,
+    ACTIONID_NAV_UP,
+    ACTIONID_NAV_DOWN,
+    ACTIONID_NAV_LEFT,
+    ACTIONID_NAV_RIGHT
+};
+
+static const uint32_t libvlc_navigate_to_action_size =                 \
+  sizeof( libvlc_navigate_to_action ) / sizeof( libvlc_navigate_to_action[0] );
+
+
+static int
+input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
+                        vlc_value_t oldval, vlc_value_t newval,
+                        void * p_userdata );
+static int
+input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
+                        vlc_value_t oldval, vlc_value_t newval,
+                        void * p_userdata );
+static int
+input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
+                     vlc_value_t oldval, vlc_value_t newval,
+                     void * p_userdata );
+
+static int
+snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,
+                    vlc_value_t oldval, vlc_value_t newval, void *p_data );
+
+static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
+
+/*
+ * Shortcuts
+ */
+
+#define register_event(a, b) __register_event(a, libvlc_MediaPlayer ## b)
+static inline void __register_event(libvlc_media_player_t *mp, libvlc_event_type_t type)
+{
+    libvlc_event_manager_register_event_type(mp->p_event_manager, type);
+}
+
+/*
+ * The input lock protects the input and input resource pointer.
+ * It MUST NOT be used from callbacks.
+ *
+ * The object lock protects the reset, namely the media and the player state.
+ * It can, and usually needs to be taken from callbacks.
+ * The object lock can be acquired under the input lock... and consequently
+ * the opposite order is STRICTLY PROHIBITED.
+ */
+static inline void lock(libvlc_media_player_t *mp)
+{
+    vlc_mutex_lock(&mp->object_lock);
+}
+
+static inline void unlock(libvlc_media_player_t *mp)
+{
+    vlc_mutex_unlock(&mp->object_lock);
+}
+
+static inline void lock_input(libvlc_media_player_t *mp)
+{
+    vlc_mutex_lock(&mp->input.lock);
+}
+
+static inline void unlock_input(libvlc_media_player_t *mp)
+{
+    vlc_mutex_unlock(&mp->input.lock);
+}
+
+/*
+ * Release the associated input thread.
+ *
+ * Object lock is NOT held.
+ * Input lock is held or instance is being destroyed.
+ */
+static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
+{
+    assert( p_mi );
+
+    input_thread_t *p_input_thread = p_mi->input.p_thread;
+    if( !p_input_thread )
+        return;
+    p_mi->input.p_thread = NULL;
+
+    var_DelCallback( p_input_thread, "can-seek",
+                     input_seekable_changed, p_mi );
+    var_DelCallback( p_input_thread, "can-pause",
+                    input_pausable_changed, p_mi );
+    var_DelCallback( p_input_thread, "intf-event",
+                     input_event_changed, p_mi );
+
+    /* We owned this one */
+    input_Stop( p_input_thread, b_input_abort );
+    input_Close( p_input_thread );
+}
+
+/*
+ * Retrieve the input thread. Be sure to release the object
+ * once you are done with it. (libvlc Internal)
+ */
+input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+
+    assert( p_mi );
+
+    lock_input(p_mi);
+    p_input_thread = p_mi->input.p_thread;
+    if( p_input_thread )
+        vlc_object_hold( p_input_thread );
+    else
+        libvlc_printerr( "No active input" );
+    unlock_input(p_mi);
+
+    return p_input_thread;
+}
+
+/*
+ * Set the internal state of the media_player. (media player Internal)
+ *
+ * Function will lock the media_player.
+ */
+static void set_state( libvlc_media_player_t *p_mi, libvlc_state_t state,
+    bool b_locked )
+{
+    if(!b_locked)
+        lock(p_mi);
+    p_mi->state = state;
+
+    libvlc_media_t *media = p_mi->p_md;
+    if (media)
+        libvlc_media_retain(media);
+
+    if(!b_locked)
+        unlock(p_mi);
+
+    if (media)
+    {
+        // Also set the state of the corresponding media
+        // This is strictly for convenience.
+        libvlc_media_set_state(media, state);
+
+        libvlc_media_release(media);
+    }
+}
+
+static int
+input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
+                        vlc_value_t oldval, vlc_value_t newval,
+                        void * p_userdata )
+{
+    VLC_UNUSED(oldval);
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(psz_cmd);
+    libvlc_media_player_t * p_mi = p_userdata;
+    libvlc_event_t event;
+
+    event.type = libvlc_MediaPlayerSeekableChanged;
+    event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
+
+    libvlc_event_send( p_mi->p_event_manager, &event );
+    return VLC_SUCCESS;
+}
+
+static int
+input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
+                        vlc_value_t oldval, vlc_value_t newval,
+                        void * p_userdata )
+{
+    VLC_UNUSED(oldval);
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(psz_cmd);
+    libvlc_media_player_t * p_mi = p_userdata;
+    libvlc_event_t event;
+
+    event.type = libvlc_MediaPlayerPausableChanged;
+    event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
+
+    libvlc_event_send( p_mi->p_event_manager, &event );
+    return VLC_SUCCESS;
+}
+
+static int
+input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
+                     vlc_value_t oldval, vlc_value_t newval,
+                     void * p_userdata )
+{
+    VLC_UNUSED(oldval);
+    input_thread_t * p_input = (input_thread_t *)p_this;
+    libvlc_media_player_t * p_mi = p_userdata;
+    libvlc_event_t event;
+
+    assert( !strcmp( psz_cmd, "intf-event" ) );
+
+    if( newval.i_int == INPUT_EVENT_STATE )
+    {
+        libvlc_state_t libvlc_state;
+
+        switch ( var_GetInteger( p_input, "state" ) )
+        {
+            case INIT_S:
+                libvlc_state = libvlc_NothingSpecial;
+                event.type = libvlc_MediaPlayerNothingSpecial;
+                break;
+            case OPENING_S:
+                libvlc_state = libvlc_Opening;
+                event.type = libvlc_MediaPlayerOpening;
+                break;
+            case PLAYING_S:
+                libvlc_state = libvlc_Playing;
+                event.type = libvlc_MediaPlayerPlaying;
+                break;
+            case PAUSE_S:
+                libvlc_state = libvlc_Paused;
+                event.type = libvlc_MediaPlayerPaused;
+                break;
+            case END_S:
+                libvlc_state = libvlc_Ended;
+                event.type = libvlc_MediaPlayerEndReached;
+                break;
+            case ERROR_S:
+                libvlc_state = libvlc_Error;
+                event.type = libvlc_MediaPlayerEncounteredError;
+                break;
+
+            default:
+                return VLC_SUCCESS;
+        }
+
+        set_state( p_mi, libvlc_state, false );
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+    else if( newval.i_int == INPUT_EVENT_ABORT )
+    {
+        libvlc_state_t libvlc_state = libvlc_Stopped;
+        event.type = libvlc_MediaPlayerStopped;
+
+        set_state( p_mi, libvlc_state, false );
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+    else if( newval.i_int == INPUT_EVENT_POSITION )
+    {
+        if( var_GetInteger( p_input, "state" ) != PLAYING_S )
+            return VLC_SUCCESS; /* Don't send the position while stopped */
+
+        /* */
+        event.type = libvlc_MediaPlayerPositionChanged;
+        event.u.media_player_position_changed.new_position =
+                                          var_GetFloat( p_input, "position" );
+        libvlc_event_send( p_mi->p_event_manager, &event );
+
+        /* */
+        event.type = libvlc_MediaPlayerTimeChanged;
+        event.u.media_player_time_changed.new_time =
+           from_mtime(var_GetTime( p_input, "time" ));
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+    else if( newval.i_int == INPUT_EVENT_LENGTH )
+    {
+        event.type = libvlc_MediaPlayerLengthChanged;
+        event.u.media_player_length_changed.new_length =
+           from_mtime(var_GetTime( p_input, "length" ));
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+    else if( newval.i_int == INPUT_EVENT_CACHE )
+    {
+        event.type = libvlc_MediaPlayerBuffering;
+        event.u.media_player_buffering.new_cache = (int)(100 *
+            var_GetFloat( p_input, "cache" ));
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+
+    return VLC_SUCCESS;
+}
+
+/**************************************************************************
+ * Snapshot Taken Event.
+ *
+ * FIXME: This snapshot API interface makes no sense in media_player.
+ *************************************************************************/
+static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd,
+                              vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this);
+
+    libvlc_media_player_t *mp = p_data;
+    libvlc_event_t event;
+    event.type = libvlc_MediaPlayerSnapshotTaken;
+    event.u.media_player_snapshot_taken.psz_filename = newval.psz_string;
+    libvlc_event_send(mp->p_event_manager, &event);
+
+    return VLC_SUCCESS;
+}
+
+static input_thread_t *find_input (vlc_object_t *obj)
+{
+    libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
+
+    return libvlc_get_input_thread (mp);
+}
+
+/* */
+static void libvlc_media_player_destroy( libvlc_media_player_t * );
+
+
+/**************************************************************************
+ * Create a Media Instance object.
+ *
+ * Refcount strategy:
+ * - All items created by _new start with a refcount set to 1.
+ * - Accessor _release decrease the refcount by 1, if after that
+ *   operation the refcount is 0, the object is destroyed.
+ * - Accessor _retain increase the refcount by 1 (XXX: to implement)
+ *
+ * Object locking strategy:
+ * - No lock held while in constructor.
+ * - When accessing any member variable this lock is held. (XXX who locks?)
+ * - When attempting to destroy the object the lock is also held.
+ **************************************************************************/
+libvlc_media_player_t *
+libvlc_media_player_new( libvlc_instance_t *instance )
+{
+    libvlc_media_player_t * mp;
+
+    assert(instance);
+
+    mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
+    if (unlikely(mp == NULL))
+    {
+        libvlc_printerr("Not enough memory");
+        return NULL;
+    }
+
+    /* Input */
+    var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
+
+    /* Video */
+    var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
+    var_Create (mp, "window", VLC_VAR_STRING);
+    var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
+    var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
+    var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
+    var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
+    var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
+    var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
+    var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
+    var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
+#ifdef WIN32
+    var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
+#endif
+#ifdef __APPLE__
+    var_Create (mp, "drawable-agl", VLC_VAR_INTEGER);
+    var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
+#endif
+
+    var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
+    var_SetBool (mp, "keyboard-events", true);
+    var_Create (mp, "mouse-events", VLC_VAR_BOOL);
+    var_SetBool (mp, "mouse-events", true);
+
+    var_Create (mp, "fullscreen", VLC_VAR_BOOL);
+    var_Create (mp, "autoscale", VLC_VAR_BOOL);
+    var_SetBool (mp, "autoscale", true);
+    var_Create (mp, "scale", VLC_VAR_FLOAT);
+    var_SetFloat (mp, "scale", 1.);
+    var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
+    var_Create (mp, "crop", VLC_VAR_STRING);
+    var_Create (mp, "deinterlace", VLC_VAR_INTEGER);
+    var_Create (mp, "deinterlace-mode", VLC_VAR_STRING);
+
+    var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
+
+    var_Create (mp, "marq-marquee", VLC_VAR_STRING);
+    var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+
+    var_Create (mp, "logo-file", VLC_VAR_STRING);
+    var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+
+    var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+    var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+    var_Create (mp, "hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+    var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+
+     /* Audio */
+    var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
+    var_Create (mp, "mute", VLC_VAR_BOOL);
+    var_Create (mp, "volume", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "find-input-callback", VLC_VAR_ADDRESS);
+    var_SetAddress (mp, "find-input-callback", find_input);
+    var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-close", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
+    var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
+    var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+
+    mp->p_md = NULL;
+    mp->state = libvlc_NothingSpecial;
+    mp->p_libvlc_instance = instance;
+    mp->input.p_thread = NULL;
+    mp->input.p_resource = NULL;
+    vlc_mutex_init (&mp->input.lock);
+    mp->i_refcount = 1;
+    mp->p_event_manager = libvlc_event_manager_new(mp, instance);
+    if (unlikely(mp->p_event_manager == NULL))
+    {
+        vlc_object_release(mp);
+        return NULL;
+    }
+    vlc_mutex_init(&mp->object_lock);
+
+    register_event(mp, NothingSpecial);
+    register_event(mp, Opening);
+    register_event(mp, Buffering);
+    register_event(mp, Playing);
+    register_event(mp, Paused);
+    register_event(mp, Stopped);
+    register_event(mp, Forward);
+    register_event(mp, Backward);
+    register_event(mp, EndReached);
+    register_event(mp, EncounteredError);
+    register_event(mp, SeekableChanged);
+
+    register_event(mp, PositionChanged);
+    register_event(mp, TimeChanged);
+    register_event(mp, LengthChanged);
+    register_event(mp, TitleChanged);
+    register_event(mp, PausableChanged);
+
+    /* Snapshot initialization */
+    register_event(mp, SnapshotTaken);
+
+    register_event(mp, MediaChanged);
+
+    /* Attach a var callback to the global object to provide the glue between
+     * vout_thread that generates the event and media_player that re-emits it
+     * with its own event manager
+     *
+     * FIXME: It's unclear why we want to put this in public API, and why we
+     * want to expose it in such a limiting and ugly way.
+     */
+    var_AddCallback(mp->p_libvlc, "snapshot-file", snapshot_was_taken, mp);
+
+    libvlc_retain(instance);
+    return mp;
+}
+
+/**************************************************************************
+ * Create a Media Instance object with a media descriptor.
+ **************************************************************************/
+libvlc_media_player_t *
+libvlc_media_player_new_from_media( libvlc_media_t * p_md )
+{
+    libvlc_media_player_t * p_mi;
+
+    p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
+    if( !p_mi )
+        return NULL;
+
+    libvlc_media_retain( p_md );
+    p_mi->p_md = p_md;
+
+    return p_mi;
+}
+
+/**************************************************************************
+ * Destroy a Media Instance object (libvlc internal)
+ *
+ * Warning: No lock held here, but hey, this is internal. Caller must lock.
+ **************************************************************************/
+static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
+{
+    assert( p_mi );
+
+    /* Detach Callback from the main libvlc object */
+    var_DelCallback( p_mi->p_libvlc,
+                     "snapshot-file", snapshot_was_taken, p_mi );
+
+    /* No need for lock_input() because no other threads knows us anymore */
+    if( p_mi->input.p_thread )
+        release_input_thread(p_mi, true);
+    if( p_mi->input.p_resource )
+    {
+        input_resource_Terminate( p_mi->input.p_resource );
+        input_resource_Release( p_mi->input.p_resource );
+        p_mi->input.p_resource = NULL;
+    }
+    vlc_mutex_destroy( &p_mi->input.lock );
+
+    libvlc_event_manager_release( p_mi->p_event_manager );
+    libvlc_media_release( p_mi->p_md );
+    vlc_mutex_destroy( &p_mi->object_lock );
+
+    libvlc_instance_t *instance = p_mi->p_libvlc_instance;
+    vlc_object_release( p_mi );
+    libvlc_release(instance);
+}
+
+/**************************************************************************
+ * Release a Media Instance object.
+ *
+ * Function does the locking.
+ **************************************************************************/
+void libvlc_media_player_release( libvlc_media_player_t *p_mi )
+{
+    bool destroy;
+
+    assert( p_mi );
+    lock(p_mi);
+    destroy = !--p_mi->i_refcount;
+    unlock(p_mi);
+
+    if( destroy )
+        libvlc_media_player_destroy( p_mi );
+}
+
+/**************************************************************************
+ * Retain a Media Instance object.
+ *
+ * Caller must hold the lock.
+ **************************************************************************/
+void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
+{
+    assert( p_mi );
+
+    lock(p_mi);
+    p_mi->i_refcount++;
+    unlock(p_mi);
+}
+
+/**************************************************************************
+ * Set the Media descriptor associated with the instance.
+ *
+ * Enter without lock -- function will lock the object.
+ **************************************************************************/
+void libvlc_media_player_set_media(
+                            libvlc_media_player_t *p_mi,
+                            libvlc_media_t *p_md )
+{
+    lock_input(p_mi);
+
+    /* FIXME I am not sure if it is a user request or on die(eof/error)
+     * request here */
+    release_input_thread( p_mi,
+                          p_mi->input.p_thread &&
+                          !p_mi->input.p_thread->b_eof &&
+                          !p_mi->input.p_thread->b_error );
+
+    lock( p_mi );
+    set_state( p_mi, libvlc_NothingSpecial, true );
+    unlock_input( p_mi );
+
+    libvlc_media_release( p_mi->p_md );
+
+    if( !p_md )
+    {
+        p_mi->p_md = NULL;
+        unlock(p_mi);
+        return; /* It is ok to pass a NULL md */
+    }
+
+    libvlc_media_retain( p_md );
+    p_mi->p_md = p_md;
+
+    /* The policy here is to ignore that we were created using a different
+     * libvlc_instance, because we don't really care */
+    p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
+
+    unlock(p_mi);
+
+    /* Send an event for the newly available media */
+    libvlc_event_t event;
+    event.type = libvlc_MediaPlayerMediaChanged;
+    event.u.media_player_media_changed.new_media = p_md;
+    libvlc_event_send( p_mi->p_event_manager, &event );
+
+}
+
+/**************************************************************************
+ * Get the Media descriptor associated with the instance.
+ **************************************************************************/
+libvlc_media_t *
+libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
+{
+    libvlc_media_t *p_m;
+
+    lock(p_mi);
+    p_m = p_mi->p_md;
+    if( p_m )
+        libvlc_media_retain( p_mi->p_md );
+    unlock(p_mi);
+    return p_mi->p_md;
+}
+
+/**************************************************************************
+ * Get the event Manager.
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
+{
+    return p_mi->p_event_manager;
+}
+
+/**************************************************************************
+ * Tell media player to start playing.
+ **************************************************************************/
+int libvlc_media_player_play( libvlc_media_player_t *p_mi )
+{
+    lock_input( p_mi );
+
+    input_thread_t *p_input_thread = p_mi->input.p_thread;
+    if( p_input_thread )
+    {
+        /* A thread already exists, send it a play message */
+        input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
+        unlock_input( p_mi );
+        return 0;
+    }
+
+    /* Ignore previous exception */
+    lock(p_mi);
+
+    if( !p_mi->p_md )
+    {
+        unlock(p_mi);
+        unlock_input( p_mi );
+        libvlc_printerr( "No associated media descriptor" );
+        return -1;
+    }
+
+    if( !p_mi->input.p_resource )
+        p_mi->input.p_resource = input_resource_New( VLC_OBJECT( p_mi ) );
+    p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
+                                   p_mi->input.p_resource );
+    unlock(p_mi);
+    if( !p_input_thread )
+    {
+        unlock_input(p_mi);
+        libvlc_printerr( "Not enough memory" );
+        return -1;
+    }
+
+    var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
+    var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
+    var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
+
+    if( input_Start( p_input_thread ) )
+    {
+        unlock_input(p_mi);
+        var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
+        var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
+        var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
+        vlc_object_release( p_input_thread );
+        libvlc_printerr( "Input initialization failure" );
+        return -1;
+    }
+    p_mi->input.p_thread = p_input_thread;
+    unlock_input(p_mi);
+    return 0;
+}
+
+void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
+{
+    input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
+    if( !p_input_thread )
+        return;
+
+    libvlc_state_t state = libvlc_media_player_get_state( p_mi );
+    if( state == libvlc_Playing || state == libvlc_Buffering )
+    {
+        if( paused )
+        {
+            if( libvlc_media_player_can_pause( p_mi ) )
+                input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
+            else
+                libvlc_media_player_stop( p_mi );
+        }
+    }
+    else
+    {
+        if( !paused )
+            input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
+    }
+
+    vlc_object_release( p_input_thread );
+}
+
+/**************************************************************************
+ * Toggle pause.
+ **************************************************************************/
+void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
+{
+    libvlc_state_t state = libvlc_media_player_get_state( p_mi );
+    bool playing = (state == libvlc_Playing || state == libvlc_Buffering);
+
+    libvlc_media_player_set_pause( p_mi, playing );
+}
+
+/**************************************************************************
+ * Tells whether the media player is currently playing.
+ *
+ * Enter with lock held.
+ **************************************************************************/
+int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
+{
+    libvlc_state_t state = libvlc_media_player_get_state( p_mi );
+    return (libvlc_Playing == state) || (libvlc_Buffering == state);
+}
+
+/**************************************************************************
+ * Stop playing.
+ **************************************************************************/
+void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
+{
+    libvlc_state_t state = libvlc_media_player_get_state( p_mi );
+
+    lock_input(p_mi);
+    release_input_thread( p_mi, true ); /* This will stop the input thread */
+
+    /* Force to go to stopped state, in case we were in Ended, or Error
+     * state. */
+    if( state != libvlc_Stopped )
+    {
+        set_state( p_mi, libvlc_Stopped, false );
+
+        /* Construct and send the event */
+        libvlc_event_t event;
+        event.type = libvlc_MediaPlayerStopped;
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+
+    if( p_mi->input.p_resource != NULL )
+        input_resource_Terminate( p_mi->input.p_resource );
+    unlock_input(p_mi);
+}
+
+
+void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
+    void *(*lock_cb) (void *, void **),
+    void (*unlock_cb) (void *, void *, void *const *),
+    void (*display_cb) (void *, void *),
+    void *opaque )
+{
+    var_SetAddress( mp, "vmem-lock", lock_cb );
+    var_SetAddress( mp, "vmem-unlock", unlock_cb );
+    var_SetAddress( mp, "vmem-display", display_cb );
+    var_SetAddress( mp, "vmem-data", opaque );
+    var_SetString( mp, "vout", "vmem" );
+}
+
+void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
+                                        libvlc_video_format_cb setup,
+                                        libvlc_video_cleanup_cb cleanup )
+{
+    var_SetAddress( mp, "vmem-setup", setup );
+    var_SetAddress( mp, "vmem-cleanup", cleanup );
+}
+
+void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
+                              unsigned width, unsigned height, unsigned pitch )
+{
+    var_SetString( mp, "vmem-chroma", chroma );
+    var_SetInteger( mp, "vmem-width", width );
+    var_SetInteger( mp, "vmem-height", height );
+    var_SetInteger( mp, "vmem-pitch", pitch );
+}
+
+/**************************************************************************
+ * set_nsobject
+ **************************************************************************/
+void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
+                                        void * drawable )
+{
+    assert (p_mi != NULL);
+#ifdef __APPLE__
+    var_SetAddress (p_mi, "drawable-nsobject", drawable);
+#else
+    (void) p_mi; (void)drawable;
+#endif
+}
+
+/**************************************************************************
+ * get_nsobject
+ **************************************************************************/
+void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
+{
+    assert (p_mi != NULL);
+#ifdef __APPLE__
+    return var_GetAddress (p_mi, "drawable-nsobject");
+#else
+    return NULL;
+#endif
+}
+
+/**************************************************************************
+ * set_agl
+ **************************************************************************/
+void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
+                                  uint32_t drawable )
+{
+#ifdef __APPLE__
+    var_SetInteger (p_mi, "drawable-agl", drawable);
+#else
+    (void) p_mi; (void)drawable;
+#endif
+}
+
+/**************************************************************************
+ * get_agl
+ **************************************************************************/
+uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
+{
+    assert (p_mi != NULL);
+#ifdef __APPLE__
+    return var_GetInteger (p_mi, "drawable-agl");
+#else
+    return 0;
+#endif
+}
+
+/**************************************************************************
+ * set_xwindow
+ **************************************************************************/
+void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
+                                      uint32_t drawable )
+{
+    assert (p_mi != NULL);
+
+    var_SetString (p_mi, "vout", drawable ? "xid" : "any");
+    var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "any");
+    var_SetInteger (p_mi, "drawable-xid", drawable);
+}
+
+/**************************************************************************
+ * get_xwindow
+ **************************************************************************/
+uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
+{
+    return var_GetInteger (p_mi, "drawable-xid");
+}
+
+/**************************************************************************
+ * set_hwnd
+ **************************************************************************/
+void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
+                                   void *drawable )
+{
+    assert (p_mi != NULL);
+#ifdef WIN32
+    var_SetString (p_mi, "window",
+                   (drawable != NULL) ? "embed-hwnd,any" : "");
+    var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
+#else
+    (void) p_mi; (void) drawable;
+#endif
+}
+
+/**************************************************************************
+ * get_hwnd
+ **************************************************************************/
+void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
+{
+    assert (p_mi != NULL);
+#ifdef WIN32
+    return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
+#else
+    return NULL;
+#endif
+}
+
+void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
+                                 libvlc_audio_play_cb play_cb,
+                                 libvlc_audio_pause_cb pause_cb,
+                                 libvlc_audio_resume_cb resume_cb,
+                                 libvlc_audio_flush_cb flush_cb,
+                                 libvlc_audio_drain_cb drain_cb,
+                                 void *opaque )
+{
+    var_SetAddress( mp, "amem-play", play_cb );
+    var_SetAddress( mp, "amem-pause", pause_cb );
+    var_SetAddress( mp, "amem-resume", resume_cb );
+    var_SetAddress( mp, "amem-flush", flush_cb );
+    var_SetAddress( mp, "amem-drain", drain_cb );
+    var_SetAddress( mp, "amem-data", opaque );
+    var_SetString( mp, "aout", "amem,none" );
+}
+
+void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
+                                       libvlc_audio_set_volume_cb cb )
+{
+    var_SetAddress( mp, "amem-set-volume", cb );
+}
+
+void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
+                                        libvlc_audio_setup_cb setup,
+                                        libvlc_audio_cleanup_cb cleanup )
+{
+    var_SetAddress( mp, "amem-setup", setup );
+    var_SetAddress( mp, "amem-cleanup", cleanup );
+}
+
+void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
+                              unsigned rate, unsigned channels )
+{
+    var_SetString( mp, "amem-format", format );
+    var_SetInteger( mp, "amem-rate", rate );
+    var_SetInteger( mp, "amem-channels", channels );
+}
+
+
+/**************************************************************************
+ * Getters for stream information
+ **************************************************************************/
+libvlc_time_t libvlc_media_player_get_length(
+                             libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    libvlc_time_t i_time;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    i_time = from_mtime(var_GetTime( p_input_thread, "length" ));
+    vlc_object_release( p_input_thread );
+
+    return i_time;
+}
+
+libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    libvlc_time_t i_time;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    i_time = from_mtime(var_GetTime( p_input_thread , "time" ));
+    vlc_object_release( p_input_thread );
+    return i_time;
+}
+
+void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
+                                   libvlc_time_t i_time )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    var_SetTime( p_input_thread, "time", to_mtime(i_time) );
+    vlc_object_release( p_input_thread );
+}
+
+void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
+                                       float position )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    var_SetFloat( p_input_thread, "position", position );
+    vlc_object_release( p_input_thread );
+}
+
+float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    float f_position;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1.0;
+
+    f_position = var_GetFloat( p_input_thread, "position" );
+    vlc_object_release( p_input_thread );
+
+    return f_position;
+}
+
+void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
+                                      int chapter )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    var_SetInteger( p_input_thread, "chapter", chapter );
+    vlc_object_release( p_input_thread );
+}
+
+int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    int i_chapter;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    i_chapter = var_GetInteger( p_input_thread, "chapter" );
+    vlc_object_release( p_input_thread );
+
+    return i_chapter;
+}
+
+int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    vlc_value_t val;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
+    vlc_object_release( p_input_thread );
+
+    return val.i_int;
+}
+
+int libvlc_media_player_get_chapter_count_for_title(
+                                 libvlc_media_player_t *p_mi,
+                                 int i_title )
+{
+    input_thread_t *p_input_thread;
+    vlc_value_t val;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    char *psz_name;
+    if( asprintf( &psz_name,  "title %2i", i_title ) == -1 )
+    {
+        vlc_object_release( p_input_thread );
+        return -1;
+    }
+    var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
+    vlc_object_release( p_input_thread );
+    free( psz_name );
+
+    return val.i_int;
+}
+
+void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
+                                    int i_title )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    var_SetInteger( p_input_thread, "title", i_title );
+    vlc_object_release( p_input_thread );
+
+    //send event
+    libvlc_event_t event;
+    event.type = libvlc_MediaPlayerTitleChanged;
+    event.u.media_player_title_changed.new_title = i_title;
+    libvlc_event_send( p_mi->p_event_manager, &event );
+}
+
+int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    int i_title;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    i_title = var_GetInteger( p_input_thread, "title" );
+    vlc_object_release( p_input_thread );
+
+    return i_title;
+}
+
+int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    vlc_value_t val;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
+    vlc_object_release( p_input_thread );
+
+    return val.i_int;
+}
+
+void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    int i_type = var_Type( p_input_thread, "next-chapter" );
+    var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
+                            "next-chapter":"next-title" );
+
+    vlc_object_release( p_input_thread );
+}
+
+void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    int i_type = var_Type( p_input_thread, "next-chapter" );
+    var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
+                            "prev-chapter":"prev-title" );
+
+    vlc_object_release( p_input_thread );
+}
+
+float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
+    double f_fps = 0.0;
+
+    if( p_input_thread )
+    {
+        if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
+            f_fps = 0.0;
+        vlc_object_release( p_input_thread );
+    }
+    return f_fps;
+}
+
+int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
+{
+    bool b_will_play;
+    input_thread_t *p_input_thread =
+                            libvlc_get_input_thread ( p_mi );
+    if ( !p_input_thread )
+        return false;
+
+    b_will_play = !p_input_thread->b_die && !p_input_thread->b_dead;
+    vlc_object_release( p_input_thread );
+
+    return b_will_play;
+}
+
+int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
+{
+    if (rate < 0.)
+    {
+        libvlc_printerr ("Playing backward not supported");
+        return -1;
+    }
+
+    var_SetFloat (p_mi, "rate", rate);
+
+    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return 0;
+    var_SetFloat( p_input_thread, "rate", rate );
+    vlc_object_release( p_input_thread );
+    return 0;
+}
+
+float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
+{
+    return var_GetFloat (p_mi, "rate");
+}
+
+libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
+{
+    lock(p_mi);
+    libvlc_state_t state = p_mi->state;
+    unlock(p_mi);
+    return state;
+}
+
+int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    bool b_seekable;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if ( !p_input_thread )
+        return false;
+    b_seekable = var_GetBool( p_input_thread, "can-seek" );
+    vlc_object_release( p_input_thread );
+
+    return b_seekable;
+}
+
+void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
+                                  unsigned navigate )
+{
+    input_thread_t *p_input_thread;
+
+    if ( navigate > libvlc_navigate_to_action_size)
+      return;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if ( !p_input_thread )
+      return;
+
+    var_SetInteger( p_mi->p_libvlc_instance->p_libvlc_int,
+                   "key-action", libvlc_navigate_to_action[navigate] );
+
+    vlc_object_release( p_input_thread );
+}
+
+/* internal function, used by audio, video */
+libvlc_track_description_t *
+        libvlc_get_track_description( libvlc_media_player_t *p_mi,
+                                      const char *psz_variable )
+{
+    input_thread_t *p_input = libvlc_get_input_thread( p_mi );
+    libvlc_track_description_t *p_track_description = NULL,
+                               *p_actual, *p_previous;
+
+    if( !p_input )
+        return NULL;
+
+    vlc_value_t val_list, text_list;
+    var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
+
+    /* no tracks */
+    if( val_list.p_list->i_count <= 0 )
+        goto end;
+
+    p_track_description = ( libvlc_track_description_t * )
+        malloc( sizeof( libvlc_track_description_t ) );
+    if ( !p_track_description )
+    {
+        libvlc_printerr( "Not enough memory" );
+        goto end;
+    }
+    p_actual = p_track_description;
+    p_previous = NULL;
+    for( int i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        if( !p_actual )
+        {
+            p_actual = ( libvlc_track_description_t * )
+                malloc( sizeof( libvlc_track_description_t ) );
+            if ( !p_actual )
+            {
+                libvlc_track_description_release( p_track_description );
+                libvlc_printerr( "Not enough memory" );
+                goto end;
+            }
+        }
+        p_actual->i_id = val_list.p_list->p_values[i].i_int;
+        p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
+        p_actual->p_next = NULL;
+        if( p_previous )
+            p_previous->p_next = p_actual;
+        p_previous = p_actual;
+        p_actual =  NULL;
+    }
+
+end:
+    var_FreeList( &val_list, &text_list );
+    vlc_object_release( p_input );
+
+    return p_track_description;
+}
+
+void libvlc_track_description_release( libvlc_track_description_t *p_td )
+{
+    libvlc_track_description_t *p_actual, *p_before;
+    p_actual = p_td;
+
+    while ( p_actual )
+    {
+        free( p_actual->psz_name );
+        p_before = p_actual;
+        p_actual = p_before->p_next;
+        free( p_before );
+    }
+}
+
+int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    bool b_can_pause;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if ( !p_input_thread )
+        return false;
+    b_can_pause = var_GetBool( p_input_thread, "can-pause" );
+    vlc_object_release( p_input_thread );
+
+    return b_can_pause;
+}
+
+void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( p_input_thread != NULL )
+    {
+        var_TriggerCallback( p_input_thread, "frame-next" );
+        vlc_object_release( p_input_thread );
+    }
+}
diff --git a/lib/media_player_internal.h b/lib/media_player_internal.h
new file mode 100644 (file)
index 0000000..5b12ff7
--- /dev/null
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * libvlc_internal.h : Definition of opaque structures for libvlc exported API
+ * Also contains some internal utility functions
+ *****************************************************************************
+ * Copyright (C) 2005-2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBVLC_MEDIA_PLAYER_INTERNAL_H
+#define _LIBVLC_MEDIA_PLAYER_INTERNAL_H 1
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/vlc.h>
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc_media.h>
+#include <vlc_input.h>
+
+struct libvlc_media_player_t
+{
+    VLC_COMMON_MEMBERS
+
+    int                i_refcount;
+    vlc_mutex_t        object_lock;
+
+    struct
+    {
+        input_thread_t   *p_thread;
+        input_resource_t *p_resource;
+        vlc_mutex_t       lock;
+    } input;
+
+    struct libvlc_instance_t * p_libvlc_instance; /* Parent instance */
+    libvlc_media_t * p_md; /* current media descriptor */
+    libvlc_event_manager_t * p_event_manager;
+    libvlc_state_t state;
+};
+
+/* Media player - audio, video */
+input_thread_t *libvlc_get_input_thread(libvlc_media_player_t * );
+
+
+libvlc_track_description_t * libvlc_get_track_description(
+        libvlc_media_player_t *p_mi,
+        const char *psz_variable );
+
+#endif
diff --git a/lib/playlist.c b/lib/playlist.c
new file mode 100644 (file)
index 0000000..7250552
--- /dev/null
@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * playlist.c: libvlc new API playlist handling functions
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "libvlc_internal.h"
+#include "../src/libvlc.h"
+
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_player.h>
+#include <vlc/deprecated.h>
+
+#include <vlc_playlist.h>
+
+#include <assert.h>
+
+void libvlc_playlist_play( libvlc_instance_t *p_instance, int i_id,
+                           int i_options, char **ppsz_options )
+{
+    playlist_t *pl = libvlc_priv (p_instance->p_libvlc_int)->p_playlist;
+    VLC_UNUSED(i_id); VLC_UNUSED(i_options); VLC_UNUSED(ppsz_options);
+
+    assert( pl );
+    if( !var_GetBool( pl, "playlist-autostart" )
+     || pl->items.i_size == 0 )
+        return;
+    playlist_Control( pl, PLAYLIST_PLAY, false );
+}
diff --git a/lib/video.c b/lib/video.c
new file mode 100644 (file)
index 0000000..ff06979
--- /dev/null
@@ -0,0 +1,925 @@
+/*****************************************************************************
+ * video.c: libvlc new API video functions
+ *****************************************************************************
+ * Copyright (C) 2005-2010 the VideoLAN team
+ *
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *          Filippo Carone <littlejohn@videolan.org>
+ *          Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
+ *          Damien Fouilleul <damienf a_t videolan dot org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_media_player.h>
+
+#include <vlc_common.h>
+#include <vlc_input.h>
+#include <vlc_vout.h>
+
+#include "media_player_internal.h"
+#include <assert.h>
+
+/*
+ * Remember to release the returned vout_thread_t.
+ */
+static vout_thread_t **GetVouts( libvlc_media_player_t *p_mi, size_t *n )
+{
+    input_thread_t *p_input = libvlc_get_input_thread( p_mi );
+    if( !p_input )
+    {
+        *n = 0;
+        return NULL;
+    }
+
+    vout_thread_t **pp_vouts;
+    if (input_Control( p_input, INPUT_GET_VOUTS, &pp_vouts, n))
+    {
+        *n = 0;
+        pp_vouts = NULL;
+    }
+    vlc_object_release (p_input);
+    return pp_vouts;
+}
+
+static vout_thread_t *GetVout (libvlc_media_player_t *mp, size_t num)
+{
+    vout_thread_t *p_vout = NULL;
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (mp, &n);
+    if (pp_vouts == NULL)
+        goto err;
+
+    if (num < n)
+        p_vout = pp_vouts[num];
+
+    for (size_t i = 0; i < n; i++)
+        if (i != num)
+            vlc_object_release (pp_vouts[i]);
+    free (pp_vouts);
+
+    if (p_vout == NULL)
+err:
+        libvlc_printerr ("Video output not active");
+    return p_vout;
+}
+
+/**********************************************************************
+ * Exported functions
+ **********************************************************************/
+
+void libvlc_set_fullscreen( libvlc_media_player_t *p_mi, int b_fullscreen )
+{
+    /* This will work even if the video is not currently active */
+    var_SetBool (p_mi, "fullscreen", !!b_fullscreen);
+
+    /* Apply to current video outputs (if any) */
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
+    for (size_t i = 0; i < n; i++)
+    {
+        var_SetBool (pp_vouts[i], "fullscreen", b_fullscreen);
+        vlc_object_release (pp_vouts[i]);
+    }
+    free (pp_vouts);
+}
+
+int libvlc_get_fullscreen( libvlc_media_player_t *p_mi )
+{
+    return var_GetBool (p_mi, "fullscreen");
+}
+
+void libvlc_toggle_fullscreen( libvlc_media_player_t *p_mi )
+{
+    bool b_fullscreen = var_ToggleBool (p_mi, "fullscreen");
+
+    /* Apply to current video outputs (if any) */
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
+    for (size_t i = 0; i < n; i++)
+    {
+        vout_thread_t *p_vout = pp_vouts[i];
+
+        var_SetBool (p_vout, "fullscreen", b_fullscreen);
+        vlc_object_release (p_vout);
+    }
+    free (pp_vouts);
+}
+
+void libvlc_video_set_key_input( libvlc_media_player_t *p_mi, unsigned on )
+{
+    var_SetBool (p_mi, "keyboard-events", !!on);
+}
+
+void libvlc_video_set_mouse_input( libvlc_media_player_t *p_mi, unsigned on )
+{
+    var_SetBool (p_mi, "mouse-events", !!on);
+}
+
+int
+libvlc_video_take_snapshot( libvlc_media_player_t *p_mi, unsigned num,
+                            const char *psz_filepath,
+                            unsigned int i_width, unsigned int i_height )
+{
+    assert( psz_filepath );
+
+    vout_thread_t *p_vout = GetVout (p_mi, num);
+    if (p_vout == NULL)
+        return -1;
+
+    /* FIXME: This is not atomic. Someone else could change the values,
+     * at least in theory. */
+    var_SetInteger( p_vout, "snapshot-width", i_width);
+    var_SetInteger( p_vout, "snapshot-height", i_height );
+    var_SetString( p_vout, "snapshot-path", psz_filepath );
+    var_SetString( p_vout, "snapshot-format", "png" );
+    var_TriggerCallback( p_vout, "video-snapshot" );
+    vlc_object_release( p_vout );
+    return 0;
+}
+
+int libvlc_video_get_size( libvlc_media_player_t *p_mi, unsigned num,
+                           unsigned *restrict px, unsigned *restrict py )
+{
+#if 0
+    vout_thread_t *p_vout = GetVout (p_mi, num);
+    if (p_vout == NULL)
+        return -1;
+
+    *px = p_vout->i_window_height;
+    *py = p_vout->i_window_width;
+    vlc_object_release (p_vout);
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+int libvlc_video_get_height( libvlc_media_player_t *p_mi )
+{
+    unsigned height, width;
+
+    if (libvlc_video_get_size (p_mi, 0, &height, &width))
+        return 0;
+    return height;
+}
+
+int libvlc_video_get_width( libvlc_media_player_t *p_mi )
+{
+    unsigned height, width;
+
+    if (libvlc_video_get_size (p_mi, 0, &height, &width))
+        return 0;
+    return width;
+}
+
+int libvlc_video_get_cursor( libvlc_media_player_t *mp, unsigned num,
+                             int *restrict px, int *restrict py )
+{
+    vout_thread_t *p_vout = GetVout (mp, num);
+    if (p_vout == NULL)
+        return -1;
+
+    var_GetCoords (p_vout, "mouse-moved", px, py);
+    vlc_object_release (p_vout);
+    return 0;
+}
+
+unsigned libvlc_media_player_has_vout( libvlc_media_player_t *p_mi )
+{
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
+    for (size_t i = 0; i < n; i++)
+        vlc_object_release (pp_vouts[i]);
+    free (pp_vouts);
+    return n;
+}
+
+float libvlc_video_get_scale( libvlc_media_player_t *mp )
+{
+    float f_scale = var_GetFloat (mp, "scale");
+    if (var_GetBool (mp, "autoscale"))
+        f_scale = 0.;
+    return f_scale;
+}
+
+void libvlc_video_set_scale( libvlc_media_player_t *p_mp, float f_scale )
+{
+    if (f_scale != 0.)
+        var_SetFloat (p_mp, "scale", f_scale);
+    var_SetBool (p_mp, "autoscale", f_scale == 0.);
+
+    /* Apply to current video outputs (if any) */
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mp, &n);
+    for (size_t i = 0; i < n; i++)
+    {
+        vout_thread_t *p_vout = pp_vouts[i];
+
+        if (f_scale != 0.)
+            var_SetFloat (p_vout, "scale", f_scale);
+        var_SetBool (p_vout, "autoscale", f_scale == 0.);
+        vlc_object_release (p_vout);
+    }
+    free (pp_vouts);
+}
+
+char *libvlc_video_get_aspect_ratio( libvlc_media_player_t *p_mi )
+{
+    return var_GetNonEmptyString (p_mi, "aspect-ratio");
+}
+
+void libvlc_video_set_aspect_ratio( libvlc_media_player_t *p_mi,
+                                    const char *psz_aspect )
+{
+    if (psz_aspect == NULL)
+        psz_aspect = "";
+    var_SetString (p_mi, "aspect-ratio", psz_aspect);
+
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
+    for (size_t i = 0; i < n; i++)
+    {
+        vout_thread_t *p_vout = pp_vouts[i];
+
+        var_SetString (p_vout, "aspect-ratio", psz_aspect);
+        vlc_object_release (p_vout);
+    }
+    free (pp_vouts);
+}
+
+int libvlc_video_get_spu( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    vlc_value_t val_list;
+    vlc_value_t val;
+    int i_spu = -1;
+    int i_ret = -1;
+    int i;
+
+    if( !p_input_thread )
+    {
+        libvlc_printerr( "No active input" );
+        return -1;
+    }
+
+    i_ret = var_Get( p_input_thread, "spu-es", &val );
+    if( i_ret < 0 )
+    {
+        vlc_object_release( p_input_thread );
+        libvlc_printerr( "Subtitle information not found" );
+        return -1;
+    }
+
+    var_Change( p_input_thread, "spu-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        if( val.i_int == val_list.p_list->p_values[i].i_int )
+        {
+            i_spu = i;
+            break;
+        }
+    }
+    var_FreeList( &val_list, NULL );
+    vlc_object_release( p_input_thread );
+    return i_spu;
+}
+
+int libvlc_video_get_spu_count( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    int i_spu_count;
+
+    if( !p_input_thread )
+        return 0;
+
+    i_spu_count = var_CountChoices( p_input_thread, "spu-es" );
+    vlc_object_release( p_input_thread );
+    return i_spu_count;
+}
+
+libvlc_track_description_t *
+        libvlc_video_get_spu_description( libvlc_media_player_t *p_mi )
+{
+    return libvlc_get_track_description( p_mi, "spu-es" );
+}
+
+int libvlc_video_set_spu( libvlc_media_player_t *p_mi, unsigned i_spu )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    vlc_value_t list;
+    int i_ret = 0;
+
+    if( !p_input_thread )
+        return -1;
+
+    var_Change (p_input_thread, "spu-es", VLC_VAR_GETCHOICES, &list, NULL);
+
+    if (i_spu > (unsigned)list.p_list->i_count)
+    {
+        libvlc_printerr( "Subtitle number out of range (%u/%u)",
+                         i_spu, list.p_list->i_count );
+        i_ret = -1;
+        goto end;
+    }
+    var_SetInteger (p_input_thread, "spu-es",
+                    list.p_list->p_values[i_spu].i_int);
+end:
+    vlc_object_release (p_input_thread);
+    var_FreeList (&list, NULL);
+    return i_ret;
+}
+
+int libvlc_video_set_subtitle_file( libvlc_media_player_t *p_mi,
+                                    const char *psz_subtitle )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
+    bool b_ret = false;
+
+    if( p_input_thread )
+    {
+        if( !input_AddSubtitle( p_input_thread, psz_subtitle, true ) )
+            b_ret = true;
+        vlc_object_release( p_input_thread );
+    }
+    return b_ret;
+}
+
+libvlc_track_description_t *
+        libvlc_video_get_title_description( libvlc_media_player_t *p_mi )
+{
+    return libvlc_get_track_description( p_mi, "title" );
+}
+
+libvlc_track_description_t *
+        libvlc_video_get_chapter_description( libvlc_media_player_t *p_mi,
+                                              int i_title )
+{
+    char psz_title[12];
+    sprintf( psz_title,  "title %2i", i_title );
+    return libvlc_get_track_description( p_mi, psz_title );
+}
+
+char *libvlc_video_get_crop_geometry (libvlc_media_player_t *p_mi)
+{
+    return var_GetNonEmptyString (p_mi, "crop");
+}
+
+void libvlc_video_set_crop_geometry( libvlc_media_player_t *p_mi,
+                                     const char *psz_geometry )
+{
+    if (psz_geometry == NULL)
+        psz_geometry = "";
+
+    var_SetString (p_mi, "crop", psz_geometry);
+
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
+
+    for (size_t i = 0; i < n; i++)
+    {
+        vout_thread_t *p_vout = pp_vouts[i];
+        vlc_value_t val;
+
+        /* Make sure the geometry is in the choice list */
+        /* Earlier choices are removed to not grow a long list over time. */
+        /* FIXME: not atomic - lock? */
+        val.psz_string = (char *)psz_geometry;
+        var_Change (p_vout, "crop", VLC_VAR_CLEARCHOICES, NULL, NULL);
+        var_Change (p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &val);
+        var_SetString (p_vout, "crop", psz_geometry);
+        vlc_object_release (p_vout);
+    }
+    free (pp_vouts);
+}
+
+int libvlc_video_get_teletext( libvlc_media_player_t *p_mi )
+{
+    return var_GetInteger (p_mi, "vbi-page");
+}
+
+void libvlc_video_set_teletext( libvlc_media_player_t *p_mi, int i_page )
+{
+    input_thread_t *p_input_thread;
+    vlc_object_t *p_zvbi = NULL;
+    int telx;
+
+    var_SetInteger (p_mi, "vbi-page", i_page);
+
+    p_input_thread = libvlc_get_input_thread( p_mi );
+    if( !p_input_thread ) return;
+
+    if( var_CountChoices( p_input_thread, "teletext-es" ) <= 0 )
+    {
+        vlc_object_release( p_input_thread );
+        return;
+    }
+
+    telx = var_GetInteger( p_input_thread, "teletext-es" );
+    if( input_GetEsObjects( p_input_thread, telx, &p_zvbi, NULL, NULL )
+        == VLC_SUCCESS )
+    {
+        var_SetInteger( p_zvbi, "vbi-page", i_page );
+        vlc_object_release( p_zvbi );
+    }
+    vlc_object_release( p_input_thread );
+}
+
+void libvlc_toggle_teletext( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread(p_mi);
+    if( !p_input_thread ) return;
+
+    if( var_CountChoices( p_input_thread, "teletext-es" ) <= 0 )
+    {
+        vlc_object_release( p_input_thread );
+        return;
+    }
+    const bool b_selected = var_GetInteger( p_input_thread, "teletext-es" ) >= 0;
+    if( b_selected )
+    {
+        var_SetInteger( p_input_thread, "spu-es", -1 );
+    }
+    else
+    {
+        vlc_value_t list;
+        if( !var_Change( p_input_thread, "teletext-es", VLC_VAR_GETLIST, &list, NULL ) )
+        {
+            if( list.p_list->i_count > 0 )
+                var_SetInteger( p_input_thread, "spu-es", list.p_list->p_values[0].i_int );
+
+            var_FreeList( &list, NULL );
+        }
+    }
+    vlc_object_release( p_input_thread );
+}
+
+int libvlc_video_get_track_count( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    int i_track_count;
+
+    if( !p_input_thread )
+        return -1;
+
+    i_track_count = var_CountChoices( p_input_thread, "video-es" );
+
+    vlc_object_release( p_input_thread );
+    return i_track_count;
+}
+
+libvlc_track_description_t *
+        libvlc_video_get_track_description( libvlc_media_player_t *p_mi )
+{
+    return libvlc_get_track_description( p_mi, "video-es" );
+}
+
+int libvlc_video_get_track( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    vlc_value_t val_list;
+    vlc_value_t val;
+    int i_track = -1;
+
+    if( !p_input_thread )
+        return -1;
+
+    if( var_Get( p_input_thread, "video-es", &val ) < 0 )
+    {
+        libvlc_printerr( "Video track information not found" );
+        vlc_object_release( p_input_thread );
+        return -1;
+    }
+
+    var_Change( p_input_thread, "video-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( int i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        if( val_list.p_list->p_values[i].i_int == val.i_int )
+        {
+            i_track = i;
+            break;
+        }
+    }
+    var_FreeList( &val_list, NULL );
+    vlc_object_release( p_input_thread );
+    return i_track;
+}
+
+int libvlc_video_set_track( libvlc_media_player_t *p_mi, int i_track )
+{
+    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
+    vlc_value_t val_list;
+    int i_ret = -1;
+
+    if( !p_input_thread )
+        return -1;
+
+    var_Change( p_input_thread, "video-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( int i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        if( i_track == val_list.p_list->p_values[i].i_int )
+        {
+            if( var_SetInteger( p_input_thread, "video-es", i_track ) < 0 )
+                break;
+            i_ret = 0;
+            goto end;
+        }
+    }
+    libvlc_printerr( "Video track number out of range" );
+end:
+    var_FreeList( &val_list, NULL );
+    vlc_object_release( p_input_thread );
+    return i_ret;
+}
+
+/******************************************************************************
+ * libvlc_video_set_deinterlace : enable deinterlace
+ *****************************************************************************/
+void libvlc_video_set_deinterlace( libvlc_media_player_t *p_mi,
+                                   const char *psz_mode )
+{
+    if (psz_mode == NULL)
+        psz_mode = "";
+    if (*psz_mode
+     && strcmp (psz_mode, "blend")    && strcmp (psz_mode, "bob")
+     && strcmp (psz_mode, "discard")  && strcmp (psz_mode, "linear")
+     && strcmp (psz_mode, "mean")     && strcmp (psz_mode, "x")
+     && strcmp (psz_mode, "yadif")    && strcmp (psz_mode, "yadif2x")
+     && strcmp (psz_mode, "phosphor") && strcmp (psz_mode, "ivtc"))
+        return;
+
+    if (*psz_mode)
+    {
+        var_SetString (p_mi, "deinterlace-mode", psz_mode);
+        var_SetInteger (p_mi, "deinterlace", 1);
+    }
+    else
+        var_SetInteger (p_mi, "deinterlace", 0);
+
+    size_t n;
+    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
+    for (size_t i = 0; i < n; i++)
+    {
+        vout_thread_t *p_vout = pp_vouts[i];
+
+        if (*psz_mode)
+        {
+            var_SetString (p_vout, "deinterlace-mode", psz_mode);
+            var_SetInteger (p_vout, "deinterlace", 1);
+        }
+        else
+            var_SetInteger (p_vout, "deinterlace", 0);
+        vlc_object_release (p_vout);
+    }
+    free (pp_vouts);
+}
+
+/* ************** */
+/* module helpers */
+/* ************** */
+
+
+static vlc_object_t *get_object( libvlc_media_player_t * p_mi,
+                                 const char *name )
+{
+    vlc_object_t *object;
+    vout_thread_t *vout = GetVout( p_mi, 0 );
+
+    if( vout )
+    {
+        object = vlc_object_find_name( vout, name );
+        vlc_object_release(vout);
+    }
+    else
+        object = NULL;
+
+    if( !object )
+        libvlc_printerr( "%s not enabled", name );
+    return object;
+}
+
+
+typedef const struct {
+    const char name[20];
+    unsigned type;
+} opt_t;
+
+
+static void
+set_int( libvlc_media_player_t *p_mi, const char *restrict name,
+         const opt_t *restrict opt, int value )
+{
+    if( !opt ) return;
+
+    if( !opt->type ) /* the enabler */
+    {
+        vout_thread_t *vout = GetVout( p_mi, 0 );
+        if (vout)
+        {
+            vout_EnableFilter( vout, opt->name, value, false );
+            vlc_object_release( vout );
+        }
+        return;
+    }
+
+    if( opt->type != VLC_VAR_INTEGER )
+    {
+        libvlc_printerr( "Invalid argument to %s in %s", name, "set int" );
+        return;
+    }
+
+    var_SetInteger(p_mi, opt->name, value);
+    vlc_object_t *object = get_object( p_mi, name );
+    if( object )
+    {
+        var_SetInteger(object, opt->name, value);
+        vlc_object_release( object );
+    }
+}
+
+
+static int
+get_int( libvlc_media_player_t *p_mi, const char *restrict name,
+         const opt_t *restrict opt )
+{
+    if( !opt ) return 0;
+
+    switch( opt->type )
+    {
+        case 0: /* the enabler */
+        {
+            vlc_object_t *object = get_object( p_mi, name );
+            vlc_object_release( object );
+            return object != NULL;
+        }
+    case VLC_VAR_INTEGER:
+        return var_GetInteger(p_mi, opt->name);
+    default:
+        libvlc_printerr( "Invalid argument to %s in %s", name, "get int" );
+        return 0;
+    }
+}
+
+
+static void
+set_float( libvlc_media_player_t *p_mi, const char *restrict name,
+            const opt_t *restrict opt, float value )
+{
+    if( !opt ) return;
+
+    if( opt->type != VLC_VAR_FLOAT )
+    {
+        libvlc_printerr( "Invalid argument to %s in %s", name, "set float" );
+        return;
+    }
+
+    var_SetFloat( p_mi, opt->name, value );
+
+    vlc_object_t *object = get_object( p_mi, name );
+    if( object )
+    {
+        var_SetFloat(object, opt->name, value );
+        vlc_object_release( object );
+    }
+}
+
+
+static float
+get_float( libvlc_media_player_t *p_mi, const char *restrict name,
+            const opt_t *restrict opt )
+{
+    if( !opt ) return 0.0;
+
+
+    if( opt->type != VLC_VAR_FLOAT )
+    {
+        libvlc_printerr( "Invalid argument to %s in %s", name, "get float" );
+        return 0.0;
+    }
+
+    return var_GetFloat( p_mi, opt->name );
+}
+
+
+static void
+set_string( libvlc_media_player_t *p_mi, const char *restrict name,
+            const opt_t *restrict opt, const char *restrict psz_value )
+{
+    if( !opt ) return;
+
+    if( opt->type != VLC_VAR_STRING )
+    {
+        libvlc_printerr( "Invalid argument to %s in %s", name, "set string" );
+        return;
+    }
+
+    var_SetString( p_mi, opt->name, psz_value );
+
+    vlc_object_t *object = get_object( p_mi, name );
+    if( object )
+    {
+        var_SetString(object, opt->name, psz_value );
+        vlc_object_release( object );
+    }
+}
+
+
+static char *
+get_string( libvlc_media_player_t *p_mi, const char *restrict name,
+            const opt_t *restrict opt )
+{
+    if( !opt ) return NULL;
+
+    if( opt->type != VLC_VAR_STRING )
+    {
+        libvlc_printerr( "Invalid argument to %s in %s", name, "get string" );
+        return NULL;
+    }
+
+    return var_GetString( p_mi, opt->name );
+}
+
+
+static const opt_t *
+marq_option_bynumber(unsigned option)
+{
+    static const opt_t optlist[] =
+    {
+        { "marq",          0 },
+        { "marq-marquee",  VLC_VAR_STRING },
+        { "marq-color",    VLC_VAR_INTEGER },
+        { "marq-opacity",  VLC_VAR_INTEGER },
+        { "marq-position", VLC_VAR_INTEGER },
+        { "marq-refresh",  VLC_VAR_INTEGER },
+        { "marq-size",     VLC_VAR_INTEGER },
+        { "marq-timeout",  VLC_VAR_INTEGER },
+        { "marq-x",        VLC_VAR_INTEGER },
+        { "marq-y",        VLC_VAR_INTEGER },
+    };
+    enum { num_opts = sizeof(optlist) / sizeof(*optlist) };
+
+    const opt_t *r = option < num_opts ? optlist+option : NULL;
+    if( !r )
+        libvlc_printerr( "Unknown marquee option" );
+    return r;
+}
+
+static vlc_object_t *get_object( libvlc_media_player_t *, const char *);
+
+/*****************************************************************************
+ * libvlc_video_get_marquee_int : get a marq option value
+ *****************************************************************************/
+int libvlc_video_get_marquee_int( libvlc_media_player_t *p_mi,
+                                  unsigned option )
+{
+    return get_int( p_mi, "marq", marq_option_bynumber(option) );
+}
+
+/*****************************************************************************
+ * libvlc_video_get_marquee_string : get a marq option value
+ *****************************************************************************/
+char * libvlc_video_get_marquee_string( libvlc_media_player_t *p_mi,
+                                        unsigned option )
+{
+    return get_string( p_mi, "marq", marq_option_bynumber(option) );
+}
+
+/*****************************************************************************
+ * libvlc_video_set_marquee_int: enable, disable or set an int option
+ *****************************************************************************/
+void libvlc_video_set_marquee_int( libvlc_media_player_t *p_mi,
+                         unsigned option, int value )
+{
+    set_int( p_mi, "marq", marq_option_bynumber(option), value );
+}
+
+/*****************************************************************************
+ * libvlc_video_set_marquee_string: set a string option
+ *****************************************************************************/
+void libvlc_video_set_marquee_string( libvlc_media_player_t *p_mi,
+                unsigned option, const char * value )
+{
+    set_string( p_mi, "marq", marq_option_bynumber(option), value );
+}
+
+
+/* logo module support */
+
+
+static const opt_t *
+logo_option_bynumber( unsigned option )
+{
+    static const opt_t vlogo_optlist[] =
+    /* depends on libvlc_video_logo_option_t */
+    {
+        { "logo",          0 },
+        { "logo-file",     VLC_VAR_STRING },
+        { "logo-x",        VLC_VAR_INTEGER },
+        { "logo-y",        VLC_VAR_INTEGER },
+        { "logo-delay",    VLC_VAR_INTEGER },
+        { "logo-repeat",   VLC_VAR_INTEGER },
+        { "logo-opacity",  VLC_VAR_INTEGER },
+        { "logo-position", VLC_VAR_INTEGER },
+    };
+    enum { num_vlogo_opts = sizeof(vlogo_optlist) / sizeof(*vlogo_optlist) };
+
+    const opt_t *r = option < num_vlogo_opts ? vlogo_optlist+option : NULL;
+    if( !r )
+        libvlc_printerr( "Unknown logo option" );
+    return r;
+}
+
+
+void libvlc_video_set_logo_string( libvlc_media_player_t *p_mi,
+                                   unsigned option, const char *psz_value )
+{
+    set_string( p_mi,"logo",logo_option_bynumber(option),psz_value );
+}
+
+
+void libvlc_video_set_logo_int( libvlc_media_player_t *p_mi,
+                                unsigned option, int value )
+{
+    set_int( p_mi, "logo", logo_option_bynumber(option), value );
+}
+
+
+int libvlc_video_get_logo_int( libvlc_media_player_t *p_mi,
+                               unsigned option )
+{
+    return get_int( p_mi, "logo", logo_option_bynumber(option) );
+}
+
+
+/* adjust module support */
+
+
+static const opt_t *
+adjust_option_bynumber( unsigned option )
+{
+    static const opt_t optlist[] =
+    {
+        { "adjust",               0 },
+        { "contrast",             VLC_VAR_FLOAT },
+        { "brightness",           VLC_VAR_FLOAT },
+        { "hue",                  VLC_VAR_INTEGER },
+        { "saturation",           VLC_VAR_FLOAT },
+        { "gamma",                VLC_VAR_FLOAT },
+    };
+    enum { num_opts = sizeof(optlist) / sizeof(*optlist) };
+
+    const opt_t *r = option < num_opts ? optlist+option : NULL;
+    if( !r )
+        libvlc_printerr( "Unknown adjust option" );
+    return r;
+}
+
+
+void libvlc_video_set_adjust_int( libvlc_media_player_t *p_mi,
+                                  unsigned option, int value )
+{
+    set_int( p_mi, "adjust", adjust_option_bynumber(option), value );
+}
+
+
+int libvlc_video_get_adjust_int( libvlc_media_player_t *p_mi,
+                                 unsigned option )
+{
+    return get_int( p_mi, "adjust", adjust_option_bynumber(option) );
+}
+
+
+void libvlc_video_set_adjust_float( libvlc_media_player_t *p_mi,
+                                    unsigned option, float value )
+{
+    set_float( p_mi, "adjust", adjust_option_bynumber(option), value );
+}
+
+
+float libvlc_video_get_adjust_float( libvlc_media_player_t *p_mi,
+                                     unsigned option )
+{
+    return get_float( p_mi, "adjust", adjust_option_bynumber(option) );
+}
diff --git a/lib/vlm.c b/lib/vlm.c
new file mode 100644 (file)
index 0000000..c6d5f36
--- /dev/null
+++ b/lib/vlm.c
@@ -0,0 +1,768 @@
+/*****************************************************************************
+ * vlm.c: libvlc new API VLM handling functions
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Clément Stenac <zorglub@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_vlm.h>
+#include <vlc_es.h>
+#include <vlc_input.h>
+#include <vlc_vlm.h>
+#include <assert.h>
+
+#include "libvlc_internal.h"
+
+/* VLM events callback. Transmit to libvlc */
+static int VlmEvent( vlc_object_t *p_this, const char * name,
+                     vlc_value_t old_val, vlc_value_t newval, void *param )
+{
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(name);
+    VLC_UNUSED(old_val);    
+    vlm_event_t *event = (vlm_event_t*)newval.p_address;
+    libvlc_event_manager_t *p_event_manager = (libvlc_event_manager_t *) param;
+    libvlc_event_t libvlc_event;
+
+    libvlc_event.u.vlm_media_event.psz_instance_name = NULL;
+    libvlc_event.u.vlm_media_event.psz_media_name = event->psz_name;
+
+    switch( event->i_type )
+    {
+    case VLM_EVENT_MEDIA_ADDED:
+        libvlc_event.type = libvlc_VlmMediaAdded;
+        break;
+    case VLM_EVENT_MEDIA_REMOVED:
+        libvlc_event.type = libvlc_VlmMediaRemoved;
+        break;
+    case VLM_EVENT_MEDIA_CHANGED:
+        libvlc_event.type = libvlc_VlmMediaChanged;
+        break;
+    case VLM_EVENT_MEDIA_INSTANCE_STARTED:
+        libvlc_event.type = libvlc_VlmMediaInstanceStarted;
+        break;
+    case VLM_EVENT_MEDIA_INSTANCE_STOPPED:
+        libvlc_event.type = libvlc_VlmMediaInstanceStopped;
+        break;
+    case VLM_EVENT_MEDIA_INSTANCE_STATE:
+        libvlc_event.u.vlm_media_event.psz_instance_name =
+            event->psz_instance_name;
+        switch( event->input_state )
+        {
+        case INIT_S:
+            libvlc_event.type = libvlc_VlmMediaInstanceStatusInit;
+            break;
+        case OPENING_S:
+            libvlc_event.type =
+                libvlc_VlmMediaInstanceStatusOpening;
+            break;
+        case PLAYING_S:
+            libvlc_event.type =
+                libvlc_VlmMediaInstanceStatusPlaying;
+            break;
+        case PAUSE_S:
+            libvlc_event.type = libvlc_VlmMediaInstanceStatusPause;
+            break;
+        case END_S:
+            libvlc_event.type = libvlc_VlmMediaInstanceStatusEnd;
+            break;
+        case ERROR_S:
+            libvlc_event.type = libvlc_VlmMediaInstanceStatusError;
+            break;
+        default:
+            return 0;
+        }
+        break;
+    default:
+        return 0;
+    }
+    libvlc_event_send( p_event_manager, &libvlc_event );
+    return 0;
+}
+
+static void libvlc_vlm_release_internal( libvlc_instance_t *p_instance )
+{
+    vlm_t *p_vlm = p_instance->libvlc_vlm.p_vlm;
+    if( !p_instance->libvlc_vlm.p_vlm )
+        return;
+    /* We need to remove medias in order to receive events */
+    vlm_Control( p_vlm, VLM_CLEAR_MEDIAS );
+    vlm_Control( p_vlm, VLM_CLEAR_SCHEDULES );
+
+    var_DelCallback( (vlc_object_t *)p_vlm, "intf-event", VlmEvent,
+                     p_instance->libvlc_vlm.p_event_manager );
+    p_instance->libvlc_vlm.pf_release = NULL;
+    libvlc_event_manager_release( p_instance->libvlc_vlm.p_event_manager );
+    p_instance->libvlc_vlm.p_event_manager = NULL;
+    vlm_Delete( p_vlm );
+    p_instance->libvlc_vlm.p_vlm = NULL;
+}
+
+static int libvlc_vlm_init( libvlc_instance_t *p_instance )
+{
+    if( !p_instance->libvlc_vlm.p_event_manager )
+    {
+        p_instance->libvlc_vlm.p_event_manager =
+            libvlc_event_manager_new( p_instance->libvlc_vlm.p_vlm, p_instance );
+        if( unlikely(p_instance->libvlc_vlm.p_event_manager == NULL) )
+            return VLC_ENOMEM;
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaAdded );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaRemoved );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaChanged );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStarted );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStopped );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStatusInit );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStatusOpening );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStatusPlaying );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStatusPause );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStatusEnd );
+        libvlc_event_manager_register_event_type(
+            p_instance->libvlc_vlm.p_event_manager,
+            libvlc_VlmMediaInstanceStatusError );
+    }
+
+    if( !p_instance->libvlc_vlm.p_vlm )
+    {
+        p_instance->libvlc_vlm.p_vlm = vlm_New( p_instance->p_libvlc_int );
+        if( !p_instance->libvlc_vlm.p_vlm )
+        {
+            libvlc_printerr( "VLM not supported or out of memory" );
+            return VLC_EGENERIC;
+        }
+        var_AddCallback( (vlc_object_t *)p_instance->libvlc_vlm.p_vlm,
+                         "intf-event", VlmEvent,
+                         p_instance->libvlc_vlm.p_event_manager );
+        p_instance->libvlc_vlm.pf_release = libvlc_vlm_release_internal;
+    }
+
+    return VLC_SUCCESS;
+}
+
+void libvlc_vlm_release( libvlc_instance_t *p_instance )
+{
+    libvlc_vlm_release_internal( p_instance );
+}
+
+#define VLM_RET(p,ret) do { \
+    if( libvlc_vlm_init( p_instance ) ) \
+        return (ret); \
+    (p) = p_instance->libvlc_vlm.p_vlm; \
+  } while(0)
+
+static vlm_media_instance_t *
+libvlc_vlm_get_media_instance( libvlc_instance_t *p_instance,
+                               const char *psz_name, int i_minstance_idx )
+{
+    vlm_t *p_vlm;
+    vlm_media_instance_t **pp_minstance;
+    vlm_media_instance_t *p_minstance;
+    int i_minstance;
+    int64_t id;
+
+    VLM_RET(p_vlm, NULL);
+
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
+        vlm_Control( p_vlm, VLM_GET_MEDIA_INSTANCES, id, &pp_minstance,
+                     &i_minstance ) )
+    {
+        libvlc_printerr( "%s: media instances not found", psz_name );
+        return NULL;
+    }
+    p_minstance = NULL;
+    if( i_minstance_idx >= 0 && i_minstance_idx < i_minstance )
+    {
+        p_minstance = pp_minstance[i_minstance_idx];
+        TAB_REMOVE( i_minstance, pp_minstance, p_minstance );
+    }
+    while( i_minstance > 0 )
+        vlm_media_instance_Delete( pp_minstance[--i_minstance] );
+    TAB_CLEAN( i_minstance, pp_minstance );
+    return p_minstance;
+}
+
+/* local function to be used in libvlc_vlm_show_media only */
+static char* recurse_answer( vlm_message_t *p_answer, const char* psz_delim,
+                             const int i_list ) {
+    char* psz_childdelim = NULL;
+    char* psz_nametag = NULL;
+    char* psz_response = strdup( "" );
+    char *psz_tmp;
+    int i_success = 0;
+    int i;
+    vlm_message_t *aw_child, **paw_child;
+
+    i_success = asprintf( &psz_childdelim, "%s\t", psz_delim);
+    if( i_success == -1 )
+        return psz_response;
+
+    paw_child = p_answer->child;
+    aw_child = *( paw_child );
+    /* Iterate over children */
+    for( i = 0; i < p_answer->i_child; i++ )
+    {
+        /* Spare comma if it is the last element */
+        char c_comma = ',';
+        if( i == (p_answer->i_child - 1) )
+            c_comma = ' ';
+
+        /* Append name of child node, if not in a list */
+        if( !i_list )
+        {
+            i_success = asprintf( &psz_tmp, "%s\"%s\": ",
+                          psz_response, aw_child->psz_name );
+            if( i_success == -1 ) break;
+            free( psz_response );
+            psz_response = psz_tmp;
+        }
+
+        /* If child node has children, */
+        if( aw_child->i_child )
+        {
+            /* If the parent node is a list (hence the child node is
+             * inside a list), create a property of its name as if it
+             * had a name value node
+             */
+            if( i_list )
+            {
+                i_success = asprintf( &psz_nametag, "\"name\": \"%s\",%s",
+                              aw_child->psz_name, psz_childdelim );
+                if( i_success == -1 ) break;
+            }
+            else
+            {
+                psz_nametag = strdup( "" );
+            }
+            /* If the child is a list itself, format it accordingly and
+             * recurse through the child's children, telling them that
+             * they are inside a list.
+             */
+            if( strcmp( aw_child->psz_name, "media" ) == 0 ||
+                strcmp( aw_child->psz_name, "inputs" ) == 0 ||
+                strcmp( aw_child->psz_name, "options" ) == 0 )
+            {
+                char *psz_recurse = recurse_answer( aw_child, psz_childdelim, 1 ),
+                i_success = asprintf( &psz_tmp, "%s[%s%s%s]%c%s",
+                                      psz_response, psz_childdelim, psz_recurse,
+                                      psz_delim, c_comma, psz_delim );
+                free( psz_recurse );
+                if( i_success == -1 ) break;
+                free( psz_response );
+                psz_response = psz_tmp;
+            }
+            /* Not a list, so format the child as a JSON object and
+             * recurse through the child's children
+             */
+            else
+            {
+                char *psz_recurse = recurse_answer( aw_child, psz_childdelim, 0 ),
+                i_success = asprintf( &psz_tmp, "%s{%s%s%s%s}%c%s",
+                                      psz_response, psz_childdelim, psz_nametag,
+                                      psz_recurse, psz_delim, c_comma, psz_delim );
+                free( psz_recurse );
+                if( i_success == -1 ) break;
+                free( psz_response );
+                psz_response = psz_tmp;
+            }
+        }
+        /* Otherwise - when no children are present - the node is a
+         * value node. So print the value string
+         */
+        else
+        {
+            /* If value is equivalent to NULL, print it as null */
+            if( aw_child->psz_value == NULL
+                || strcmp( aw_child->psz_value, "(null)" ) == 0 )
+            {
+                i_success = asprintf( &psz_tmp, "%snull%c%s",
+                                      psz_response, c_comma, psz_delim );
+                if( i_success == -1 ) break;
+                free( psz_response );
+                psz_response = psz_tmp;
+            }
+            /* Otherwise print the value in quotation marks */
+            else
+            {
+                i_success = asprintf( &psz_tmp, "%s\"%s\"%c%s",
+                                      psz_response, aw_child->psz_value,
+                                      c_comma, psz_delim );
+                if( i_success == -1 ) break;
+                free( psz_response );
+                psz_response = psz_tmp;
+            }
+        }
+        /* getting next child */
+        paw_child++;
+        aw_child = *( paw_child );
+    }
+    free( psz_nametag );
+    free( psz_childdelim );
+    if( i_success == -1 )
+    {
+        free( psz_response );
+        psz_response = strdup( "" );
+    }
+    return psz_response;
+}
+
+const char* libvlc_vlm_show_media( libvlc_instance_t *p_instance,
+                                   const char *psz_name )
+{
+    char *psz_message = NULL;
+    vlm_message_t *answer = NULL;
+    char *psz_response = NULL;
+    const char *psz_fmt = NULL;
+    const char *psz_delimiter = NULL;
+    int i_list;
+    vlm_t *p_vlm = NULL;
+
+    VLM_RET(p_vlm, NULL);
+
+    assert( psz_name );
+
+    if( asprintf( &psz_message, "show %s", psz_name ) == -1 )
+        return NULL;
+
+    vlm_ExecuteCommand( p_vlm, psz_message, &answer );
+    if( answer->psz_value )
+    {
+        libvlc_printerr( "Unable to call show %s: %s",
+                         psz_name, answer->psz_value );
+    }
+    else if ( answer->child )
+    {   /* in case everything was requested  */
+        if ( strcmp( psz_name, "" ) == 0 )
+        {
+            psz_fmt = "{\n\t%s\n}\n";
+            psz_delimiter = "\n\t";
+            i_list = 0;
+        }
+        else
+        {
+            psz_fmt = "%s\n";
+            psz_delimiter = "\n";
+            i_list = 1;
+        }
+        char *psz_tmp = recurse_answer( answer, psz_delimiter, i_list );
+        if( asprintf( &psz_response, psz_fmt, psz_tmp ) == -1 )
+        {
+            libvlc_printerr( "Out of memory" );
+            psz_response = NULL;
+        }
+        free( psz_tmp );
+    }
+    free( psz_message );
+    return( psz_response );
+}
+
+
+int libvlc_vlm_add_broadcast( libvlc_instance_t *p_instance,
+                              const char *psz_name,
+                              const char *psz_input,
+                              const char *psz_output, int i_options,
+                              const char * const *ppsz_options,
+                              int b_enabled, int b_loop )
+{
+    vlm_t *p_vlm;
+    vlm_media_t m;
+    int n;
+
+    VLM_RET(p_vlm, -1);
+
+    vlm_media_Init( &m );
+    m.psz_name = strdup( psz_name );
+    m.b_enabled = b_enabled;
+    m.b_vod = false;
+    m.broadcast.b_loop = b_loop;
+    if( psz_input )
+        TAB_APPEND( m.i_input, m.ppsz_input, strdup(psz_input) );
+    if( psz_output )
+        m.psz_output = strdup( psz_output );
+    for( n = 0; n < i_options; n++ )
+        TAB_APPEND( m.i_option, m.ppsz_option, strdup(ppsz_options[n]) );
+
+    n = vlm_Control( p_vlm, VLM_ADD_MEDIA, &m, NULL );
+    vlm_media_Clean( &m );
+    if( n )
+    {
+        libvlc_printerr( "Media %s creation failed", psz_name );
+        return -1;
+    }
+    return 0;
+}
+
+int libvlc_vlm_add_vod( libvlc_instance_t *p_instance, const char *psz_name,
+                        const char *psz_input, int i_options,
+                        const char * const *ppsz_options, int b_enabled,
+                        const char *psz_mux )
+{
+    vlm_t *p_vlm;
+    vlm_media_t m;
+    int n;
+
+    VLM_RET(p_vlm, -1);
+
+    vlm_media_Init( &m );
+    m.psz_name = strdup( psz_name );
+    m.b_enabled = b_enabled;
+    m.b_vod = true;
+    m.vod.psz_mux = psz_mux ? strdup( psz_mux ) : NULL;
+    if( psz_input )
+        TAB_APPEND( m.i_input, m.ppsz_input, strdup(psz_input) );
+    for( n = 0; n < i_options; n++ )
+        TAB_APPEND( m.i_option, m.ppsz_option, strdup(ppsz_options[n]) );
+
+    n = vlm_Control( p_vlm, VLM_ADD_MEDIA, &m, NULL );
+    vlm_media_Clean( &m );
+    if( n )
+    {
+        libvlc_printerr( "Media %s creation failed", psz_name );
+        return -1;
+    }
+    return 0;
+}
+
+int libvlc_vlm_del_media( libvlc_instance_t *p_instance, const char *psz_name )
+{
+    vlm_t *p_vlm;
+    int64_t id;
+
+    VLM_RET(p_vlm, -1);
+
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
+        vlm_Control( p_vlm, VLM_DEL_MEDIA, id ) )
+    {
+        libvlc_printerr( "Unable to delete %s", psz_name );
+        return -1;
+    }
+    return 0;
+}
+
+static vlm_media_t *get_media( libvlc_instance_t *p_instance,
+                               vlm_t **restrict pp_vlm, const char *name )
+{
+    vlm_media_t *p_media;
+    vlm_t *p_vlm;
+    int64_t id;
+
+    VLM_RET(p_vlm, NULL);
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, name, &id ) ||
+        vlm_Control( p_vlm, VLM_GET_MEDIA, id, &p_media ) )
+        return NULL;
+    *pp_vlm = p_vlm;
+    return p_media;
+}
+
+#define VLM_CHANGE(psz_error, code ) do {   \
+    vlm_t *p_vlm;           \
+    vlm_media_t *p_media = get_media( p_instance, &p_vlm, psz_name ); \
+    if( p_media != NULL ) { \
+        code;               \
+        if( vlm_Control( p_vlm, VLM_CHANGE_MEDIA, p_media ) )       \
+            p_vlm = NULL;                                           \
+        vlm_media_Delete( p_media );                                \
+        if( p_vlm != NULL ) \
+            return 0;       \
+    }                       \
+    libvlc_printerr( psz_error, psz_name );                         \
+    return -1;              \
+  } while(0)
+
+int libvlc_vlm_set_enabled( libvlc_instance_t *p_instance,
+                            const char *psz_name, int b_enabled )
+{
+#define VLM_CHANGE_CODE { p_media->b_enabled = b_enabled; }
+    VLM_CHANGE( "Unable to delete %s", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_set_loop( libvlc_instance_t *p_instance, const char *psz_name,
+                         int b_loop )
+{
+#define VLM_CHANGE_CODE { p_media->broadcast.b_loop = b_loop; }
+    VLM_CHANGE( "Unable to change %s loop property", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_set_mux( libvlc_instance_t *p_instance, const char *psz_name,
+                        const char *psz_mux )
+{
+#define VLM_CHANGE_CODE { if( p_media->b_vod ) { \
+                            free( p_media->vod.psz_mux ); \
+                            p_media->vod.psz_mux = psz_mux \
+                                 ? strdup( psz_mux ) : NULL; \
+                          } }
+    VLM_CHANGE( "Unable to change %s mux property", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_set_output( libvlc_instance_t *p_instance,
+                           const char *psz_name, const char *psz_output )
+{
+#define VLM_CHANGE_CODE { free( p_media->psz_output ); \
+                          p_media->psz_output = strdup( psz_output ); }
+    VLM_CHANGE( "Unable to change %s output property", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_set_input( libvlc_instance_t *p_instance,
+                          const char *psz_name, const char *psz_input )
+{
+#define VLM_CHANGE_CODE { while( p_media->i_input > 0 ) \
+                            free( p_media->ppsz_input[--p_media->i_input] );\
+                          TAB_APPEND( p_media->i_input, p_media->ppsz_input, \
+                                      strdup(psz_input) ); }
+    VLM_CHANGE( "Unable to change %s input property", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_add_input( libvlc_instance_t *p_instance,
+                          const char *psz_name, const char *psz_input )
+{
+#define VLM_CHANGE_CODE { TAB_APPEND( p_media->i_input, p_media->ppsz_input, \
+                          strdup(psz_input) ); }
+    VLM_CHANGE( "Unable to change %s input property", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_change_media( libvlc_instance_t *p_instance,
+                             const char *psz_name, const char *psz_input,
+                             const char *psz_output, int i_options,
+                             const char * const *ppsz_options, int b_enabled,
+                             int b_loop )
+{
+#define VLM_CHANGE_CODE { int n;        \
+    p_media->b_enabled = b_enabled;     \
+    p_media->broadcast.b_loop = b_loop; \
+    while( p_media->i_input > 0 )       \
+        free( p_media->ppsz_input[--p_media->i_input] );    \
+    if( psz_input )                     \
+        TAB_APPEND( p_media->i_input, p_media->ppsz_input, strdup(psz_input) ); \
+    free( p_media->psz_output );        \
+    p_media->psz_output = psz_output ? strdup( psz_output ) : NULL; \
+    while( p_media->i_option > 0 )     \
+        free( p_media->ppsz_option[--p_media->i_option] );        \
+    for( n = 0; n < i_options; n++ )    \
+        TAB_APPEND( p_media->i_option, p_media->ppsz_option, \
+                    strdup(ppsz_options[n]) );   \
+  }
+    VLM_CHANGE( "Unable to change %s properties", VLM_CHANGE_CODE );
+#undef VLM_CHANGE_CODE
+}
+
+int libvlc_vlm_play_media( libvlc_instance_t *p_instance,
+                           const char *psz_name )
+{
+    vlm_t *p_vlm;
+    int64_t id;
+
+    VLM_RET(p_vlm, -1);
+
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
+        vlm_Control( p_vlm, VLM_START_MEDIA_BROADCAST_INSTANCE, id, NULL, 0 ) )
+    {
+        libvlc_printerr( "Unable to play %s", psz_name );
+        return -1;
+    }
+    return 0;
+}
+
+int libvlc_vlm_stop_media( libvlc_instance_t *p_instance,
+                           const char *psz_name )
+{
+    vlm_t *p_vlm;
+    int64_t id;
+
+    VLM_RET(p_vlm, -1);
+
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
+        vlm_Control( p_vlm, VLM_STOP_MEDIA_INSTANCE, id, NULL ) )
+    {
+        libvlc_printerr( "Unable to stop %s", psz_name );
+        return -1;
+    }
+    return 0;
+}
+
+int libvlc_vlm_pause_media( libvlc_instance_t *p_instance,
+                            const char *psz_name )
+{
+    vlm_t *p_vlm;
+    int64_t id;
+
+    VLM_RET(p_vlm, -1);
+
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
+        vlm_Control( p_vlm, VLM_PAUSE_MEDIA_INSTANCE, id, NULL ) )
+    {
+        libvlc_printerr( "Unable to pause %s", psz_name );
+        return -1;
+    }
+    return 0;
+}
+
+int libvlc_vlm_seek_media( libvlc_instance_t *p_instance,
+                           const char *psz_name, float f_percentage )
+{
+    vlm_t *p_vlm;
+    int64_t id;
+
+    VLM_RET(p_vlm, -1);
+
+    if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
+        vlm_Control( p_vlm, VLM_SET_MEDIA_INSTANCE_POSITION, id, NULL,
+                     f_percentage ) )
+    {
+        libvlc_printerr( "Unable to seek %s to %f%%", psz_name, f_percentage );
+        return -1;
+    }
+    return 0;
+}
+
+float libvlc_vlm_get_media_instance_position( libvlc_instance_t *p_instance,
+                                              const char *psz_name,
+                                              int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+    float result = -1.;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name, i_instance );
+    if( p_mi )
+    {
+        result = p_mi->d_position;
+        vlm_media_instance_Delete( p_mi );
+    }
+    return result;
+}
+
+int libvlc_vlm_get_media_instance_time( libvlc_instance_t *p_instance,
+                                        const char *psz_name, int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+    int result = -1;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name, i_instance );
+    if( p_mi )
+    {
+        result = p_mi->i_time;
+        vlm_media_instance_Delete( p_mi );
+    }
+    return result;
+}
+
+int libvlc_vlm_get_media_instance_length( libvlc_instance_t *p_instance,
+                                          const char *psz_name,
+                                          int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+    int result = -1;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name, i_instance );
+    if( p_mi )
+    {
+        result = p_mi->i_length;
+        vlm_media_instance_Delete( p_mi );
+    }
+    return result;
+}
+
+int libvlc_vlm_get_media_instance_rate( libvlc_instance_t *p_instance,
+                                        const char *psz_name, int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+    int result = -1;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name, i_instance );
+    if( p_mi )
+    {
+        result = p_mi->i_rate;
+        vlm_media_instance_Delete( p_mi );
+    }
+    return result;
+}
+
+#if 0
+int libvlc_vlm_get_media_instance_title( libvlc_instance_t *p_instance,
+                                         const char *psz_name, int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name, i_instance );
+    if( p_mi )
+        vlm_media_instance_Delete( p_mi );
+    return p_mi ? 0 : -1;
+}
+
+int libvlc_vlm_get_media_instance_chapter( libvlc_instance_t *p_instance,
+                                           const char *psz_name,
+                                           int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
+                                          i_instance );
+    if( p_mi )
+        vlm_media_instance_Delete( p_mi );
+    return p_mi ? 0 : -1;
+}
+
+int libvlc_vlm_get_media_instance_seekable( libvlc_instance_t *p_instance,
+                                            const char *psz_name,
+                                            int i_instance )
+{
+    vlm_media_instance_t *p_mi;
+
+    p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name, i_instance );
+    if( p_mi )
+        vlm_media_instance_Delete( p_mi );
+    return p_mi ? 0 : -1;
+}
+#endif
+
+libvlc_event_manager_t *
+libvlc_vlm_get_event_manager( libvlc_instance_t *p_instance )
+{
+    vlm_t *p_vlm;
+    VLM_RET( p_vlm, NULL);
+    return p_instance->libvlc_vlm.p_event_manager;
+}
index bd8d1a0..8f3cd21 100644 (file)
@@ -322,7 +322,7 @@ static bool active = false;
 
 #ifdef Q_WS_MAC
 /* Used to abort the app.exec() on OSX after libvlc_Quit is called */
-#include "../../../src/control/libvlc_internal.h" /* libvlc_SetExitHandler */
+#include "../../../lib/libvlc_internal.h" /* libvlc_SetExitHandler */
 static void Abort( void *obj )
 {
     QVLCApp::triggerQuit();
index a0b6fdb..bc0b1da 100644 (file)
@@ -78,21 +78,6 @@ src/config/core.c
 src/config/file.c
 src/config/help.c
 src/config/intf.c
-src/control/audio.c
-src/control/core.c
-src/control/event.c
-src/control/libvlc_internal.h
-src/control/log.c
-src/control/media.c
-src/control/media_discoverer.c
-src/control/media_library.c
-src/control/media_list.c
-src/control/media_list_path.h
-src/control/media_list_player.c
-src/control/media_player.c
-src/control/playlist.c
-src/control/video.c
-src/control/vlm.c
 src/extras/libc.c
 src/extras/tdestroy.c
 src/input/access.c
@@ -184,6 +169,22 @@ src/video_output/vout_internal.h
 src/video_output/vout_intf.c
 src/video_output/vout_subpictures.c
 
+lib/audio.c
+lib/core.c
+lib/event.c
+lib/libvlc_internal.h
+lib/log.c
+lib/media.c
+lib/media_discoverer.c
+lib/media_library.c
+lib/media_list.c
+lib/media_list_path.h
+lib/media_list_player.c
+lib/media_player.c
+lib/playlist.c
+lib/video.c
+lib/vlm.c
+
 # modules
 modules/3dnow/memcpy.c
 modules/access/alsa.c
index c2401a3..3210814 100644 (file)
@@ -7,16 +7,11 @@ SUBDIRS = . test
 
 NULL =
 EXTRA_DIST = \
-       libvlc.pc.in \
        vlc-plugin.pc.in \
-       libvlc.sym \
        libvlccore.sym \
-       revision.txt \
-       ../include/vlc/libvlc_version.h.in
+       revision.txt
 
-BUILT_SOURCES = \
-       $(nodist_pkginclude_HEADERS) \
-       $(nodist_pluginsinclude_HEADERS)
+BUILT_SOURCES = $(nodist_pluginsinclude_HEADERS)
 CLEANFILES = $(BUILT_SOURCES)
 
 SUFFIXES = .pc.in .pc .rc.in .rc
@@ -27,22 +22,6 @@ SUFFIXES = .pc.in .pc .rc.in .rc
 
 pluginsincludedir = $(pkgincludedir)/plugins
 
-pkginclude_HEADERS = \
-       ../include/vlc/vlc.h \
-       ../include/vlc/deprecated.h \
-       ../include/vlc/libvlc.h \
-       ../include/vlc/libvlc_events.h \
-       ../include/vlc/libvlc_media.h \
-       ../include/vlc/libvlc_media_discoverer.h \
-       ../include/vlc/libvlc_media_library.h \
-       ../include/vlc/libvlc_media_list.h \
-       ../include/vlc/libvlc_media_list_player.h \
-       ../include/vlc/libvlc_media_player.h \
-       ../include/vlc/libvlc_structures.h \
-       ../include/vlc/libvlc_vlm.h \
-       $(NULL)
-nodist_pkginclude_HEADERS = ../include/vlc/libvlc_version.h
-
 pluginsinclude_HEADERS = \
        ../include/vlc_access.h \
        ../include/vlc_acl.h \
@@ -138,10 +117,6 @@ noinst_HEADERS = \
        ../include/vlc_windows_interfaces.h \
        $(NULL)
 
-../include/vlc/libvlc_version.h: ../include/vlc/libvlc_version.h.in $(top_builddir)/config.status
-       $(AM_V_GEN)cd "$(top_builddir)" && \
-       $(SHELL) ./config.status --file="src/$@"
-
 ../include/vlc_about.h: Makefile.am $(top_srcdir)/COPYING $(top_srcdir)/THANKS $(top_srcdir)/AUTHORS
        $(AM_V_at)rm -f -- "$@.tmp"
        $(AM_V_at)mkdir -p -- ../include
@@ -164,7 +139,7 @@ noinst_HEADERS = \
 ###############################################################################
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libvlc.pc vlc-plugin.pc
+pkgconfig_DATA = vlc-plugin.pc
 CLEANFILES += $(pkgconfig_DATA)
 
 .pc.in.pc: $(top_builddir)/config.status
@@ -188,25 +163,20 @@ EXTRA_DIST += libvlc_win32_rc.rc.in
 # Building libvlc
 ###############################################################################
 
-lib_LTLIBRARIES = libvlccore.la libvlc.la
-
-AM_LDFLAGS = -no-undefined
-if HAVE_WIN32
-AM_LDFLAGS += -avoid-version
-endif
-if HAVE_WINCE
-AM_LDFLAGS += -avoid-version
-endif
+lib_LTLIBRARIES = libvlccore.la
 
-libvlccore_la_SOURCES = $(SOURCES_libvlc)
-libvlccore_la_CPPFLAGS = $(INCICONV) \
+AM_CPPFLAGS = $(INCICONV) \
        -DMODULE_STRING=\"main\" \
        -DLOCALEDIR=\"$(localedir)\" \
        -DSYSCONFDIR=\"$(sysconfdir)\" \
        -DDATA_PATH=\"$(vlcdatadir)\" \
        -DPKGLIBDIR=\"$(vlclibdir)\"
-libvlccore_la_CFLAGS = $(CFLAGS_libvlccore)
-libvlccore_la_LDFLAGS = $(LDFLAGS_libvlccore) $(AM_LDFLAGS) \
+AM_CFLAGS = $(CFLAGS_libvlccore)
+
+libvlccore_la_SOURCES = $(SOURCES_libvlc)
+libvlccore_la_LDFLAGS = \
+       -no-undefined \
+       $(LDFLAGS_libvlccore) \
        -no-undefined \
        -export-symbols $(srcdir)/libvlccore.sym \
        -version-info 5:0:0
@@ -217,27 +187,12 @@ libvlccore_la_LIBADD = $(LIBS_libvlccore) \
 libvlccore_la_DEPENDENCIES = libvlccore.sym
 if HAVE_WIN32
 libvlccore_la_DEPENDENCIES += libvlc_win32_rc.$(OBJEXT)
-libvlccore_la_LDFLAGS += -Wl,libvlc_win32_rc.$(OBJEXT)
+libvlccore_la_LDFLAGS += -Wl,libvlc_win32_rc.$(OBJEXT) -avoid-version
 endif
 
 libvlc_win32_rc.$(OBJEXT): libvlc_win32_rc.rc
        $(WINDRES) --include-dir $(top_srcdir)/share -i $< -o $@
 
-libvlc_la_SOURCES = $(SOURCES_libvlc_control)
-libvlc_la_LIBADD = $(LIBS_libvlc) \
-       libvlccore.la ../compat/libcompat.la
-libvlc_la_CPPFLAGS = -DMODULE_STRING=\"libvlc\"
-libvlc_la_CFLAGS = $(CFLAGS_libvlc)
-libvlc_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_libvlc) \
-       -version-info 6:0:1 \
-       -export-symbols $(srcdir)/libvlc.sym
-libvlc_la_DEPENDENCIES = libvlc.sym libvlccore.la
-if HAVE_WIN32
-libvlc_la_DEPENDENCIES += libvlc_win32_rc.$(OBJEXT)
-libvlc_la_LDFLAGS += -Wl,libvlc_win32_rc.$(OBJEXT)
-endif
-
-
 EXTRA_libvlccore_la_SOURCES = \
        $(SOURCES_libvlc_darwin) \
        $(SOURCES_libvlc_linux) \
@@ -511,30 +466,6 @@ SOURCES_libvlc = \
        $(SOURCES_libvlc_common) \
        $(NULL)
 
-SOURCES_libvlc_control = \
-       revision.c \
-       control/libvlc_internal.h \
-       control/event_internal.h \
-       control/media_internal.h \
-       control/media_list_internal.h \
-       control/media_player_internal.h \
-       control/core.c \
-       control/error.c \
-       control/log.c \
-       control/playlist.c \
-       control/vlm.c \
-       control/video.c \
-       control/audio.c \
-       control/event.c \
-       control/event_async.c \
-       control/media.c \
-       control/media_player.c \
-       control/media_list.c \
-       control/media_list_path.h \
-       control/media_list_player.c \
-       control/media_library.c \
-       control/media_discoverer.c
-
 ###############################################################################
 # libvlc pulse
 ###############################################################################
@@ -593,7 +524,6 @@ check-local:
                        exit 1; \
                fi ; \
        done
-       $(srcdir)/check_headers $(pkginclude_HEADERS)
        $(srcdir)/check_headers $(pluginsinclude_HEADERS)
 
 FORCE:
diff --git a/src/control/audio.c b/src/control/audio.c
deleted file mode 100644 (file)
index c7d1ba1..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-/*****************************************************************************
- * libvlc_audio.c: New libvlc audio control API
- *****************************************************************************
- * Copyright (C) 2006 the VideoLAN team
- * $Id$
- *
- * Authors: Filippo Carone <filippo@carone.org>
- *          Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <assert.h>
-
-#include <vlc/libvlc.h>
-#include <vlc/libvlc_media.h>
-#include <vlc/libvlc_media_player.h>
-
-#include <vlc_common.h>
-#include <vlc_input.h>
-#include <vlc_aout_intf.h>
-#include <vlc_aout.h>
-#include <vlc_modules.h>
-
-#include "libvlc_internal.h"
-#include "media_player_internal.h"
-
-/*
- * Remember to release the returned audio_output_t since it is locked at
- * the end of this function.
- */
-static audio_output_t *GetAOut( libvlc_media_player_t *mp )
-{
-    assert( mp != NULL );
-
-    input_thread_t *p_input = libvlc_get_input_thread( mp );
-    if( p_input == NULL )
-        return NULL;
-
-    audio_output_t * p_aout = input_GetAout( p_input );
-    vlc_object_release( p_input );
-    if( p_aout == NULL )
-        libvlc_printerr( "No active audio output" );
-    return p_aout;
-}
-
-/*****************************************
- * Get the list of available audio outputs
- *****************************************/
-libvlc_audio_output_t *
-        libvlc_audio_output_list_get( libvlc_instance_t *p_instance )
-{
-    VLC_UNUSED( p_instance );
-    libvlc_audio_output_t *p_list = NULL,
-                          *p_actual = NULL,
-                          *p_previous = NULL;
-    module_t **module_list = module_list_get( NULL );
-
-    for (size_t i = 0; module_list[i]; i++)
-    {
-        module_t *p_module = module_list[i];
-
-        if( module_provides( p_module, "audio output" ) )
-        {
-            if( p_actual == NULL)
-            {
-                p_actual = ( libvlc_audio_output_t * )
-                    malloc( sizeof( libvlc_audio_output_t ) );
-                if( p_actual == NULL )
-                {
-                    libvlc_printerr( "Not enough memory" );
-                    libvlc_audio_output_list_release( p_list );
-                    module_list_free( module_list );
-                    return NULL;
-                }
-                if( p_list == NULL )
-                {
-                    p_list = p_actual;
-                    p_previous = p_actual;
-                }
-            }
-            p_actual->psz_name = strdup( module_get_object( p_module ) );
-            p_actual->psz_description = strdup( module_get_name( p_module, true )  );
-            p_actual->p_next = NULL;
-            if( p_previous != p_actual ) /* not first item */
-                p_previous->p_next = p_actual;
-            p_previous = p_actual;
-            p_actual = p_actual->p_next;
-        }
-    }
-
-    module_list_free( module_list );
-
-    return p_list;
-}
-
-/********************************************
- * Free the list of available audio outputs
- ***********************************************/
-void libvlc_audio_output_list_release( libvlc_audio_output_t *p_list )
-{
-    libvlc_audio_output_t *p_actual, *p_before;
-    p_actual = p_list;
-
-    while ( p_actual )
-    {
-        free( p_actual->psz_name );
-        free( p_actual->psz_description );
-        p_before = p_actual;
-        p_actual = p_before->p_next;
-        free( p_before );
-    }
-}
-
-
-/***********************
- * Set the audio output.
- ***********************/
-int libvlc_audio_output_set( libvlc_media_player_t *mp, const char *psz_name )
-{
-    char *value;
-
-    if( !module_exists( psz_name )
-     || asprintf( &value, "%s,none", psz_name ) == -1 )
-        return -1;
-    var_SetString( mp, "aout", value );
-    free( value );
-    return 0;
-}
-
-/****************************
- * Get count of devices.
- *****************************/
-int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
-                                      const char *psz_audio_output )
-{
-    char *psz_config_name;
-    if( !psz_audio_output )
-        return 0;
-    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
-        return 0;
-
-    module_config_t *p_module_config = config_FindConfig(
-        VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
-
-    if( p_module_config && p_module_config->pf_update_list )
-    {
-        vlc_value_t val;
-        val.psz_string = strdup( p_module_config->value.psz );
-
-        p_module_config->pf_update_list(
-            VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
-        free( val.psz_string );
-        free( psz_config_name );
-
-        return p_module_config->i_list;
-    }
-
-    free( psz_config_name );
-    return 0;
-}
-
-/********************************
- * Get long name of device
- *********************************/
-char * libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
-                                            const char *psz_audio_output,
-                                            int i_device )
-{
-    char *psz_config_name;
-    if( !psz_audio_output )
-        return NULL;
-    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
-        return NULL;
-
-    module_config_t *p_module_config = config_FindConfig(
-        VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
-
-    if( p_module_config )
-    {
-        // refresh if there arent devices
-        if( p_module_config->i_list < 2 && p_module_config->pf_update_list )
-        {
-            vlc_value_t val;
-            val.psz_string = strdup( p_module_config->value.psz );
-
-            p_module_config->pf_update_list(
-                VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
-            free( val.psz_string );
-        }
-
-        if( i_device >= 0 && i_device < p_module_config->i_list )
-        {
-            free( psz_config_name );
-
-            if( p_module_config->ppsz_list_text[i_device] )
-                return strdup( p_module_config->ppsz_list_text[i_device] );
-            else
-                return strdup( p_module_config->ppsz_list[i_device] );
-        }
-    }
-
-    free( psz_config_name );
-    return NULL;
-}
-
-/********************************
- * Get id name of device
- *********************************/
-char * libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
-                                      const char *psz_audio_output,
-                                      int i_device )
-{
-    char *psz_config_name;
-    if( !psz_audio_output )
-        return NULL;
-    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1)
-        return NULL;
-
-    module_config_t *p_module_config = config_FindConfig(
-        VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
-
-    if( p_module_config )
-    {
-        // refresh if there arent devices
-        if( p_module_config->i_list < 2 && p_module_config->pf_update_list )
-        {
-            vlc_value_t val;
-            val.psz_string = strdup( p_module_config->value.psz );
-
-            p_module_config->pf_update_list(
-                VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
-            free( val.psz_string );
-        }
-
-        if( i_device >= 0 && i_device < p_module_config->i_list )
-        {
-            free( psz_config_name );
-            return strdup( p_module_config->ppsz_list[i_device] );
-        }
-    }
-
-    free( psz_config_name );
-    return NULL;
-}
-
-/*****************************
- * Set device for using
- *****************************/
-void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
-                                     const char *psz_audio_output,
-                                     const char *psz_device_id )
-{
-    char *psz_config_name;
-    if( !psz_audio_output || !psz_device_id )
-        return;
-    if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
-        return;
-    if( !var_Type( mp, psz_config_name ) )
-        /* Don't recreate the same variable over and over and over... */
-        var_Create( mp, psz_config_name, VLC_VAR_STRING );
-    var_SetString( mp, psz_config_name, psz_device_id );
-    free( psz_config_name );
-}
-
-/*****************************************************************************
- * libvlc_audio_output_get_device_type : Get the current audio device type
- *****************************************************************************/
-int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
-{
-    audio_output_t *p_aout = GetAOut( mp );
-    if( p_aout )
-    {
-        int i_device_type = var_GetInteger( p_aout, "audio-device" );
-        vlc_object_release( p_aout );
-        return i_device_type;
-    }
-    return libvlc_AudioOutputDevice_Error;
-}
-
-/*****************************************************************************
- * libvlc_audio_output_set_device_type : Set the audio device type
- *****************************************************************************/
-void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
-                                          int device_type )
-{
-    audio_output_t *p_aout = GetAOut( mp );
-    if( !p_aout )
-        return;
-    if( var_SetInteger( p_aout, "audio-device", device_type ) < 0 )
-        libvlc_printerr( "Error setting audio device" );
-    vlc_object_release( p_aout );
-}
-
-/*****************************************************************************
- * libvlc_audio_get_mute : Get the volume state, true if muted
- *****************************************************************************/
-void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
-{
-    aout_ToggleMute( mp, NULL );
-}
-
-int libvlc_audio_get_mute( libvlc_media_player_t *mp )
-{
-    return aout_IsMuted( VLC_OBJECT(mp) );
-}
-
-void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
-{
-    aout_SetMute( VLC_OBJECT(mp), NULL, !!mute );
-}
-
-/*****************************************************************************
- * libvlc_audio_get_volume : Get the current volume
- *****************************************************************************/
-int libvlc_audio_get_volume( libvlc_media_player_t *mp )
-{
-    unsigned volume = aout_VolumeGet( mp );
-
-    return (volume * 100 + AOUT_VOLUME_DEFAULT / 2) / AOUT_VOLUME_DEFAULT;
-}
-
-
-/*****************************************************************************
- * libvlc_audio_set_volume : Set the current volume
- *****************************************************************************/
-int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
-{
-    volume = (volume * AOUT_VOLUME_DEFAULT + 50) / 100;
-    if (volume < 0 || volume > AOUT_VOLUME_MAX)
-    {
-        libvlc_printerr( "Volume out of range" );
-        return -1;
-    }
-    aout_VolumeSet (mp, volume);
-    return 0;
-}
-
-/*****************************************************************************
- * libvlc_audio_get_track_count : Get the number of available audio tracks
- *****************************************************************************/
-int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
-{
-    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
-    int i_track_count;
-
-    if( !p_input_thread )
-        return -1;
-
-    i_track_count = var_CountChoices( p_input_thread, "audio-es" );
-
-    vlc_object_release( p_input_thread );
-    return i_track_count;
-}
-
-/*****************************************************************************
- * libvlc_audio_get_track_description : Get the description of available audio tracks
- *****************************************************************************/
-libvlc_track_description_t *
-        libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
-{
-    return libvlc_get_track_description( p_mi, "audio-es" );
-}
-
-/*****************************************************************************
- * libvlc_audio_get_track : Get the current audio track
- *****************************************************************************/
-int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
-{
-    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
-    vlc_value_t val_list;
-    vlc_value_t val;
-    int i_track = -1;
-    int i;
-
-    if( !p_input_thread )
-        return -1;
-
-    if( var_Get( p_input_thread, "audio-es", &val ) < 0 )
-    {
-        vlc_object_release( p_input_thread );
-        libvlc_printerr( "Audio track information not found" );
-        return -1;
-    }
-
-    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
-    for( i = 0; i < val_list.p_list->i_count; i++ )
-    {
-        if( val_list.p_list->p_values[i].i_int == val.i_int )
-        {
-            i_track = i;
-            break;
-        }
-    }
-    var_FreeList( &val_list, NULL );
-    vlc_object_release( p_input_thread );
-    return i_track;
-}
-
-/*****************************************************************************
- * libvlc_audio_set_track : Set the current audio track
- *****************************************************************************/
-int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
-{
-    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
-    vlc_value_t val_list;
-    vlc_value_t newval;
-    int i_ret;
-
-    if( !p_input_thread )
-        return -1;
-
-    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
-    if( (i_track < 0) || (i_track > val_list.p_list->i_count) )
-    {
-        libvlc_printerr( "Audio track out of range" );
-        i_ret = -1;
-        goto end;
-    }
-
-    newval = val_list.p_list->p_values[i_track];
-    i_ret = var_Set( p_input_thread, "audio-es", newval );
-    if( i_ret < 0 )
-    {
-        libvlc_printerr( "Audio track out of range" ); /* Race... */
-        i_ret = -1;
-        goto end;
-    }
-    i_ret = 0;
-
-end:
-    var_FreeList( &val_list, NULL );
-    vlc_object_release( p_input_thread );
-    return i_ret;
-}
-
-/*****************************************************************************
- * libvlc_audio_get_channel : Get the current audio channel
- *****************************************************************************/
-int libvlc_audio_get_channel( libvlc_media_player_t *mp )
-{
-    audio_output_t *p_aout = GetAOut( mp );
-    if( !p_aout )
-        return 0;
-
-    int val = var_GetInteger( p_aout, "audio-channels" );
-    vlc_object_release( p_aout );
-    return val;
-}
-
-/*****************************************************************************
- * libvlc_audio_set_channel : Set the current audio channel
- *****************************************************************************/
-int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
-{
-    audio_output_t *p_aout = GetAOut( mp );
-    int ret = 0;
-
-    if( !p_aout )
-        return -1;
-
-    if( var_SetInteger( p_aout, "audio-channels", channel ) < 0 )
-    {
-        libvlc_printerr( "Audio channel out of range" );
-        ret = -1;
-    }
-    vlc_object_release( p_aout );
-    return ret;
-}
-
-/*****************************************************************************
- * libvlc_audio_get_delay : Get the current audio delay
- *****************************************************************************/
-int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
-{
-    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
-    int64_t val = 0;
-    if( p_input_thread != NULL )
-    {
-      val = var_GetTime( p_input_thread, "audio-delay" );
-      vlc_object_release( p_input_thread );
-    }
-    return val;
-}
-
-/*****************************************************************************
- * libvlc_audio_set_delay : Set the current audio delay
- *****************************************************************************/
-int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
-{
-    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
-    int ret = 0;
-    if( p_input_thread != NULL )
-    {
-      var_SetTime( p_input_thread, "audio-delay", i_delay );
-      vlc_object_release( p_input_thread );
-    }
-    else
-    {
-      ret = -1;
-    }
-    return ret;
-}
diff --git a/src/control/core.c b/src/control/core.c
deleted file mode 100644 (file)
index 6e88b94..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/*****************************************************************************
- * core.c: Core libvlc new API functions : initialization
- *****************************************************************************
- * Copyright (C) 2005 the VideoLAN team
- * $Id$
- *
- * Authors: Clément Stenac <zorglub@videolan.org>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "libvlc_internal.h"
-#include <vlc_modules.h>
-#include <vlc/libvlc.h>
-
-#include <vlc_interface.h>
-#include <vlc_vlm.h>
-
-#include <stdarg.h>
-#include <limits.h>
-#include <assert.h>
-
-static const char nomemstr[] = "Insufficient memory";
-
-libvlc_instance_t * libvlc_new( int argc, const char *const *argv )
-{
-    libvlc_instance_t *p_new = malloc (sizeof (*p_new));
-    if (unlikely(p_new == NULL))
-        return NULL;
-
-    libvlc_init_threads ();
-
-    const char *my_argv[argc + 2];
-    my_argv[0] = "libvlc"; /* dummy arg0, skipped by getopt() et al */
-    for( int i = 0; i < argc; i++ )
-         my_argv[i + 1] = argv[i];
-    my_argv[argc + 1] = NULL; /* C calling conventions require a NULL */
-
-    libvlc_int_t *p_libvlc_int = libvlc_InternalCreate();
-    if (unlikely (p_libvlc_int == NULL))
-        goto error;
-
-    if (libvlc_InternalInit( p_libvlc_int, argc + 1, my_argv ))
-    {
-        libvlc_InternalDestroy( p_libvlc_int );
-        goto error;
-    }
-
-    p_new->p_libvlc_int = p_libvlc_int;
-    p_new->libvlc_vlm.p_vlm = NULL;
-    p_new->libvlc_vlm.p_event_manager = NULL;
-    p_new->libvlc_vlm.pf_release = NULL;
-    p_new->ref_count = 1;
-    p_new->p_callback_list = NULL;
-    vlc_mutex_init(&p_new->instance_lock);
-    var_Create( p_libvlc_int, "http-user-agent",
-                VLC_VAR_STRING|VLC_VAR_DOINHERIT );
-    return p_new;
-
-error:
-    libvlc_deinit_threads ();
-    free (p_new);
-    return NULL;
-}
-
-void libvlc_retain( libvlc_instance_t *p_instance )
-{
-    assert( p_instance != NULL );
-    assert( p_instance->ref_count < UINT_MAX );
-
-    vlc_mutex_lock( &p_instance->instance_lock );
-    p_instance->ref_count++;
-    vlc_mutex_unlock( &p_instance->instance_lock );
-}
-
-void libvlc_release( libvlc_instance_t *p_instance )
-{
-    vlc_mutex_t *lock = &p_instance->instance_lock;
-    int refs;
-
-    vlc_mutex_lock( lock );
-    assert( p_instance->ref_count > 0 );
-    refs = --p_instance->ref_count;
-    vlc_mutex_unlock( lock );
-
-    if( refs == 0 )
-    {
-        vlc_mutex_destroy( lock );
-        if( p_instance->libvlc_vlm.pf_release )
-            p_instance->libvlc_vlm.pf_release( p_instance );
-        libvlc_InternalCleanup( p_instance->p_libvlc_int );
-        libvlc_InternalDestroy( p_instance->p_libvlc_int );
-        free( p_instance );
-        libvlc_deinit_threads ();
-    }
-}
-
-int libvlc_add_intf( libvlc_instance_t *p_i, const char *name )
-{
-    if( libvlc_InternalAddIntf( p_i->p_libvlc_int, name ))
-    {
-        if( name )
-        {
-            libvlc_printerr("interface \"%s\" initialization failed",
-                name );
-        }
-        else
-        {
-            libvlc_printerr("default interface initialization failed");
-        }
-        return -1;
-    }
-    return 0;
-}
-
-void libvlc_set_exit_handler( libvlc_instance_t *p_i, void (*cb) (void *),
-                              void *data )
-{
-    libvlc_int_t *p_libvlc = p_i->p_libvlc_int;
-    libvlc_SetExitHandler( p_libvlc, cb, data );
-}
-
-void libvlc_wait( libvlc_instance_t *p_i )
-{
-    libvlc_int_t *p_libvlc = p_i->p_libvlc_int;
-    libvlc_InternalWait( p_libvlc );
-}
-
-void libvlc_set_user_agent (libvlc_instance_t *p_i,
-                            const char *name, const char *http)
-{
-    libvlc_int_t *p_libvlc = p_i->p_libvlc_int;
-    char *str;
-
-    var_SetString (p_libvlc, "user-agent", name);
-    if ((http != NULL)
-     && (asprintf (&str, "%s LibVLC/"PACKAGE_VERSION, http) != -1))
-    {
-        var_SetString (p_libvlc, "http-user-agent", str);
-        free (str);
-    }
-}
-
-const char * libvlc_get_version(void)
-{
-    return VERSION_MESSAGE;
-}
-
-const char * libvlc_get_compiler(void)
-{
-    return VLC_Compiler();
-}
-
-const char * libvlc_get_changeset(void)
-{
-    extern const char psz_vlc_changeset[];
-    return psz_vlc_changeset;
-}
-
-void libvlc_free( void *ptr )
-{
-    free( ptr );
-}
-
-static libvlc_module_description_t *module_description_list_get(
-                libvlc_instance_t *p_instance, const char *capability )
-{
-    VLC_UNUSED( p_instance );
-    libvlc_module_description_t *p_list = NULL,
-                          *p_actual = NULL,
-                          *p_previous = NULL;
-    module_t **module_list = module_list_get( NULL );
-
-    for (size_t i = 0; module_list[i]; i++)
-    {
-        module_t *p_module = module_list[i];
-
-        if ( !module_provides( p_module, capability ) )
-            continue;
-
-        p_actual = ( libvlc_module_description_t * ) malloc( sizeof( libvlc_module_description_t ) );
-        if ( p_actual == NULL )
-        {
-            libvlc_printerr( "Not enough memory" );
-            libvlc_module_description_list_release( p_list );
-            module_list_free( module_list );
-            return NULL;
-        }
-
-        if ( p_list == NULL )
-            p_list = p_actual;
-
-        const char* name = module_get_object( p_module );
-        const char* shortname = module_get_name( p_module, false );
-        const char* longname = module_get_name( p_module, true );
-        const char* help = module_get_help( p_module );
-        p_actual->psz_name = name ? strdup( name ) : NULL;
-        p_actual->psz_shortname = shortname ? strdup( shortname ) : NULL;
-        p_actual->psz_longname = longname ? strdup( longname ) : NULL;
-        p_actual->psz_help = help ? strdup( help ) : NULL;
-
-        p_actual->p_next = NULL;
-        if ( p_previous )
-            p_previous->p_next = p_actual;
-        p_previous = p_actual;
-    }
-
-    module_list_free( module_list );
-    return p_list;
-}
-
-void libvlc_module_description_list_release( libvlc_module_description_t *p_list )
-{
-    libvlc_module_description_t *p_actual, *p_before;
-    p_actual = p_list;
-
-    while ( p_actual )
-    {
-        free( p_actual->psz_name );
-        free( p_actual->psz_shortname );
-        free( p_actual->psz_longname );
-        free( p_actual->psz_help );
-        p_before = p_actual;
-        p_actual = p_before->p_next;
-        free( p_before );
-    }
-}
-
-libvlc_module_description_t *libvlc_audio_filter_list_get( libvlc_instance_t *p_instance )
-{
-    return module_description_list_get( p_instance, "audio filter" );
-}
-
-libvlc_module_description_t *libvlc_video_filter_list_get( libvlc_instance_t *p_instance )
-{
-    return module_description_list_get( p_instance, "video filter2" );
-}
-
-int64_t libvlc_clock(void)
-{
-    return mdate();
-}
diff --git a/src/control/error.c b/src/control/error.c
deleted file mode 100644 (file)
index e3f7051..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*****************************************************************************
- * error.c: Error handling for libvlc
- *****************************************************************************
- * Copyright (C) 2009 Rémi Denis-Courmont
- *
- * 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.
- *****************************************************************************/
-
-#include "libvlc_internal.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <assert.h>
-#include <vlc/libvlc.h>
-
-
-static const char oom[] = "Out of memory";
-/* TODO: use only one thread-specific key for whole libvlc */
-static vlc_threadvar_t context;
-
-static void libvlc_setup_threads (bool init)
-{
-    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
-    static uintptr_t refs = 0;
-
-    vlc_mutex_lock (&lock);
-    if (init)
-    {
-        if (refs++ == 0)
-            vlc_threadvar_create (&context, free);
-    }
-    else
-    {
-        assert (refs > 0);
-        if (--refs == 0)
-            vlc_threadvar_delete (&context);
-    }
-    vlc_mutex_unlock (&lock);
-}
-
-void libvlc_init_threads (void)
-{
-    libvlc_setup_threads (true);
-}
-
-void libvlc_deinit_threads (void)
-{
-    libvlc_setup_threads (false);
-}
-
-static char *get_error (void)
-{
-    return vlc_threadvar_get (context);
-}
-
-static void free_error (void)
-{
-    char *msg = get_error ();
-    if (msg != oom)
-        free (msg);
-}
-
-/**
- * Gets a human-readable error message for the last LibVLC error in the calling
- * thread. The resulting string is valid until another error occurs (at least
- * until the next LibVLC call).
- *
- * @return NULL if there was no error, a nul-terminated string otherwise.
- */
-const char *libvlc_errmsg (void)
-{
-    return get_error ();
-}
-
-/**
- * Clears the LibVLC error status for the current thread. This is optional.
- * By default, the error status is automatically overridden when a new error
- * occurs, and destroyed when the thread exits.
- */
-void libvlc_clearerr (void)
-{
-    free_error ();
-    vlc_threadvar_set (context, NULL);
-}
-
-/**
- * Sets the LibVLC error status and message for the current thread.
- * Any previous error is overridden.
- * @return a nul terminated string (always)
- */
-const char *libvlc_vprinterr (const char *fmt, va_list ap)
-{
-    char *msg;
-
-    assert (fmt != NULL);
-    if (vasprintf (&msg, fmt, ap) == -1)
-        msg = (char *)oom;
-
-    free_error ();
-    vlc_threadvar_set (context, msg);
-    return msg;
-}
-
-/**
- * Sets the LibVLC error status and message for the current thread.
- * Any previous error is overridden.
- * @return a nul terminated string (always)
- */
-const char *libvlc_printerr (const char *fmt, ...)
-{
-    va_list ap;
-    const char *msg;
-
-    va_start (ap, fmt);
-    msg = libvlc_vprinterr (fmt, ap);
-    va_end (ap);
-    return msg;
-}
-
diff --git a/src/control/event.c b/src/control/event.c
deleted file mode 100644 (file)
index 2ce0a23..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*****************************************************************************
- * event.c: New libvlc event control API
- *****************************************************************************
- * Copyright (C) 2007-2010 the VideoLAN team
- * $Id $
- *
- * Authors: Filippo Carone <filippo@carone.org>
- *          Pierre d'Herbemont <pdherbemont # videolan.org>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#define  LIBVLC_EVENT_TYPES_KEEP_DEFINE
-#include <vlc/libvlc.h>
-
-#include "libvlc_internal.h"
-#include "event_internal.h"
-#include <assert.h>
-#include <errno.h>
-
-typedef struct libvlc_event_listeners_group_t
-{
-    libvlc_event_type_t event_type;
-    vlc_array_t listeners;
-    bool b_sublistener_removed;
-} libvlc_event_listeners_group_t;
-
-/*
- * Private functions
- */
-
-static bool
-group_contains_listener( libvlc_event_listeners_group_t * group,
-                         libvlc_event_listener_t * searched_listener )
-{
-    int i;
-    for( i = 0; i < vlc_array_count(&group->listeners); i++ )
-    {
-        if( listeners_are_equal(searched_listener, vlc_array_item_at_index(&group->listeners, i)) )
-            return true;
-    }
-    return false;
-}
-
-/*
- * Internal libvlc functions
- */
-
-/**************************************************************************
- *       libvlc_event_manager_new (internal) :
- *
- * Init an object's event manager.
- **************************************************************************/
-libvlc_event_manager_t *
-libvlc_event_manager_new( void * p_obj, libvlc_instance_t * p_libvlc_inst )
-{
-    libvlc_event_manager_t * p_em;
-
-    p_em = malloc(sizeof( libvlc_event_manager_t ));
-    if( !p_em )
-    {
-        libvlc_printerr( "Not enough memory" );
-        return NULL;
-    }
-
-    p_em->p_obj = p_obj;
-    p_em->p_obj = p_obj;
-    p_em->async_event_queue = NULL;
-    p_em->p_libvlc_instance = p_libvlc_inst;
-
-    libvlc_retain( p_libvlc_inst );
-    vlc_array_init( &p_em->listeners_groups );
-    vlc_mutex_init( &p_em->object_lock );
-    vlc_mutex_init_recursive( &p_em->event_sending_lock );
-    return p_em;
-}
-
-/**************************************************************************
- *       libvlc_event_manager_release (internal) :
- *
- * Release an object's event manager.
- **************************************************************************/
-void libvlc_event_manager_release( libvlc_event_manager_t * p_em )
-{
-    libvlc_event_listeners_group_t * p_lg;
-    int i,j ;
-
-    libvlc_event_async_fini(p_em);
-
-    vlc_mutex_destroy( &p_em->event_sending_lock );
-    vlc_mutex_destroy( &p_em->object_lock );
-
-    for( i = 0; i < vlc_array_count(&p_em->listeners_groups); i++)
-    {
-        p_lg = vlc_array_item_at_index( &p_em->listeners_groups, i );
-
-        for( j = 0; j < vlc_array_count(&p_lg->listeners); j++)
-            free( vlc_array_item_at_index( &p_lg->listeners, j ) );
-
-        vlc_array_clear( &p_lg->listeners );
-        free( p_lg );
-    }
-    vlc_array_clear( &p_em->listeners_groups );
-    libvlc_release( p_em->p_libvlc_instance );
-    free( p_em );
-}
-
-/**************************************************************************
- *       libvlc_event_manager_register_event_type (internal) :
- *
- * Init an object's event manager.
- **************************************************************************/
-void libvlc_event_manager_register_event_type(
-        libvlc_event_manager_t * p_em,
-        libvlc_event_type_t event_type )
-{
-    libvlc_event_listeners_group_t * listeners_group;
-    listeners_group = xmalloc(sizeof(libvlc_event_listeners_group_t));
-    listeners_group->event_type = event_type;
-    vlc_array_init( &listeners_group->listeners );
-
-    vlc_mutex_lock( &p_em->object_lock );
-    vlc_array_append( &p_em->listeners_groups, listeners_group );
-    vlc_mutex_unlock( &p_em->object_lock );
-}
-
-/**************************************************************************
- *       libvlc_event_send (internal) :
- *
- * Send a callback.
- **************************************************************************/
-void libvlc_event_send( libvlc_event_manager_t * p_em,
-                        libvlc_event_t * p_event )
-{
-    libvlc_event_listeners_group_t * listeners_group = NULL;
-    libvlc_event_listener_t * listener_cached;
-    libvlc_event_listener_t * listener;
-    libvlc_event_listener_t * array_listeners_cached = NULL;
-    int i, i_cached_listeners = 0;
-
-    /* Fill event with the sending object now */
-    p_event->p_obj = p_em->p_obj;
-
-    /* Here a read/write lock would be nice */
-
-    vlc_mutex_lock( &p_em->object_lock );
-    for( i = 0; i < vlc_array_count(&p_em->listeners_groups); i++)
-    {
-        listeners_group = vlc_array_item_at_index(&p_em->listeners_groups, i);
-        if( listeners_group->event_type == p_event->type )
-        {
-            if( vlc_array_count( &listeners_group->listeners ) <= 0 )
-                break;
-
-            /* Cache a copy of the listener to avoid locking issues,
-             * and allow that edition of listeners during callbacks will garantee immediate effect. */
-            i_cached_listeners = vlc_array_count(&listeners_group->listeners);
-            array_listeners_cached = malloc(sizeof(libvlc_event_listener_t)*(i_cached_listeners));
-            if( !array_listeners_cached )
-            {
-                vlc_mutex_unlock( &p_em->object_lock );
-                fprintf(stderr, "Can't alloc memory in libvlc_event_send" );
-                return;
-            }
-
-            listener_cached = array_listeners_cached;
-            for( i = 0; i < vlc_array_count(&listeners_group->listeners); i++)
-            {
-                listener = vlc_array_item_at_index(&listeners_group->listeners, i);
-                memcpy( listener_cached, listener, sizeof(libvlc_event_listener_t) );
-                listener_cached++;
-            }
-            break;
-        }
-    }
-
-    if( !listeners_group )
-    {
-        free( array_listeners_cached );
-        vlc_mutex_unlock( &p_em->object_lock );
-        return;
-    }
-
-    vlc_mutex_unlock( &p_em->object_lock );
-
-    vlc_mutex_lock( &p_em->event_sending_lock );
-    listener_cached = array_listeners_cached;
-    listeners_group->b_sublistener_removed = false;
-    for( i = 0; i < i_cached_listeners; i++ )
-    {
-        if(listener_cached->is_asynchronous)
-        {
-            /* The listener wants not to block the emitter during event callback */
-            libvlc_event_async_dispatch(p_em, listener_cached, p_event);
-        }
-        else
-        {
-            /* The listener wants to block the emitter during event callback */
-
-            listener_cached->pf_callback( p_event, listener_cached->p_user_data );
-            listener_cached++;
-
-            if( listeners_group->b_sublistener_removed )
-            {
-                /* If a callback was removed, this gets called */
-                bool valid_listener;
-                vlc_mutex_lock( &p_em->object_lock );
-                valid_listener = group_contains_listener( listeners_group, listener_cached );
-                vlc_mutex_unlock( &p_em->object_lock );
-                if( !valid_listener )
-                {
-                    listener_cached++;
-                    continue;
-                }
-            }
-        }
-    }
-    vlc_mutex_unlock( &p_em->event_sending_lock );
-
-    free( array_listeners_cached );
-}
-
-/*
- * Public libvlc functions
- */
-
-#define DEF( a ) { libvlc_##a, #a, },
-
-typedef struct
-{
-    int type;
-    const char name[40];
-} event_name_t;
-
-static const event_name_t event_list[] = {
-    DEF(MediaMetaChanged)
-    DEF(MediaSubItemAdded)
-    DEF(MediaDurationChanged)
-    DEF(MediaParsedChanged)
-    DEF(MediaFreed)
-    DEF(MediaStateChanged)
-
-    DEF(MediaPlayerMediaChanged)
-    DEF(MediaPlayerNothingSpecial)
-    DEF(MediaPlayerOpening)
-    DEF(MediaPlayerBuffering)
-    DEF(MediaPlayerPlaying)
-    DEF(MediaPlayerPaused)
-    DEF(MediaPlayerStopped)
-    DEF(MediaPlayerForward)
-    DEF(MediaPlayerBackward)
-    DEF(MediaPlayerEndReached)
-    DEF(MediaPlayerEncounteredError)
-    DEF(MediaPlayerTimeChanged)
-    DEF(MediaPlayerPositionChanged)
-    DEF(MediaPlayerSeekableChanged)
-    DEF(MediaPlayerPausableChanged)
-    DEF(MediaPlayerTitleChanged)
-    DEF(MediaPlayerSnapshotTaken)
-    DEF(MediaPlayerLengthChanged)
-
-    DEF(MediaListItemAdded)
-    DEF(MediaListWillAddItem)
-    DEF(MediaListItemDeleted)
-    DEF(MediaListWillDeleteItem)
-
-    DEF(MediaListViewItemAdded)
-    DEF(MediaListViewWillAddItem)
-    DEF(MediaListViewItemDeleted)
-    DEF(MediaListViewWillDeleteItem)
-
-    DEF(MediaListPlayerPlayed)
-    DEF(MediaListPlayerNextItemSet)
-    DEF(MediaListPlayerStopped)
-
-    DEF(MediaDiscovererStarted)
-    DEF(MediaDiscovererEnded)
-
-    DEF(VlmMediaAdded)
-    DEF(VlmMediaRemoved)
-    DEF(VlmMediaChanged)
-    DEF(VlmMediaInstanceStarted)
-    DEF(VlmMediaInstanceStopped)
-    DEF(VlmMediaInstanceStatusInit)
-    DEF(VlmMediaInstanceStatusOpening)
-};
-#undef DEF
-
-static const char unknown_event_name[] = "Unknown Event";
-
-static int evcmp( const void *a, const void *b )
-{
-    return (*(const int *)a) - ((event_name_t *)b)->type;
-}
-
-const char * libvlc_event_type_name( int event_type )
-{
-    const event_name_t *p;
-
-    p = bsearch( &event_type, event_list,
-                 sizeof(event_list)/sizeof(event_list[0]), sizeof(*p),
-                 evcmp );
-    return p ? p->name : unknown_event_name;
-}
-
-/**************************************************************************
- *       event_attach (internal) :
- *
- * Add a callback for an event.
- **************************************************************************/
-static
-int event_attach( libvlc_event_manager_t * p_event_manager,
-                  libvlc_event_type_t event_type,
-                  libvlc_callback_t pf_callback, void *p_user_data,
-                  bool is_asynchronous )
-{
-    libvlc_event_listeners_group_t * listeners_group;
-    libvlc_event_listener_t * listener;
-    int i;
-
-    listener = malloc(sizeof(libvlc_event_listener_t));
-    if( unlikely(listener == NULL) )
-        return ENOMEM;
-
-    listener->event_type = event_type;
-    listener->p_user_data = p_user_data;
-    listener->pf_callback = pf_callback;
-    listener->is_asynchronous = is_asynchronous;
-
-    vlc_mutex_lock( &p_event_manager->object_lock );
-    for( i = 0; i < vlc_array_count(&p_event_manager->listeners_groups); i++ )
-    {
-        listeners_group = vlc_array_item_at_index(&p_event_manager->listeners_groups, i);
-        if( listeners_group->event_type == listener->event_type )
-        {
-            vlc_array_append( &listeners_group->listeners, listener );
-            vlc_mutex_unlock( &p_event_manager->object_lock );
-            return 0;
-        }
-    }
-    vlc_mutex_unlock( &p_event_manager->object_lock );
-
-    free(listener);
-    fprintf( stderr, "This object event manager doesn't know about '%s' events",
-             libvlc_event_type_name(event_type) );
-    assert(0);
-    return -1;
-}
-
-/**************************************************************************
- *       libvlc_event_attach (public) :
- *
- * Add a callback for an event.
- **************************************************************************/
-int libvlc_event_attach( libvlc_event_manager_t * p_event_manager,
-                         libvlc_event_type_t event_type,
-                         libvlc_callback_t pf_callback,
-                         void *p_user_data )
-{
-    return event_attach(p_event_manager, event_type, pf_callback, p_user_data,
-                        false /* synchronous */);
-}
-
-/**************************************************************************
- *       libvlc_event_attach (public) :
- *
- * Add a callback for an event.
- **************************************************************************/
-void libvlc_event_attach_async( libvlc_event_manager_t * p_event_manager,
-                         libvlc_event_type_t event_type,
-                         libvlc_callback_t pf_callback,
-                         void *p_user_data )
-{
-    event_attach(p_event_manager, event_type, pf_callback, p_user_data,
-                 true /* asynchronous */);
-}
-
-/**************************************************************************
- *       libvlc_event_detach (public) :
- *
- * Remove a callback for an event.
- **************************************************************************/
-void libvlc_event_detach( libvlc_event_manager_t *p_event_manager,
-                                     libvlc_event_type_t event_type,
-                                     libvlc_callback_t pf_callback,
-                                     void *p_user_data )
-{
-    libvlc_event_listeners_group_t * listeners_group;
-    libvlc_event_listener_t * listener;
-    int i, j;
-    bool found = false;
-
-    vlc_mutex_lock( &p_event_manager->event_sending_lock );
-    vlc_mutex_lock( &p_event_manager->object_lock );
-    for( i = 0; i < vlc_array_count(&p_event_manager->listeners_groups); i++)
-    {
-        listeners_group = vlc_array_item_at_index(&p_event_manager->listeners_groups, i);
-        if( listeners_group->event_type == event_type )
-        {
-            for( j = 0; j < vlc_array_count(&listeners_group->listeners); j++)
-            {
-                listener = vlc_array_item_at_index(&listeners_group->listeners, j);
-                if( listener->event_type == event_type &&
-                    listener->pf_callback == pf_callback &&
-                    listener->p_user_data == p_user_data )
-                {
-                    /* that's our listener */
-
-                    /* Mark this group as edited so that libvlc_event_send
-                     * will recheck what listener to call */
-                    listeners_group->b_sublistener_removed = false;
-
-                    free( listener );
-                    vlc_array_remove( &listeners_group->listeners, j );
-                    found = true;
-                    break;
-                }
-            }
-        }
-    }
-    vlc_mutex_unlock( &p_event_manager->object_lock );
-    vlc_mutex_unlock( &p_event_manager->event_sending_lock );
-
-    /* Now make sure any pending async event won't get fired after that point */
-    libvlc_event_listener_t listener_to_remove;
-    listener_to_remove.event_type  = event_type;
-    listener_to_remove.pf_callback = pf_callback;
-    listener_to_remove.p_user_data = p_user_data;
-    listener_to_remove.is_asynchronous = true;
-
-    libvlc_event_async_ensure_listener_removal(p_event_manager, &listener_to_remove);
-
-    assert(found);
-}
diff --git a/src/control/event_async.c b/src/control/event_async.c
deleted file mode 100644 (file)
index 5dce2a3..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*****************************************************************************
- * event.c: New libvlc event control API
- *****************************************************************************
- * Copyright (C) 2007 the VideoLAN team
- * $Id $
- *
- * Authors: Filippo Carone <filippo@carone.org>
- *          Pierre d'Herbemont <pdherbemont # videolan.org>
- *
- * 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.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <assert.h>
-
-#include <vlc/libvlc.h>
-
-#include "libvlc_internal.h"
-#include "event_internal.h"
-
-struct queue_elmt {
-    libvlc_event_listener_t listener;
-    libvlc_event_t event;
-    struct queue_elmt * next;
-};
-
-struct libvlc_event_async_queue {
-    struct queue_elmt *first_elmt, *last_elmt;
-    vlc_mutex_t lock;
-    vlc_cond_t signal;
-    vlc_thread_t thread;
-    bool is_idle;
-    vlc_cond_t signal_idle;
-    vlc_threadvar_t is_asynch_dispatch_thread_var;
-#ifndef NDEBUG
-    long count;
-#endif
-};
-
-/*
- * Utilities
- */
-
-static void*  event_async_loop(void * arg);
-
-static inline struct libvlc_event_async_queue * queue(libvlc_event_manager_t * p_em)
-{
-    return p_em->async_event_queue;
-}
-
-static inline bool is_queue_initialized(libvlc_event_manager_t * p_em)
-{
-    return queue(p_em) != NULL;
-}
-
-static inline bool current_thread_is_asynch_thread(libvlc_event_manager_t * p_em)
-{
-    return vlc_threadvar_get(queue(p_em)->is_asynch_dispatch_thread_var)
-            != NULL;
-}
-
-/* Lock must be held */
-static void push(libvlc_event_manager_t * p_em,
-                 libvlc_event_listener_t * listener, libvlc_event_t * event)
-{
-    struct queue_elmt * elmt = malloc(sizeof(struct queue_elmt));
-    elmt->listener = *listener;
-    elmt->event = *event;
-    elmt->next = NULL;
-
-    /* Append to the end of the queue */
-    if(!queue(p_em)->first_elmt)
-        queue(p_em)->first_elmt = elmt;
-    else
-        queue(p_em)->last_elmt->next = elmt;
-    queue(p_em)->last_elmt = elmt;
-
-#ifndef NDEBUG
-    enum { MaxQueueSize = 300000 };
-    if(queue(p_em)->count++ > MaxQueueSize)
-    {
-        fprintf(stderr, "Warning: libvlc event overflow.\n");
-        abort();
-    }
-#endif
-}
-
-static inline void queue_lock(libvlc_event_manager_t * p_em)
-{
-    vlc_mutex_lock(&queue(p_em)->lock);
-}
-
-static inline void queue_unlock(libvlc_event_manager_t * p_em)
-{
-    vlc_mutex_unlock(&queue(p_em)->lock);
-}
-
-/* Lock must be held */
-static bool pop(libvlc_event_manager_t * p_em,
-                libvlc_event_listener_t * listener, libvlc_event_t * event)
-{
-    if(!queue(p_em)->first_elmt)
-        return false; /* No first_elmt */
-
-    struct queue_elmt * elmt = queue(p_em)->first_elmt;
-    *listener = elmt->listener;
-    *event = elmt->event;
-
-    queue(p_em)->first_elmt = elmt->next;
-    if( !elmt->next ) queue(p_em)->last_elmt=NULL;
-
-#ifndef NDEBUG
-    queue(p_em)->count--;
-#endif
-
-    free(elmt);
-    return true;
-}
-
-/* Lock must be held */
-static void pop_listener(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener)
-{
-    struct queue_elmt * iter = queue(p_em)->first_elmt;
-    struct queue_elmt * prev = NULL;
-    while (iter) {
-        if(listeners_are_equal(&iter->listener, listener))
-        {
-            struct queue_elmt * to_delete = iter;
-            if(!prev)
-                queue(p_em)->first_elmt = to_delete->next;
-            else
-                prev->next = to_delete->next;
-            iter = to_delete->next;
-            free(to_delete);
-#ifndef NDEBUG
-            queue(p_em)->count--;
-#endif
-        }
-        else {
-            prev = iter;
-            iter = iter->next;
-        }
-    }
-    queue(p_em)->last_elmt=prev;
-}
-
-/**************************************************************************
- *       libvlc_event_async_fini (internal) :
- *
- * Destroy what might have been created by.
- **************************************************************************/
-void
-libvlc_event_async_fini(libvlc_event_manager_t * p_em)
-{
-    if(!is_queue_initialized(p_em)) return;
-
-    if(current_thread_is_asynch_thread(p_em))
-    {
-        fprintf(stderr, "*** Error: releasing the last reference of the observed object from its callback thread is not (yet!) supported\n");
-        abort();
-    }
-
-    vlc_thread_t thread = queue(p_em)->thread;
-    if(thread)
-    {
-        vlc_cancel(thread);
-        vlc_join(thread, NULL);
-    }
-
-    vlc_mutex_destroy(&queue(p_em)->lock);
-    vlc_cond_destroy(&queue(p_em)->signal);
-    vlc_cond_destroy(&queue(p_em)->signal_idle);
-    vlc_threadvar_delete(&queue(p_em)->is_asynch_dispatch_thread_var);
-
-    struct queue_elmt * iter = queue(p_em)->first_elmt;
-    while (iter) {
-        struct queue_elmt * elemt_to_delete = iter;
-        iter = iter->next;
-        free(elemt_to_delete);
-    }
-
-    free(queue(p_em));
-}
-
-/**************************************************************************
- *       libvlc_event_async_init (private) :
- *
- * Destroy what might have been created by.
- **************************************************************************/
-static void
-libvlc_event_async_init(libvlc_event_manager_t * p_em)
-{
-    p_em->async_event_queue = calloc(1, sizeof(struct libvlc_event_async_queue));
-
-    int error = vlc_threadvar_create(&queue(p_em)->is_asynch_dispatch_thread_var, NULL);
-    assert(!error);
-
-    vlc_mutex_init(&queue(p_em)->lock);
-    vlc_cond_init(&queue(p_em)->signal);
-    vlc_cond_init(&queue(p_em)->signal_idle);
-
-    error = vlc_clone (&queue(p_em)->thread, event_async_loop, p_em, VLC_THREAD_PRIORITY_LOW);
-    if(error)
-    {
-        free(p_em->async_event_queue);
-        p_em->async_event_queue = NULL;
-        return;
-    }
-
-}
-
-/**************************************************************************
- *       libvlc_event_async_ensure_listener_removal (internal) :
- *
- * Make sure no more message will be issued to the listener.
- **************************************************************************/
-void
-libvlc_event_async_ensure_listener_removal(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener)
-{
-    if(!is_queue_initialized(p_em)) return;
-
-    queue_lock(p_em);
-    pop_listener(p_em, listener);
-
-    // Wait for the asynch_loop to have processed all events.
-    if(!current_thread_is_asynch_thread(p_em))
-    {
-        while(!queue(p_em)->is_idle)
-            vlc_cond_wait(&queue(p_em)->signal_idle, &queue(p_em)->lock);
-    }
-    queue_unlock(p_em);
-}
-
-/**************************************************************************
- *       libvlc_event_async_dispatch (internal) :
- *
- * Send an event in an asynchronous way.
- **************************************************************************/
-void
-libvlc_event_async_dispatch(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener, libvlc_event_t * event)
-{
-    // We do a lazy init here, to prevent constructing the thread when not needed.
-    vlc_mutex_lock(&p_em->object_lock);
-    if(!queue(p_em))
-        libvlc_event_async_init(p_em);
-    vlc_mutex_unlock(&p_em->object_lock);
-
-    queue_lock(p_em);
-    push(p_em, listener, event);
-    vlc_cond_signal(&queue(p_em)->signal);
-    queue_unlock(p_em);
-}
-
-/**************************************************************************
- *       event_async_loop (private) :
- *
- * Send queued events.
- **************************************************************************/
-static void * event_async_loop(void * arg)
-{
-    libvlc_event_manager_t * p_em = arg;
-    libvlc_event_listener_t listener;
-    libvlc_event_t event;
-
-    vlc_threadvar_set(queue(p_em)->is_asynch_dispatch_thread_var, p_em);
-
-    queue_lock(p_em);
-    while (true) {
-        int has_listener = pop(p_em, &listener, &event);
-
-        if (has_listener)
-        {
-            queue_unlock(p_em);
-            listener.pf_callback(&event, listener.p_user_data); // This might edit the queue
-            queue_lock(p_em);
-        }
-        else
-        {
-            queue(p_em)->is_idle = true;
-
-            mutex_cleanup_push(&queue(p_em)->lock);
-            vlc_cond_broadcast(&queue(p_em)->signal_idle); // We'll be idle
-            vlc_cond_wait(&queue(p_em)->signal, &queue(p_em)->lock);
-            vlc_cleanup_pop();
-
-            queue(p_em)->is_idle = false;
-        }
-    }
-    queue_unlock(p_em);
-    return NULL;
-}
diff --git a/src/control/event_internal.h b/src/control/event_internal.h
deleted file mode 100644 (file)
index b7df2cb..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*****************************************************************************
- * libvlc_internal.h : Definition of opaque structures for libvlc exported API
- * Also contains some internal utility functions
- *****************************************************************************
- * Copyright (C) 2005-2009 the VideoLAN team
- * $Id$
- *
- * Authors: Clément Stenac <zorglub@videolan.org>
- *
- * 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.
- *****************************************************************************/
-
-#ifndef _LIBVLC_EVENT_H
-#define _LIBVLC_EVENT_H 1
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <vlc/libvlc_structures.h>
-#include <vlc/libvlc.h>
-#include <vlc/libvlc_events.h>
-
-#include <vlc_common.h>
-
-
-/*
- * Event Handling
- */
-
-/* Example usage
- *
- * struct libvlc_cool_object_t
- * {
- *        ...
- *        libvlc_event_manager_t * p_event_manager;
- *        ...
- * }
- *
- * libvlc_my_cool_object_new()
- * {
- *        ...
- *        p_self->p_event_manager = libvlc_event_manager_new( p_self,
- *                                                   p_self->p_libvlc_instance, p_e);
- *        libvlc_event_manager_register_event_type(p_self->p_event_manager,
- *                libvlc_MyCoolObjectDidSomething, p_e)
- *        ...
- * }
- *
- * libvlc_my_cool_object_release()
- * {
- *         ...
- *         libvlc_event_manager_release( p_self->p_event_manager );
- *         ...
- * }
- *
- * libvlc_my_cool_object_do_something()
- * {
- *        ...
- *        libvlc_event_t event;
- *        event.type = libvlc_MyCoolObjectDidSomething;
- *        event.u.my_cool_object_did_something.what_it_did = kSomething;
- *        libvlc_event_send( p_self->p_event_manager, &event );
- * }
- * */
-
-typedef struct libvlc_event_listener_t
-{
-    libvlc_event_type_t event_type;
-    void *              p_user_data;
-    libvlc_callback_t   pf_callback;
-    bool                is_asynchronous;
-} libvlc_event_listener_t;
-
-typedef struct libvlc_event_manager_t
-{
-    void * p_obj;
-    struct libvlc_instance_t * p_libvlc_instance;
-    vlc_array_t listeners_groups;
-    vlc_mutex_t object_lock;
-    vlc_mutex_t event_sending_lock;
-    struct libvlc_event_async_queue * async_event_queue;
-} libvlc_event_sender_t;
-
-
-static inline bool
-listeners_are_equal( libvlc_event_listener_t * listener1,
-                    libvlc_event_listener_t * listener2 )
-{
-    return listener1->event_type  == listener2->event_type &&
-    listener1->pf_callback == listener2->pf_callback &&
-    listener1->p_user_data == listener2->p_user_data &&
-    listener1->is_asynchronous == listener2->is_asynchronous;
-}
-
-/* event_async.c */
-void libvlc_event_async_fini(libvlc_event_manager_t * p_em);
-void libvlc_event_async_dispatch(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener, libvlc_event_t * event);
-void libvlc_event_async_ensure_listener_removal(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener);
-
-#endif
diff --git a/src/control/libvlc_internal.h b/src/control/libvlc_internal.h
deleted file mode 100644 (file)
index 6e7c173..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*****************************************************************************
- * libvlc_internal.h : Definition of opaque structures for libvlc exported API
- * Also contains some internal utility functions
- *****************************************************************************