]> git.sesse.net Git - vlc/blobdiff - projects/activex/plugin.cpp
Qt: CaptureOpenPanel: check and prefill with usual devices
[vlc] / projects / activex / plugin.cpp
index 22a1ed4f767a0e5764a99097dd6db629362c6e43..52c19652bd4d58a45dd559026d11c3ab0f313bd0 100644 (file)
@@ -1,9 +1,10 @@
 /*****************************************************************************
  * plugin.cpp: ActiveX control for VLC
  *****************************************************************************
- * Copyright (C) 2006 the VideoLAN team
+ * Copyright (C) 2006-2010 the VideoLAN team
  *
  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
+ *          Jean-Paul Saman <jpsaman@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
 
 #include "utils.h"
 
+#include <stdio.h>
 #include <string.h>
 #include <winreg.h>
 #include <winuser.h>
 #include <servprov.h>
 #include <shlwapi.h>
 #include <wininet.h>
+#include <assert.h>
 
 using namespace std;
 
@@ -205,9 +208,17 @@ VLCPlugin::VLCPlugin(VLCPluginClass *p_class, LPUNKNOWN pUnkOuter) :
     _p_class(p_class),
     _i_ref(1UL),
     _p_libvlc(NULL),
+    _p_mlist(NULL),
+    _p_mplayer(NULL),
+    _i_midx(-1),
     _i_codepage(CP_ACP),
     _b_usermode(TRUE)
 {
+    /*
+    ** bump refcount to avoid recursive release from
+    ** following interfaces when releasing this interface
+    */
+    AddRef();
     p_class->AddRef();
 
     vlcOleControl = new VLCOleControl(this);
@@ -238,12 +249,6 @@ VLCPlugin::VLCPlugin(VLCPluginClass *p_class, LPUNKNOWN pUnkOuter) :
 
 VLCPlugin::~VLCPlugin()
 {
-    /*
-    ** bump refcount to avoid recursive release from
-    ** following interfaces when releasing this interface
-    */
-    AddRef();
-
     delete vlcSupportErrorInfo;
     delete vlcOleObject;
     delete vlcDataObject;
@@ -266,7 +271,20 @@ VLCPlugin::~VLCPlugin()
     SysFreeString(_bstr_mrl);
     SysFreeString(_bstr_baseurl);
 
+    if( _p_mplayer )
+    {
+        if( isPlaying() )
+            playlist_stop();
+
+        player_unregister_events();
+        libvlc_media_player_release(_p_mplayer);
+        _p_mplayer=NULL;
+    }
+    if( _p_mlist )   { libvlc_media_list_release(_p_mlist); _p_mlist=NULL; }
+    if( _p_libvlc )  { libvlc_release(_p_libvlc); _p_libvlc=NULL; }
+
     _p_class->Release();
+    Release();
 };
 
 STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
@@ -349,15 +367,16 @@ HRESULT VLCPlugin::onInit(void)
     if( NULL == _p_libvlc )
     {
         // initialize persistable properties
-        _b_autoplay = TRUE;
-        _b_autoloop = FALSE;
+        _b_autoplay   = TRUE;
+        _b_autoloop   = FALSE;
+        _b_toolbar    = FALSE;
         _bstr_baseurl = NULL;
-        _bstr_mrl = NULL;
-        _b_visible = TRUE;
-        _b_mute = FALSE;
-        _i_volume = 50;
-        _i_time   = 0;
-        _i_backcolor = 0;
+        _bstr_mrl     = NULL;
+        _b_visible    = TRUE;
+        _b_mute       = FALSE;
+        _i_volume     = 50;
+        _i_time       = 0;
+        _i_backcolor  = 0;
         // set default/preferred size (320x240) pixels in HIMETRIC
         HDC hDC = CreateDevDC(NULL);
         _extent.cx = 320;
@@ -409,148 +428,125 @@ HRESULT VLCPlugin::onLoad(void)
     return S_OK;
 };
 
-HRESULT VLCPlugin::getVLCObject(int* i_vlc)
-{
-    libvlc_instance_t *p_libvlc;
-    HRESULT result = getVLC(&p_libvlc);
-    if( SUCCEEDED(result) )
-    {
-        *i_vlc = libvlc_get_vlc_id(p_libvlc);
-    }
-    else
-    {
-        *i_vlc = 0;
-    }
-    return result;
-}
-
-HRESULT VLCPlugin::getVLC(libvlc_instance_t** pp_libvlc)
+void VLCPlugin::initVLC()
 {
     extern HMODULE DllGetModule();
 
-    if( ! isRunning() )
-    {
-        /*
-        ** default initialization options
-        */
-        const char *ppsz_argv[32] = { };
-        int   ppsz_argc = 0;
+    /*
+    ** default initialization options
+    */
+    const char *ppsz_argv[32] = { };
+    int   ppsz_argc = 0;
 
-        char p_progpath[MAX_PATH];
+    char p_progpath[MAX_PATH];
+    {
+        TCHAR w_progpath[MAX_PATH];
+        DWORD len = GetModuleFileName(DllGetModule(), w_progpath, MAX_PATH);
+        w_progpath[MAX_PATH-1] = '\0';
+        if( len > 0 )
         {
-            TCHAR w_progpath[MAX_PATH];
-            DWORD len = GetModuleFileName(DllGetModule(), w_progpath, MAX_PATH);
+            len = WideCharToMultiByte(CP_UTF8, 0, w_progpath, len, p_progpath,
+                       sizeof(p_progpath)-1, NULL, NULL);
             if( len > 0 )
             {
-                len = WideCharToMultiByte(CP_UTF8, 0, w_progpath, len, p_progpath,
-                           sizeof(p_progpath)-1, NULL, NULL);
-                if( len > 0 )
-                {
-                    p_progpath[len] = '\0';
-                    ppsz_argv[0] = p_progpath;
-                }
+                p_progpath[len] = '\0';
+                ppsz_argv[0] = p_progpath;
             }
         }
+    }
 
-        ppsz_argv[ppsz_argc++] = "-vv";
+    ppsz_argv[ppsz_argc++] = "-vv";
 
-        HKEY h_key;
-        char p_pluginpath[MAX_PATH];
-        if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Software\\VideoLAN\\VLC"),
-                          0, KEY_READ, &h_key ) == ERROR_SUCCESS )
+    HKEY h_key;
+    char p_pluginpath[MAX_PATH];
+    if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Software\\VideoLAN\\VLC"),
+                      0, KEY_READ, &h_key ) == ERROR_SUCCESS )
+    {
+        DWORD i_type, i_data = MAX_PATH;
+        TCHAR w_pluginpath[MAX_PATH];
+        if( RegQueryValueEx( h_key, TEXT("InstallDir"), 0, &i_type,
+                             (LPBYTE)w_pluginpath, &i_data ) == ERROR_SUCCESS )
         {
-            DWORD i_type, i_data = MAX_PATH;
-            TCHAR w_pluginpath[MAX_PATH];
-            if( RegQueryValueEx( h_key, TEXT("InstallDir"), 0, &i_type,
-                                 (LPBYTE)w_pluginpath, &i_data ) == ERROR_SUCCESS )
+            w_pluginpath[MAX_PATH-1] = '\0';
+            if( i_type == REG_SZ )
             {
-                if( i_type == REG_SZ )
+                if( WideCharToMultiByte(CP_UTF8, 0, w_pluginpath, -1, p_pluginpath,
+                         sizeof(p_pluginpath)-sizeof("\\plugins")+1, NULL, NULL) )
                 {
-                    if( WideCharToMultiByte(CP_UTF8, 0, w_pluginpath, -1, p_pluginpath,
-                             sizeof(p_pluginpath)-sizeof("\\plugins")+1, NULL, NULL) )
-                    {
-                        strcat( p_pluginpath, "\\plugins" );
-                        ppsz_argv[ppsz_argc++] = "--plugin-path";
-                        ppsz_argv[ppsz_argc++] = p_pluginpath;
-                    }
+                    strcat( p_pluginpath, "\\plugins" );
+                    ppsz_argv[ppsz_argc++] = "--plugin-path";
+                    ppsz_argv[ppsz_argc++] = p_pluginpath;
                 }
             }
-            RegCloseKey( h_key );
         }
+        RegCloseKey( h_key );
+    }
 
-        // make sure plugin isn't affected with VLC single instance mode
-        ppsz_argv[ppsz_argc++] = "--no-one-instance";
+    // make sure plugin isn't affected with VLC single instance mode
+    ppsz_argv[ppsz_argc++] = "--no-one-instance";
 
-        /* common settings */
-        ppsz_argv[ppsz_argc++] = "--no-stats";
-        ppsz_argv[ppsz_argc++] = "--no-media-library";
-        ppsz_argv[ppsz_argc++] = "--intf=dummy";
+    /* common settings */
+    ppsz_argv[ppsz_argc++] = "-vv";
+    ppsz_argv[ppsz_argc++] = "--no-stats";
+    ppsz_argv[ppsz_argc++] = "--no-media-library";
+    ppsz_argv[ppsz_argc++] = "--intf=dummy";
+    ppsz_argv[ppsz_argc++] = "--no-video-title-show";
 
-        // loop mode is a configuration option only
-        if( _b_autoloop )
-            ppsz_argv[ppsz_argc++] = "--loop";
 
-        _p_libvlc = libvlc_new(ppsz_argc, ppsz_argv, NULL);
-        if( NULL == _p_libvlc )
-        {
-            *pp_libvlc = NULL;
-            return E_FAIL;
-        }
+    // loop mode is a configuration option only
+    if( _b_autoloop )
+        ppsz_argv[ppsz_argc++] = "--loop";
 
-        // initial volume setting
-        libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
-        if( _b_mute )
-        {
-            libvlc_audio_set_mute(_p_libvlc, TRUE, NULL);
-        }
+    _p_libvlc = libvlc_new(ppsz_argc, ppsz_argv);
+    if( !_p_libvlc )
+        return;
 
-        // initial playlist item
-        if( SysStringLen(_bstr_mrl) > 0 )
-        {
-            char *psz_mrl = NULL;
+    _p_mlist = libvlc_media_list_new(_p_libvlc);
 
-            if( SysStringLen(_bstr_baseurl) > 0 )
+    // initial playlist item
+    if( SysStringLen(_bstr_mrl) > 0 )
+    {
+        char *psz_mrl = NULL;
+
+        if( SysStringLen(_bstr_baseurl) > 0 )
+        {
+            /*
+            ** if the MRL a relative URL, we should end up with an absolute URL
+            */
+            LPWSTR abs_url = CombineURL(_bstr_baseurl, _bstr_mrl);
+            if( NULL != abs_url )
             {
-                /*
-                ** if the MRL a relative URL, we should end up with an absolute URL
-                */
-                LPWSTR abs_url = CombineURL(_bstr_baseurl, _bstr_mrl);
-                if( NULL != abs_url )
-                {
-                    psz_mrl = CStrFromWSTR(CP_UTF8, abs_url, wcslen(abs_url));
-                    CoTaskMemFree(abs_url);
-                }
-                else
-                {
-                    psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
-                }
+                psz_mrl = CStrFromWSTR(CP_UTF8, abs_url, wcslen(abs_url));
+                CoTaskMemFree(abs_url);
             }
             else
             {
-                /*
-                ** baseURL is empty, assume MRL is absolute
-                */
                 psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
             }
-            if( NULL != psz_mrl )
-            {
-                const char *options[1];
-                int i_options = 0;
+        }
+        else
+        {
+            /*
+            ** baseURL is empty, assume MRL is absolute
+            */
+            psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
+        }
+        if( NULL != psz_mrl )
+        {
+            const char *options[1];
+            int i_options = 0;
 
-                char timeBuffer[32];
-                if( _i_time )
-                {
-                    snprintf(timeBuffer, sizeof(timeBuffer), ":start-time=%d", _i_time);
-                    options[i_options++] = timeBuffer;
-                }
-                // add default target to playlist
-                libvlc_playlist_add_extended(_p_libvlc, psz_mrl, NULL, i_options, options, NULL);
-                CoTaskMemFree(psz_mrl);
+            char timeBuffer[32];
+            if( _i_time )
+            {
+                snprintf(timeBuffer, sizeof(timeBuffer), ":start-time=%d", _i_time);
+                options[i_options++] = timeBuffer;
             }
+            // add default target to playlist
+            playlist_add_extended_untrusted(psz_mrl, i_options, options);
+            CoTaskMemFree(psz_mrl);
         }
     }
-    *pp_libvlc = _p_libvlc;
-    return S_OK;
 };
 
 void VLCPlugin::setErrorInfo(REFIID riid, const char *description)
@@ -656,18 +652,11 @@ HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
     {
         libvlc_instance_t* p_libvlc = _p_libvlc;
 
-        IVLCLog *p_log;
-        if( SUCCEEDED(vlcControl2->get_log(&p_log)) )
-        {
-            // make sure the log is disabled
-            p_log->put_verbosity(-1);
-            p_log->Release();
-        }
-
         _p_libvlc = NULL;
         vlcDataObject->onClose();
 
-        libvlc_release(p_libvlc);
+        if( p_libvlc )
+            libvlc_release(p_libvlc);
     }
     return S_OK;
 };
@@ -724,19 +713,9 @@ HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprc
         if( FAILED(result) )
             return result;
 
-        /* set internal video width and height */
-        libvlc_video_set_size(p_libvlc,
-            lprcPosRect->right-lprcPosRect->left,
-            lprcPosRect->bottom-lprcPosRect->top,
-            NULL );
-
-        /* set internal video parent window */
-        libvlc_video_set_parent(p_libvlc,
-            reinterpret_cast<libvlc_drawable_t>(_inplacewnd), NULL);
-
-        if( _b_autoplay & (libvlc_playlist_items_count(p_libvlc, NULL) > 0) )
+        if( _b_autoplay && playlist_select(0) )
         {
-            libvlc_playlist_play(p_libvlc, 0, 0, NULL, NULL);
+            libvlc_media_player_play(_p_mplayer);
             fireOnPlayEvent();
         }
     }
@@ -749,9 +728,9 @@ HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprc
 
 HRESULT VLCPlugin::onInPlaceDeactivate(void)
 {
-    if( isRunning() )
+    if( isPlaying() )
     {
-        libvlc_playlist_stop(_p_libvlc, NULL);
+        playlist_stop();
         fireOnStopEvent();
     }
 
@@ -789,7 +768,10 @@ void VLCPlugin::setVolume(int volume)
         _i_volume = volume;
         if( isRunning() )
         {
-            libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
+            libvlc_media_player_t *p_md;
+            HRESULT hr = getMD(&p_md);
+            if( SUCCEEDED(hr) )
+                libvlc_audio_set_volume(p_md, _i_volume);
         }
         setDirty(TRUE);
     }
@@ -816,14 +798,9 @@ void VLCPlugin::setTime(int seconds)
     if( seconds != _i_time )
     {
         setStartTime(_i_time);
-        if( isRunning() )
+        if( NULL != _p_mplayer )
         {
-            libvlc_media_instance_t *p_md = libvlc_playlist_get_media_instance(_p_libvlc, NULL);
-            if( NULL != p_md )
-            {
-                libvlc_media_instance_set_time(p_md, _i_time, NULL);
-                libvlc_media_instance_release(p_md);
-            }
+            libvlc_media_player_set_time(_p_mplayer, _i_time);
         }
     }
 };
@@ -999,13 +976,6 @@ void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
     SetWindowRgn(_inplacewnd, clipRgn, FALSE);
 
     //RedrawWindow(_videownd, &posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
-    if( isRunning() )
-    {
-        libvlc_video_set_size(_p_libvlc,
-            lprcPosRect->right-lprcPosRect->left,
-            lprcPosRect->bottom-lprcPosRect->top,
-            NULL );
-    }
 };
 
 void VLCPlugin::freezeEvents(BOOL freeze)
@@ -1035,3 +1005,342 @@ void VLCPlugin::fireOnStopEvent(void)
     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
     vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs);
 };
+
+/*
+ * Async events
+ */
+void VLCPlugin::fireOnMediaPlayerNothingSpecialEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerNothingSpecialEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerOpeningEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerOpeningEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerBufferingEvent(long cache)
+{
+    DISPPARAMS params;
+    params.cArgs = 1;
+    params.rgvarg = (VARIANTARG *) CoTaskMemAlloc(sizeof(VARIANTARG) * params.cArgs) ;
+    memset(params.rgvarg, 0, sizeof(VARIANTARG) * params.cArgs);
+    params.rgvarg[0].vt = VT_I4;
+    params.rgvarg[0].lVal = cache;
+    params.rgdispidNamedArgs = NULL;
+    params.cNamedArgs = 0;
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerBufferingEvent, &params);
+};
+
+void VLCPlugin::fireOnMediaPlayerPlayingEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerPlayingEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerPausedEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerPausedEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerEncounteredErrorEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerEncounteredErrorEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerEndReachedEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerEndReachedEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerStoppedEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerStoppedEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerForwardEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerForwardEvent, &dispparamsNoArgs);
+};
+
+void VLCPlugin::fireOnMediaPlayerBackwardEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerBackwardEvent, &dispparamsNoArgs);
+};
+
+static void handle_input_state_event(const libvlc_event_t* event, void *param)
+{
+    VLCPlugin *plugin = (VLCPlugin*)param;
+    switch( event->type )
+    {
+        case libvlc_MediaPlayerNothingSpecial:
+            plugin->fireOnMediaPlayerNothingSpecialEvent();
+            break;
+        case libvlc_MediaPlayerOpening:
+            plugin->fireOnMediaPlayerOpeningEvent();
+            break;
+        case libvlc_MediaPlayerBuffering:
+            plugin->fireOnMediaPlayerBufferingEvent(event->u.media_player_buffering.new_cache);
+            break;
+        case libvlc_MediaPlayerPlaying:
+            plugin->fireOnMediaPlayerPlayingEvent();
+            break;
+        case libvlc_MediaPlayerPaused:
+            plugin->fireOnMediaPlayerPausedEvent();
+            break;
+        case libvlc_MediaPlayerStopped:
+            plugin->fireOnMediaPlayerStoppedEvent();
+            break;
+        case libvlc_MediaPlayerForward:
+            plugin->fireOnMediaPlayerForwardEvent();
+            break;
+        case libvlc_MediaPlayerBackward:
+            plugin->fireOnMediaPlayerBackwardEvent();
+            break;
+        case libvlc_MediaPlayerEndReached:
+            plugin->fireOnMediaPlayerEndReachedEvent();
+            break;
+        case libvlc_MediaPlayerEncounteredError:
+            plugin->fireOnMediaPlayerEncounteredErrorEvent();
+            break;
+    }
+}
+
+void VLCPlugin::fireOnMediaPlayerTimeChangedEvent(long time)
+{
+    DISPPARAMS params;
+    params.cArgs = 1;
+    params.rgvarg = (VARIANTARG *) CoTaskMemAlloc(sizeof(VARIANTARG) * params.cArgs) ;
+    memset(params.rgvarg, 0, sizeof(VARIANTARG) * params.cArgs);
+    params.rgvarg[0].vt = VT_I4;
+    params.rgvarg[0].lVal = time;
+    params.rgdispidNamedArgs = NULL;
+    params.cNamedArgs = 0;
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerTimeChangedEvent, &params);
+};
+
+static void handle_time_changed_event(const libvlc_event_t* event, void *param)
+{
+    VLCPlugin *plugin = (VLCPlugin*)param;
+    plugin->fireOnMediaPlayerTimeChangedEvent(event->u.media_player_time_changed.new_time);
+}
+
+void VLCPlugin::fireOnMediaPlayerPositionChangedEvent(long position)
+{
+    DISPPARAMS params;
+    params.cArgs = 1;
+    params.rgvarg = (VARIANTARG *) CoTaskMemAlloc(sizeof(VARIANTARG) * params.cArgs) ;
+    memset(params.rgvarg, 0, sizeof(VARIANTARG) * params.cArgs);
+    params.rgvarg[0].vt = VT_I4;
+    params.rgvarg[0].lVal = position;
+    params.rgdispidNamedArgs = NULL;
+    params.cNamedArgs = 0;
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerPositionChangedEvent, &params);
+};
+
+static void handle_position_changed_event(const libvlc_event_t* event, void *param)
+{
+    VLCPlugin *plugin = (VLCPlugin*)param;
+    plugin->fireOnMediaPlayerPositionChangedEvent(event->u.media_player_position_changed.new_position);
+}
+
+#define B(val) ((val) ? 0xFFFF : 0x0000)
+void VLCPlugin::fireOnMediaPlayerSeekableChangedEvent(VARIANT_BOOL seekable)
+{
+    DISPPARAMS params;
+    params.cArgs = 1;
+    params.rgvarg = (VARIANTARG *) CoTaskMemAlloc(sizeof(VARIANTARG) * params.cArgs) ;
+    memset(params.rgvarg, 0, sizeof(VARIANTARG) * params.cArgs);
+    params.rgvarg[0].vt = VT_BOOL;
+    params.rgvarg[0].boolVal = seekable;
+    params.rgdispidNamedArgs = NULL;
+    params.cNamedArgs = 0;
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerSeekableChangedEvent, &params);
+};
+
+static void handle_seekable_changed_event(const libvlc_event_t* event, void *param)
+{
+    VLCPlugin *plugin = (VLCPlugin*)param;
+    plugin->fireOnMediaPlayerSeekableChangedEvent(B(event->u.media_player_seekable_changed.new_seekable));
+}
+
+void VLCPlugin::fireOnMediaPlayerPausableChangedEvent(VARIANT_BOOL pausable)
+{
+    DISPPARAMS params;
+    params.cArgs = 1;
+    params.rgvarg = (VARIANTARG *) CoTaskMemAlloc(sizeof(VARIANTARG) * params.cArgs) ;
+    memset(params.rgvarg, 0, sizeof(VARIANTARG) * params.cArgs);
+    params.rgvarg[0].vt = VT_BOOL;
+    params.rgvarg[0].boolVal = pausable;
+    params.rgdispidNamedArgs = NULL;
+    params.cNamedArgs = 0;
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerPausableChangedEvent, &params);
+};
+
+static void handle_pausable_changed_event(const libvlc_event_t* event, void *param)
+{
+    VLCPlugin *plugin = (VLCPlugin*)param;
+    plugin->fireOnMediaPlayerPausableChangedEvent(B(event->u.media_player_pausable_changed.new_pausable));
+}
+#undef B
+
+/* */
+
+bool VLCPlugin::playlist_select( int idx )
+{
+    libvlc_media_t *p_m = NULL;
+
+    assert(_p_mlist);
+
+    libvlc_media_list_lock(_p_mlist);
+
+    int count = libvlc_media_list_count(_p_mlist);
+
+    if( (idx < 0) || (idx >= count) )
+        goto bad_unlock;
+
+    _i_midx = idx;
+
+    p_m = libvlc_media_list_item_at_index(_p_mlist,_i_midx);
+    libvlc_media_list_unlock(_p_mlist);
+    if( !p_m )
+        return false;
+
+    if( _p_mplayer )
+    {
+        if( isPlaying() )
+            playlist_stop();
+        player_unregister_events();
+        libvlc_media_player_release( _p_mplayer );
+        _p_mplayer = NULL;
+    }
+
+    _p_mplayer = libvlc_media_player_new_from_media(p_m);
+    if( _p_mplayer )
+    {
+        // initial volume setting
+        libvlc_audio_set_volume(_p_mplayer, _i_volume);
+        if( _b_mute )
+            libvlc_audio_set_mute(_p_mplayer, TRUE);
+        set_player_window();
+        player_register_events();
+    }
+
+    libvlc_media_release(p_m);
+    return _p_mplayer ? true : false;
+
+bad_unlock:
+    libvlc_media_list_unlock(_p_mlist);
+    return false;
+}
+
+void VLCPlugin::set_player_window()
+{
+    // XXX FIXME no idea if this is correct or not
+    libvlc_media_player_set_hwnd(_p_mplayer,getInPlaceWindow());
+}
+
+void VLCPlugin::player_register_events()
+{
+    libvlc_event_manager_t *eventManager = NULL;
+    assert(_p_mplayer);
+
+    eventManager = libvlc_media_player_event_manager(_p_mplayer);
+    if(eventManager) {
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerNothingSpecial,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerOpening,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerPaused,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerStopped,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerForward,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerBackward,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached,
+                            handle_input_state_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError,
+                            handle_input_state_event, this);
+
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged,
+                            handle_time_changed_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged,
+                            handle_position_changed_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerSeekableChanged,
+                            handle_seekable_changed_event, this);
+        libvlc_event_attach(eventManager, libvlc_MediaPlayerPausableChanged,
+                            handle_pausable_changed_event, this);
+    }
+}
+
+void VLCPlugin::player_unregister_events()
+{
+    libvlc_event_manager_t *eventManager = NULL;
+    assert(_p_mplayer);
+
+    eventManager = libvlc_media_player_event_manager(_p_mplayer);
+    if(eventManager) {
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerNothingSpecial,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerOpening,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerBuffering,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerPlaying,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerPaused,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerStopped,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerForward,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerBackward,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerEndReached,
+                            handle_input_state_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerEncounteredError,
+                            handle_input_state_event, this);
+
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerTimeChanged,
+                            handle_time_changed_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerPositionChanged,
+                            handle_position_changed_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerSeekableChanged,
+                            handle_seekable_changed_event, this);
+        libvlc_event_detach(eventManager, libvlc_MediaPlayerPausableChanged,
+                            handle_pausable_changed_event, this);
+    }
+}
+
+int  VLCPlugin::playlist_add_extended_untrusted(const char *mrl, int optc, const char **optv)
+{
+    int item = -1;
+    libvlc_media_t *p_m = libvlc_media_new_location(_p_libvlc,mrl);
+    if( !p_m )
+        return -1;
+
+    for( int i = 0; i < optc; ++i )
+        libvlc_media_add_option_flag(p_m, optv[i], libvlc_media_option_unique);
+
+    libvlc_media_list_lock(_p_mlist);
+    if( libvlc_media_list_add_media(_p_mlist,p_m) == 0 )
+        item = libvlc_media_list_count(_p_mlist)-1;
+    libvlc_media_list_unlock(_p_mlist);
+    libvlc_media_release(p_m);
+
+    return item;
+}