Fix bug in vlc.audio.track and add new properties vlc.video.subtitle
authorJean-Paul Saman <jpsaman@videolan.org>
Sun, 11 Mar 2007 20:17:04 +0000 (20:17 +0000)
committerJean-Paul Saman <jpsaman@videolan.org>
Sun, 11 Mar 2007 20:17:04 +0000 (20:17 +0000)
to JavaScript API implementation.

12 files changed:
activex/axvlc.idl
activex/axvlc.tlb
activex/axvlc_idl.c
activex/axvlc_idl.h
activex/vlccontrol2.cpp
activex/vlccontrol2.h
include/vlc/libvlc.h
mozilla/control/npolibvlc.cpp
mozilla/control/npolibvlc.h
src/control/audio.c
src/control/input.c
src/control/video.c

index 910557c..bc2e184 100644 (file)
@@ -205,9 +205,9 @@ library AXVLC
         [propput, helpstring("Returns/sets audio track used/to use.")]\r
         HRESULT track([in] long track);\r
 \r
-        [propget, helpstring("Returns audio channel: reverse stereo, stereo, left, right, dolby.")]\r
+        [propget, helpstring("Returns audio channel [1-5] indicating; stereo, reverse stereo, left, right, dolby.")]\r
         HRESULT channel([out, retval] long* channel);\r
-        [propput, helpstring("Sets audio channel to: reverse stereo, stereo, left, right, dolby.")]\r
+        [propput, helpstring("Sets audio channel to [1-5] indicating; stereo, reverse stereo, left, right, dolby.")]\r
         HRESULT channel([in] long channel);\r
     };\r
 \r
@@ -422,6 +422,11 @@ library AXVLC
         [propput, helpstring("Sets video aspect ratio.")]\r
         HRESULT aspectRatio([in] BSTR aspect);\r
 \r
+        [propget, helpstring("Returns video subtitle used.")]\r
+        HRESULT subtitle([out, retval] long* spu);\r
+        [propput, helpstring("Sets video subtitle to use.")]\r
+        HRESULT subtitle([in] long spu);\r
+\r
         [propget, helpstring("Returns crop filter geometry.")]\r
         HRESULT crop([out, retval] BSTR* geometry);\r
         [propput, helpstring("Sets crop filter geometry.")]\r
index 4839f43..99342d7 100644 (file)
Binary files a/activex/axvlc.tlb and b/activex/axvlc.tlb differ
index 17b6b83..7313f35 100644 (file)
@@ -1,4 +1,4 @@
-/*** Autogenerated by WIDL 0.9.27 from axvlc.idl - Do not edit ***/
+/*** Autogenerated by WIDL 0.9.30 from axvlc.idl - Do not edit ***/
 
 #include <rpc.h>
 #include <rpcndr.h>
index 014ebf1..722cf80 100644 (file)
@@ -1,4 +1,4 @@
-/*** Autogenerated by WIDL 0.9.27 from axvlc.idl - Do not edit ***/
+/*** Autogenerated by WIDL 0.9.30 from axvlc.idl - Do not edit ***/
 #include <rpc.h>
 #include <rpcndr.h>
 
@@ -2253,6 +2253,12 @@ interface IVLCVideo : public IDispatch
     virtual HRESULT STDMETHODCALLTYPE put_aspectRatio(
         BSTR aspect) = 0;
 
+    virtual HRESULT STDMETHODCALLTYPE get_subtitle(
+        long* spu) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE put_subtitle(
+        long spu) = 0;
+
     virtual HRESULT STDMETHODCALLTYPE get_crop(
         BSTR* geometry) = 0;
 
@@ -2337,6 +2343,14 @@ typedef struct IVLCVideoVtbl {
         IVLCVideo* This,
         BSTR aspect);
 
+    HRESULT (STDMETHODCALLTYPE *get_subtitle)(
+        IVLCVideo* This,
+        long* spu);
+
+    HRESULT (STDMETHODCALLTYPE *put_subtitle)(
+        IVLCVideo* This,
+        long spu);
+
     HRESULT (STDMETHODCALLTYPE *get_crop)(
         IVLCVideo* This,
         BSTR* geometry);
@@ -2375,6 +2389,8 @@ interface IVLCVideo {
 #define IVLCVideo_get_height(p,a) (p)->lpVtbl->get_height(p,a)
 #define IVLCVideo_get_aspectRatio(p,a) (p)->lpVtbl->get_aspectRatio(p,a)
 #define IVLCVideo_put_aspectRatio(p,a) (p)->lpVtbl->put_aspectRatio(p,a)
+#define IVLCVideo_get_subtitle(p,a) (p)->lpVtbl->get_subtitle(p,a)
+#define IVLCVideo_put_subtitle(p,a) (p)->lpVtbl->put_subtitle(p,a)
 #define IVLCVideo_get_crop(p,a) (p)->lpVtbl->get_crop(p,a)
 #define IVLCVideo_put_crop(p,a) (p)->lpVtbl->put_crop(p,a)
 #define IVLCVideo_toggleFullscreen(p) (p)->lpVtbl->toggleFullscreen(p)
@@ -2431,6 +2447,22 @@ void __RPC_STUB IVLCVideo_put_aspectRatio_Stub(
     IRpcChannelBuffer* pRpcChannelBuffer,
     PRPC_MESSAGE pRpcMessage,
     DWORD* pdwStubPhase);
+HRESULT CALLBACK IVLCVideo_get_subtitle_Proxy(
+    IVLCVideo* This,
+    long* spu);
+void __RPC_STUB IVLCVideo_get_subtitle_Stub(
+    IRpcStubBuffer* This,
+    IRpcChannelBuffer* pRpcChannelBuffer,
+    PRPC_MESSAGE pRpcMessage,
+    DWORD* pdwStubPhase);
+HRESULT CALLBACK IVLCVideo_put_subtitle_Proxy(
+    IVLCVideo* This,
+    long spu);
+void __RPC_STUB IVLCVideo_put_subtitle_Stub(
+    IRpcStubBuffer* This,
+    IRpcChannelBuffer* pRpcChannelBuffer,
+    PRPC_MESSAGE pRpcMessage,
+    DWORD* pdwStubPhase);
 HRESULT CALLBACK IVLCVideo_get_crop_Proxy(
     IVLCVideo* This,
     BSTR* geometry);
index 9cf4930..b772e74 100644 (file)
@@ -87,7 +87,7 @@ STDMETHODIMP VLCAudio::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCAudio::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCAudio::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -190,7 +190,8 @@ STDMETHODIMP VLCAudio::put_volume(long volume)
         libvlc_audio_set_volume(p_libvlc, volume, &ex);
         if( libvlc_exception_raised(&ex) )
         {
-            _p_instance->setErrorInfo(IID_IVLCAudio, libvlc_exception_get_message(&ex));
+            _p_instance->setErrorInfo(IID_IVLCAudio,
+                         libvlc_exception_get_message(&ex));
             libvlc_exception_clear(&ex);
             return E_FAIL;
         }
@@ -216,7 +217,8 @@ STDMETHODIMP VLCAudio::get_track(long* track)
         libvlc_input_free(p_input);
         if( libvlc_exception_raised(&ex) )
         {
-            _p_instance->setErrorInfo(IID_IVLCAudio, libvlc_exception_get_message(&ex));
+            _p_instance->setErrorInfo(IID_IVLCAudio,
+                         libvlc_exception_get_message(&ex));
             libvlc_exception_clear(&ex);
             return E_FAIL;
         }
@@ -239,7 +241,8 @@ STDMETHODIMP VLCAudio::put_track(long track)
         libvlc_input_free(p_input);
         if( libvlc_exception_raised(&ex) )
         {
-            _p_instance->setErrorInfo(IID_IVLCAudio, libvlc_exception_get_message(&ex));
+            _p_instance->setErrorInfo(IID_IVLCAudio,
+                         libvlc_exception_get_message(&ex));
             libvlc_exception_clear(&ex);
             return E_FAIL;
         }
@@ -307,7 +310,8 @@ STDMETHODIMP VLCAudio::toggleMute()
         libvlc_audio_toggle_mute(p_libvlc, &ex);
         if( libvlc_exception_raised(&ex) )
         {
-            _p_instance->setErrorInfo(IID_IVLCAudio, libvlc_exception_get_message(&ex));
+            _p_instance->setErrorInfo(IID_IVLCAudio,
+                         libvlc_exception_get_message(&ex));
             libvlc_exception_clear(&ex);
             return E_FAIL;
         }
@@ -373,7 +377,7 @@ STDMETHODIMP VLCInput::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCInput::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCInput::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -738,7 +742,7 @@ STDMETHODIMP VLCLog::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCLog::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCLog::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -991,7 +995,7 @@ STDMETHODIMP VLCMessages::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInf
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCMessages::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCMessages::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -1157,7 +1161,7 @@ STDMETHODIMP VLCMessageIterator::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO*
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCMessageIterator::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCMessageIterator::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -1288,7 +1292,7 @@ STDMETHODIMP VLCMessage::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCMessage::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCMessage::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -1448,7 +1452,7 @@ STDMETHODIMP VLCPlaylistItems::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* p
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCPlaylistItems::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCPlaylistItems::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -1597,7 +1601,7 @@ STDMETHODIMP VLCPlaylist::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInf
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCPlaylist::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCPlaylist::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -2003,7 +2007,7 @@ STDMETHODIMP VLCVideo::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCVideo::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCVideo::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
@@ -2217,6 +2221,58 @@ STDMETHODIMP VLCVideo::put_aspectRatio(BSTR aspect)
     return hr;
 };
 
+STDMETHODIMP VLCVideo::get_subtitle(long* spu)
+{
+    if( NULL == spu )
+        return E_POINTER;
+
+    libvlc_instance_t* p_libvlc;
+    HRESULT hr = _p_instance->getVLC(&p_libvlc);
+    if( SUCCEEDED(hr) )
+    {
+        libvlc_exception_t ex;
+        libvlc_exception_init(&ex);
+
+        libvlc_input_t *p_input = libvlc_playlist_get_input(p_libvlc, &ex);
+        if( ! libvlc_exception_raised(&ex) )
+        {
+            *spu = libvlc_video_get_spu(p_input, &ex);
+            libvlc_input_free(p_input);
+            if( ! libvlc_exception_raised(&ex) )
+            {
+                return NOERROR;
+            }
+        }
+        _p_instance->setErrorInfo(IID_IVLCVideo, libvlc_exception_get_message(&ex));
+        libvlc_exception_clear(&ex);
+        return E_FAIL;
+    }
+    return hr;
+};
+
+STDMETHODIMP VLCVideo::put_subtitle(long spu)
+{
+    libvlc_instance_t* p_libvlc;
+    HRESULT hr = _p_instance->getVLC(&p_libvlc);
+    if( SUCCEEDED(hr) )
+    {
+        libvlc_exception_t ex;
+        libvlc_exception_init(&ex);
+
+        libvlc_input_t *p_input = libvlc_playlist_get_input(p_libvlc, &ex);
+        libvlc_video_set_spu(p_input, spu, &ex);
+        libvlc_input_free(p_input);
+        if( libvlc_exception_raised(&ex) )
+        {
+            _p_instance->setErrorInfo(IID_IVLCVideo, libvlc_exception_get_message(&ex));
+            libvlc_exception_clear(&ex);
+            return E_FAIL;
+        }
+        return NOERROR;
+    }
+    return hr;
+};
+
 STDMETHODIMP VLCVideo::get_crop(BSTR* geometry)
 {
     if( NULL == geometry )
@@ -2438,7 +2494,7 @@ STDMETHODIMP VLCControl2::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInf
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCControl2::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCControl2::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(loadTypeInfo()) )
index 1bee4fa..832e1a9 100644 (file)
@@ -522,6 +522,8 @@ public:
     STDMETHODIMP get_height(long*);
     STDMETHODIMP get_aspectRatio(BSTR*);
     STDMETHODIMP put_aspectRatio(BSTR);
+    STDMETHODIMP get_subtitle(long*);
+    STDMETHODIMP put_subtitle(long);
     STDMETHODIMP get_crop(BSTR*);
     STDMETHODIMP put_crop(BSTR);
     STDMETHODIMP takeSnapshot(BSTR);
index e910bff..d3320ce 100644 (file)
@@ -188,6 +188,18 @@ VLC_PUBLIC_API int libvlc_playlist_isplaying( libvlc_instance_t *, libvlc_except
  */
 VLC_PUBLIC_API int libvlc_playlist_items_count( libvlc_instance_t *, libvlc_exception_t * );
 
+/**
+ * Lock the playlist instance
+ * \param p_instance the instance
+ */
+VLC_PUBLIC_API void libvlc_playlist_lock( libvlc_instance_t * );
+
+/**
+ * Unlock the playlist instance
+ * \param p_instance the instance
+ */
+VLC_PUBLIC_API void libvlc_playlist_unlock( libvlc_instance_t * );
+
 /**
  * Stop playing
  * \param p_instance the instance to stop
@@ -377,6 +389,22 @@ VLC_PUBLIC_API char *libvlc_video_get_aspect_ratio( libvlc_input_t *, libvlc_exc
  */
 VLC_PUBLIC_API void libvlc_video_set_aspect_ratio( libvlc_input_t *, char *, libvlc_exception_t * );
 
+/**
+ * Get current video subtitle
+ * \param p_input the input
+ * \param p_exception an initialized exception
+ * \return the video subtitle selected
+ */
+VLC_PUBLIC_API int libvlc_video_get_spu( libvlc_input_t *, libvlc_exception_t * );
+
+/**
+ * Set new video subtitle
+ * \param p_input the input
+ * \param i_spu new video subtitle to select
+ * \param p_exception an initialized exception
+ */
+VLC_PUBLIC_API void libvlc_video_set_spu( libvlc_input_t *, int , libvlc_exception_t * );
+
 /**
  * Get current crop filter geometry
  * \param p_input the input
@@ -606,6 +634,15 @@ VLC_PUBLIC_API void libvlc_vlm_set_output( libvlc_instance_t *, char *, char*,
 VLC_PUBLIC_API void libvlc_vlm_set_input( libvlc_instance_t *, char *, char*,
                                           libvlc_exception_t *);
 
+/**
+ * Add a media's input MRL. This will add the specified one.
+ * \param p_instance the instance
+ * \param psz_name the media to work on
+ * \param psz_input the input MRL
+ * \param p_exception an initialized exception
+ */
+VLC_PUBLIC_API void libvlc_vlm_add_input( libvlc_instance_t *, char *, char *,
+                                          libvlc_exception_t *p_exception );
 /**
  * Set output for a media
  * \param p_instance the instance
index 7e3ae5f..4a13d3e 100755 (executable)
@@ -1760,6 +1760,7 @@ const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
     "height",\r
     "width",\r
     "aspectRatio",\r
+    "subtitle",\r
     "crop"\r
 };\r
 \r
@@ -1769,6 +1770,7 @@ enum LibvlcVideoNPObjectPropertyIds
     ID_video_height,\r
     ID_video_width,\r
     ID_video_aspectratio,\r
+    ID_video_subtitle,\r
     ID_video_crop\r
 };\r
 \r
@@ -1847,6 +1849,19 @@ RuntimeNPObject::InvokeResult LibvlcVideoNPObject::getProperty(int index, NPVari
                 STRINGZ_TO_NPVARIANT(psz_aspect, result);\r
                 return INVOKERESULT_NO_ERROR;\r
             }\r
+            case ID_video_subtitle:\r
+            {\r
+                int i_spu = libvlc_video_get_spu(p_input, &ex);\r
+                libvlc_input_free(p_input);\r
+                if( libvlc_exception_raised(&ex) )\r
+                {\r
+                    NPN_SetException(this, libvlc_exception_get_message(&ex));\r
+                    libvlc_exception_clear(&ex);\r
+                    return INVOKERESULT_GENERIC_ERROR;\r
+                }\r
+                INT32_TO_NPVARIANT(i_spu, result);\r
+                return INVOKERESULT_NO_ERROR;\r
+            }\r
             case ID_video_crop:\r
             {\r
                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_input, &ex);\r
@@ -1936,6 +1951,24 @@ RuntimeNPObject::InvokeResult LibvlcVideoNPObject::setProperty(int index, const
                 }\r
                 return INVOKERESULT_NO_ERROR;\r
             }\r
+            case ID_video_subtitle:\r
+            {\r
+                if( isNumberValue(value) )\r
+                {\r
+                    libvlc_video_set_spu(p_input,\r
+                                         numberValue(value), &ex);\r
+                    libvlc_input_free(p_input);\r
+                    if( libvlc_exception_raised(&ex) )\r
+                    {\r
+                        NPN_SetException(this, libvlc_exception_get_message(&ex));\r
+                        libvlc_exception_clear(&ex);\r
+                        return INVOKERESULT_GENERIC_ERROR;\r
+                    }\r
+                    return INVOKERESULT_NO_ERROR;\r
+                }\r
+                libvlc_input_free(p_input);\r
+                return INVOKERESULT_INVALID_VALUE;\r
+            }\r
             case ID_video_crop:\r
             {\r
                 char *psz_geometry = NULL;\r
index b0639ff..96be103 100755 (executable)
@@ -252,4 +252,3 @@ protected:
 \r
     InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result);\r
 };\r
-\r
index 1500a24..9c0185c 100644 (file)
@@ -146,14 +146,34 @@ int libvlc_audio_get_track( libvlc_input_t *p_input,
                             libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread = GetInput( p_input, p_e );
-    int i_track = 0;
+    vlc_value_t val_list;
+    vlc_value_t val;
+    int i_track = -1;
+    int i_ret = -1;
+    int i;
 
     if( !p_input_thread )
         return -1;
 
-    i_track = var_GetInteger( p_input_thread, "audio-es" );
-    vlc_object_release( p_input_thread );
+    i_ret = var_Get( p_input_thread, "audio-es", &val );
+    if( i_ret < 0 )
+    {
+        libvlc_exception_raise( p_e, "Getting Audio track information failed" );
+        vlc_object_release( p_input_thread );
+        return i_ret;
+    }
 
+    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        vlc_value_t track_val = val_list.p_list->p_values[i];
+        if( track_val.i_int == val.i_int )
+        {
+            i_track = i;
+            break;
+       }
+    }
+    vlc_object_release( p_input_thread );
     return i_track;
 }
 
@@ -175,9 +195,9 @@ void libvlc_audio_set_track( libvlc_input_t *p_input, int i_track,
     for( i = 0; i < val_list.p_list->i_count; i++ )
     {
         vlc_value_t val = val_list.p_list->p_values[i];
-        if( i_track == val.i_int )
+        if( i_track == i )
         {
-            i_ret = var_SetInteger( p_input_thread, "audio-es", i_track );
+            i_ret = var_Set( p_input_thread, "audio-es", val );
             if( i_ret < 0 )
             {
                 libvlc_exception_raise( p_e, "Setting audio track failed" );
index 140b018..6835e54 100644 (file)
@@ -137,7 +137,7 @@ float libvlc_input_get_position( libvlc_input_t *p_input,
 float libvlc_input_get_fps( libvlc_input_t *p_input,
                             libvlc_exception_t *p_e) 
 {
-    double f_fps;
+    double f_fps = 0.0;
     input_thread_t *p_input_thread;
 
     p_input_thread = libvlc_get_input_thread ( p_input, p_e );
index 7a1a932..48f8e7d 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Authors: Cl´┐Żent Stenac <zorglub@videolan.org>
  *          Filippo Carone <littlejohn@videolan.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
@@ -352,7 +353,7 @@ void libvlc_video_set_viewport( libvlc_instance_t *p_instance,
 }
 
 char *libvlc_video_get_aspect_ratio( libvlc_input_t *p_input,
-                                   libvlc_exception_t *p_e )
+                                     libvlc_exception_t *p_e )
 {
     char *psz_aspect = 0;
     vout_thread_t *p_vout = GetVout( p_input, p_e );
@@ -382,6 +383,74 @@ void libvlc_video_set_aspect_ratio( libvlc_input_t *p_input,
     vlc_object_release( p_vout );
 }
 
+int libvlc_video_get_spu( libvlc_input_t *p_input,
+                          libvlc_exception_t *p_e )
+{
+    input_thread_t *p_input_thread = GetInputThread( p_input, p_e );
+    vlc_value_t val_list;
+    vlc_value_t val;
+    int i_spu = -1;
+    int i_ret = -1;
+    int i;
+
+    if( !p_input_thread )
+        return -1;
+
+    i_ret = var_Get( p_input_thread, "spu-es", &val );
+    if( i_ret < 0 )
+    {
+        libvlc_exception_raise( p_e, "Getting subtitle information failed" );
+        vlc_object_release( p_input_thread );
+        return i_ret;
+    }
+
+    var_Change( p_input_thread, "spu-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        vlc_value_t spu_val = val_list.p_list->p_values[i];
+        if( val.i_int == spu_val.i_int )
+        {
+            i_spu = i;
+            break;
+        }
+    }
+    vlc_object_release( p_input_thread );
+    return i_spu;
+}
+
+void libvlc_video_set_spu( libvlc_input_t *p_input, int i_spu,
+                           libvlc_exception_t *p_e )
+{
+    input_thread_t *p_input_thread = GetInputThread( p_input, p_e );
+    vlc_value_t val_list;
+    int i_ret = -1;
+    int i;
+
+    if( !p_input_thread )
+        return;
+
+    var_Change( p_input_thread, "spu-es", VLC_VAR_GETCHOICES, &val_list, NULL );
+    for( i = 0; i < val_list.p_list->i_count; i++ )
+    {
+        vlc_value_t val = val_list.p_list->p_values[i];
+        if( i_spu == i )
+        {
+            vlc_value_t new_val;
+
+            new_val.i_int = val.i_int;
+            i_ret = var_Set( p_input_thread, "spu-es", new_val );
+            if( i_ret < 0 )
+            {
+                libvlc_exception_raise( p_e, "Setting subtitle value failed" );
+            }
+            vlc_object_release( p_input_thread );
+            return;
+        }
+    }
+    libvlc_exception_raise( p_e, "Subtitle value out of range" );
+    vlc_object_release( p_input_thread );
+}
+
 char *libvlc_video_get_crop_geometry( libvlc_input_t *p_input,
                                    libvlc_exception_t *p_e )
 {