context: using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Runtime.InteropServices;
  using System.Diagnostics;
  using System.Threading;
  using System.Windows.Forms;
  using System.Collections;
  using Microsoft.Win32;
  using System.IO;
  using System.Runtime.Remoting.Messaging;
  using FFDShowAPI.Interfaces;
  
  namespace FFDShowAPI
  {
    /// <summary>
    /// FFDShowAPI library class. Use this class to get/set FFDShow live settings
    /// </summary>
    public class FFDShowAPI : IDisposable
    {
      #region Guids
      public static readonly Guid FFDShowVideoGuid = new Guid("04FE9017-F873-410E-871E-AB91661A4EF7");
      public static readonly Guid FFDShowVideoDXVAGuid = new Guid("0B0EFF97-C750-462C-9488-B10E7D87F1A6");
      public static readonly Guid FFDShowVideoRawGuid = new Guid("0B390488-D80F-4A68-8408-48DC199F0E97");
      #endregion
  
      #region Constants
      /// <summary>
      /// Identifier of Window messages structure that can carry string for interprocess communication
      /// </summary>
      public const int WM_COPYDATA = 0x004A;
  
      /// <summary>
      /// List of commands understood by FFDShow remote API
      /// These are commands that concern integers transmission (get or set) or
      /// single commands such as "Pause video"
      /// </summary>
      private enum FFD_WPRM : int
      {
        SET_PARAM_NAME = 0,
        SET_PARAM_VALUE_INT = 1,
        GET_PARAM_NAME = 2,
        GET_PARAM_VALUE_INT = 3,
        PAUSE_VIDEO = 4,
        RESUME_VIDEO = 5,
        GET_STATE = 6,
        GET_DURATION = 7,
        GET_CUR_TIME = 8,
        SET_PARAM_VALUE_STR = 9,
        //GET_PARAM_VALUE_STR = 13,
        SET_CURTIME = 13,
        SET_ADDTOROT = 14,
        FASTFORWARD = 15,
        FASTREWIND = 16,
        GETFASTFORWARDSPEED = 17,
        CAPTUREIMAGE = 18,
        SET_OSD_POSX = 19,
        SET_OSD_POSY = 20,
        //SET_STREAM = 21,
        //GET_CURRENT_AUDIO_STREAM = 22,
        //GET_CURRENT_SUBTITLE_STREAM = 23,
        GET_FRAMERATE = 24,
        SET_AUDIO_STREAM = 25,
        SET_SUBTITLE_STREAM = 26,
        SET_FFRW_NO_OSD = 27
      }
  
      /// <summary>
      /// List of commands understood by FFDShow remote API.
      /// These are commands that require strings transmissions
      /// </summary>
  #pragma warning disable 1591
      public enum FFD_MSG
      {
        GET_PARAMSTR = 19,
        GET_CURRENT_SUBTITLES = 20,
        GET_PRESETLIST = 21,
        GET_SOURCEFILE = 22,
        GET_SUBTITLEFILESLIST = 23,
        GET_CHAPTERSLIST = 25,
        GET_AUDIOSTREAMSLIST = 300,
        GET_SUBTITLESTREAMSLIST = 301
      }
  #pragma warning restore 1591
  
      //Copy data flags
      private const int FFDSM_SET_ACTIVE_PRESET_STR = 10;
      private const int FFDSM_SET_SHORTOSD_MSG = 18;
      private const int FFDSM_SET_OSD_MSG = 19;
  
  
      /// <summary>
      /// Playing state
      /// </summary>
      public enum PlayState : int
      {
        /// <summary>
        /// Stop state
        /// </summary>
        StopState = 0,
        /// <summary>
        /// Pause state
        /// </summary>
        PauseState = 1,
        /// <summary>
        /// Play state
        /// </summary>
        PlayState = 2,
        /// <summary>
        /// Fast forwarding or rewinding state
        /// </summary>
        FastForwardRewind = 3
      };
  
      /// <summary>
      /// Running object table registration
      /// </summary>
      public enum ROTRegistration : int
      {
        /// <summary>
        /// Register the DirectShow graph in the running object table (graph can be read and modified after that)
        /// Don't forget to unregister it.
        /// </summary>
        RegisterToRot = 1,
        /// <summary>
        /// Unregister the DirectShow graph from the running object table
        /// </summary>
        UnregisterToRot = 0
      };
  
      /// <summary>
      /// File name mode
      /// </summary>
      public enum FileNameMode : int
      {
        /// <summary>
        /// Full path (including drive and directories)
        /// </summary>
        FullPath,
        /// <summary>
        /// File name with extension but without the directory path
        /// </summary>
        FileName,
        /// <summary>
        /// File name without extension and without the directory path
        /// </summary>
        FileNameWithoutExtension,
        /// <summary>
        /// File name without extension and without the directory path and with suffixe only
        /// </summary>
        FileNameLanguage
      }
  
      private const int FALSE = 0;
      private const int TRUE = 1;
  
      public const int minRevision = 3640;
      #endregion Constants
  
      #region Structures
  
      /// <summary>
      /// FFDShow instance structure
      /// </summary>
      public struct FFDShowInstance
      {
        /// <summary>
        /// Unique identifier for this FFDShow instance
        /// </summary>
        public int handle;
        /// <summary>
        /// File name of the media being played by this instance (may be null)
        /// </summary>
        public string fileName;
      }
      #endregion Structures
  
      #region Variables
      private static string ffdshowRegKey = @"SOFTWARE\GNU\ffdshow";
      private static string ffdshowAudioRegKey = @"SOFTWARE\GNU\ffdshow_audio";
  
      private uint FFDShowAPIRemoteId = 32786;
      /// <summary>
      /// Unique identifier of the running instance of FFDShow
      /// </summary>
      protected int ffDShowInstanceHandle = 0;
      private int requestTimeout = 2000;
      private FFDShowReceiver receiver = null;
      private bool IsFFDShowActive = false;
      private static string strAppName = "ffdshow_remote_class";
      private string fileName = null;
      private FileNameMode fileNameMode = FileNameMode.FullPath;
      private int initFFDShowInstanceHandle = 0;
      private static bool ffrwNoOSD = false;
      private IffdshowDec ffdshowDec = null;
      private IffDecoder ffDecoder = null;
      private IffdshowBase ffdshowBase = null;
      private IffdshowDecVideo ffdshowDecVideo = null;
      private IAMStreamSelect streamSelect = null;
      public enum FFDShowAPIMode { DirectShowMode, InterProcessMode };
      private FFDShowAPIMode ffdshowAPIMode = FFDShowAPIMode.InterProcessMode;
  
      //private AutoResetEvent resetEvent = new AutoResetEvent(false);
  
      #endregion Variables
  
      #region Helper methods
      public static string getFileName(string fileName, FileNameMode mode)
      {
        FileInfo fileInfo = new FileInfo(fileName);
        switch (mode)
        {
          case FileNameMode.FullPath: return fileInfo.FullName;
          case FileNameMode.FileName: return fileInfo.Name;
          case FileNameMode.FileNameWithoutExtension:
            string formattedFileName = fileInfo.Name;
            if (formattedFileName.LastIndexOf('.') != -1)
              formattedFileName = formattedFileName.Substring(0, formattedFileName.LastIndexOf('.'));
            return formattedFileName;
          case FileNameMode.FileNameLanguage:
            string formattedFileNameLanguage = fileInfo.Name;
            //string[] words = formattedFileNameLanguage.Split(new char[] { '.', '-', '_' });
            string[] words = formattedFileNameLanguage.Split(new char[] { '.', '_' });
            if (formattedFileNameLanguage.LastIndexOf('.') != -1)
              formattedFileNameLanguage = words[words.Length - 2];
            //Log.Error("FFDSHOWAPI(getFileName): formattedFileNameLanguage \"{0}\"", formattedFileNameLanguage);
            return formattedFileNameLanguage;
        }
        return null;
      }
      #endregion
  
      #region WIN32 Class
  
  #pragma warning disable 1591
      /// <summary>
      /// Win32 COM methods and constants
      /// </summary>
      public class Win32
      {
        // The CopyData Constant for SendMessage
        public const Int32 WM_COPYDATA = 0x004A;
        public const Int32 WM_KEYDOWN = 0x0100;
        public const Int32 WM_APPCOMMAND = 0x0319;
        public const Int32 WM_INPUT = 0x00FF;
  
        [StructLayout(LayoutKind.Sequential)]
        public struct COPYDATASTRUCT
        {
          internal UIntPtr dwData;
          internal uint cbData;
          internal IntPtr lpData;
        }
  
        // Import the SendMessage function for use with COPYDATASTRUCT
        [DllImport("User32.Dll")]
        public static extern IntPtr SendMessage(IntPtr hwnd, Int32 msg, Int32 hwndFrom, ref COPYDATASTRUCT cds);
  
        [DllImport("User32.Dll")]
        public static extern IntPtr SendMessage(IntPtr hwnd, Int32 msg, Int32 hwndFrom, IntPtr cds);
  
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(
            IntPtr windowHandle,
            int Msg,
            IntPtr wParam,
            ref COPYDATASTRUCT cds,
            SendMessageTimeoutFlags flags,
            int timeout,
            out IntPtr result);
  
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(
            IntPtr windowHandle,
            [MarshalAs(UnmanagedType.U4)]
                  int Msg,
            IntPtr wParam,
            IntPtr lParam,
            SendMessageTimeoutFlags flags,
            int timeout,
            out IntPtr result);
  
        public enum SendMessageTimeoutFlags
        {
          SMTO_NORMAL = 0x0000,
          SMTO_BLOCK = 0x0001,
          SMTO_ABORTIFHUNG = 0x0002,
          SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
        }
  
  
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern IntPtr PostMessage(IntPtr hwnd, Int32 msg, Int32 hwndFrom, ref COPYDATASTRUCT cds);
  
        // Use COM interop to call the Win32 API GetLocalInfo.
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern int GetLocaleInfo(
          // The locale identifier.
           int Locale,
          // The information type.
           int LCType,
          // The buffer size.
           [In, MarshalAs(UnmanagedType.LPWStr)] string lpLCData, int cchData
         );
  
  
  
        // Import the GlobalSize function
        [DllImport("kernel32.dll")]
        public static extern Int32 GlobalSize(IntPtr hmem);
  
        public const int WM_SYSCOMMAND = 0x0112;
        public const int SC_CLOSE = 0xF060;
  
        [DllImport("User32.Dll")]
        public static extern int FindWindow(string lpClassName,
            string lpWindowName);
  
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern IntPtr SendMessage(int hWnd, uint Msg,
            int wParam, int lParam);
  
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern IntPtr PostMessage(int hWnd, uint Msg,
            int wParam, int lParam);
  
        public delegate bool CallBack(int hwnd, IntPtr lParam);
  
        [DllImport("User32.Dll")]
        public static extern int EnumWindows(CallBack x, IntPtr y);
        [DllImport("User32.Dll")]
        public static extern void GetWindowText(int h, StringBuilder s, int nMaxCount);
        [DllImport("User32.Dll")]
        public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
        [DllImport("User32.Dll")]
        public static extern int IsWindow(int hwnd);
      }
  #pragma warning restore 1591
      #endregion WIN32 Class
  
      #region Base Properties
      /// <summary>
      /// Gets the FFDShow instance handle (number that identifies the FFDShow instance)
      /// </summary>
      public int FFDShowInstanceHandle
      {
        get
        {
          return ffDShowInstanceHandle;
        }
      }
  
      /// <summary>
      /// Gets or sets the FFDShow remote identifier
      /// </summary>
      public uint FFDShowAPIRemote
      {
        get
        {
          return FFDShowAPIRemoteId;
        }
        set
        {
          FFDShowAPIRemoteId = value;
        }
      }
      /// <summary>
      /// Gets or sets the FFDShow registry key. Used sometimes when ffdshow is not active (for presets)
      /// </summary>
      public static string FFDShowRegKey
      {
        get
        {
          return ffdshowRegKey;
        }
        set
        {
          ffdshowRegKey = value;
        }
      }
  
      /// <summary>
      /// Gets or sets the registry key of FFDShow audio
      /// Used to get or set the default audio preset
      /// </summary>
      public static string FFDShowAudioRegKey
      {
        get
        {
          return ffdshowAudioRegKey;
        }
        set
        {
          ffdshowAudioRegKey = value;
        }
      }
  
      private static int osdX = 0;
      private static int osdY = 10;
      private bool updateOSD = false;
  
      /// <summary>
      /// Horizontal OSD position
      /// </summary>
      public static int OSDX
      {
        get
        {
          return osdX;
        }
        set
        {
          osdX = value;
        }
      }
  
      /// <summary>
      /// Vertical OSD position
      /// </summary>
      public static int OSDY
      {
        get
        {
          return osdY;
        }
        set
        {
          osdY = value;
        }
      }
  
      /// <summary>
      /// Gets or sets the OSD display when doing FastForward/Rewind
      /// This is a static parameter that will be applied to all the running FFDShow instances
      /// </summary>
      public static bool FFRWNoOSD
      {
        get
        {
          return ffrwNoOSD;
        }
        set
        {
          ffrwNoOSD = value;
        }
      }
  
  
      #endregion Base Properties
  
      #region Presets properties
  
      /// <summary>
      /// Gets or sets the default video preset (does not apply to currently running instances)
      /// </summary>
      public static String DefaultVideoPreset
      {
        get
        {
          using (RegistryKey preferencesKey = Registry.CurrentUser.OpenSubKey(ffdshowRegKey))
          {
            if (preferencesKey != null)
            {
              return (string)preferencesKey.GetValue("activePreset");
            }
            else return null;
          }
        }
  
        set
        {
          string[] presetList = VideoPresets;
          // Check if we set an existing preset
          bool found = false;
          for (int i = 0; i < presetList.Length; i++)
          {
            if (presetList[i].Equals(value))
            {
              found = true;
              break;
            }
          }
          if (found)
            using (RegistryKey preferencesKey = Registry.CurrentUser.CreateSubKey(ffdshowRegKey))
            {
              if (preferencesKey != null)
              {
                preferencesKey.SetValue("activePreset", value);
              }
            }
        }
      }
  
      /// <summary>
      /// Gets or sets the default audio preset (does not apply to currently running instances)
      /// </summary>
      public static string DefaultAudioPreset
      {
        get
        {
          using (RegistryKey preferencesKey = Registry.CurrentUser.OpenSubKey(ffdshowAudioRegKey))
          {
            if (preferencesKey != null)
            {
              return (string)preferencesKey.GetValue("activePreset");
            }
            else return null;
          }
        }
        set
        {
          string[] presetList = AudioPresets;
          // Check if we set an existing preset
          bool found = false;
          for (int i = 0; i < presetList.Length; i++)
          {
            if (presetList[i].Equals(value))
            {
              found = true;
              break;
            }
          }
          if (!found) return;
          using (RegistryKey preferencesKey = Registry.CurrentUser.CreateSubKey(ffdshowAudioRegKey))
          {
            if (preferencesKey != null)
            {
              preferencesKey.SetValue("activePreset", value);
            }
          }
        }
      }
  
  
  
      /// <summary>
      /// Gets or sets the video preset for the current instance. Also sets the preset as default.
      /// </summary>
      public String ActivePreset
      {
        get
        {
          string tmpStr = getStringParam(FFDShowConstants.FFDShowDataId.IDFF_OSDcurPreset);
          if (tmpStr != null && !tmpStr.Equals(""))
          {
            return tmpStr;
          }
          else
          {
            return DefaultVideoPreset;
          }
        }
        set
        {
          if (IsFFDShowActive)
          {
            PlayState playState = getState();
            if (playState == PlayState.PlayState || playState == PlayState.FastForwardRewind)
              pauseVideo();
            Win32.COPYDATASTRUCT cd = new Win32.COPYDATASTRUCT();
            cd.dwData = new UIntPtr((uint)FFDSM_SET_ACTIVE_PRESET_STR);
  #if UNICODE
                      cd.lpData = Marshal.StringToHGlobalUni(value);
  #else
            cd.lpData = Marshal.StringToHGlobalAnsi(value);
  #endif
            cd.cbData = (uint)Win32.GlobalSize(cd.lpData);
            if (receiver == null)
              receiver = new FFDShowReceiver(Thread.CurrentThread);
            receiver.ReceivedString = null;
            receiver.ReceivedType = 0;
            //receiver.ParentThread = Thread.CurrentThread;
            Win32.SendMessage(new IntPtr(ffDShowInstanceHandle), Win32.WM_COPYDATA, receiver.Handle.ToInt32(), ref cd);
            if (playState == PlayState.PlayState || playState == PlayState.FastForwardRewind)
              startVideo();
          }
          DefaultVideoPreset = value;
        }
      }
  
  
      /// <summary>
      /// Gets or sets the default audio preset (does not apply to currently running instances).
      /// Same behaviour as DefaultAudioPreset property
      /// </summary>
      public string ActiveAudioPreset
      {
        get
        {
          return DefaultAudioPreset;
        }
        set
        {
          DefaultAudioPreset = value;
        }
      }
      #endregion Presets properties
  
      #region Enabled Properties
      // Show/hide subtitles
      /// <summary>
      /// Enable or disable subtitles filter
      /// </summary>
      public bool DoShowSubtitles
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isSubtitles);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isSubtitles, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isSubtitles, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable crop and zoom
      /// </summary>
      public bool DoCropZoom
      {
        get
        {
          return (getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isCropNzoom) == 1);
        }
        set
        {
          if (value)
          {
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isCropNzoom, 1);
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_magnificationLocked, 0);
            //IDFF_cropNzoomMode => 2
          }
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isCropNzoom, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable lock of cropping
      /// </summary>
      public bool isCropZoomLocked
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_magnificationLocked);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_magnificationLocked, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_magnificationLocked, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable picture properties
      /// </summary>
      public bool DoPictureProperties
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isPictProp);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isPictProp, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isPictProp, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable crop and zoom
      /// </summary>
      public bool DoPostProcessing
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isPostproc);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isPostproc, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isPostproc, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable crop and zoom
      /// </summary>
      public bool DoResize
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isResize);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isResize, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isResize, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable noise reduction
      /// </summary>
      public bool DoNoiseReduction
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isBlur);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isBlur, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isBlur, 0);
        }
      }
  
      /// <summary>
      /// Enable/disable sharpen
      /// </summary>
      public bool DoSharpen
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isSharpen);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isSharpen, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isSharpen, 0);
        }
      }
  
      /// <summary>
      /// Get/Set deinterlace
      /// </summary>
      public bool DoDeinterlace
      {
        get
        {
          int value = getIntParam(FFDShowConstants.FFDShowDataId.IDFF_isDeinterlace);
          if (value == 1)
            return true;
          else return false;
        }
        set
        {
          if (value)
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isDeinterlace, 1);
          else
            setIntParam(FFDShowConstants.FFDShowDataId.IDFF_isDeinterlace, 0);
        }
      }
      #endregion Enabled Properties
  
      #region Subtitles/Audio streams Properties
      /// <summary>
      /// Subtitles/audio stream structure
      /// </summary>
      public struct Stream
      {
        /// <summary>
        /// Name of the stream
        /// </summary>
        public string name;
        /// <summary>
        /// Language name of the stream
        /// </summary>
        public string languageName;
        /// <summary>
        /// True if the stream is active
        /// </summary>
        public bool enabled;
        /// <summary>
        /// True if this is an external file
        /// </summary>
        public bool isFile;
        /// <summary>
        /// Constructor of a stream structure
        /// </summary>
        /// <param name="name">Name of the stream</param>
        /// <param name="languageName">Language name of the stream</param>
        /// <param name="enabled">True if the stream is active</param>
        public Stream(string name, string languageName, bool enabled)
        {
          this.name = name;
          this.languageName = languageName;
          this.enabled = enabled;
          this.isFile = false;
        }
  
        /// <summary>
        /// Constructor of a stream structure with external file flag
        /// </summary>
        /// <param name="name">Name of the stream</param>
        /// <param name="languageName">Language name of the stream</param>
        /// <param name="enabled">True if the stream is active</param>
        /// <param name="isFile">True if this stream is an external file</param>
        public Stream(string name, string languageName, bool enabled, bool isFile)
        {
          this.name = name;
          this.languageName = languageName;
          this.enabled = enabled;
          this.isFile = isFile;
        }
      }
  
      public class Streams : SortedDictionary<int, Stream>
      {
        public enum StreamType { EmbeddedOnly, FilesOnly }
        public int Size(StreamType type)
        {
          int cnt = 0;
          foreach (KeyValuePair<int, Stream> streamPair in this)
          {
            if (type == StreamType.EmbeddedOnly && !streamPair.Value.isFile) cnt++;
            else if (type == StreamType.FilesOnly && streamPair.Value.isFile) cnt++;
          }
          return cnt;
        }
      }
  
      /// <summary>
      /// Gets the list of subtitle streams
      /// </summary>
      public Streams SubtitleStreams
      {
        get
        {
          Streams subtitleStreams = new Streams();
          if (ffdshowAPIMode == FFDShowAPIMode.DirectShowMode && streamSelect != null)
          {
            int streamsNb = 0;
            streamSelect.Count(out streamsNb);
            if (streamsNb == 0) return subtitleStreams;
            for (int i = 0; i < streamsNb; i++)
            {
              AMMediaType mediaType;
              AMStreamSelectInfoFlags flag;
              int group, langId;
              string streamName;
              object pppunk, ppobject;
              streamSelect.Info(i, out mediaType, out flag, out langId,
                         out group, out streamName, out pppunk, out ppobject);
              if (group == 4 || group == 2 && streamName.LastIndexOf("No ") == -1)
              {
                if ((streamName == null || streamName.Equals("")) && subtitleStreams.Count == 0)
                  streamName = "No subtitles";
  
                String langName = "";
  
                if (langId != 0)
                {
                  int size = Win32.GetLocaleInfo(langId, 2, null, 0);
                  String languageName = new String(' ', size);
  
                  Win32.GetLocaleInfo(langId, 2, languageName, size);
                  if (!languageName.Equals(new String(' ', size)))
                  {
                    if (languageName.Contains("\0"))
                      langName = languageName.Substring(0, languageName.IndexOf("\0"));
                    else
                      langName = languageName;
                    int ipos = langName.IndexOf("(");
                    if (ipos > 0)
                    {
                      langName = langName.Substring(0, ipos);
                      langName = langName.Trim();
                    }
                  }
                }
                else
                {
                  langName = streamName; // If some splitter doesn't give LCID but Language is here need a little hack for parsing in VideoPlayerVRM7.
                }
  
gt:               if (group == 4)