#region License

/*
    Adapted work from:

    DirectShowLib - Provide access to DirectShow interfaces via .NET
    Copyright (C) 2007
    http://sourceforge.net/projects/directshownet/
    This library 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; either
    version 2.1 of the License, or (at your option) any later version.
    This library 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
    Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#endregion

using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

namespace ScreenToGif.Webcam.DirectShow
{
    public class CoreStreaming
    {
        [ComVisible(true), ComImport, Guid("56a86891-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IPin
        {
            [PreserveSig]
            int Connect([In] IPin pReceivePin, [In, MarshalAs(UnmanagedType.LPStruct)] AmMediaType pmt);

            [PreserveSig]
            int ReceiveConnection([In] IPin pReceivePin, [In, MarshalAs(UnmanagedType.LPStruct)] AmMediaType pmt);

            [PreserveSig]
            int Disconnect();

            [PreserveSig]
            int ConnectedTo([Out] out IPin ppPin);

            /// <summary>
            /// Release returned parameter with DsUtils.FreeAMMediaType
            /// </summary>
            [PreserveSig]
            int ConnectionMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] AmMediaType pmt);

            /// <summary>
            /// Release returned parameter with DsUtils.FreePinInfo
            /// </summary>
            [PreserveSig]
            int QueryPinInfo([Out] out PinInfo pInfo);

            [PreserveSig]
            int QueryDirection(out PinDirection pPinDir);

            [PreserveSig]
            int QueryId([Out, MarshalAs(UnmanagedType.LPWStr)] out string id);

            [PreserveSig]
            int QueryAccept([In, MarshalAs(UnmanagedType.LPStruct)] AmMediaType pmt);

            [PreserveSig]
            int EnumMediaTypes([Out] out IEnumMediaTypes ppEnum);

            [PreserveSig]
            int QueryInternalConnections([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] IPin[] ppPins, [In, Out] ref int nPin);

            [PreserveSig]
            int EndOfStream();

            [PreserveSig]
            int BeginFlush();

            [PreserveSig]
            int EndFlush();

            [PreserveSig]
            int NewSegment([In] long tStart, [In] long tStop, [In] double dRate);
        }

        [ComImport, System.Security.SuppressUnmanagedCodeSecurity, Guid("89c31040-846b-11ce-97d3-00aa0055595a"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IEnumMediaTypes
        {
            [PreserveSig]
            int Next([In] int cMediaTypes, [In, Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(EMTMarshaler), SizeParamIndex = 0)] AmMediaType[] ppMediaTypes, [In] IntPtr pcFetched);

            [PreserveSig]
            int Skip([In] int cMediaTypes);

            [PreserveSig]
            int Reset();

            [PreserveSig]
            int Clone([Out] out IEnumMediaTypes ppEnum);
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct PinInfo 
        {
            public IBaseFilter filter;
            public PinDirection dir;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string name;
        }

        public enum PinDirection
        {
            Input,
            Output
        }

        [ComImport, System.Security.SuppressUnmanagedCodeSecurity, Guid("0000010c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IPersist
        {
            [PreserveSig]
            int GetClassID([Out] out Guid pClassID);
        }

        [ComImport, System.Security.SuppressUnmanagedCodeSecurity, Guid("56a86899-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMediaFilter : IPersist
        {
            #region IPersist Methods

            [PreserveSig]
            new int GetClassID([Out] out Guid pClassID);

            #endregion

            [PreserveSig]
            int Stop();

            [PreserveSig]
            int Pause();

            [PreserveSig]
            int Run([In] long tStart);

            [PreserveSig]
            int GetState([In] int dwMilliSecsTimeout, [Out] out ControlStreaming.FilterState filtState);

            [PreserveSig]
            int SetSyncSource([In] IReferenceClock pClock);

            [PreserveSig]
            int GetSyncSource([Out] out IReferenceClock pClock);
        }

        [ComVisible(true), ComImport, Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IBaseFilter : IMediaFilter
        {
            #region IPersist Methods
            
            [PreserveSig]
            new int GetClassID([Out] out Guid pClassID);

            #endregion

            #region IMediaFilter Methods

            [PreserveSig]
            new int Stop();

            [PreserveSig]
            new int Pause();

            [PreserveSig]
            new int Run(long tStart);

            [PreserveSig]
            new int GetState([In] int dwMilliSecsTimeout, [Out] out ControlStreaming.FilterState filtState);

            [PreserveSig]
            new int SetSyncSource([In] IReferenceClock pClock);

            [PreserveSig]
            new int GetSyncSource([Out] out IReferenceClock pClock);

            #endregion

            [PreserveSig]
            int EnumPins([Out] out IEnumPins ppEnum);

            [PreserveSig]
            int FindPin([In, MarshalAs(UnmanagedType.LPWStr)] string Id, [Out] out IPin ppPin);

            [PreserveSig]
            int QueryFilterInfo([Out] FilterInfo pInfo);

            [PreserveSig]
            int JoinFilterGraph([In] IFilterGraph pGraph, [In, MarshalAs(UnmanagedType.LPWStr)] string pName);

            [PreserveSig]
            int QueryVendorInfo([Out, MarshalAs(UnmanagedType.LPWStr)] out string pVendorInfo);
        }

        [ComVisible(true), ComImport, Guid("56a86897-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IReferenceClock
        {
            [PreserveSig]
            int GetTime([Out] out long pTime);

            [PreserveSig]
            int AdviseTime([In] long baseTime, [In] long streamTime, [In] IntPtr hEvent, [Out] out int pdwAdviseCookie);

            [PreserveSig]
            int AdvisePeriodic([In] long startTime, [In] long periodTime, [In] IntPtr hSemaphore, [Out] out int pdwAdviseCookie);

            [PreserveSig]
            int Unadvise([In] int dwAdviseCookie);
        }

        [ComVisible(true), ComImport, Guid("56a86892-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IEnumPins
        {
            [PreserveSig]
            int Next([In] int cPins, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IPin[] ppPins, [Out] out int pcFetched);

            [PreserveSig]
            int Skip([In] int cPins);

            void Reset();
            
            void Clone([Out] out IEnumPins ppEnum);
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public class FilterInfo
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string achName;

            [MarshalAs(UnmanagedType.IUnknown)]
            public object pUnk;
        }

        [ComVisible(true), ComImport, Guid("56a8689f-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IFilterGraph
        {
            [PreserveSig]
            int AddFilter([In] IBaseFilter pFilter, [In, MarshalAs(UnmanagedType.LPWStr)] string pName);

            [PreserveSig]
            int RemoveFilter([In] IBaseFilter pFilter);

            [PreserveSig]
            int EnumFilters([Out] out IEnumFilters ppEnum);

            [PreserveSig]
            int FindFilterByName([In, MarshalAs(UnmanagedType.LPWStr)] string pName, [Out] out IBaseFilter ppFilter);

            [PreserveSig]
            int ConnectDirect([In] IPin ppinOut, [In] IPin ppinIn, [In, MarshalAs(UnmanagedType.LPStruct)] AmMediaType pmt);

            [PreserveSig]
            int Reconnect([In] IPin ppin);

            [PreserveSig]
            int Disconnect([In] IPin ppin);

            [PreserveSig]
            int SetDefaultSyncSource();
        }

        [ComVisible(true), ComImport, Guid("56a86893-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IEnumFilters
        {
            [PreserveSig]
            int Next([In] uint cFilters, out IBaseFilter x, [Out] out uint pcFetched);

            [PreserveSig]
            int Skip([In] int cFilters);

            void Reset();
            
            void Clone([Out] out IEnumFilters ppEnum);
        }

        /// <summary>
        /// From AM_MEDIA_TYPE - When you are done with an instance of this class,
        /// it should be released with FreeAMMediaType() to avoid leaking
        /// </summary>
        [StructLayout(LayoutKind.Sequential), ComVisible(false)]
        public class AmMediaType
        {
            public Guid majorType;

            public Guid subType;
            
            [MarshalAs(UnmanagedType.Bool)]
            
            public bool fixedSizeSamples;
            
            [MarshalAs(UnmanagedType.Bool)]
            public bool temporalCompression;
            
            public int sampleSize;
            
            public Guid formatType;
            
            public IntPtr unkPtr;
            
            public int formatSize;
            
            public IntPtr formatPtr;
        }

        [ComVisible(true), ComImport, Guid("56a8689a-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMediaSample
        {
            [PreserveSig]
            int GetPointer([Out] out IntPtr ppBuffer);

            [PreserveSig]
            int GetSize();

            [PreserveSig]
            int GetTime([Out] out long pTimeStart, [Out] out long pTimeEnd);

            [PreserveSig]
            int SetTime([In, MarshalAs(UnmanagedType.LPStruct)] Util.DsOptInt64 pTimeStart, [In, MarshalAs(UnmanagedType.LPStruct)] Util.DsOptInt64 pTimeEnd);

            [PreserveSig]
            int IsSyncPoint();

            [PreserveSig]
            int SetSyncPoint([In, MarshalAs(UnmanagedType.Bool)] bool bIsSyncPoint);

            [PreserveSig]
            int IsPreroll();

            [PreserveSig]
            int SetPreroll([In, MarshalAs(UnmanagedType.Bool)] bool bIsPreroll);

            [PreserveSig]
            int GetActualDataLength();

            [PreserveSig]
            int SetActualDataLength([In] int len);

            /// <summary>
            /// Returned object must be released with DsUtils.FreeAMMediaType()
            /// </summary>
            [PreserveSig]
            int GetMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] out AmMediaType ppMediaType);

            [PreserveSig]
            int SetMediaType([In, MarshalAs(UnmanagedType.LPStruct)] AmMediaType pMediaType);

            [PreserveSig]
            int IsDiscontinuity();

            [PreserveSig]
            int SetDiscontinuity([In, MarshalAs(UnmanagedType.Bool)] bool bDiscontinuity);

            [PreserveSig]
            int GetMediaTime([Out] out long pTimeStart, [Out] out long pTimeEnd);

            [PreserveSig]
            int SetMediaTime([In, MarshalAs(UnmanagedType.LPStruct)] Util.DsOptInt64 pTimeStart, [In, MarshalAs(UnmanagedType.LPStruct)] Util.DsOptInt64 pTimeEnd);
        }

        [ComVisible(false)]
        public class DsHlp
        {
            public const int OATRUE = -1;
            public const int OAFALSE = 0;

            [DllImport("quartz.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "AMGetErrorTextW"), SuppressUnmanagedCodeSecurity]
            public static extern int AMGetErrorText(int hr, StringBuilder buf, int max);
        }
    }
}
