NativeLibVlc.cs
Jump to navigation
Jump to search
This page contains example code for .Net Interface to VLC. This code is licensed under the GNU Lesser General public license |
/***************************************************************************** * NativeLibVlc.cs: NativeLibVlc class definition ***************************************************************************** * Copyright (C) 2006 Chris Meadowcroft * * Authors: Chris Meadowcroft * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * 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 Lesser 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. *****************************************************************************/ using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using Microsoft.Win32; namespace VLanControl { internal enum ObjectType : int { VLC_OBJECT_ROOT = (-1), VLC_OBJECT_VLC = (-2), VLC_OBJECT_MODULE = (-3), VLC_OBJECT_INTF = (-4), VLC_OBJECT_PLAYLIST = (-5), VLC_OBJECT_ITEM = (-6), VLC_OBJECT_INPUT = (-7), VLC_OBJECT_DECODER = (-8), VLC_OBJECT_VOUT = (-9), VLC_OBJECT_AOUT = (-10), VLC_OBJECT_SOUT = (-11), VLC_OBJECT_HTTPD = (-12), VLC_OBJECT_PACKETIZER = (-13), VLC_OBJECT_ENCODER = (-14), VLC_OBJECT_DIALOGS = (-15), VLC_OBJECT_VLM = (-16), VLC_OBJECT_ANNOUNCE = (-17), VLC_OBJECT_DEMUX = (-18), VLC_OBJECT_ACCESS = (-19), VLC_OBJECT_STREAM = (-20), VLC_OBJECT_OPENGL = (-21), VLC_OBJECT_FILTER = (-22), VLC_OBJECT_VOD = (-23), VLC_OBJECT_SPU = (-24), VLC_OBJECT_TLS = (-25), VLC_OBJECT_SD = (-26), VLC_OBJECT_XML = (-27), VLC_OBJECT_OSDMENU = (-28), VLC_OBJECT_STATS = (-29), VLC_OBJECT_HTTPD_HOST = (-30), VLC_OBJECT_GENERIC = (-666), } internal enum VlcError : int { Success = -0, NoMem = -1, Thread = -2, Timeout = -3, NoMod = -10, NoObj = -20, BadObj = -21, NoVar = -30, BadVar = -31, Exit = -255, Generic = -666, Exception = -998, NoInit = -999, }; internal enum InputState : int { INIT_S = 0, OPENING_S = 1, BUFFERING_S = 2, PLAYING_S = 3, PAUSE_S = 4, END_S = 5, ERROR_S = 6, } internal class NativeLibVlc : IDisposable { #region private vlc enums enum Mode : int { Insert = 0x01, Replace = 0x02, Append = 0x04, Go = 0x08, CheckInsert = 0x10 }; public const Int32 EndOfPlaylist = -666; [Flags] enum ObjectSearchMode : int { FIND_PARENT = 0x0001, FIND_CHILD = 0x0002, FIND_ANYWHERE = 0x0003, FIND_STRICT = 0x0010, } [Flags] enum VarFlags : int { /** \defgroup var_flags Additive flags * These flags are added to the type field of the variable. Most as a result of * a __var_Change() call, but some may be added at creation time * @{ */ VLC_VAR_HASCHOICE = 0x0100, VLC_VAR_HASMIN = 0x0200, VLC_VAR_HASMAX = 0x0400, VLC_VAR_HASSTEP = 0x0800, VLC_VAR_ISLIST = 0x1000, VLC_VAR_ISCOMMAND = 0x2000, VLC_VAR_ISCONFIG = 0x2000, /** Creation flag */ VLC_VAR_DOINHERIT = 0x8000, /** * \defgroup var_action Variable actions * These are the different actions that can be used with __var_Change(). * The parameters given are the meaning of the two last parameters of * __var_Change() when this action is being used. * @{ */ /** * Set the minimum value of this variable * \param p_val The new minimum value * \param p_val2 Unused */ VLC_VAR_SETMIN = 0x0010, /** * Set the maximum value of this variable * \param p_val The new maximum value * \param p_val2 Unused */ VLC_VAR_SETMAX = 0x0011, VLC_VAR_SETSTEP = 0x0012, /** * Set the value of this variable without triggering any callbacks * \param p_val The new value * \param p_val2 Unused */ VLC_VAR_SETVALUE = 0x0013, VLC_VAR_SETTEXT = 0x0014, VLC_VAR_GETTEXT = 0x0015, VLC_VAR_ADDCHOICE = 0x0020, VLC_VAR_DELCHOICE = 0x0021, VLC_VAR_CLEARCHOICES = 0x0022, VLC_VAR_SETDEFAULT = 0x0023, VLC_VAR_GETCHOICES = 0x0024, VLC_VAR_FREECHOICES = 0x0025, VLC_VAR_GETLIST = 0x0026, VLC_VAR_FREELIST = 0x0027, VLC_VAR_CHOICESCOUNT = 0x0028, VLC_VAR_INHERITVALUE = 0x0030, VLC_VAR_TRIGGER_CALLBACKS = 0x0035, } enum playlist_command : int { PLAYLIST_PLAY = 0, /**< No arg. res=can fail*/ PLAYLIST_AUTOPLAY = 1, /**< No arg. res=cant fail*/ PLAYLIST_VIEWPLAY = 2, /**< arg1= int, arg2= playlist_item_t*,*/ /** arg3 = playlist_item_t* , res=can fail */ PLAYLIST_ITEMPLAY = 3, /** <arg1 = playlist_item_t * , res=can fail */ PLAYLIST_PAUSE = 4, /**< No arg res=can fail*/ PLAYLIST_STOP = 5, /**< No arg res=can fail*/ PLAYLIST_SKIP = 6, /**< arg1=int, res=can fail*/ PLAYLIST_GOTO = 7, /**< arg1=int res=can fail */ PLAYLIST_VIEWGOTO = 8 /**< arg1=int res=can fail */ } enum CONFIG_ITEM : int { CONFIG_ITEM_STRING = 0x0010, CONFIG_ITEM_FILE = 0x0020, CONFIG_ITEM_MODULE = 0x0030, CONFIG_ITEM_INTEGER = 0x0040, CONFIG_ITEM_BOOL = 0x0050, CONFIG_ITEM_FLOAT = 0x0060, } enum input_query_e : int { /* input variable "position" */ INPUT_GET_POSITION = 0, /* arg1= double * res= */ INPUT_SET_POSITION, /* arg1= double res=can fail */ /* input variable "length" */ INPUT_GET_LENGTH, /* arg1= int64_t * res=can fail */ /* input variable "time" */ INPUT_GET_TIME, /* arg1= int64_t * res= */ INPUT_SET_TIME, /* arg1= int64_t res=can fail */ /* input variable "rate" (1 is DEFAULT_RATE) */ INPUT_GET_RATE, /* arg1= int * res= */ INPUT_SET_RATE, /* arg1= int res=can fail */ /* input variable "state" */ INPUT_GET_STATE, /* arg1= int * res= */ INPUT_SET_STATE, /* arg1= int res=can fail */ /* input variable "audio-delay" and "sub-delay" */ INPUT_GET_AUDIO_DELAY, /* arg1 = int* res=can fail */ INPUT_SET_AUDIO_DELAY, /* arg1 = int res=can fail */ INPUT_GET_SPU_DELAY, /* arg1 = int* res=can fail */ INPUT_SET_SPU_DELAY, /* arg1 = int res=can fail */ /* Meta datas */ INPUT_ADD_INFO, /* arg1= char* arg2= char* arg3=... res=can fail */ INPUT_GET_INFO, /* arg1= char* arg2= char* arg3= char** res=can fail */ INPUT_DEL_INFO, /* arg1= char* arg2= char* res=can fail */ INPUT_SET_NAME, /* arg1= char* res=can fail */ /* Input config options */ INPUT_ADD_OPTION, /* arg1= char * arg2= char * res=can fail*/ /* Input properties */ INPUT_GET_BYTE_POSITION, /* arg1= int64_t * res= */ INPUT_SET_BYTE_SIZE, /* arg1= int64_t * res= */ /* bookmarks */ INPUT_GET_BOOKMARKS, /* arg1= seekpoint_t *** arg2= int * res=can fail */ INPUT_CLEAR_BOOKMARKS, /* res=can fail */ INPUT_ADD_BOOKMARK, /* arg1= seekpoint_t * res=can fail */ INPUT_CHANGE_BOOKMARK, /* arg1= seekpoint_t * arg2= int * res=can fail */ INPUT_DEL_BOOKMARK, /* arg1= seekpoint_t * res=can fail */ INPUT_SET_BOOKMARK, /* arg1= int res=can fail */ /* On the fly input slave */ INPUT_ADD_SLAVE /* arg1= char * */ } #endregion #region private vlc structs [StructLayout(LayoutKind.Sequential)] struct libvlc_exception_t { public Int32 b_raised; public IntPtr psz_message; public void Init() { libvlc_exception_init(out this); } public bool WasExceptionRaised() { if(0 != libvlc_exception_raised(ref this)) { libvlc_exception_clear(ref this); return true; } return false; } } [StructLayout(LayoutKind.Sequential)] struct libvlc_instance_t { public IntPtr p_vlc; public IntPtr p_playlist; public IntPtr p_vlm; public Int32 i_vlc_id; public libvlc_instance_t(IntPtr vlc, IntPtr playlist, int vlcHandle) { this.p_vlc = vlc; this.p_playlist = playlist; this.p_vlm = IntPtr.Zero; this.i_vlc_id = vlcHandle; } } [StructLayout(LayoutKind.Sequential)] struct vlc_list_t { public Int32 i_count; public IntPtr p_values; public IntPtr pi_types; } [StructLayout( LayoutKind.Explicit )] struct vlc_value_t { [FieldOffset( 0 )] public Int32 i_int; [FieldOffset( 0 )] public Int32 b_bool; [FieldOffset( 0 )][MarshalAs(UnmanagedType.R4)] public float f_float; [FieldOffset( 0 )] public IntPtr psz_string; [FieldOffset( 0 )] public IntPtr p_address; [FieldOffset( 0 )] public IntPtr p_object; [FieldOffset( 0 )] public IntPtr p_list; [FieldOffset( 0 )][MarshalAs(UnmanagedType.I8)] public Int64 i_time; [FieldOffset( 0 )] public IntPtr psz_name; [FieldOffset( 4 )] public Int32 i_object_id; } [StructLayout(LayoutKind.Sequential)] struct module_config_t { public CONFIG_ITEM i_type; } #endregion #region vlc api interop const int AOUT_VOLUME_MAX = 1024; const int VOLUME_MAX = 200; const int DEFAULT_CHAN = 1; const String Playlist_Current = "item-change"; const String Now_Playing = "Now Playing"; const String Meta_information = "Meta-information"; const String Meta_title = "meta-title"; const String Meta_author = "meta-author"; const String Meta_artist = "meta-artist"; const String Meta_genre = "meta-genre"; const String Meta_description = "meta-description"; const String Meta_url = "meta-url"; [DllImport("libvlc")] static extern int VLC_Create(); [DllImport("libvlc")] static extern VlcError VLC_Init(int iVLC, int Argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)]string[] Argv); [DllImport("libvlc")] static extern string VLC_Version(); [DllImport("libvlc")] static extern VlcError VLC_CleanUp(int iVLC); [DllImport("libvlc")] static extern VlcError VLC_Destroy(int iVLC); [DllImport("libvlc")] static extern string VLC_Error(int i_err); [DllImport("libvlc")] static extern IntPtr vlc_current_object(int i_object); [DllImport("libvlc")] static extern IntPtr __vlc_object_find(IntPtr p_vlc, ObjectType objectType, ObjectSearchMode mode); [DllImport("libvlc")] static extern void __vlc_object_release(IntPtr p_vlc); [DllImport("libvlc")] static extern VlcError __var_Set(IntPtr p_vlc, String name, vlc_value_t value); [DllImport("libvlc")] static extern VlcError __var_Get(IntPtr p_this, String name, ref vlc_value_t value); [DllImport("libvlc")] static extern VlcError __var_Change(IntPtr p_this, String name, VarFlags varFlags, ref vlc_value_t value, ref vlc_value_t value2); [DllImport("libvlc")] static extern VlcError __aout_VolumeGet(IntPtr p_vlc, ref Int16 volume); [DllImport("libvlc")] static extern VlcError __aout_VolumeSet(IntPtr p_vlc, Int16 volume); [DllImport("libvlc")] static extern VlcError __aout_VolumeMute(IntPtr p_vlc, IntPtr alwaysNull); [DllImport("libvlc")] static extern void libvlc_exception_init(out libvlc_exception_t p_exception); [DllImport("libvlc")] static extern Int32 libvlc_exception_raised(ref libvlc_exception_t p_exception); [DllImport("libvlc")] static extern void libvlc_exception_clear(ref libvlc_exception_t p_exception); [DllImport("libvlc")] static extern void libvlc_playlist_play(ref libvlc_instance_t libvlc, Int32 id, Int32 optionsCount, IntPtr optionsAlwaysNull, ref libvlc_exception_t p_exception); [DllImport("libvlc")] static extern IntPtr libvlc_playlist_get_input(ref libvlc_instance_t libvlc, ref libvlc_exception_t p_exception); [DllImport("libvlc")] static extern int VLC_PlaylistIndex(int vlcObject); [DllImport("libvlc")] static extern int VLC_PlaylistNumberOfItems(int vlcObject); [DllImport("libvlc")] static extern void libvlc_input_free(IntPtr p_input); [DllImport("libvlc")] static extern int libvlc_video_get_width(IntPtr p_input, ref libvlc_exception_t p_exception); [DllImport("libvlc")] static extern int libvlc_video_get_height(IntPtr p_input, ref libvlc_exception_t p_exception); [DllImport("libvlc", CallingConvention=CallingConvention.Cdecl)] static extern VlcError playlist_LockControl(IntPtr p_playlist, playlist_command i_query); [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl)] static extern VlcError playlist_LockControl(IntPtr p_playlist, playlist_command i_query, Int32 arg1); [DllImport("libvlc")] static extern VlcError playlist_Clear(IntPtr p_playlist); [DllImport("libvlc")] static extern VlcError playlist_AddExt(IntPtr p_playlist, String mrl, String mrlDuplicate, Mode mode, Int32 pos, Int64 mtime_t, [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)]string[] Options, int OptionsCount); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate int VarChangedCallback(IntPtr vlc, String variable, vlc_value_t old_val, vlc_value_t new_val, IntPtr param); [DllImport("libvlc")] static extern int __var_AddCallback(IntPtr vlc, String variable, VarChangedCallback cb, IntPtr param); [DllImport("libvlc")] static extern int __var_DelCallback(IntPtr vlc, String variable, VarChangedCallback cb, IntPtr param); [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Ansi)] static extern VlcError input_Control(IntPtr input_thread_t, input_query_e i_query, String category, String name, ref IntPtr result); [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl)] static extern void __vout_OSDMessage(IntPtr p_input, int i_channel, String message); [DllImport("libvlc")] static extern IntPtr config_FindConfig(IntPtr vlc, String name); [DllImport("libvlc")] static extern void __config_PutInt(IntPtr vlc, String name, int value); [DllImport("libvlc")] static extern void __config_PutFloat(IntPtr vlc, String name, float value); [DllImport("libvlc")] static extern void __config_PutPsz(IntPtr vlc, String name, String value); [DllImport("libvlc")] static extern int __config_GetInt(IntPtr vlc, String name); [DllImport("libvlc")] static extern float __config_GetFloat(IntPtr vlc, String name); [DllImport("libvlc")] static extern String __config_GetPsz(IntPtr vlc, String name); #endregion static NativeLibVlc() { NativeLibVlc.vlcInstallDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Substring(6); //NativeLibVlc.vlcInstallDirectory = Environment.CurrentDirectory; //NativeLibVlc.vlcInstallDirectory = QueryVlcInstallPath(); } public NativeLibVlc() { } #region IDisposable public void Dispose() { if(vlcHandle != -1) { try { if(this.gch.IsAllocated) { UnhookPlaylistChanges(); } VideoOutput = null; VLC_CleanUp(this.vlcHandle); VLC_Destroy(this.vlcHandle); } catch { } } vlcHandle = -1; } #endregion #region internal Vlc interop helper classes internal class VlcObject : IDisposable { IntPtr vlc = IntPtr.Zero; IntPtr subObject = IntPtr.Zero; bool isDisposed; public VlcObject(int vlcHandle, ObjectType objectType) { vlc = vlc_current_object(vlcHandle); if(IntPtr.Zero != vlc) { if(objectType == ObjectType.VLC_OBJECT_VLC) { subObject = vlc; } else { subObject = __vlc_object_find(vlc, objectType, ObjectSearchMode.FIND_CHILD); } } } public IntPtr Vlc { get { return this.vlc; } } public IntPtr SubObject { get { return this.subObject; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if(!this.isDisposed) { this.isDisposed = true; if((IntPtr.Zero != subObject) && (subObject != vlc)) { __vlc_object_release(subObject); } if(IntPtr.Zero != vlc) { __vlc_object_release(vlc); } } } protected bool IsDisposed { get { return this.isDisposed; } } ~VlcObject() { Dispose(false); } } private class VlcPlaylistObject : VlcObject { public libvlc_instance_t libvlc; public libvlc_exception_t exception; public VlcPlaylistObject(int vlcHandle) : base(vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST) { if(this.SubObject != IntPtr.Zero) { this.libvlc = new libvlc_instance_t(this.Vlc, this.SubObject, vlcHandle); this.exception.Init(); } } } #endregion #region public Vlc interop helper functions public VlcObject OpenVlcObject(ObjectType objectType) { return new VlcObject(this.vlcHandle, objectType); } public int GetVlcObjectInt(ObjectType objectType, String propertyName, int errorReturn) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { vlc_value_t intValue = new vlc_value_t(); if((vobj.SubObject != IntPtr.Zero) && (VlcError.Success == __var_Get(vobj.SubObject, propertyName, ref intValue))) { return intValue.i_int; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return errorReturn; } public VlcError SetVlcObjectInt(ObjectType objectType, String propertyName, int value) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { if(vobj.SubObject != IntPtr.Zero) { vlc_value_t intValue = new vlc_value_t(); intValue.i_int = value; return __var_Set(vobj.SubObject, propertyName, intValue); } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return VlcError.NoObj; } public long GetVlcObjectLong(ObjectType objectType, String propertyName, long errorReturn) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { vlc_value_t longValue = new vlc_value_t(); if((vobj.SubObject != IntPtr.Zero) && (VlcError.Success == __var_Get(vobj.SubObject, propertyName, ref longValue))) { return longValue.i_time; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return errorReturn; } public VlcError SetVlcObjectLong(ObjectType objectType, String propertyName, long value) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { if(vobj.SubObject != IntPtr.Zero) { vlc_value_t longValue = new vlc_value_t(); longValue.i_time = value; return __var_Set(vobj.SubObject, propertyName, longValue); } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return VlcError.NoObj; } public float GetVlcObjectFloat(ObjectType objectType, String propertyName, float errorReturn) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { vlc_value_t floatValue = new vlc_value_t(); if((vobj.SubObject != IntPtr.Zero) && (VlcError.Success == __var_Get(vobj.SubObject, propertyName, ref floatValue))) { return floatValue.f_float; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return errorReturn; } public VlcError SetVlcObjectFloat(ObjectType objectType, String propertyName, float value) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { if(vobj.SubObject != IntPtr.Zero) { vlc_value_t floatValue = new vlc_value_t(); floatValue.f_float = value; return __var_Set(vobj.SubObject, propertyName, floatValue); } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return VlcError.NoObj; } public String GetVlcObjectString(ObjectType objectType, String propertyName, String errorReturn) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { vlc_value_t stringValue = new vlc_value_t(); if((vobj.SubObject != IntPtr.Zero) && (VlcError.Success == __var_Get(vobj.SubObject, propertyName, ref stringValue))) { return Marshal.PtrToStringAnsi(stringValue.psz_string); } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return errorReturn; } public VlcError SetVlcObjectString(ObjectType objectType, String propertyName, String value) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { if(vobj.SubObject != IntPtr.Zero) { vlc_value_t stringValue = new vlc_value_t(); IntPtr valuePtr = Marshal.StringToCoTaskMemAnsi(value); stringValue.psz_string = valuePtr; VlcError ret = __var_Set(vobj.SubObject, propertyName, stringValue); Marshal.ZeroFreeCoTaskMemAnsi(valuePtr); return ret; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return VlcError.NoObj; } public VlcError GetVlcVariableChoiceList(ObjectType objectType, String propertyName, out int[] choiceIds, out String[] choiceText) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { if(vobj.SubObject != IntPtr.Zero) { vlc_value_t idValues = new vlc_value_t(); vlc_value_t textValues = new vlc_value_t(); if(VlcError.Success == __var_Change(vobj.SubObject, propertyName, VarFlags.VLC_VAR_GETLIST, ref idValues, ref textValues)) { try { vlc_list_t idList = (vlc_list_t)Marshal.PtrToStructure( idValues.p_list, typeof(vlc_list_t)); vlc_list_t textList = (vlc_list_t)Marshal.PtrToStructure( textValues.p_list, typeof(vlc_list_t)); int choiceCount = idList.i_count; choiceIds = new Int32[choiceCount]; choiceText = new String[choiceCount]; for(int index = 0; index < choiceCount; index++) { IntPtr idPtr = new IntPtr(idList.p_values.ToInt32() + index * Marshal.SizeOf(typeof(vlc_value_t))); vlc_value_t idValue = (vlc_value_t)Marshal.PtrToStructure( idPtr, typeof(vlc_value_t)); choiceIds[index] = idValue.i_int; IntPtr textPtr = new IntPtr(textList.p_values.ToInt32() + index * Marshal.SizeOf(typeof(vlc_value_t))); vlc_value_t textValue = (vlc_value_t)Marshal.PtrToStructure( textPtr, typeof(vlc_value_t)); choiceText[index] = Marshal.PtrToStringAnsi(textValue.psz_string); } return VlcError.Success; } finally { __var_Change(vobj.SubObject, propertyName, VarFlags.VLC_VAR_FREELIST, ref idValues, ref textValues); } } } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } choiceIds = new int[0]; choiceText = new string[0]; return VlcError.NoObj; } public VlcError GetVlcVariableChoiceList(ObjectType objectType, String propertyName, out String[] choices, out String[] choiceText) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, objectType)) { if(vobj.SubObject != IntPtr.Zero) { vlc_value_t idValues = new vlc_value_t(); vlc_value_t textValues = new vlc_value_t(); if(VlcError.Success == __var_Change(vobj.SubObject, propertyName, VarFlags.VLC_VAR_GETLIST, ref idValues, ref textValues)) { try { vlc_list_t idList = (vlc_list_t)Marshal.PtrToStructure( idValues.p_list, typeof(vlc_list_t)); vlc_list_t textList = (vlc_list_t)Marshal.PtrToStructure( textValues.p_list, typeof(vlc_list_t)); int choiceCount = idList.i_count; List<String> choiceList = new List<string>(choiceCount); List<String> choiceTextList = new List<string>(choiceCount); Dictionary<String, int> choiceDict = new Dictionary<string, int>(choiceCount); for(int index = 0; index < choiceCount; index++) { IntPtr idPtr = new IntPtr(idList.p_values.ToInt32() + index * Marshal.SizeOf(typeof(vlc_value_t))); vlc_value_t idValue = (vlc_value_t)Marshal.PtrToStructure( idPtr, typeof(vlc_value_t)); String choice = Marshal.PtrToStringAnsi(idValue.psz_name); choiceList.Add(choice); if(choiceDict.ContainsKey(choice)) { choiceDict[choice] = choiceDict[choice] + 1; } else { choiceDict[choice] = 1; } IntPtr textPtr = new IntPtr(textList.p_values.ToInt32() + index * Marshal.SizeOf(typeof(vlc_value_t))); vlc_value_t textValue = (vlc_value_t)Marshal.PtrToStructure( textPtr, typeof(vlc_value_t)); choiceTextList.Add(Marshal.PtrToStringAnsi(textValue.psz_string)); } int listIndex = 0; for(int index = 0; index < choiceCount; index++) { String choice = choiceList[listIndex]; if((choiceDict[choice] > 1) && (choiceTextList[listIndex] == null)) { choiceList.RemoveAt(listIndex); choiceTextList.RemoveAt(listIndex); choiceDict[choice] = choiceDict[choice] - 1; } else { listIndex++; } } for(int index = 0; index < choiceList.Count; index++) { if(choiceTextList[index] == null) { choiceTextList[index] = choiceList[index]; } } choices = choiceList.ToArray(); choiceText = choiceTextList.ToArray(); return VlcError.Success; } finally { __var_Change(vobj.SubObject, propertyName, VarFlags.VLC_VAR_FREELIST, ref idValues, ref textValues); } } } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } choices = new string[0]; choiceText = new string[0]; return VlcError.NoObj; } #endregion #region public Properties public static string VlcInstallDir { get{ return vlcInstallDirectory; } set{ vlcInstallDirectory = value; } } public bool IsInitialized { get{return (vlcHandle != -1);} } public Control VideoOutput { get { return outputWindow; } set { if(value == null) { if(outputWindow != null) { outputWindow = null; if(vlcHandle != -1) { SetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, "drawable", 0); } } } else { outputWindow = value; if(vlcHandle != -1) { SetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, "drawable", outputWindow.Handle.ToInt32()); } } } } public string LastError { get{return lastErrorMessage;} } public event MetaDataEventHandler NowPlaying; protected virtual void OnNowPlaying(MetaDataUpdateEventArgs args) { if(this.NowPlaying != null) { this.NowPlaying(this, args); } } protected delegate void HandleNowPlaying(MetaDataUpdateEventArgs args); protected virtual void VlcNowPlayingChanged(String newText) { // switch out of the Vlc thread to our User Interface thread if possible if(this.VideoOutput != null) { this.VideoOutput.BeginInvoke(new HandleNowPlaying(OnNowPlaying), new MetaDataUpdateEventArgs(MetaData.NowPlaying, newText)); } else { OnNowPlaying(new MetaDataUpdateEventArgs(MetaData.NowPlaying, newText)); } } public int Length { get { if(this.artificialLength != 0) { return this.artificialLength; } else { return Convert.ToInt32(GetVlcObjectLong(ObjectType.VLC_OBJECT_INPUT, "length", 0) / 1000000L); } } } public void SetArtificialLength(int newLength) { this.artificialLength = newLength; } public int Time { get { int time = Convert.ToInt32(GetVlcObjectLong(ObjectType.VLC_OBJECT_INPUT, "time", 0) / 1000000L); if((time == 0) && (this.artificialLength != 0)) { time = Convert.ToInt32(Position * this.artificialLength + .5d); } if(this.timeScaling != 0.0d) { time = Convert.ToInt32(time / this.timeScaling); } return time; } set { if(this.artificialLength != 0) { float position = Convert.ToSingle(value) / Convert.ToSingle(this.artificialLength); if(this.timeScaling != 0.0d) { position = Convert.ToSingle(position * this.timeScaling); } Debug.WriteLine(String.Format("Set Position {0}", position)); SetVlcObjectFloat(ObjectType.VLC_OBJECT_INPUT, "position", position); } else { long time = Convert.ToInt64(value) * 1000000L; if(this.timeScaling != 0.0d) { time = Convert.ToInt64(time * this.timeScaling); } Debug.WriteLine(String.Format("Set Time {0}", time)); SetVlcObjectLong(ObjectType.VLC_OBJECT_INPUT, "time", time); } } } public double TimeScaling { get { return this.timeScaling; } set { this.timeScaling = value; } } public double Position { get { double position = GetVlcObjectFloat(ObjectType.VLC_OBJECT_INPUT, "position", 0.0f); if(this.timeScaling != 0.0d) { position = position / this.timeScaling; } return position; } set { double position = value; if(this.timeScaling != 0.0d) { position = position * this.timeScaling; } Debug.WriteLine(String.Format("Set Position {0}", position)); SetVlcObjectFloat(ObjectType.VLC_OBJECT_INPUT, "position", Convert.ToSingle(position)); } } public int Volume { get { IntPtr vlc = vlc_current_object(vlcHandle); if(IntPtr.Zero != vlc) { try { Int16 aoutVol = 0; if(__aout_VolumeGet(vlc, ref aoutVol) == VlcError.Success) { return (aoutVol * VOLUME_MAX + AOUT_VOLUME_MAX / 2) / AOUT_VOLUME_MAX; } } catch(Exception) { } finally { __vlc_object_release(vlc); } } return 0; } set { IntPtr vlc = vlc_current_object(vlcHandle); if(IntPtr.Zero != vlc) { try { Int16 aoutVol = Convert.ToInt16((value * AOUT_VOLUME_MAX + VOLUME_MAX / 2) / VOLUME_MAX); __aout_VolumeSet(vlc, aoutVol); } catch(Exception) { } finally { __vlc_object_release(vlc); } } } } public bool Fullscreen { get { int isFullScreen = GetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, "fullscreen", -666); if((isFullScreen != -666) && (isFullScreen != 0)) { return true; } return false; } set { SetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, "fullscreen", value ? 1 : 0); } } public int PlaylistIndex { get { try { return VLC_PlaylistIndex(this.vlcHandle); } catch(Exception ex) { this.lastErrorMessage = ex.Message; return -1; } } } public int PlaylistCount { get { try { return VLC_PlaylistNumberOfItems(this.vlcHandle); } catch(Exception ex) { this.lastErrorMessage = ex.Message; return -1; } } } #endregion #region public Methods public bool Initialize() { // check if already initializes if(vlcHandle != -1) return true; string oldDir = Environment.CurrentDirectory; // try init try { // create instance Environment.CurrentDirectory = NativeLibVlc.vlcInstallDirectory; this.vlcHandle = VLC_Create(); if(this.vlcHandle < 0) { lastErrorMessage = "Failed to create VLC instance"; return false; } string[] initOptions = { NativeLibVlc.vlcInstallDirectory, ":no-one-instance", ":no-loop", ":no-drop-late-frames", ":disable-screensaver", ":vout=vout_directx", "--plugin-path=" + NativeLibVlc.vlcInstallDirectory + @"\plugins", }; // init libvlc VlcError errVlcLib = VLC_Init(vlcHandle, initOptions.Length, initOptions); if(errVlcLib != VlcError.Success) { VLC_Destroy(vlcHandle); lastErrorMessage = "Failed to initialise VLC"; this.vlcHandle = -1; return false; } } catch { lastErrorMessage = "Could not find libvlc"; return false; } finally { Environment.CurrentDirectory = oldDir; } // check output window if(outputWindow != null) { SetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, "drawable", outputWindow.Handle.ToInt32()); } return true; } // there's an overhead to supporting Vlc events, a memory leak, so we need to have them off by default public bool ProducingEvents { get { return this.gch.IsAllocated; } set { if(value) { if(!this.gch.IsAllocated) { HookPlaylistChanges(); } } else { if(this.gch.IsAllocated) { UnhookPlaylistChanges(); } } } } private static String AdjustFilterString(String current, String filter, bool add) { String newFilter = null; int findFilter = current.IndexOf(filter); if(findFilter == -1) { if(add) { if(current.Length == 0) { newFilter = filter; } else { newFilter = String.Format("{0}:{1}", current, filter); } } } else { if(!add) { int colonAfterAdjust = current.IndexOf(':', findFilter + 1); if(findFilter == 0) { if(colonAfterAdjust == -1) { newFilter = String.Empty; } else { newFilter = current.Substring(colonAfterAdjust + 1); } } else { if(colonAfterAdjust == -1) { newFilter = current.Substring(0, findFilter - 1); } else { newFilter = current.Substring(0, findFilter - 1) + current.Substring(colonAfterAdjust); } } } } return newFilter; } const String VideoFilterList = "vout-filter"; const String AdjustFilter = "adjust"; public bool AllowVideoAdjustments { get { String voutFilter = GetVlcObjectString(ObjectType.VLC_OBJECT_VOUT, VideoFilterList, null); if(voutFilter == null) { GetConfigVariable(VideoFilterList, out voutFilter); } if(voutFilter != null) { return voutFilter.IndexOf(AdjustFilter) != -1; } else { return false; } } set { bool useConfig = false; String voutFilter = GetVlcObjectString(ObjectType.VLC_OBJECT_VOUT, VideoFilterList, null); if(voutFilter == null) { using(VlcObject vlc = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_VLC)) { GetConfigVariable(VideoFilterList, out voutFilter); useConfig = true; } } if(voutFilter != null) { String newVoutFilter = AdjustFilterString(voutFilter, AdjustFilter, value); if(newVoutFilter != null) { if(useConfig) { SetConfigVariable(VideoFilterList, newVoutFilter); } else { SetVlcObjectString(ObjectType.VLC_OBJECT_VOUT, VideoFilterList, newVoutFilter); } } } } } public VlcError AddTarget(string target, ref int itemId) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vobj.SubObject != IntPtr.Zero) { VlcError enmErr = playlist_AddExt(vobj.SubObject, target, target, Mode.Append, EndOfPlaylist, -1L, null, 0); if(enmErr >= VlcError.Success) { itemId = (int)enmErr; } return enmErr; } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public VlcError AddTarget(string target, string[] options, ref int itemId) { int optionsCount = 0; if(options != null) { optionsCount = options.Length; } try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vobj.SubObject != IntPtr.Zero) { VlcError enmErr = playlist_AddExt(vobj.SubObject, target, target, Mode.Append, EndOfPlaylist, -1L, options, optionsCount); if(enmErr >= VlcError.Success) { itemId = (int)enmErr; } return enmErr; } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public Size VideoSize { get { try { using(VlcPlaylistObject vpobj = new VlcPlaylistObject(this.vlcHandle)) { if(vpobj.SubObject != IntPtr.Zero) { IntPtr p_input = libvlc_playlist_get_input(ref vpobj.libvlc, ref vpobj.exception); if(vpobj.exception.WasExceptionRaised()) { this.lastErrorMessage = Marshal.PtrToStringAnsi(vpobj.exception.psz_message); } else { try { int width = libvlc_video_get_width(p_input, ref vpobj.exception); if(!vpobj.exception.WasExceptionRaised()) { int height = libvlc_video_get_height(p_input, ref vpobj.exception); if(!vpobj.exception.WasExceptionRaised()) { return new Size(width, height); } } } finally { libvlc_input_free(p_input); } } } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; } return new Size(); } } public VlcError Play(int itemId) { try { this.artificialLength = 0; this.timeScaling = 0.0d; using(VlcPlaylistObject vpobj = new VlcPlaylistObject(this.vlcHandle)) { if(vpobj.SubObject != IntPtr.Zero) { libvlc_playlist_play(ref vpobj.libvlc, itemId, 0, IntPtr.Zero, ref vpobj.exception); if(vpobj.exception.WasExceptionRaised()) { return VlcError.Generic; } return VlcError.Success; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } return VlcError.NoObj; } public VlcError Play() { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vobj.SubObject != IntPtr.Zero) { return playlist_LockControl(vobj.SubObject, playlist_command.PLAYLIST_PLAY); } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public VlcError Pause() { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vobj.SubObject != IntPtr.Zero) { return playlist_LockControl(vobj.SubObject, playlist_command.PLAYLIST_PAUSE); } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public VlcError Stop() { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vobj.SubObject != IntPtr.Zero) { return playlist_LockControl(vobj.SubObject, playlist_command.PLAYLIST_PAUSE); } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public VlcError PlaylistClear() { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vobj.SubObject != IntPtr.Zero) { return playlist_Clear(vobj.SubObject); } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public VlcError ToggleVolumeMute() { IntPtr vlc = vlc_current_object(vlcHandle); if(IntPtr.Zero != vlc) { try { return __aout_VolumeMute(vlc, IntPtr.Zero); } catch(Exception) { } finally { __vlc_object_release(vlc); } } return VlcError.NoObj; } public VlcError PressKey(string strKey) { int key = GetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, strKey, -666); if(key != -666) { return SetVlcObjectInt(ObjectType.VLC_OBJECT_VLC, "key-pressed", key); } return VlcError.NoVar; } public VlcError ShowMessage(String message) { try { using(VlcObject vobj = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_INPUT)) { if(vobj.SubObject != IntPtr.Zero) { __vout_OSDMessage(vobj.SubObject, DEFAULT_CHAN, message); return VlcError.Success; } else { return VlcError.NoObj; } } } catch(Exception ex) { this.lastErrorMessage = ex.Message; return VlcError.Exception; } } public VlcError GetConfigVariable(String name, out String value) { value = null; using(VlcObject vlc = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_VLC)) { if(IntPtr.Zero == vlc.SubObject) { return VlcError.NoObj; } IntPtr p_item = config_FindConfig(vlc.SubObject, name); if(IntPtr.Zero == p_item) { return VlcError.NoVar; } try { module_config_t mod = (module_config_t)Marshal.PtrToStructure(p_item, typeof(module_config_t)); switch(mod.i_type) { case CONFIG_ITEM.CONFIG_ITEM_BOOL: { bool result = (__config_GetInt(vlc.SubObject, name) == 0); value = result.ToString(); } break; case CONFIG_ITEM.CONFIG_ITEM_INTEGER: { int intResult = __config_GetInt(vlc.SubObject, name); value = intResult.ToString(); } break; case CONFIG_ITEM.CONFIG_ITEM_FLOAT: { float floatResult = __config_GetFloat(vlc.SubObject, name); value = floatResult.ToString(); } break; case CONFIG_ITEM.CONFIG_ITEM_STRING: value = __config_GetPsz(vlc.SubObject, name); break; default: return VlcError.BadVar; } } catch(Exception e) { this.lastErrorMessage = e.Message; return VlcError.Exception; } } return VlcError.Success; } public VlcError SetConfigVariable(String name, String value) { using(VlcObject vlc = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_VLC)) { if(IntPtr.Zero == vlc.SubObject) { return VlcError.NoObj; } IntPtr p_item = config_FindConfig(vlc.SubObject, name); if(IntPtr.Zero == p_item) { return VlcError.NoVar; } try { module_config_t mod = (module_config_t)Marshal.PtrToStructure(p_item, typeof(module_config_t)); switch(mod.i_type) { case CONFIG_ITEM.CONFIG_ITEM_BOOL: { bool boolResult; if(Boolean.TryParse(value, out boolResult)) { __config_PutInt(vlc.SubObject, name, boolResult ? 1 : 0); } else { return VlcError.BadVar; } } break; case CONFIG_ITEM.CONFIG_ITEM_INTEGER: { int intResult; if(Int32.TryParse(value, out intResult)) { __config_PutInt(vlc.SubObject, name, intResult); } else { return VlcError.BadVar; } } break; case CONFIG_ITEM.CONFIG_ITEM_FLOAT: { float floatResult; if(Single.TryParse(value, out floatResult)) { __config_PutFloat(vlc.SubObject, name, floatResult); } else { return VlcError.BadVar; } } break; case CONFIG_ITEM.CONFIG_ITEM_STRING: __config_PutPsz(vlc.SubObject, name, value); break; default: return VlcError.BadVar; } } catch(Exception e) { this.lastErrorMessage = e.Message; return VlcError.Exception; } } return VlcError.Success; } #endregion #region private members, properties and methods private static string vlcInstallDirectory = ""; private int vlcHandle = -1; private Control outputWindow = null; private string lastErrorMessage = ""; private int artificialLength; private double timeScaling; private GCHandle gch; private VarChangedCallback currentTrackCallback; private string previousNowPlaying = String.Empty; /// ------------------------------------------------------------------- /// <summary> /// Method name : QueryVlcInstallPath /// Author : Odysee /// Date : 10.11.2006 /// </summary> /// ------------------------------------------------------------------- private static string QueryVlcInstallPath() { // open registry RegistryKey regkeyVlcInstallPathKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\VideoLAN\VLC"); if(regkeyVlcInstallPathKey == null) return ""; return (string)regkeyVlcInstallPathKey.GetValue("InstallDir",""); } private void HookPlaylistChanges() { using(VlcObject vlc = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vlc.SubObject != IntPtr.Zero) { this.gch = GCHandle.Alloc(this); this.currentTrackCallback = new VarChangedCallback(CurrentTrackChanged); int isSet = __var_AddCallback(vlc.SubObject, Playlist_Current, this.currentTrackCallback, (IntPtr)this.gch); //Debug.WriteLine("__var_AddCallback playlistObject = " + isSet.ToString()); } } } private void UnhookPlaylistChanges() { using(VlcObject vlc = new VlcObject(this.vlcHandle, ObjectType.VLC_OBJECT_PLAYLIST)) { if(vlc.SubObject != IntPtr.Zero) { __var_DelCallback(vlc.SubObject, Playlist_Current, this.currentTrackCallback, (IntPtr)this.gch); } } this.gch.Free(); } private static int CurrentTrackChanged(IntPtr vlc, String variable, vlc_value_t old_val, vlc_value_t new_val, IntPtr param) { //Debug.WriteLine("CurrentTrackChanged: " + new_val.i_int.ToString()); GCHandle gch = (GCHandle)param; NativeLibVlc thisVlc = (NativeLibVlc)gch.Target; try { using(VlcObject vobj = new VlcObject(thisVlc.vlcHandle, ObjectType.VLC_OBJECT_INPUT)) { if(vobj.SubObject != IntPtr.Zero) { IntPtr resultString = IntPtr.Zero; input_Control(vobj.SubObject, input_query_e.INPUT_GET_INFO, Meta_information, Now_Playing, ref resultString); String nowPlaying = Marshal.PtrToStringAnsi(resultString); if(nowPlaying != thisVlc.previousNowPlaying) { thisVlc.previousNowPlaying = nowPlaying; Debug.WriteLine(String.Format("nowPlaying: {0}", nowPlaying)); thisVlc.VlcNowPlayingChanged(nowPlaying); } } } } catch(Exception ex) { thisVlc.lastErrorMessage = ex.Message; } return (int)VlcError.Success; } #endregion } /* future features add_bool( "brightness-threshold", 0, NULL, THRES_TEXT, THRES_LONGTEXT, VLC_FALSE ); */ }