Added Remote Webcam

I added remote webcam using AForge, it may be a little hackish but it
works.
This commit is contained in:
Darius Costolas 2016-06-13 17:30:04 +03:00
parent eef7d258c2
commit daac56a12c
75 changed files with 11375 additions and 16 deletions

View File

@ -53,8 +53,55 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Core\AForge\Video.DirectShow\CameraControlProperty.cs" />
<Compile Include="Core\AForge\Video.DirectShow\FileVideoSource.cs" />
<Compile Include="Core\AForge\Video.DirectShow\FilterInfo.cs" />
<Compile Include="Core\AForge\Video.DirectShow\FilterInfoCollection.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IAMCameraControl.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IAMCrossbar.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IAMStreamConfig.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IAMVideoControl.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IBaseFilter.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\ICaptureGraphBuilder2.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\ICreateDevEnum.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IEnumFilters.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IEnumPins.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IFileSourceFilter.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IFilterGraph.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IFilterGraph2.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IGraphBuilder.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IMediaControl.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IMediaEventEx.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IMediaFilter.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IPersist.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IPin.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IPropertyBag.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IReferenceClock.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\ISampleGrabber.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\ISampleGrabberCB.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\ISpecifyPropertyPages.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\IVideoWindow.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\Structures.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\Tools.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\Uuids.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Internals\Win32.cs" />
<Compile Include="Core\AForge\Video.DirectShow\PhysicalConnectorType.cs" />
<Compile Include="Core\AForge\Video.DirectShow\Uuids.cs" />
<Compile Include="Core\AForge\Video.DirectShow\VideoCapabilities.cs" />
<Compile Include="Core\AForge\Video.DirectShow\VideoCaptureDevice.cs" />
<Compile Include="Core\AForge\Video.DirectShow\VideoInput.cs" />
<Compile Include="Core\AForge\Video\AsyncVideoSource.cs" />
<Compile Include="Core\AForge\Video\ByteArrayUtils.cs" />
<Compile Include="Core\AForge\Video\Exceptions.cs" />
<Compile Include="Core\AForge\Video\IVideoSource.cs" />
<Compile Include="Core\AForge\Video\JPEGStream.cs" />
<Compile Include="Core\AForge\Video\MJPEGStream.cs" />
<Compile Include="Core\AForge\Video\ScreenCaptureStream.cs" />
<Compile Include="Core\AForge\Video\SystemTools.cs" />
<Compile Include="Core\AForge\Video\VideoEvents.cs" />
<Compile Include="Core\Commands\RegistryHandler.cs" />
<Compile Include="Core\Commands\TCPConnectionsHandler.cs" />
<Compile Include="Core\Commands\WebcamHandler.cs" />
<Compile Include="Core\Data\ClientData.cs" />
<Compile Include="Core\Data\GeoInformation.cs" />
<Compile Include="Core\Helper\CryptographyHelper.cs" />
@ -102,11 +149,14 @@
<Compile Include="Core\Packets\ClientPackets\GetCreateRegistryValueResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetDeleteRegistryKeyResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetDeleteRegistryValueResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetWebcamResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetWebcamsResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetPasswordsResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRegistryKeysResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRenameRegistryKeyResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRenameRegistryValueResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\SetStatusFileManager.cs" />
<Compile Include="Core\Packets\ServerPackets\DoWebcamStop.cs" />
<Compile Include="Core\Packets\ServerPackets\DoAskElevate.cs" />
<Compile Include="Core\Packets\ServerPackets\DoChangeRegistryValue.cs" />
<Compile Include="Core\Packets\ServerPackets\DoCloseConnection.cs" />
@ -119,6 +169,8 @@
<Compile Include="Core\Packets\ServerPackets\DoRenameRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\DoRenameRegistryValue.cs" />
<Compile Include="Core\Packets\ServerPackets\GetConnections.cs" />
<Compile Include="Core\Packets\ServerPackets\GetWebcam.cs" />
<Compile Include="Core\Packets\ServerPackets\GetWebcams.cs" />
<Compile Include="Core\Packets\ServerPackets\GetPasswords.cs" />
<Compile Include="Core\Packets\ServerPackets\SetAuthenticationSuccess.cs" />
<Compile Include="Core\Recovery\FtpClients\FileZilla.cs" />

View File

@ -0,0 +1,67 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2013
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow
{
using System;
/// <summary>
/// The enumeration specifies a setting on a camera.
/// </summary>
public enum CameraControlProperty
{
/// <summary>
/// Pan control.
/// </summary>
Pan = 0,
/// <summary>
/// Tilt control.
/// </summary>
Tilt,
/// <summary>
/// Roll control.
/// </summary>
Roll,
/// <summary>
/// Zoom control.
/// </summary>
Zoom,
/// <summary>
/// Exposure control.
/// </summary>
Exposure,
/// <summary>
/// Iris control.
/// </summary>
Iris,
/// <summary>
/// Focus control.
/// </summary>
Focus
}
/// <summary>
/// The enumeration defines whether a camera setting is controlled manually or automatically.
/// </summary>
[Flags]
public enum CameraControlFlags
{
/// <summary>
/// No control flag.
/// </summary>
None = 0x0,
/// <summary>
/// Auto control Flag.
/// </summary>
Auto = 0x0001,
/// <summary>
/// Manual control Flag.
/// </summary>
Manual = 0x0002
}
}

View File

@ -0,0 +1,621 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2011
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow
{
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Runtime.InteropServices;
using AForge.Video;
using AForge.Video.DirectShow.Internals;
/// <summary>
/// Video source for video files.
/// </summary>
///
/// <remarks><para>The video source provides access to video files. DirectShow is used to access video
/// files.</para>
///
/// <para>Sample usage:</para>
/// <code>
/// // create video source
/// FileVideoSource videoSource = new FileVideoSource( fileName );
/// // set NewFrame event handler
/// videoSource.NewFrame += new NewFrameEventHandler( video_NewFrame );
/// // start the video source
/// videoSource.Start( );
/// // ...
/// // signal to stop
/// videoSource.SignalToStop( );
/// // ...
///
/// // New frame event handler, which is invoked on each new available video frame
/// private void video_NewFrame( object sender, NewFrameEventArgs eventArgs )
/// {
/// // get new frame
/// Bitmap bitmap = eventArgs.Frame;
/// // process the frame
/// }
/// </code>
/// </remarks>
///
public class FileVideoSource : IVideoSource
{
// video file name
private string fileName;
// received frames count
private int framesReceived;
// recieved byte count
private long bytesReceived;
// prevent freezing
private bool preventFreezing = false;
// reference clock for the graph - when disabled, graph processes frames ASAP
private bool referenceClockEnabled = true;
private Thread thread = null;
private ManualResetEvent stopEvent = null;
/// <summary>
/// New frame event.
/// </summary>
///
/// <remarks><para>Notifies clients about new available frame from video source.</para>
///
/// <para><note>Since video source may have multiple clients, each client is responsible for
/// making a copy (cloning) of the passed video frame, because the video source disposes its
/// own original copy after notifying of clients.</note></para>
/// </remarks>
///
public event NewFrameEventHandler NewFrame;
/// <summary>
/// Video source error event.
/// </summary>
///
/// <remarks>This event is used to notify clients about any type of errors occurred in
/// video source object, for example internal exceptions.</remarks>
///
public event VideoSourceErrorEventHandler VideoSourceError;
/// <summary>
/// Video playing finished event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients that the video playing has finished.</para>
/// </remarks>
///
public event PlayingFinishedEventHandler PlayingFinished;
/// <summary>
/// Video source.
/// </summary>
///
/// <remarks>Video source is represented by video file name.</remarks>
///
public virtual string Source
{
get { return fileName; }
set { fileName = value; }
}
/// <summary>
/// Received frames count.
/// </summary>
///
/// <remarks>Number of frames the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public int FramesReceived
{
get
{
int frames = framesReceived;
framesReceived = 0;
return frames;
}
}
/// <summary>
/// Received bytes count.
/// </summary>
///
/// <remarks>Number of bytes the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public long BytesReceived
{
get
{
long bytes = bytesReceived;
bytesReceived = 0;
return bytes;
}
}
/// <summary>
/// State of the video source.
/// </summary>
///
/// <remarks>Current state of video source object - running or not.</remarks>
///
public bool IsRunning
{
get
{
if ( thread != null )
{
// check thread status
if ( thread.Join( 0 ) == false )
return true;
// the thread is not running, free resources
Free( );
}
return false;
}
}
/// <summary>
/// Prevent video freezing after screen saver and workstation lock or not.
/// </summary>
///
/// <remarks>
/// <para>The value specifies if the class should prevent video freezing during and
/// after screen saver or workstation lock. To prevent freezing the <i>DirectShow</i> graph
/// should not contain <i>Renderer</i> filter, which is added by <i>Render()</i> method
/// of graph. However, in some cases it may be required to call <i>Render()</i> method of graph, since
/// it may add some more filters, which may be required for playing video. So, the property is
/// a trade off - it is possible to prevent video freezing skipping adding renderer filter or
/// it is possible to keep renderer filter, but video may freeze during screen saver.</para>
///
/// <para><note>The property may become obsolete in the future when approach to disable freezing
/// and adding all required filters is found.</note></para>
///
/// <para><note>The property should be set before calling <see cref="Start"/> method
/// of the class to have effect.</note></para>
///
/// <para>Default value of this property is set to <b>false</b>.</para>
///
/// </remarks>
///
public bool PreventFreezing
{
get { return preventFreezing; }
set { preventFreezing = value; }
}
/// <summary>
/// Enables/disables reference clock on the graph.
/// </summary>
///
/// <remarks><para>Disabling reference clocks causes DirectShow graph to run as fast as
/// it can process data. When enabled, it will process frames according to presentation
/// time of a video file.</para>
///
/// <para><note>The property should be set before calling <see cref="Start"/> method
/// of the class to have effect.</note></para>
///
/// <para>Default value of this property is set to <b>true</b>.</para>
/// </remarks>
///
public bool ReferenceClockEnabled
{
get { return referenceClockEnabled; }
set { referenceClockEnabled = value;}
}
/// <summary>
/// Initializes a new instance of the <see cref="FileVideoSource"/> class.
/// </summary>
///
public FileVideoSource( ) { }
/// <summary>
/// Initializes a new instance of the <see cref="FileVideoSource"/> class.
/// </summary>
///
/// <param name="fileName">Video file name.</param>
///
public FileVideoSource( string fileName )
{
this.fileName = fileName;
}
/// <summary>
/// Start video source.
/// </summary>
///
/// <remarks>Starts video source and return execution to caller. Video source
/// object creates background thread and notifies about new frames with the
/// help of <see cref="NewFrame"/> event.</remarks>
///
public void Start( )
{
if ( !IsRunning )
{
// check source
if ( ( fileName == null ) || ( fileName == string.Empty ) )
throw new ArgumentException( "Video source is not specified" );
framesReceived = 0;
bytesReceived = 0;
// create events
stopEvent = new ManualResetEvent( false );
// create and start new thread
thread = new Thread( new ThreadStart( WorkerThread ) );
thread.Name = fileName; // mainly for debugging
thread.Start( );
}
}
/// <summary>
/// Signal video source to stop its work.
/// </summary>
///
/// <remarks>Signals video source to stop its background thread, stop to
/// provide new frames and free resources.</remarks>
///
public void SignalToStop( )
{
// stop thread
if ( thread != null )
{
// signal to stop
stopEvent.Set( );
}
}
/// <summary>
/// Wait for video source has stopped.
/// </summary>
///
/// <remarks>Waits for source stopping after it was signalled to stop using
/// <see cref="SignalToStop"/> method.</remarks>
///
public void WaitForStop( )
{
if ( thread != null )
{
// wait for thread stop
thread.Join( );
Free( );
}
}
/// <summary>
/// Stop video source.
/// </summary>
///
/// <remarks><para>Stops video source aborting its thread.</para>
///
/// <para><note>Since the method aborts background thread, its usage is highly not preferred
/// and should be done only if there are no other options. The correct way of stopping camera
/// is <see cref="SignalToStop">signaling it stop</see> and then
/// <see cref="WaitForStop">waiting</see> for background thread's completion.</note></para>
/// </remarks>
///
public void Stop( )
{
if ( this.IsRunning )
{
thread.Abort( );
WaitForStop( );
}
}
/// <summary>
/// Free resource.
/// </summary>
///
private void Free( )
{
thread = null;
// release events
stopEvent.Close( );
stopEvent = null;
}
/// <summary>
/// Worker thread.
/// </summary>
///
private void WorkerThread( )
{
ReasonToFinishPlaying reasonToStop = ReasonToFinishPlaying.StoppedByUser;
// grabber
Grabber grabber = new Grabber( this );
// objects
object graphObject = null;
object grabberObject = null;
// interfaces
IGraphBuilder graph = null;
IBaseFilter sourceBase = null;
IBaseFilter grabberBase = null;
ISampleGrabber sampleGrabber = null;
IMediaControl mediaControl = null;
IMediaEventEx mediaEvent = null;
try
{
// get type for filter graph
Type type = Type.GetTypeFromCLSID( Clsid.FilterGraph );
if ( type == null )
throw new ApplicationException( "Failed creating filter graph" );
// create filter graph
graphObject = Activator.CreateInstance( type );
graph = (IGraphBuilder) graphObject;
// create source device's object
graph.AddSourceFilter( fileName, "source", out sourceBase );
if ( sourceBase == null )
throw new ApplicationException( "Failed creating source filter" );
// get type for sample grabber
type = Type.GetTypeFromCLSID( Clsid.SampleGrabber );
if ( type == null )
throw new ApplicationException( "Failed creating sample grabber" );
// create sample grabber
grabberObject = Activator.CreateInstance( type );
sampleGrabber = (ISampleGrabber) grabberObject;
grabberBase = (IBaseFilter) grabberObject;
// add grabber filters to graph
graph.AddFilter( grabberBase, "grabber" );
// set media type
AMMediaType mediaType = new AMMediaType( );
mediaType.MajorType = MediaType.Video;
mediaType.SubType = MediaSubType.RGB24;
sampleGrabber.SetMediaType( mediaType );
// connect pins
int pinToTry = 0;
IPin inPin = Tools.GetInPin( grabberBase, 0 );
IPin outPin = null;
// find output pin acceptable by sample grabber
while ( true )
{
outPin = Tools.GetOutPin( sourceBase, pinToTry );
if ( outPin == null )
{
Marshal.ReleaseComObject( inPin );
throw new ApplicationException( "Did not find acceptable output video pin in the given source" );
}
if ( graph.Connect( outPin, inPin ) < 0 )
{
Marshal.ReleaseComObject( outPin );
outPin = null;
pinToTry++;
}
else
{
break;
}
}
Marshal.ReleaseComObject( outPin );
Marshal.ReleaseComObject( inPin );
// get media type
if ( sampleGrabber.GetConnectedMediaType( mediaType ) == 0 )
{
VideoInfoHeader vih = (VideoInfoHeader) Marshal.PtrToStructure( mediaType.FormatPtr, typeof( VideoInfoHeader ) );
grabber.Width = vih.BmiHeader.Width;
grabber.Height = vih.BmiHeader.Height;
mediaType.Dispose( );
}
// let's do rendering, if we don't need to prevent freezing
if ( !preventFreezing )
{
// render pin
graph.Render( Tools.GetOutPin( grabberBase, 0 ) );
// configure video window
IVideoWindow window = (IVideoWindow) graphObject;
window.put_AutoShow( false );
window = null;
}
// configure sample grabber
sampleGrabber.SetBufferSamples( false );
sampleGrabber.SetOneShot( false );
sampleGrabber.SetCallback( grabber, 1 );
// disable clock, if someone requested it
if ( !referenceClockEnabled )
{
IMediaFilter mediaFilter = (IMediaFilter) graphObject;
mediaFilter.SetSyncSource( null );
}
// get media control
mediaControl = (IMediaControl) graphObject;
// get media events' interface
mediaEvent = (IMediaEventEx) graphObject;
IntPtr p1, p2;
DsEvCode code;
// run
mediaControl.Run( );
do
{
if ( mediaEvent != null )
{
if ( mediaEvent.GetEvent( out code, out p1, out p2, 0 ) >= 0 )
{
mediaEvent.FreeEventParams( code, p1, p2 );
if ( code == DsEvCode.Complete )
{
reasonToStop = ReasonToFinishPlaying.EndOfStreamReached;
break;
}
}
}
}
while ( !stopEvent.WaitOne( 100, false ) );
mediaControl.Stop( );
}
catch ( Exception exception )
{
// provide information to clients
if ( VideoSourceError != null )
{
VideoSourceError( this, new VideoSourceErrorEventArgs( exception.Message ) );
}
}
finally
{
// release all objects
graph = null;
grabberBase = null;
sampleGrabber = null;
mediaControl = null;
mediaEvent = null;
if ( graphObject != null )
{
Marshal.ReleaseComObject( graphObject );
graphObject = null;
}
if ( sourceBase != null )
{
Marshal.ReleaseComObject( sourceBase );
sourceBase = null;
}
if ( grabberObject != null )
{
Marshal.ReleaseComObject( grabberObject );
grabberObject = null;
}
}
if ( PlayingFinished != null )
{
PlayingFinished( this, reasonToStop );
}
}
/// <summary>
/// Notifies client about new frame.
/// </summary>
///
/// <param name="image">New frame's image.</param>
///
protected void OnNewFrame( Bitmap image )
{
framesReceived++;
bytesReceived += image.Width * image.Height * ( Bitmap.GetPixelFormatSize( image.PixelFormat ) >> 3 );
if ( ( !stopEvent.WaitOne( 0, false ) ) && ( NewFrame != null ) )
NewFrame( this, new NewFrameEventArgs( image ) );
}
//
// Video grabber
//
private class Grabber : ISampleGrabberCB
{
private FileVideoSource parent;
private int width, height;
// Width property
public int Width
{
get { return width; }
set { width = value; }
}
// Height property
public int Height
{
get { return height; }
set { height = value; }
}
// Constructor
public Grabber( FileVideoSource parent )
{
this.parent = parent;
}
// Callback to receive samples
public int SampleCB( double sampleTime, IntPtr sample )
{
return 0;
}
// Callback method that receives a pointer to the sample buffer
public int BufferCB( double sampleTime, IntPtr buffer, int bufferLen )
{
if ( parent.NewFrame != null )
{
// create new image
System.Drawing.Bitmap image = new Bitmap( width, height, PixelFormat.Format24bppRgb );
// lock bitmap data
BitmapData imageData = image.LockBits(
new Rectangle( 0, 0, width, height ),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb );
// copy image data
int srcStride = imageData.Stride;
int dstStride = imageData.Stride;
unsafe
{
byte* dst = (byte*) imageData.Scan0.ToPointer( ) + dstStride * ( height - 1 );
byte* src = (byte*) buffer.ToPointer( );
for ( int y = 0; y < height; y++ )
{
Win32.memcpy( dst, src, srcStride );
dst -= dstStride;
src += srcStride;
}
}
// unlock bitmap data
image.UnlockBits( imageData );
// notify parent
parent.OnNewFrame( image );
// release the image
image.Dispose( );
}
return 0;
}
}
}
}

View File

@ -0,0 +1,193 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow
{
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using AForge.Video.DirectShow.Internals;
/// <summary>
/// DirectShow filter information.
/// </summary>
///
public class FilterInfo : IComparable
{
/// <summary>
/// Filter name.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Filters's moniker string.
/// </summary>
///
public string MonikerString { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="FilterInfo"/> class.
/// </summary>
///
/// <param name="monikerString">Filters's moniker string.</param>
///
public FilterInfo( string monikerString )
{
MonikerString = monikerString;
Name = GetName( monikerString );
}
/// <summary>
/// Initializes a new instance of the <see cref="FilterInfo"/> class.
/// </summary>
///
/// <param name="moniker">Filter's moniker object.</param>
///
internal FilterInfo( IMoniker moniker )
{
MonikerString = GetMonikerString( moniker );
Name = GetName( moniker );
}
/// <summary>
/// Compare the object with another instance of this class.
/// </summary>
///
/// <param name="value">Object to compare with.</param>
///
/// <returns>A signed number indicating the relative values of this instance and <b>value</b>.</returns>
///
public int CompareTo( object value )
{
FilterInfo f = (FilterInfo) value;
if ( f == null )
return 1;
return ( this.Name.CompareTo( f.Name ) );
}
/// <summary>
/// Create an instance of the filter.
/// </summary>
///
/// <param name="filterMoniker">Filter's moniker string.</param>
///
/// <returns>Returns filter's object, which implements <b>IBaseFilter</b> interface.</returns>
///
/// <remarks>The returned filter's object should be released using <b>Marshal.ReleaseComObject()</b>.</remarks>
///
public static object CreateFilter( string filterMoniker )
{
// filter's object
object filterObject = null;
// bind context and moniker objects
IBindCtx bindCtx = null;
IMoniker moniker = null;
int n = 0;
// create bind context
if ( Win32.CreateBindCtx( 0, out bindCtx ) == 0 )
{
// convert moniker`s string to a moniker
if ( Win32.MkParseDisplayName( bindCtx, filterMoniker, ref n, out moniker ) == 0 )
{
// get device base filter
Guid filterId = typeof( IBaseFilter ).GUID;
moniker.BindToObject( null, null, ref filterId, out filterObject );
Marshal.ReleaseComObject( moniker );
}
Marshal.ReleaseComObject( bindCtx );
}
return filterObject;
}
//
// Get moniker string of the moniker
//
private string GetMonikerString( IMoniker moniker )
{
string str;
moniker.GetDisplayName( null, null, out str );
return str;
}
//
// Get filter name represented by the moniker
//
private string GetName( IMoniker moniker )
{
Object bagObj = null;
IPropertyBag bag = null;
try
{
Guid bagId = typeof( IPropertyBag ).GUID;
// get property bag of the moniker
moniker.BindToStorage( null, null, ref bagId, out bagObj );
bag = (IPropertyBag) bagObj;
// read FriendlyName
object val = "";
int hr = bag.Read( "FriendlyName", ref val, IntPtr.Zero );
if ( hr != 0 )
Marshal.ThrowExceptionForHR( hr );
// get it as string
string ret = (string) val;
if ( ( ret == null ) || ( ret.Length < 1 ) )
throw new ApplicationException( );
return ret;
}
catch ( Exception )
{
return "";
}
finally
{
// release all COM objects
bag = null;
if ( bagObj != null )
{
Marshal.ReleaseComObject( bagObj );
bagObj = null;
}
}
}
//
// Get filter name represented by the moniker string
//
private string GetName( string monikerString )
{
IBindCtx bindCtx = null;
IMoniker moniker = null;
String name = "";
int n = 0;
// create bind context
if ( Win32.CreateBindCtx( 0, out bindCtx ) == 0 )
{
// convert moniker`s string to a moniker
if ( Win32.MkParseDisplayName( bindCtx, monikerString, ref n, out moniker ) == 0 )
{
// get device name
name = GetName( moniker );
Marshal.ReleaseComObject( moniker );
moniker = null;
}
Marshal.ReleaseComObject( bindCtx );
bindCtx = null;
}
return name;
}
}
}

View File

@ -0,0 +1,138 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow
{
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using AForge.Video.DirectShow.Internals;
/// <summary>
/// Collection of filters' information objects.
/// </summary>
///
/// <remarks><para>The class allows to enumerate DirectShow filters of specified category. For
/// a list of categories see <see cref="FilterCategory"/>.</para>
///
/// <para>Sample usage:</para>
/// <code>
/// // enumerate video devices
/// videoDevices = new FilterInfoCollection( FilterCategory.VideoInputDevice );
/// // list devices
/// foreach ( FilterInfo device in videoDevices )
/// {
/// // ...
/// }
/// </code>
/// </remarks>
///
public class FilterInfoCollection : CollectionBase
{
/// <summary>
/// Initializes a new instance of the <see cref="FilterInfoCollection"/> class.
/// </summary>
///
/// <param name="category">Guid of DirectShow filter category. See <see cref="FilterCategory"/>.</param>
///
/// <remarks>Build collection of filters' information objects for the
/// specified filter category.</remarks>
///
public FilterInfoCollection( Guid category )
{
CollectFilters( category );
}
/// <summary>
/// Get filter information object.
/// </summary>
///
/// <param name="index">Index of filter information object to retrieve.</param>
///
/// <returns>Filter information object.</returns>
///
public FilterInfo this[int index]
{
get
{
return ( (FilterInfo) InnerList[index] );
}
}
// Collect filters of specified category
private void CollectFilters( Guid category )
{
object comObj = null;
ICreateDevEnum enumDev = null;
IEnumMoniker enumMon = null;
IMoniker[] devMon = new IMoniker[1];
int hr;
try
{
// Get the system device enumerator
Type srvType = Type.GetTypeFromCLSID( Clsid.SystemDeviceEnum );
if ( srvType == null )
throw new ApplicationException( "Failed creating device enumerator" );
// create device enumerator
comObj = Activator.CreateInstance( srvType );
enumDev = (ICreateDevEnum) comObj;
// Create an enumerator to find filters of specified category
hr = enumDev.CreateClassEnumerator( ref category, out enumMon, 0 );
if ( hr != 0 )
throw new ApplicationException( "No devices of the category" );
// Collect all filters
IntPtr n = IntPtr.Zero;
while ( true )
{
// Get next filter
hr = enumMon.Next( 1, devMon, n );
if ( ( hr != 0 ) || ( devMon[0] == null ) )
break;
// Add the filter
FilterInfo filter = new FilterInfo( devMon[0] );
InnerList.Add( filter );
// Release COM object
Marshal.ReleaseComObject( devMon[0] );
devMon[0] = null;
}
// Sort the collection
InnerList.Sort( );
}
catch
{
}
finally
{
// release all COM objects
enumDev = null;
if ( comObj != null )
{
Marshal.ReleaseComObject( comObj );
comObj = null;
}
if ( enumMon != null )
{
Marshal.ReleaseComObject( enumMon );
enumMon = null;
}
if ( devMon[0] != null )
{
Marshal.ReleaseComObject( devMon[0] );
devMon[0] = null;
}
}
}
}
}

View File

@ -0,0 +1,81 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2013
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The IAMCameraControl interface controls camera settings such as zoom, pan, aperture adjustment,
/// or shutter speed. To obtain this interface, query the filter that controls the camera.
/// </summary>
[ComImport,
Guid( "C6E13370-30AC-11d0-A18C-00A0C9118956" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IAMCameraControl
{
/// <summary>
/// Gets the range and default value of a specified camera property.
/// </summary>
///
/// <param name="Property">Specifies the property to query.</param>
/// <param name="pMin">Receives the minimum value of the property.</param>
/// <param name="pMax">Receives the maximum value of the property.</param>
/// <param name="pSteppingDelta">Receives the step size for the property.</param>
/// <param name="pDefault">Receives the default value of the property. </param>
/// <param name="pCapsFlags">Receives a member of the CameraControlFlags enumeration, indicating whether the property is controlled automatically or manually.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetRange(
[In] CameraControlProperty Property,
[Out] out int pMin,
[Out] out int pMax,
[Out] out int pSteppingDelta,
[Out] out int pDefault,
[Out] out CameraControlFlags pCapsFlags
);
/// <summary>
/// Sets a specified property on the camera.
/// </summary>
///
/// <param name="Property">Specifies the property to set.</param>
/// <param name="lValue">Specifies the new value of the property.</param>
/// <param name="Flags">Specifies the desired control setting, as a member of the CameraControlFlags enumeration.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Set(
[In] CameraControlProperty Property,
[In] int lValue,
[In] CameraControlFlags Flags
);
/// <summary>
/// Gets the current setting of a camera property.
/// </summary>
///
/// <param name="Property">Specifies the property to retrieve.</param>
/// <param name="lValue">Receives the value of the property.</param>
/// <param name="Flags">Receives a member of the CameraControlFlags enumeration.
/// The returned value indicates whether the setting is controlled manually or automatically.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Get(
[In] CameraControlProperty Property,
[Out] out int lValue,
[Out] out CameraControlFlags Flags
);
}
}

View File

@ -0,0 +1,88 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2012
// contacts@aforgenet.com
//
using System;
using System.Runtime.InteropServices;
namespace AForge.Video.DirectShow.Internals
{
/// <summary>
/// The IAMCrossbar interface routes signals from an analog or digital source to a video capture filter.
/// </summary>
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid( "C6E13380-30AC-11D0-A18C-00A0C9118956" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IAMCrossbar
{
/// <summary>
/// Retrieves the number of input and output pins on the crossbar filter.
/// </summary>
///
/// <param name="outputPinCount">Variable that receives the number of output pins.</param>
/// <param name="inputPinCount">Variable that receives the number of input pins.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_PinCounts( [Out] out int outputPinCount, [Out] out int inputPinCount );
/// <summary>
/// Queries whether a specified input pin can be routed to a specified output pin.
/// </summary>
///
/// <param name="outputPinIndex">Specifies the index of the output pin.</param>
/// <param name="inputPinIndex">Specifies the index of input pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int CanRoute( [In] int outputPinIndex, [In] int inputPinIndex );
/// <summary>
/// Routes an input pin to an output pin.
/// </summary>
///
/// <param name="outputPinIndex">Specifies the index of the output pin.</param>
/// <param name="inputPinIndex">Specifies the index of the input pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Route( [In] int outputPinIndex, [In] int inputPinIndex );
/// <summary>
/// Retrieves the input pin that is currently routed to the specified output pin.
/// </summary>
///
/// <param name="outputPinIndex">Specifies the index of the output pin.</param>
/// <param name="inputPinIndex">Variable that receives the index of the input pin, or -1 if no input pin is routed to this output pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_IsRoutedTo( [In] int outputPinIndex, [Out] out int inputPinIndex );
/// <summary>
/// Retrieves information about a specified pin.
/// </summary>
///
/// <param name="isInputPin">Specifies the direction of the pin. Use one of the following values.</param>
/// <param name="pinIndex">Specifies the index of the pin.</param>
/// <param name="pinIndexRelated">Variable that receives the index of the related pin, or 1 if no pin is related to this pin.</param>
/// <param name="physicalType">Variable that receives a member of the PhysicalConnectorType enumeration, indicating the pin's physical type.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_CrossbarPinInfo(
[In, MarshalAs( UnmanagedType.Bool )] bool isInputPin,
[In] int pinIndex,
[Out] out int pinIndexRelated,
[Out] out PhysicalConnectorType physicalType );
}
}

View File

@ -0,0 +1,74 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// This interface sets the output format on certain capture and compression filters,
/// for both audio and video.
/// </summary>
///
[ComImport,
Guid( "C6E13340-30AC-11d0-A18C-00A0C9118956" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IAMStreamConfig
{
/// <summary>
/// Set the output format on the pin.
/// </summary>
///
/// <param name="mediaType">Media type to set.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetFormat( [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Retrieves the audio or video stream's format.
/// </summary>
///
/// <param name="mediaType">Retrieved media type.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetFormat( [Out, MarshalAs( UnmanagedType.LPStruct )] out AMMediaType mediaType );
/// <summary>
/// Retrieve the number of format capabilities that this pin supports.
/// </summary>
///
/// <param name="count">Variable that receives the number of format capabilities.</param>
/// <param name="size">Variable that receives the size of the configuration structure in bytes.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetNumberOfCapabilities( out int count, out int size );
/// <summary>
/// Retrieve a set of format capabilities.
/// </summary>
///
/// <param name="index">Specifies the format capability to retrieve, indexed from zero.</param>
/// <param name="mediaType">Retrieved media type.</param>
/// <param name="streamConfigCaps">Byte array, which receives information about capabilities.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetStreamCaps(
[In] int index,
[Out, MarshalAs( UnmanagedType.LPStruct )] out AMMediaType mediaType,
[In, MarshalAs( UnmanagedType.LPStruct )] VideoStreamConfigCaps streamConfigCaps
);
}
}

View File

@ -0,0 +1,112 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2011
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface controls certain video capture operations such as enumerating available
/// frame rates and image orientation.
/// </summary>
///
[ComImport,
Guid( "6A2E0670-28E4-11D0-A18c-00A0C9118956" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IAMVideoControl
{
/// <summary>
/// Retrieves the capabilities of the underlying hardware.
/// </summary>
///
/// <param name="pin">Pin to query capabilities from.</param>
/// <param name="flags">Get capabilities of the specified pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetCaps( [In] IPin pin, [Out, MarshalAs( UnmanagedType.I4 )] out VideoControlFlags flags );
/// <summary>
/// Sets the video control mode of operation.
/// </summary>
///
/// <param name="pin">The pin to set the video control mode on.</param>
/// <param name="mode">Value specifying a combination of the flags to set the video control mode.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetMode( [In] IPin pin, [In, MarshalAs( UnmanagedType.I4 )] VideoControlFlags mode );
/// <summary>
/// Retrieves the video control mode of operation.
/// </summary>
///
/// <param name="pin">The pin to retrieve the video control mode from.</param>
/// <param name="mode">Gets combination of flags, which specify the video control mode.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetMode( [In] IPin pin, [Out, MarshalAs( UnmanagedType.I4 )] out VideoControlFlags mode );
/// <summary>
/// The method retrieves the actual frame rate, expressed as a frame duration in 100-nanosecond units.
/// USB (Universal Serial Bus) and IEEE 1394 cameras may provide lower frame rates than requested
/// because of bandwidth availability. This is only available during video streaming.
/// </summary>
///
/// <param name="pin">The pin to retrieve the frame rate from.</param>
/// <param name="actualFrameRate">Gets frame rate in frame duration in 100-nanosecond units.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetCurrentActualFrameRate( [In] IPin pin, [Out, MarshalAs( UnmanagedType.I8 )] out long actualFrameRate );
/// <summary>
/// Retrieves the maximum frame rate currently available based on bus bandwidth usage for connections
/// such as USB and IEEE 1394 camera devices where the maximum frame rate can be limited by bandwidth
/// availability.
/// </summary>
///
/// <param name="pin">The pin to retrieve the maximum frame rate from.</param>
/// <param name="index">Index of the format to query for maximum frame rate. This index corresponds
/// to the order in which formats are enumerated by <see cref="IAMStreamConfig.GetStreamCaps"/>.</param>
/// <param name="dimensions">Frame image size (width and height) in pixels.</param>
/// <param name="maxAvailableFrameRate">Gets maximum available frame rate. The frame rate is expressed as frame duration in 100-nanosecond units.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetMaxAvailableFrameRate( [In] IPin pin, [In] int index,
[In] System.Drawing.Size dimensions,
[Out] out long maxAvailableFrameRate );
/// <summary>
/// Retrieves a list of available frame rates.
/// </summary>
///
/// <param name="pin">The pin to retrieve the maximum frame rate from.</param>
/// <param name="index">Index of the format to query for maximum frame rate. This index corresponds
/// to the order in which formats are enumerated by <see cref="IAMStreamConfig.GetStreamCaps"/>.</param>
/// <param name="dimensions">Frame image size (width and height) in pixels.</param>
/// <param name="listSize">Number of elements in the list of frame rates.</param>
/// <param name="frameRate">Array of frame rates in 100-nanosecond units.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetFrameRateList( [In] IPin pin, [In] int index,
[In] System.Drawing.Size dimensions,
[Out] out int listSize,
[Out] out IntPtr frameRate );
}
}

View File

@ -0,0 +1,161 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The IBaseFilter interface provides methods for controlling a filter.
/// All DirectShow filters expose this interface
/// </summary>
///
[ComImport,
Guid( "56A86895-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IBaseFilter
{
// --- IPersist Methods
/// <summary>
/// Returns the class identifier (CLSID) for the component object.
/// </summary>
///
/// <param name="ClassID">Points to the location of the CLSID on return.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetClassID( [Out] out Guid ClassID );
// --- IMediaFilter Methods
/// <summary>
/// Stops the filter.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Stop( );
/// <summary>
/// Pauses the filter.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Pause( );
/// <summary>
/// Runs the filter.
/// </summary>
///
/// <param name="start">Reference time corresponding to stream time 0.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Run( long start );
/// <summary>
/// Retrieves the state of the filter (running, stopped, or paused).
/// </summary>
///
/// <param name="milliSecsTimeout">Time-out interval, in milliseconds.</param>
/// <param name="filterState">Pointer to a variable that receives filter's state.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetState( int milliSecsTimeout, [Out] out int filterState );
/// <summary>
/// Sets the reference clock for the filter or the filter graph.
/// </summary>
///
/// <param name="clock">Pointer to the clock's <b>IReferenceClock</b> interface, or NULL. </param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetSyncSource( [In] IntPtr clock );
/// <summary>
/// Retrieves the current reference clock.
/// </summary>
///
/// <param name="clock">Address of a variable that receives a pointer to the clock's IReferenceClock interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetSyncSource( [Out] out IntPtr clock );
// --- IBaseFilter Methods
/// <summary>
/// Enumerates the pins on this filter.
/// </summary>
///
/// <param name="enumPins">Address of a variable that receives a pointer to the IEnumPins interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EnumPins( [Out] out IEnumPins enumPins );
/// <summary>
/// Retrieves the pin with the specified identifier.
/// </summary>
///
/// <param name="id">Pointer to a constant wide-character string that identifies the pin.</param>
/// <param name="pin">Address of a variable that receives a pointer to the pin's IPin interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FindPin( [In, MarshalAs( UnmanagedType.LPWStr )] string id, [Out] out IPin pin );
/// <summary>
/// Retrieves information about the filter.
/// </summary>
///
/// <param name="filterInfo">Pointer to <b>FilterInfo</b> structure.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryFilterInfo( [Out] out FilterInfo filterInfo );
/// <summary>
/// Notifies the filter that it has joined or left the filter graph.
/// </summary>
///
/// <param name="graph">Pointer to the Filter Graph Manager's <b>IFilterGraph</b> interface, or NULL
/// if the filter is leaving the graph.</param>
/// <param name="name">String that specifies a name for the filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int JoinFilterGraph( [In] IFilterGraph graph, [In, MarshalAs( UnmanagedType.LPWStr )] string name );
/// <summary>
/// Retrieves a string containing vendor information.
/// </summary>
///
/// <param name="vendorInfo">Receives a string containing the vendor information.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryVendorInfo( [Out, MarshalAs( UnmanagedType.LPWStr )] out string vendorInfo );
}
}

View File

@ -0,0 +1,192 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// This interface builds capture graphs and other custom filter graphs.
/// </summary>
///
[ComImport,
Guid( "93E5A4E0-2D50-11d2-ABFA-00A0C9C6E38D" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface ICaptureGraphBuilder2
{
/// <summary>
/// Specify filter graph for the capture graph builder to use.
/// </summary>
///
/// <param name="graphBuilder">Filter graph's interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetFiltergraph( [In] IGraphBuilder graphBuilder );
/// <summary>
/// Retrieve the filter graph that the builder is using.
/// </summary>
///
/// <param name="graphBuilder">Filter graph's interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetFiltergraph( [Out] out IGraphBuilder graphBuilder );
/// <summary>
/// Create file writing section of the filter graph.
/// </summary>
///
/// <param name="type">GUID that represents either the media subtype of the output or the
/// class identifier (CLSID) of a multiplexer filter or file writer filter.</param>
/// <param name="fileName">Output file name.</param>
/// <param name="baseFilter">Receives the multiplexer's <see cref="IBaseFilter"/> interface.</param>
/// <param name="fileSinkFilter">Receives the file writer's IFileSinkFilter interface. Can be NULL.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetOutputFileName(
[In, MarshalAs( UnmanagedType.LPStruct )] Guid type,
[In, MarshalAs( UnmanagedType.LPWStr )] string fileName,
[Out] out IBaseFilter baseFilter,
[Out] out IntPtr fileSinkFilter
);
/// <summary>
/// Searche the graph for a specified interface, starting from a specified filter.
/// </summary>
///
/// <param name="category">GUID that specifies the search criteria.</param>
/// <param name="type">GUID that specifies the major media type of an output pin, or NULL.</param>
/// <param name="baseFilter"><see cref="IBaseFilter"/> interface of the filter. The method begins searching from this filter.</param>
/// <param name="interfaceID">Interface identifier (IID) of the interface to locate.</param>
/// <param name="retInterface">Receives found interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FindInterface(
[In, MarshalAs( UnmanagedType.LPStruct )] Guid category,
[In, MarshalAs( UnmanagedType.LPStruct )] Guid type,
[In] IBaseFilter baseFilter,
[In, MarshalAs( UnmanagedType.LPStruct )] Guid interfaceID ,
[Out, MarshalAs( UnmanagedType.IUnknown )] out object retInterface
);
/// <summary>
/// Connect an output pin on a source filter to a rendering filter, optionally through a compression filter.
/// </summary>
///
/// <param name="category">Pin category.</param>
/// <param name="mediaType">Major-type GUID that specifies the media type of the output pin.</param>
/// <param name="source">Starting filter for the connection.</param>
/// <param name="compressor">Interface of an intermediate filter, such as a compression filter. Can be NULL.</param>
/// <param name="renderer">Sink filter, such as a renderer or mux filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RenderStream(
[In, MarshalAs( UnmanagedType.LPStruct )] Guid category,
[In, MarshalAs( UnmanagedType.LPStruct )] Guid mediaType,
[In, MarshalAs( UnmanagedType.IUnknown )] object source,
[In] IBaseFilter compressor,
[In] IBaseFilter renderer
);
/// <summary>
/// Set the start and stop times for one or more streams of captured data.
/// </summary>
///
/// <param name="category">Pin category.</param>
/// <param name="mediaType">Major-type GUID that specifies the media type.</param>
/// <param name="filter"><see cref="IBaseFilter"/> interface that specifies which filter to control.</param>
/// <param name="start">Start time.</param>
/// <param name="stop">Stop time.</param>
/// <param name="startCookie">Value that is sent as the second parameter of the
/// EC_STREAM_CONTROL_STARTED event notification.</param>
/// <param name="stopCookie">Value that is sent as the second parameter of the
/// EC_STREAM_CONTROL_STOPPED event notification.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ControlStream(
[In, MarshalAs( UnmanagedType.LPStruct )] Guid category,
[In, MarshalAs( UnmanagedType.LPStruct )] Guid mediaType,
[In, MarshalAs( UnmanagedType.Interface )] IBaseFilter filter,
[In] long start,
[In] long stop,
[In] short startCookie,
[In] short stopCookie
);
/// <summary>
/// Preallocate a capture file to a specified size.
/// </summary>
///
/// <param name="fileName">File name to create or resize.</param>
/// <param name="size">Size of the file to allocate, in bytes.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AllocCapFile(
[In, MarshalAs( UnmanagedType.LPWStr )] string fileName,
[In] long size
);
/// <summary>
/// Copy the valid media data from a capture file.
/// </summary>
///
/// <param name="oldFileName">Old file name.</param>
/// <param name="newFileName">New file name.</param>
/// <param name="allowEscAbort">Boolean value that specifies whether pressing the ESC key cancels the copy operation.</param>
/// <param name="callback">IAMCopyCaptureFileProgress interface to display progress information, or NULL.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int CopyCaptureFile(
[In, MarshalAs( UnmanagedType.LPWStr )] string oldFileName,
[In, MarshalAs( UnmanagedType.LPWStr )] string newFileName,
[In, MarshalAs( UnmanagedType.Bool )] bool allowEscAbort,
[In] IntPtr callback
);
/// <summary>
///
/// </summary>
///
/// <param name="source">Interface on a filter, or to an interface on a pin.</param>
/// <param name="pinDirection">Pin direction (input or output).</param>
/// <param name="category">Pin category.</param>
/// <param name="mediaType">Media type.</param>
/// <param name="unconnected">Boolean value that specifies whether the pin must be unconnected.</param>
/// <param name="index">Zero-based index of the pin to retrieve, from the set of matching pins.</param>
/// <param name="pin">Interface of the matching pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FindPin(
[In, MarshalAs( UnmanagedType.IUnknown )] object source,
[In] PinDirection pinDirection,
[In, MarshalAs( UnmanagedType.LPStruct )] Guid category,
[In, MarshalAs( UnmanagedType.LPStruct )] Guid mediaType,
[In, MarshalAs( UnmanagedType.Bool )] bool unconnected,
[In] int index,
[Out, MarshalAs( UnmanagedType.Interface )] out IPin pin
);
}
}

View File

@ -0,0 +1,37 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
/// <summary>
/// The <b>ICreateDevEnum</b> interface creates an enumerator for devices within a particular category,
/// such as video capture devices, audio capture devices, video compressors, and so forth.
/// </summary>
///
[ComImport,
Guid( "29840822-5B84-11D0-BD3B-00A0C911CE86" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface ICreateDevEnum
{
/// <summary>
/// Creates a class enumerator for a specified device category.
/// </summary>
///
/// <param name="type">Specifies the class identifier of the device category.</param>
/// <param name="enumMoniker">Address of a variable that receives an <b>IEnumMoniker</b> interface pointer</param>
/// <param name="flags">Bitwise combination of zero or more flags. If zero, the method enumerates every filter in the category.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int CreateClassEnumerator( [In] ref Guid type, [Out] out IEnumMoniker enumMoniker, [In] int flags );
}
}

View File

@ -0,0 +1,71 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007-2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// This interface is used by applications or other filters to determine
/// what filters exist in the filter graph.
/// </summary>
///
[ComImport,
Guid( "56A86893-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IEnumFilters
{
/// <summary>
/// Retrieves the specified number of filters in the enumeration sequence.
/// </summary>
///
/// <param name="cFilters">Number of filters to retrieve.</param>
/// <param name="filters">Array in which to place <see cref="IBaseFilter"/> interfaces.</param>
/// <param name="filtersFetched">Actual number of filters placed in the array.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Next( [In] int cFilters,
[Out, MarshalAs( UnmanagedType.LPArray, SizeParamIndex = 0 )] IBaseFilter[] filters,
[Out] out int filtersFetched );
/// <summary>
/// Skips a specified number of filters in the enumeration sequence.
/// </summary>
///
/// <param name="cFilters">Number of filters to skip.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Skip( [In] int cFilters );
/// <summary>
/// Resets the enumeration sequence to the beginning.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Reset( );
/// <summary>
/// Makes a copy of the enumerator with the same enumeration state.
/// </summary>
///
/// <param name="enumFilters">Duplicate of the enumerator.</param>
///
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
///
[PreserveSig]
int Clone( [Out] out IEnumFilters enumFilters );
}
}

View File

@ -0,0 +1,68 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Enumerates pins on a filter.
/// </summary>
///
[ComImport,
Guid( "56A86892-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IEnumPins
{
/// <summary>
/// Retrieves a specified number of pins.
/// </summary>
///
/// <param name="cPins">Number of pins to retrieve.</param>
/// <param name="pins">Array of size <b>cPins</b> that is filled with <b>IPin</b> pointers.</param>
/// <param name="pinsFetched">Receives the number of pins retrieved.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Next( [In] int cPins,
[Out, MarshalAs( UnmanagedType.LPArray, SizeParamIndex = 0 )] IPin[] pins,
[Out] out int pinsFetched );
/// <summary>
/// Skips a specified number of pins in the enumeration sequence.
/// </summary>
///
/// <param name="cPins">Number of pins to skip.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Skip( [In] int cPins );
/// <summary>
/// Resets the enumeration sequence to the beginning.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Reset( );
/// <summary>
/// Makes a copy of the enumerator with the same enumeration state.
/// </summary>
///
/// <param name="enumPins">Duplicate of the enumerator.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Clone( [Out] out IEnumPins enumPins );
}
}

View File

@ -0,0 +1,48 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface is exposed by source filters to set the file name and media type of the media file that they are to render.
/// </summary>
///
[ComImport,
Guid( "56A868A6-0Ad4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IFileSourceFilter
{
/// <summary>
/// Loads the source filter with the file.
/// </summary>
///
/// <param name="fileName">The name of the file to open.</param>
/// <param name="mediaType">Media type of the file. This can be null.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Load( [In, MarshalAs( UnmanagedType.LPWStr )] string fileName,
[In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Retrieves the current file.
/// </summary>
///
/// <param name="fileName">Name of media file.</param>
/// <param name="mediaType">Receives media type.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetCurFile([Out, MarshalAs( UnmanagedType.LPWStr )] out string fileName,
[Out, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
}
}

View File

@ -0,0 +1,113 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface provides methods for building a filter graph. An application can use it to add filters to
/// the graph, connect or disconnect filters, remove filters, and perform other basic operations.
/// </summary>
///
[ComImport,
Guid( "56A8689F-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IFilterGraph
{
/// <summary>
/// Adds a filter to the graph and gives it a name.
/// </summary>
///
/// <param name="filter">Filter to add to the graph.</param>
/// <param name="name">Name of the filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddFilter( [In] IBaseFilter filter, [In, MarshalAs( UnmanagedType.LPWStr )] string name );
/// <summary>
/// Removes a filter from the graph.
/// </summary>
///
/// <param name="filter">Filter to be removed from the graph.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RemoveFilter( [In] IBaseFilter filter );
/// <summary>
/// Provides an enumerator for all filters in the graph.
/// </summary>
///
/// <param name="enumerator">Filter enumerator.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EnumFilters( [Out] out IntPtr enumerator );
/// <summary>
/// Finds a filter that was added with a specified name.
/// </summary>
///
/// <param name="name">Name of filter to search for.</param>
/// <param name="filter">Interface of found filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FindFilterByName( [In, MarshalAs( UnmanagedType.LPWStr )] string name, [Out] out IBaseFilter filter );
/// <summary>
/// Connects two pins directly (without intervening filters).
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
/// <param name="pinIn">Input pin.</param>
/// <param name="mediaType">Media type to use for the connection.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ConnectDirect( [In] IPin pinOut, [In] IPin pinIn, [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Breaks the existing pin connection and reconnects it to the same pin.
/// </summary>
///
/// <param name="pin">Pin to disconnect and reconnect.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Reconnect( [In] IPin pin );
/// <summary>
/// Disconnects a specified pin.
/// </summary>
///
/// <param name="pin">Pin to disconnect.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Disconnect( [In] IPin pin );
/// <summary>
/// Sets the reference clock to the default clock.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetDefaultSyncSource( );
}
}

View File

@ -0,0 +1,257 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
/// <summary>
/// This interface extends the <see cref="IFilterGraph"/> and <see cref="IGraphBuilder"/>
/// interfaces, which contain methods for building filter graphs.
/// </summary>
///
[ComImport,
Guid("36B73882-C2C8-11CF-8B46-00805F6CEF60"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFilterGraph2
{
// --- IFilterGraph Methods
/// <summary>
/// Adds a filter to the graph and gives it a name.
/// </summary>
///
/// <param name="filter">Filter to add to the graph.</param>
/// <param name="name">Name of the filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddFilter( [In] IBaseFilter filter, [In, MarshalAs( UnmanagedType.LPWStr )] string name );
/// <summary>
/// Removes a filter from the graph.
/// </summary>
///
/// <param name="filter">Filter to be removed from the graph.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RemoveFilter( [In] IBaseFilter filter );
/// <summary>
/// Provides an enumerator for all filters in the graph.
/// </summary>
///
/// <param name="enumerator">Filter enumerator.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EnumFilters( [Out] out IEnumFilters enumerator );
/// <summary>
/// Finds a filter that was added with a specified name.
/// </summary>
///
/// <param name="name">Name of filter to search for.</param>
/// <param name="filter">Interface of found filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FindFilterByName( [In, MarshalAs( UnmanagedType.LPWStr )] string name, [Out] out IBaseFilter filter );
/// <summary>
/// Connects two pins directly (without intervening filters).
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
/// <param name="pinIn">Input pin.</param>
/// <param name="mediaType">Media type to use for the connection.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ConnectDirect( [In] IPin pinOut, [In] IPin pinIn, [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Breaks the existing pin connection and reconnects it to the same pin.
/// </summary>
///
/// <param name="pin">Pin to disconnect and reconnect.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Reconnect( [In] IPin pin );
/// <summary>
/// Disconnects a specified pin.
/// </summary>
///
/// <param name="pin">Pin to disconnect.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Disconnect( [In] IPin pin );
/// <summary>
/// Sets the reference clock to the default clock.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetDefaultSyncSource( );
// --- IGraphBuilder methods
/// <summary>
/// Connects two pins. If they will not connect directly, this method connects them with intervening transforms.
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
/// <param name="pinIn">Input pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Connect( [In] IPin pinOut, [In] IPin pinIn );
/// <summary>
/// Adds a chain of filters to a specified output pin to render it.
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Render( [In] IPin pinOut );
/// <summary>
/// Builds a filter graph that renders the specified file.
/// </summary>
///
/// <param name="file">Specifies a string that contains file name or device moniker.</param>
/// <param name="playList">Reserved.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RenderFile(
[In, MarshalAs( UnmanagedType.LPWStr )] string file,
[In, MarshalAs( UnmanagedType.LPWStr )] string playList );
/// <summary>
/// Adds a source filter to the filter graph for a specific file.
/// </summary>
///
/// <param name="fileName">Specifies the name of the file to load.</param>
/// <param name="filterName">Specifies a name for the source filter.</param>
/// <param name="filter">Variable that receives the interface of the source filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddSourceFilter(
[In, MarshalAs( UnmanagedType.LPWStr )] string fileName,
[In, MarshalAs( UnmanagedType.LPWStr )] string filterName,
[Out] out IBaseFilter filter );
/// <summary>
/// Sets the file for logging actions taken when attempting to perform an operation.
/// </summary>
///
/// <param name="hFile">Handle to the log file.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetLogFile( IntPtr hFile );
/// <summary>
/// Requests that the graph builder return as soon as possible from its current task.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Abort( );
/// <summary>
/// Queries whether the current operation should continue.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ShouldOperationContinue( );
// --- IFilterGraph2 methods
/// <summary>
///
/// </summary>
///
/// <param name="moniker">Moniker interface.</param>
/// <param name="bindContext">Bind context interface.</param>
/// <param name="filterName">Name for the filter.</param>
/// <param name="filter"> Receives source filter's IBaseFilter interface.
/// The caller must release the interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddSourceFilterForMoniker(
[In] IMoniker moniker,
[In] IBindCtx bindContext,
[In, MarshalAs( UnmanagedType.LPWStr )] string filterName,
[Out] out IBaseFilter filter
);
/// <summary>
/// Breaks the existing pin connection and reconnects it to the same pin,
/// using a specified media type.
/// </summary>
///
/// <param name="pin">Pin to disconnect and reconnect.</param>
/// <param name="mediaType">Media type to reconnect with.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ReconnectEx(
[In] IPin pin,
[In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType
);
/// <summary>
/// Render an output pin, with an option to use existing renderers only.
/// </summary>
///
/// <param name="outputPin">Interface of the output pin.</param>
/// <param name="flags">Flag that specifies how to render the pin.</param>
/// <param name="context">Reserved.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RenderEx(
[In] IPin outputPin,
[In] int flags,
[In] IntPtr context
);
}
}

View File

@ -0,0 +1,198 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// This interface provides methods that enable an application to build a filter graph.
/// </summary>
///
[ComImport,
Guid( "56A868A9-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IGraphBuilder
{
// --- IFilterGraph Methods
/// <summary>
/// Adds a filter to the graph and gives it a name.
/// </summary>
///
/// <param name="filter">Filter to add to the graph.</param>
/// <param name="name">Name of the filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddFilter( [In] IBaseFilter filter, [In, MarshalAs( UnmanagedType.LPWStr )] string name );
/// <summary>
/// Removes a filter from the graph.
/// </summary>
///
/// <param name="filter">Filter to be removed from the graph.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RemoveFilter( [In] IBaseFilter filter );
/// <summary>
/// Provides an enumerator for all filters in the graph.
/// </summary>
///
/// <param name="enumerator">Filter enumerator.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EnumFilters( [Out] out IEnumFilters enumerator );
/// <summary>
/// Finds a filter that was added with a specified name.
/// </summary>
///
/// <param name="name">Name of filter to search for.</param>
/// <param name="filter">Interface of found filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FindFilterByName( [In, MarshalAs( UnmanagedType.LPWStr )] string name, [Out] out IBaseFilter filter );
/// <summary>
/// Connects two pins directly (without intervening filters).
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
/// <param name="pinIn">Input pin.</param>
/// <param name="mediaType">Media type to use for the connection.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ConnectDirect( [In] IPin pinOut, [In] IPin pinIn, [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Breaks the existing pin connection and reconnects it to the same pin.
/// </summary>
///
/// <param name="pin">Pin to disconnect and reconnect.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Reconnect( [In] IPin pin );
/// <summary>
/// Disconnects a specified pin.
/// </summary>
///
/// <param name="pin">Pin to disconnect.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Disconnect( [In] IPin pin );
/// <summary>
/// Sets the reference clock to the default clock.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetDefaultSyncSource( );
// --- IGraphBuilder methods
/// <summary>
/// Connects two pins. If they will not connect directly, this method connects them with intervening transforms.
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
/// <param name="pinIn">Input pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Connect( [In] IPin pinOut, [In] IPin pinIn );
/// <summary>
/// Adds a chain of filters to a specified output pin to render it.
/// </summary>
///
/// <param name="pinOut">Output pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Render( [In] IPin pinOut );
/// <summary>
/// Builds a filter graph that renders the specified file.
/// </summary>
///
/// <param name="file">Specifies a string that contains file name or device moniker.</param>
/// <param name="playList">Reserved.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RenderFile(
[In, MarshalAs( UnmanagedType.LPWStr )] string file,
[In, MarshalAs( UnmanagedType.LPWStr )] string playList);
/// <summary>
/// Adds a source filter to the filter graph for a specific file.
/// </summary>
///
/// <param name="fileName">Specifies the name of the file to load.</param>
/// <param name="filterName">Specifies a name for the source filter.</param>
/// <param name="filter">Variable that receives the interface of the source filter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddSourceFilter(
[In, MarshalAs( UnmanagedType.LPWStr )] string fileName,
[In, MarshalAs( UnmanagedType.LPWStr )] string filterName,
[Out] out IBaseFilter filter );
/// <summary>
/// Sets the file for logging actions taken when attempting to perform an operation.
/// </summary>
///
/// <param name="hFile">Handle to the log file.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetLogFile( IntPtr hFile );
/// <summary>
/// Requests that the graph builder return as soon as possible from its current task.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Abort( );
/// <summary>
/// Queries whether the current operation should continue.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ShouldOperationContinue( );
}
}

View File

@ -0,0 +1,118 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface provides methods for controlling the flow of data through the filter graph.
/// It includes methods for running, pausing, and stopping the graph.
/// </summary>
///
[ComImport,
Guid( "56A868B1-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsDual )]
internal interface IMediaControl
{
/// <summary>
/// Runs all the filters in the filter graph.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Run( );
/// <summary>
/// Pauses all filters in the filter graph.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Pause( );
/// <summary>
/// Stops all the filters in the filter graph.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Stop( );
/// <summary>
/// Retrieves the state of the filter graph.
/// </summary>
///
/// <param name="timeout">Duration of the time-out, in milliseconds, or INFINITE to specify an infinite time-out.</param>
/// <param name="filterState">Ìariable that receives a member of the <b>FILTER_STATE</b> enumeration.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetState( int timeout, out int filterState );
/// <summary>
/// Builds a filter graph that renders the specified file.
/// </summary>
///
/// <param name="fileName">Name of the file to render</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RenderFile( string fileName );
/// <summary>
/// Adds a source filter to the filter graph, for a specified file.
/// </summary>
///
/// <param name="fileName">Name of the file containing the source video.</param>
/// <param name="filterInfo">Receives interface of filter information object.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AddSourceFilter( [In] string fileName, [Out, MarshalAs( UnmanagedType.IDispatch )] out object filterInfo );
/// <summary>
/// Retrieves a collection of the filters in the filter graph.
/// </summary>
///
/// <param name="collection">Receives the <b>IAMCollection</b> interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_FilterCollection(
[Out, MarshalAs( UnmanagedType.IDispatch )] out object collection );
/// <summary>
/// Retrieves a collection of all the filters listed in the registry.
/// </summary>
///
/// <param name="collection">Receives the <b>IDispatch</b> interface of <b>IAMCollection</b> object.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_RegFilterCollection(
[Out, MarshalAs( UnmanagedType.IDispatch )] out object collection );
/// <summary>
/// Pauses the filter graph, allowing filters to queue data, and then stops the filter graph.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int StopWhenReady( );
}
}

View File

@ -0,0 +1,126 @@
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2011
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface inherits contains methods for retrieving event notifications and for overriding the
/// filter graph's default handling of events.
/// </summary>
[ComVisible( true ), ComImport,
Guid( "56a868c0-0ad4-11ce-b03a-0020af0ba770" ),
InterfaceType( ComInterfaceType.InterfaceIsDual )]
internal interface IMediaEventEx
{
/// <summary>
/// Retrieves a handle to a manual-reset event that remains signaled while the queue contains event notifications.
/// </summary>
/// <param name="hEvent">Pointer to a variable that receives the event handle.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetEventHandle( out IntPtr hEvent );
/// <summary>
/// Retrieves the next event notification from the event queue.
/// </summary>
///
/// <param name="lEventCode">Variable that receives the event code.</param>
/// <param name="lParam1">Pointer to a variable that receives the first event parameter.</param>
/// <param name="lParam2">Pointer to a variable that receives the second event parameter.</param>
/// <param name="msTimeout">Time-out interval, in milliseconds.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetEvent( [Out, MarshalAs( UnmanagedType.I4 )] out DsEvCode lEventCode, [Out] out IntPtr lParam1, [Out] out IntPtr lParam2, int msTimeout );
/// <summary>
/// Waits for the filter graph to render all available data.
/// </summary>
///
/// <param name="msTimeout">Time-out interval, in milliseconds. Pass zero to return immediately.</param>
/// <param name="pEvCode">Pointer to a variable that receives an event code.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int WaitForCompletion( int msTimeout, [Out] out int pEvCode );
/// <summary>
/// Cancels the Filter Graph Manager's default handling for a specified event.
/// </summary>
///
/// <param name="lEvCode">Event code for which to cancel default handling.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int CancelDefaultHandling( int lEvCode );
/// <summary>
/// Restores the Filter Graph Manager's default handling for a specified event.
/// </summary>
/// <param name="lEvCode">Event code for which to restore default handling.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int RestoreDefaultHandling( int lEvCode );
/// <summary>
/// Frees resources associated with the parameters of an event.
/// </summary>
/// <param name="lEvCode">Event code.</param>
/// <param name="lParam1">First event parameter.</param>
/// <param name="lParam2">Second event parameter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int FreeEventParams( [In, MarshalAs( UnmanagedType.I4 )] DsEvCode lEvCode, IntPtr lParam1, IntPtr lParam2 );
/// <summary>
/// Registers a window to process event notifications.
/// </summary>
///
/// <param name="hwnd">Handle to the window, or <see cref="IntPtr.Zero"/> to stop receiving event messages.</param>
/// <param name="lMsg">Window message to be passed as the notification.</param>
/// <param name="lInstanceData">Value to be passed as the <i>lParam</i> parameter for the <i>lMsg</i> message.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetNotifyWindow( IntPtr hwnd, int lMsg, IntPtr lInstanceData );
/// <summary>
/// Enables or disables event notifications.
/// </summary>
///
/// <param name="lNoNotifyFlags">Value indicating whether to enable or disable event notifications.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetNotifyFlags( int lNoNotifyFlags );
/// <summary>
/// Determines whether event notifications are enabled.
/// </summary>
///
/// <param name="lplNoNotifyFlags">Variable that receives current notification status.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetNotifyFlags( out int lplNoNotifyFlags );
}
}

View File

@ -0,0 +1,102 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © Andrew Kirillov, 2010
// andrew.kirillov@gmail.com
//
// Written by Jeremy Noring
// kidjan@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface provides methods for controlling the flow of data through the filter graph.
/// It includes methods for running, pausing, and stopping the graph.
/// </summary>
///
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid( "56a86899-0ad4-11ce-b03a-0020af0ba770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IMediaFilter : IPersist
{
#region IPersist Methods
[PreserveSig]
new int GetClassID(
[Out] out Guid pClassID );
#endregion
/// <summary>
/// This method informs the filter to transition to the new state.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Stop( );
/// <summary>
/// This method informs the filter to transition to the new state.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Pause( );
/// <summary>
/// This method informs the filter to transition to the new (running) state. Passes a time value to synchronize independent streams.
/// </summary>
///
/// <param name="tStart">Time value of the reference clock. The amount to be added to the IMediaSample time stamp to determine the time at which that sample should be rendered according to the reference clock. That is, it is the reference time at which a sample with a stream time of zero should be rendered.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Run( [In] long tStart );
/// <summary>
/// This method determines the filter's state.
/// </summary>
///
/// <param name="dwMilliSecsTimeout">Duration of the time-out, in milliseconds. To block indefinitely, pass INFINITE. </param>
/// <param name="filtState">Returned state of the filter. States include stopped, paused, running, or intermediate (in the process of changing). </param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetState(
[In] int dwMilliSecsTimeout,
[Out] out FilterState filtState );
/// <summary>
/// This method identifies the reference clock to which the filter should synchronize activity.
/// </summary>
///
/// <param name="pClock">Pointer to the IReferenceClock interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetSyncSource( [In] IReferenceClock pClock );
/// <summary>
/// This method retrieves the current reference clock in use by this filter.
/// </summary>
///
/// <param name="pClock">Pointer to a reference clock; it will be set to the IReferenceClock interface. </param>
///
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetSyncSource( [Out] out IReferenceClock pClock );
}
}

View File

@ -0,0 +1,32 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2010
// andrew.kirillov@gmail.com
//
// Written by Jeremy Noring
// kidjan@gmail.com
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Provides the CLSID of an object that can be stored persistently in the system. Allows the object to specify which object
/// handler to use in the client process, as it is used in the default implementation of marshaling.
/// </summary>
[ComImport,
Guid("0000010c-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IPersist
{
/// <summary>
/// Retrieves the class identifier (CLSID) of the object.
/// </summary>
/// <param name="pClassID"></param>
/// <returns></returns>
[PreserveSig]
int GetClassID([Out] out Guid pClassID);
}
}

View File

@ -0,0 +1,191 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// This interface is exposed by all input and output pins of DirectShow filters.
/// </summary>
///
[ComImport,
Guid( "56A86891-0AD4-11CE-B03A-0020AF0BA770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IPin
{
/// <summary>
/// Connects the pin to another pin.
/// </summary>
///
/// <param name="receivePin">Other pin to connect to.</param>
/// <param name="mediaType">Type to use for the connections (optional).</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Connect( [In] IPin receivePin, [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Makes a connection to this pin and is called by a connecting pin.
/// </summary>
///
/// <param name="receivePin">Connecting pin.</param>
/// <param name="mediaType">Media type of the samples to be streamed.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ReceiveConnection( [In] IPin receivePin, [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Breaks the current pin connection.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Disconnect( );
/// <summary>
/// Returns a pointer to the connecting pin.
/// </summary>
///
/// <param name="pin">Receives <b>IPin</b> interface of connected pin (if any).</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ConnectedTo( [Out] out IPin pin );
/// <summary>
/// Returns the media type of this pin's connection.
/// </summary>
///
/// <param name="mediaType">Pointer to an <see cref="AMMediaType"/> structure. If the pin is connected,
/// the media type is returned. Otherwise, the structure is initialized to a default state in which
/// all elements are 0, with the exception of <b>lSampleSize</b>, which is set to 1, and
/// <b>FixedSizeSamples</b>, which is set to <b>true</b>.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int ConnectionMediaType( [Out, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Retrieves information about this pin (for example, the name, owning filter, and direction).
/// </summary>
///
/// <param name="pinInfo"><see cref="PinInfo"/> structure that receives the pin information.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryPinInfo( [Out] out PinInfo pinInfo );
/// <summary>
/// Retrieves the direction for this pin.
/// </summary>
///
/// <param name="pinDirection">Receives direction of the pin.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryDirection( out PinDirection pinDirection );
/// <summary>
/// Retrieves an identifier for the pin.
/// </summary>
///
/// <param name="id">Pin identifier.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryId( [Out, MarshalAs( UnmanagedType.LPWStr )] out string id );
/// <summary>
/// Queries whether a given media type is acceptable by the pin.
/// </summary>
///
/// <param name="mediaType"><see cref="AMMediaType"/> structure that specifies the media type.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryAccept( [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Provides an enumerator for this pin's preferred media types.
/// </summary>
///
/// <param name="enumerator">Address of a variable that receives a pointer to the <b>IEnumMediaTypes</b> interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EnumMediaTypes( IntPtr enumerator );
/// <summary>
/// Provides an array of the pins to which this pin internally connects.
/// </summary>
///
/// <param name="apPin">Address of an array of <b>IPin</b> pointers.</param>
/// <param name="nPin">On input, specifies the size of the array. When the method returns,
/// the value is set to the number of pointers returned in the array.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int QueryInternalConnections( IntPtr apPin, [In, Out] ref int nPin );
/// <summary>
/// Notifies the pin that no additional data is expected.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EndOfStream( );
/// <summary>
/// Begins a flush operation.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int BeginFlush( );
/// <summary>
/// Ends a flush operation.
/// </summary>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int EndFlush( );
/// <summary>
/// Specifies that samples following this call are grouped as a segment with a given start time, stop time, and rate.
/// </summary>
///
/// <param name="start">Start time of the segment, relative to the original source, in 100-nanosecond units.</param>
/// <param name="stop">End time of the segment, relative to the original source, in 100-nanosecond units.</param>
/// <param name="rate">Rate at which this segment should be processed, as a percentage of the original rate.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int NewSegment(
long start,
long stop,
double rate );
}
}

View File

@ -0,0 +1,53 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The <b>IPropertyBag</b> interface provides an object with a property bag in
/// which the object can persistently save its properties.
/// </summary>
///
[ComImport,
Guid( "55272A00-42CB-11CE-8135-00AA004BB851" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IPropertyBag
{
/// <summary>
/// Read a property from property bag.
/// </summary>
///
/// <param name="propertyName">Property name to read.</param>
/// <param name="pVar">Property value.</param>
/// <param name="pErrorLog">Caller's error log.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Read(
[In, MarshalAs( UnmanagedType.LPWStr )] string propertyName,
[In, Out, MarshalAs( UnmanagedType.Struct )] ref object pVar,
[In] IntPtr pErrorLog );
/// <summary>
/// Write property to property bag.
/// </summary>
///
/// <param name="propertyName">Property name to read.</param>
/// <param name="pVar">Property value.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Write(
[In, MarshalAs( UnmanagedType.LPWStr )] string propertyName,
[In, MarshalAs( UnmanagedType.Struct )] ref object pVar );
}
}

View File

@ -0,0 +1,87 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © Andrew Kirillov, 2010
// andrew.kirillov@gmail.com
//
// Written by Jeremy Noring
// kidjan@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The IReferenceClock interface provides the reference time for the filter graph.
///
/// Filters that can act as a reference clock can expose this interface. It is also exposed by the System Reference Clock.
/// The filter graph manager uses this interface to synchronize the filter graph. Applications can use this interface to
/// retrieve the current reference time, or to request notification of an elapsed time.
/// </summary>
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid( "56a86897-0ad4-11ce-b03a-0020af0ba770" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IReferenceClock
{
/// <summary>
/// The GetTime method retrieves the current reference time.
/// </summary>
///
/// <param name="pTime">Pointer to a variable that receives the current time, in 100-nanosecond units.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetTime( [Out] out long pTime );
/// <summary>
/// The AdviseTime method creates a one-shot advise request.
/// </summary>
///
/// <param name="baseTime">Base reference time, in 100-nanosecond units. See Remarks.</param>
/// <param name="streamTime">Stream offset time, in 100-nanosecond units. See Remarks.</param>
/// <param name="hEvent">Handle to an event, created by the caller.</param>
/// <param name="pdwAdviseCookie">Pointer to a variable that receives an identifier for the advise request.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AdviseTime(
[In] long baseTime,
[In] long streamTime,
[In] IntPtr hEvent,
[Out] out int pdwAdviseCookie );
/// <summary>
/// The AdvisePeriodic method creates a periodic advise request.
/// </summary>
///
/// <param name="startTime">Time of the first notification, in 100-nanosecond units. Must be greater than zero and less than MAX_TIME.</param>
/// <param name="periodTime">Time between notifications, in 100-nanosecond units. Must be greater than zero.</param>
/// <param name="hSemaphore">Handle to a semaphore, created by the caller.</param>
/// <param name="pdwAdviseCookie">Pointer to a variable that receives an identifier for the advise request.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int AdvisePeriodic(
[In] long startTime,
[In] long periodTime,
[In] IntPtr hSemaphore,
[Out] out int pdwAdviseCookie );
/// <summary>
/// The Unadvise method removes a pending advise request.
/// </summary>
///
/// <param name="dwAdviseCookie">Identifier of the request to remove. Use the value returned by IReferenceClock::AdviseTime or IReferenceClock::AdvisePeriodic in the pdwAdviseToken parameter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int Unadvise( [In] int dwAdviseCookie );
}
}

View File

@ -0,0 +1,103 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface is exposed by the Sample Grabber Filter. It enables an application to retrieve
/// individual media samples as they move through the filter graph.
/// </summary>
///
[ComImport,
Guid("6B652FFF-11FE-4FCE-92AD-0266B5D7C78F"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ISampleGrabber
{
/// <summary>
/// Specifies whether the filter should stop the graph after receiving one sample.
/// </summary>
///
/// <param name="oneShot">Boolean value specifying whether the filter should stop the graph after receiving one sample.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetOneShot( [In, MarshalAs( UnmanagedType.Bool )] bool oneShot );
/// <summary>
/// Specifies the media type for the connection on the Sample Grabber's input pin.
/// </summary>
///
/// <param name="mediaType">Specifies the required media type.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetMediaType( [In, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Retrieves the media type for the connection on the Sample Grabber's input pin.
/// </summary>
///
/// <param name="mediaType"><see cref="AMMediaType"/> structure, which receives media type.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetConnectedMediaType( [Out, MarshalAs( UnmanagedType.LPStruct )] AMMediaType mediaType );
/// <summary>
/// Specifies whether to copy sample data into a buffer as it goes through the filter.
/// </summary>
///
/// <param name="bufferThem">Boolean value specifying whether to buffer sample data.
/// If <b>true</b>, the filter copies sample data into an internal buffer.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetBufferSamples( [In, MarshalAs( UnmanagedType.Bool )] bool bufferThem );
/// <summary>
/// Retrieves a copy of the sample that the filter received most recently.
/// </summary>
///
/// <param name="bufferSize">Pointer to the size of the buffer. If pBuffer is NULL, this parameter receives the required size.</param>
/// <param name="buffer">Pointer to a buffer to receive a copy of the sample, or NULL.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetCurrentBuffer( ref int bufferSize, IntPtr buffer );
/// <summary>
/// Not currently implemented.
/// </summary>
///
/// <param name="sample"></param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetCurrentSample( IntPtr sample );
/// <summary>
/// Specifies a callback method to call on incoming samples.
/// </summary>
///
/// <param name="callback"><see cref="ISampleGrabberCB"/> interface containing the callback method, or NULL to cancel the callback.</param>
/// <param name="whichMethodToCallback">Index specifying the callback method.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetCallback( ISampleGrabberCB callback, int whichMethodToCallback );
}
}

View File

@ -0,0 +1,47 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface provides callback methods for the <see cref="ISampleGrabber.SetCallback"/> method.
/// </summary>
///
[ComImport,
Guid("0579154A-2B53-4994-B0D0-E773148EFF85"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ISampleGrabberCB
{
/// <summary>
/// Callback method that receives a pointer to the media sample.
/// </summary>
///
/// <param name="sampleTime">Starting time of the sample, in seconds.</param>
/// <param name="sample">Pointer to the sample's <b>IMediaSample</b> interface.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SampleCB( double sampleTime, IntPtr sample );
/// <summary>
/// Callback method that receives a pointer to the sample bufferþ
/// </summary>
///
/// <param name="sampleTime">Starting time of the sample, in seconds.</param>
/// <param name="buffer">Pointer to a buffer that contains the sample data.</param>
/// <param name="bufferLen">Length of the buffer pointed to by <b>buffer</b>, in bytes</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int BufferCB( double sampleTime, IntPtr buffer, int bufferLen );
}
}

View File

@ -0,0 +1,36 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface indicates that an object supports property pages.
/// </summary>
///
[ComImport,
Guid( "B196B28B-BAB4-101A-B69C-00AA00341D07" ),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface ISpecifyPropertyPages
{
/// <summary>
/// Fills a counted array of GUID values where each GUID specifies the
/// CLSID of each property page that can be displayed in the property
/// sheet for this object.
/// </summary>
///
/// <param name="pPages">Pointer to a CAUUID structure that must be initialized
/// and filled before returning.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetPages( out CAUUID pPages );
}
}

View File

@ -0,0 +1,466 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// The interface sets properties on the video window.
/// </summary>
///
[ComImport,
Guid("56A868B4-0AD4-11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IVideoWindow
{
/// <summary>
/// Sets the video window caption.
/// </summary>
///
/// <param name="caption">Caption.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Caption( string caption );
/// <summary>
/// Retrieves the video window caption.
/// </summary>
///
/// <param name="caption">Caption.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Caption( [Out] out string caption );
/// <summary>
/// Sets the window style on the video window.
/// </summary>
///
/// <param name="windowStyle">Window style flags.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_WindowStyle( int windowStyle );
/// <summary>
/// Retrieves the window style on the video window.
/// </summary>
///
/// <param name="windowStyle">Window style flags.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_WindowStyle( out int windowStyle );
/// <summary>
/// Sets the extended window style on the video window.
/// </summary>
///
/// <param name="windowStyleEx">Window extended style flags.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_WindowStyleEx( int windowStyleEx );
/// <summary>
/// Retrieves the extended window style on the video window.
/// </summary>
///
/// <param name="windowStyleEx">Window extended style flags.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_WindowStyleEx( out int windowStyleEx );
/// <summary>
/// Specifies whether the video renderer automatically shows the video window when it receives video data.
/// </summary>
///
/// <param name="autoShow">Specifies whether the video renderer automatically shows the video window.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_AutoShow( [In, MarshalAs( UnmanagedType.Bool )] bool autoShow );
/// <summary>
/// Queries whether the video renderer automatically shows the video window when it receives video data.
/// </summary>
///
/// <param name="autoShow">REceives window auto show flag.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_AutoShow( [Out, MarshalAs( UnmanagedType.Bool )] out bool autoShow );
/// <summary>
/// Shows, hides, minimizes, or maximizes the video window.
/// </summary>
///
/// <param name="windowState">Window state.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_WindowState( int windowState );
/// <summary>
/// Queries whether the video window is visible, hidden, minimized, or maximized.
/// </summary>
///
/// <param name="windowState">Window state.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_WindowState( out int windowState );
/// <summary>
/// Specifies whether the video window realizes its palette in the background.
/// </summary>
///
/// <param name="backgroundPalette">Value that specifies whether the video renderer realizes it palette in the background.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_BackgroundPalette( [In, MarshalAs( UnmanagedType.Bool )] bool backgroundPalette );
/// <summary>
/// Queries whether the video window realizes its palette in the background.
/// </summary>
///
/// <param name="backgroundPalette">Receives state of background palette flag.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_BackgroundPalette( [Out, MarshalAs( UnmanagedType.Bool )] out bool backgroundPalette );
/// <summary>
/// Shows or hides the video window.
/// </summary>
///
/// <param name="visible">Value that specifies whether to show or hide the window.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Visible( [In, MarshalAs( UnmanagedType.Bool )] bool visible );
/// <summary>
/// Queries whether the video window is visible.
/// </summary>
///
/// <param name="visible">Visibility flag.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Visible( [Out, MarshalAs( UnmanagedType.Bool )] out bool visible );
/// <summary>
/// Sets the video window's x-coordinate.
/// </summary>
///
/// <param name="left">Specifies the x-coordinate, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Left( int left );
/// <summary>
/// Retrieves the video window's x-coordinate.
/// </summary>
///
/// <param name="left">x-coordinate, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Left( out int left );
/// <summary>
/// Sets the width of the video window.
/// </summary>
///
/// <param name="width">Specifies the width, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Width( int width );
/// <summary>
/// Retrieves the width of the video window.
/// </summary>
///
/// <param name="width">Width, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Width( out int width );
/// <summary>
/// Sets the video window's y-coordinate.
/// </summary>
///
/// <param name="top">Specifies the y-coordinate, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Top( int top );
/// <summary>
/// Retrieves the video window's y-coordinate.
/// </summary>
///
/// <param name="top">y-coordinate, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Top( out int top );
/// <summary>
/// Sets the height of the video window.
/// </summary>
///
/// <param name="height">Specifies the height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Height( int height );
/// <summary>
/// Retrieves the height of the video window.
/// </summary>
///
/// <param name="height">Height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Height( out int height );
/// <summary>
/// Specifies a parent window for the video windowþ
/// </summary>
///
/// <param name="owner">Specifies a handle to the parent window.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_Owner( IntPtr owner );
/// <summary>
/// Retrieves the video window's parent window, if anyþ
/// </summary>
///
/// <param name="owner">Parent window's handle.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_Owner( out IntPtr owner );
/// <summary>
/// Specifies a window to receive mouse and keyboard messages from the video window.
/// </summary>
///
/// <param name="drain">Specifies a handle to the window.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_MessageDrain( IntPtr drain );
/// <summary>
/// Retrieves the window that receives mouse and keyboard messages from the video window, if any.
/// </summary>
///
/// <param name="drain">Window's handle.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_MessageDrain( out IntPtr drain );
/// <summary>
/// Retrieves the color that appears around the edges of the destination rectangle.
/// </summary>
///
/// <param name="color">Border's color.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_BorderColor( out int color );
/// <summary>
/// Sets the color that appears around the edges of the destination rectangle.
/// </summary>
///
/// <param name="color">Specifies the border color.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_BorderColor( int color );
/// <summary>
/// Queries whether the video renderer is in full-screen mode.
/// </summary>
///
/// <param name="fullScreenMode">Full-screen mode.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int get_FullScreenMode(
[Out, MarshalAs( UnmanagedType.Bool )] out bool fullScreenMode );
/// <summary>
/// Enables or disables full-screen mode.
/// </summary>
///
/// <param name="fullScreenMode">Boolean value that specifies whether to enable or disable full-screen mode.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int put_FullScreenMode( [In, MarshalAs( UnmanagedType.Bool )] bool fullScreenMode );
/// <summary>
/// Places the video window at the top of the Z order.
/// </summary>
///
/// <param name="focus">Value that specifies whether to give the window focus.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetWindowForeground( int focus );
/// <summary>
/// Forwards a message to the video window.
/// </summary>
///
/// <param name="hwnd">Handle to the window.</param>
/// <param name="msg">Specifies the message.</param>
/// <param name="wParam">Message parameter.</param>
/// <param name="lParam">Message parameter.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int NotifyOwnerMessage( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam );
/// <summary>
/// Sets the position of the video windowþ
/// </summary>
///
/// <param name="left">Specifies the x-coordinate, in pixels.</param>
/// <param name="top">Specifies the y-coordinate, in pixels.</param>
/// <param name="width">Specifies the width, in pixels.</param>
/// <param name="height">Specifies the height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int SetWindowPosition( int left, int top, int width, int height );
/// <summary>
/// Retrieves the position of the video window.
/// </summary>
///
/// <param name="left">x-coordinate, in pixels.</param>
/// <param name="top">y-coordinate, in pixels.</param>
/// <param name="width">Width, in pixels.</param>
/// <param name="height">Height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetWindowPosition( out int left, out int top, out int width, out int height );
/// <summary>
/// Retrieves the minimum ideal size for the video image.
/// </summary>
///
/// <param name="width">Receives the minimum ideal width, in pixels.</param>
/// <param name="height">Receives the minimum ideal height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetMinIdealImageSize( out int width, out int height );
/// <summary>
/// Retrieves the maximum ideal size for the video image.
/// </summary>
///
/// <param name="width">Receives the maximum ideal width, in pixels.</param>
/// <param name="height">Receives the maximum ideal height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetMaxIdealImageSize( out int width, out int height );
/// <summary>
/// Retrieves the restored window position.
/// </summary>
///
/// <param name="left">x-coordinate, in pixels.</param>
/// <param name="top">y-coordinate, in pixels.</param>
/// <param name="width">Width, in pixels.</param>
/// <param name="height">Height, in pixels.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int GetRestorePosition( out int left, out int top, out int width, out int height );
/// <summary>
/// Hides the cursor.
/// </summary>
///
/// <param name="hideCursor">Specifies whether to hide or display the cursor.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int HideCursor( [In, MarshalAs( UnmanagedType.Bool )] bool hideCursor );
/// <summary>
/// Queries whether the cursor is hidden.
/// </summary>
///
/// <param name="hideCursor">Specifies if cursor is hidden or not.</param>
///
/// <returns>Return's <b>HRESULT</b> error code.</returns>
///
[PreserveSig]
int IsCursorHidden( [Out, MarshalAs( UnmanagedType.Bool )] out bool hideCursor );
}
}

View File

@ -0,0 +1,518 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2013
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
using System.Drawing;
// PIN_DIRECTION
/// <summary>
/// This enumeration indicates a pin's direction.
/// </summary>
///
[ComVisible( false )]
internal enum PinDirection
{
/// <summary>
/// Input pin.
/// </summary>
Input,
/// <summary>
/// Output pin.
/// </summary>
Output
}
// AM_MEDIA_TYPE
/// <summary>
/// The structure describes the format of a media sample.
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential )]
internal class AMMediaType : IDisposable
{
/// <summary>
/// Globally unique identifier (GUID) that specifies the major type of the media sample.
/// </summary>
public Guid MajorType;
/// <summary>
/// GUID that specifies the subtype of the media sample.
/// </summary>
public Guid SubType;
/// <summary>
/// If <b>true</b>, samples are of a fixed size.
/// </summary>
[MarshalAs( UnmanagedType.Bool )]
public bool FixedSizeSamples = true;
/// <summary>
/// If <b>true</b>, samples are compressed using temporal (interframe) compression.
/// </summary>
[MarshalAs( UnmanagedType.Bool )]
public bool TemporalCompression;
/// <summary>
/// Size of the sample in bytes. For compressed data, the value can be zero.
/// </summary>
public int SampleSize = 1;
/// <summary>
/// GUID that specifies the structure used for the format block.
/// </summary>
public Guid FormatType;
/// <summary>
/// Not used.
/// </summary>
public IntPtr unkPtr;
/// <summary>
/// Size of the format block, in bytes.
/// </summary>
public int FormatSize;
/// <summary>
/// Pointer to the format block.
/// </summary>
public IntPtr FormatPtr;
/// <summary>
/// Destroys the instance of the <see cref="AMMediaType"/> class.
/// </summary>
///
~AMMediaType( )
{
Dispose( false );
}
/// <summary>
/// Dispose the object.
/// </summary>
///
public void Dispose( )
{
Dispose( true );
// remove me from the Finalization queue
GC.SuppressFinalize( this );
}
/// <summary>
/// Dispose the object
/// </summary>
///
/// <param name="disposing">Indicates if disposing was initiated manually.</param>
///
protected virtual void Dispose( bool disposing )
{
if ( ( FormatSize != 0 ) && ( FormatPtr != IntPtr.Zero ) )
{
Marshal.FreeCoTaskMem( FormatPtr );
FormatSize = 0;
}
if ( unkPtr != IntPtr.Zero )
{
Marshal.Release( unkPtr );
unkPtr = IntPtr.Zero;
}
}
}
// PIN_INFO
/// <summary>
/// The structure contains information about a pin.
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode )]
internal struct PinInfo
{
/// <summary>
/// Owning filter.
/// </summary>
public IBaseFilter Filter;
/// <summary>
/// Direction of the pin.
/// </summary>
public PinDirection Direction;
/// <summary>
/// Name of the pin.
/// </summary>
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 128 )]
public string Name;
}
// FILTER_INFO
[ComVisible( false ),
StructLayout( LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode )]
internal struct FilterInfo
{
/// <summary>
/// Filter's name.
/// </summary>
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 128 )]
public string Name;
/// <summary>
/// Owning graph.
/// </summary>
public IFilterGraph FilterGraph;
}
// VIDEOINFOHEADER
/// <summary>
/// The structure describes the bitmap and color information for a video image.
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential )]
internal struct VideoInfoHeader
{
/// <summary>
/// <see cref="RECT"/> structure that specifies the source video window.
/// </summary>
public RECT SrcRect;
/// <summary>
/// <see cref="RECT"/> structure that specifies the destination video window.
/// </summary>
public RECT TargetRect;
/// <summary>
/// Approximate data rate of the video stream, in bits per second.
/// </summary>
public int BitRate;
/// <summary>
/// Data error rate, in bit errors per second.
/// </summary>
public int BitErrorRate;
/// <summary>
/// The desired average display time of the video frames, in 100-nanosecond units.
/// </summary>
public long AverageTimePerFrame;
/// <summary>
/// <see cref="BitmapInfoHeader"/> structure that contains color and dimension information for the video image bitmap.
/// </summary>
public BitmapInfoHeader BmiHeader;
}
// VIDEOINFOHEADER2
/// <summary>
/// The structure describes the bitmap and color information for a video image (v2).
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential )]
internal struct VideoInfoHeader2
{
/// <summary>
/// <see cref="RECT"/> structure that specifies the source video window.
/// </summary>
public RECT SrcRect;
/// <summary>
/// <see cref="RECT"/> structure that specifies the destination video window.
/// </summary>
public RECT TargetRect;
/// <summary>
/// Approximate data rate of the video stream, in bits per second.
/// </summary>
public int BitRate;
/// <summary>
/// Data error rate, in bit errors per second.
/// </summary>
public int BitErrorRate;
/// <summary>
/// The desired average display time of the video frames, in 100-nanosecond units.
/// </summary>
public long AverageTimePerFrame;
/// <summary>
/// Flags that specify how the video is interlaced.
/// </summary>
public int InterlaceFlags;
/// <summary>
/// Flag set to indicate that the duplication of the stream should be restricted.
/// </summary>
public int CopyProtectFlags;
/// <summary>
/// The X dimension of picture aspect ratio.
/// </summary>
public int PictAspectRatioX;
/// <summary>
/// The Y dimension of picture aspect ratio.
/// </summary>
public int PictAspectRatioY;
/// <summary>
/// Reserved for future use.
/// </summary>
public int Reserved1;
/// <summary>
/// Reserved for future use.
/// </summary>
public int Reserved2;
/// <summary>
/// <see cref="BitmapInfoHeader"/> structure that contains color and dimension information for the video image bitmap.
/// </summary>
public BitmapInfoHeader BmiHeader;
}
/// <summary>
/// The structure contains information about the dimensions and color format of a device-independent bitmap (DIB).
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential, Pack = 2 )]
internal struct BitmapInfoHeader
{
/// <summary>
/// Specifies the number of bytes required by the structure.
/// </summary>
public int Size;
/// <summary>
/// Specifies the width of the bitmap.
/// </summary>
public int Width;
/// <summary>
/// Specifies the height of the bitmap, in pixels.
/// </summary>
public int Height;
/// <summary>
/// Specifies the number of planes for the target device. This value must be set to 1.
/// </summary>
public short Planes;
/// <summary>
/// Specifies the number of bits per pixel.
/// </summary>
public short BitCount;
/// <summary>
/// If the bitmap is compressed, this member is a <b>FOURCC</b> the specifies the compression.
/// </summary>
public int Compression;
/// <summary>
/// Specifies the size, in bytes, of the image.
/// </summary>
public int ImageSize;
/// <summary>
/// Specifies the horizontal resolution, in pixels per meter, of the target device for the bitmap.
/// </summary>
public int XPelsPerMeter;
/// <summary>
/// Specifies the vertical resolution, in pixels per meter, of the target device for the bitmap.
/// </summary>
public int YPelsPerMeter;
/// <summary>
/// Specifies the number of color indices in the color table that are actually used by the bitmap.
/// </summary>
public int ColorsUsed;
/// <summary>
/// Specifies the number of color indices that are considered important for displaying the bitmap.
/// </summary>
public int ColorsImportant;
}
// RECT
/// <summary>
/// The structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential )]
internal struct RECT
{
/// <summary>
/// Specifies the x-coordinate of the upper-left corner of the rectangle.
/// </summary>
public int Left;
/// <summary>
/// Specifies the y-coordinate of the upper-left corner of the rectangle.
/// </summary>
public int Top;
/// <summary>
/// Specifies the x-coordinate of the lower-right corner of the rectangle.
/// </summary>
public int Right;
/// <summary>
/// Specifies the y-coordinate of the lower-right corner of the rectangle.
/// </summary>
public int Bottom;
}
// CAUUID
/// <summary>
/// The CAUUID structure is a Counted Array of UUID or GUID types.
/// </summary>
///
[ComVisible( false ),
StructLayout( LayoutKind.Sequential )]
internal struct CAUUID
{
/// <summary>
/// Size of the array pointed to by <b>pElems</b>.
/// </summary>
public int cElems;
/// <summary>
/// Pointer to an array of UUID values, each of which specifies UUID.
/// </summary>
public IntPtr pElems;
/// <summary>
/// Performs manual marshaling of <b>pElems</b> to retrieve an array of Guid objects.
/// </summary>
///
/// <returns>A managed representation of <b>pElems</b>.</returns>
///
public Guid[] ToGuidArray( )
{
Guid[] retval = new Guid[cElems];
for ( int i = 0; i < cElems; i++ )
{
IntPtr ptr = new IntPtr( pElems.ToInt64( ) + i * Marshal.SizeOf( typeof( Guid ) ) );
retval[i] = (Guid) Marshal.PtrToStructure( ptr, typeof( Guid ) );
}
return retval;
}
}
/// <summary>
/// Enumeration of DirectShow event codes.
/// </summary>
internal enum DsEvCode
{
None,
Complete = 0x01, // EC_COMPLETE
DeviceLost = 0x1F, // EC_DEVICE_LOST
//(...) not yet interested in other events
}
[Flags, ComVisible( false )]
internal enum AnalogVideoStandard
{
None = 0x00000000, // This is a digital sensor
NTSC_M = 0x00000001, // 75 IRE Setup
NTSC_M_J = 0x00000002, // Japan, 0 IRE Setup
NTSC_433 = 0x00000004,
PAL_B = 0x00000010,
PAL_D = 0x00000020,
PAL_G = 0x00000040,
PAL_H = 0x00000080,
PAL_I = 0x00000100,
PAL_M = 0x00000200,
PAL_N = 0x00000400,
PAL_60 = 0x00000800,
SECAM_B = 0x00001000,
SECAM_D = 0x00002000,
SECAM_G = 0x00004000,
SECAM_H = 0x00008000,
SECAM_K = 0x00010000,
SECAM_K1 = 0x00020000,
SECAM_L = 0x00040000,
SECAM_L1 = 0x00080000,
PAL_N_COMBO = 0x00100000 // Argentina
}
[Flags, ComVisible( false )]
internal enum VideoControlFlags
{
FlipHorizontal = 0x0001,
FlipVertical = 0x0002,
ExternalTriggerEnable = 0x0004,
Trigger = 0x0008
}
[StructLayout( LayoutKind.Sequential ), ComVisible( false )]
internal class VideoStreamConfigCaps // VIDEO_STREAM_CONFIG_CAPS
{
public Guid Guid;
public AnalogVideoStandard VideoStandard;
public Size InputSize;
public Size MinCroppingSize;
public Size MaxCroppingSize;
public int CropGranularityX;
public int CropGranularityY;
public int CropAlignX;
public int CropAlignY;
public Size MinOutputSize;
public Size MaxOutputSize;
public int OutputGranularityX;
public int OutputGranularityY;
public int StretchTapsX;
public int StretchTapsY;
public int ShrinkTapsX;
public int ShrinkTapsY;
public long MinFrameInterval;
public long MaxFrameInterval;
public int MinBitsPerSecond;
public int MaxBitsPerSecond;
}
/// <summary>
/// Specifies a filter's state or the state of the filter graph.
/// </summary>
internal enum FilterState
{
/// <summary>
/// Stopped. The filter is not processing data.
/// </summary>
State_Stopped,
/// <summary>
/// Paused. The filter is processing data, but not rendering it.
/// </summary>
State_Paused,
/// <summary>
/// Running. The filter is processing and rendering data.
/// </summary>
State_Running
}
}

View File

@ -0,0 +1,95 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Some miscellaneous functions.
/// </summary>
///
internal static class Tools
{
/// <summary>
/// Get filter's pin.
/// </summary>
///
/// <param name="filter">Filter to get pin of.</param>
/// <param name="dir">Pin's direction.</param>
/// <param name="num">Pin's number.</param>
///
/// <returns>Returns filter's pin.</returns>
///
public static IPin GetPin( IBaseFilter filter, PinDirection dir, int num )
{
IPin[] pin = new IPin[1];
IEnumPins pinsEnum = null;
// enum filter pins
if ( filter.EnumPins( out pinsEnum ) == 0 )
{
PinDirection pinDir;
int n;
try
{
// get next pin
while ( pinsEnum.Next( 1, pin, out n ) == 0 )
{
// query pin`s direction
pin[0].QueryDirection( out pinDir );
if ( pinDir == dir )
{
if ( num == 0 )
return pin[0];
num--;
}
Marshal.ReleaseComObject( pin[0] );
pin[0] = null;
}
}
finally
{
Marshal.ReleaseComObject( pinsEnum );
}
}
return null;
}
/// <summary>
/// Get filter's input pin.
/// </summary>
///
/// <param name="filter">Filter to get pin of.</param>
/// <param name="num">Pin's number.</param>
///
/// <returns>Returns filter's pin.</returns>
///
public static IPin GetInPin( IBaseFilter filter, int num )
{
return GetPin( filter, PinDirection.Input, num );
}
/// <summary>
/// Get filter's output pin.
/// </summary>
///
/// <param name="filter">Filter to get pin of.</param>
/// <param name="num">Pin's number.</param>
///
/// <returns>Returns filter's pin.</returns>
///
public static IPin GetOutPin( IBaseFilter filter, int num )
{
return GetPin( filter, PinDirection.Output, num );
}
}
}

View File

@ -0,0 +1,299 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2013
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// DirectShow class IDs.
/// </summary>
[ComVisible( false )]
static internal class Clsid
{
/// <summary>
/// System device enumerator.
/// </summary>
///
/// <remarks>Equals to CLSID_SystemDeviceEnum.</remarks>
///
public static readonly Guid SystemDeviceEnum =
new Guid( 0x62BE5D10, 0x60EB, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
/// <summary>
/// Filter graph.
/// </summary>
///
/// <remarks>Equals to CLSID_FilterGraph.</remarks>
///
public static readonly Guid FilterGraph =
new Guid( 0xE436EBB3, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// Sample grabber.
/// </summary>
///
/// <remarks>Equals to CLSID_SampleGrabber.</remarks>
///
public static readonly Guid SampleGrabber =
new Guid( 0xC1F400A0, 0x3F08, 0x11D3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 );
/// <summary>
/// Capture graph builder.
/// </summary>
///
/// <remarks>Equals to CLSID_CaptureGraphBuilder2.</remarks>
///
public static readonly Guid CaptureGraphBuilder2 =
new Guid( 0xBF87B6E1, 0x8C27, 0x11D0, 0xB3, 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5 );
/// <summary>
/// Async reader.
/// </summary>
///
/// <remarks>Equals to CLSID_AsyncReader.</remarks>
///
public static readonly Guid AsyncReader =
new Guid( 0xE436EBB5, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
}
/// <summary>
/// DirectShow format types.
/// </summary>
///
[ComVisible( false )]
static internal class FormatType
{
/// <summary>
/// VideoInfo.
/// </summary>
///
/// <remarks>Equals to FORMAT_VideoInfo.</remarks>
///
public static readonly Guid VideoInfo =
new Guid( 0x05589F80, 0xC356, 0x11CE, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, 0x5A );
/// <summary>
/// VideoInfo2.
/// </summary>
///
/// <remarks>Equals to FORMAT_VideoInfo2.</remarks>
///
public static readonly Guid VideoInfo2 =
new Guid( 0xf72A76A0, 0xEB0A, 0x11D0, 0xAC, 0xE4, 0x00, 0x00, 0xC0, 0xCC, 0x16, 0xBA );
}
/// <summary>
/// DirectShow media types.
/// </summary>
///
[ComVisible( false )]
static internal class MediaType
{
/// <summary>
/// Video.
/// </summary>
///
/// <remarks>Equals to MEDIATYPE_Video.</remarks>
///
public static readonly Guid Video =
new Guid( 0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// Interleaved. Used by Digital Video (DV).
/// </summary>
///
/// <remarks>Equals to MEDIATYPE_Interleaved.</remarks>
///
public static readonly Guid Interleaved =
new Guid( 0x73766169, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// Audio.
/// </summary>
///
/// <remarks>Equals to MEDIATYPE_Audio.</remarks>
///
public static readonly Guid Audio =
new Guid( 0x73647561, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// Text.
/// </summary>
///
/// <remarks>Equals to MEDIATYPE_Text.</remarks>
///
public static readonly Guid Text =
new Guid( 0x73747874, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// Byte stream with no time stamps.
/// </summary>
///
/// <remarks>Equals to MEDIATYPE_Stream.</remarks>
///
public static readonly Guid Stream =
new Guid( 0xE436EB83, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
}
/// <summary>
/// DirectShow media subtypes.
/// </summary>
///
[ComVisible( false )]
static internal class MediaSubType
{
/// <summary>
/// YUY2 (packed 4:2:2).
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_YUYV.</remarks>
///
public static readonly Guid YUYV =
new Guid( 0x56595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// IYUV.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_IYUV.</remarks>
///
public static readonly Guid IYUV =
new Guid( 0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// A DV encoding format. (FOURCC 'DVSD')
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_DVSD.</remarks>
///
public static readonly Guid DVSD =
new Guid( 0x44535644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 );
/// <summary>
/// RGB, 1 bit per pixel (bpp), palettized.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB1.</remarks>
///
public static readonly Guid RGB1 =
new Guid( 0xE436EB78, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// RGB, 4 bpp, palettized.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB4.</remarks>
///
public static readonly Guid RGB4 =
new Guid( 0xE436EB79, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// RGB, 8 bpp.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB8.</remarks>
///
public static readonly Guid RGB8 =
new Guid( 0xE436EB7A, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// RGB 565, 16 bpp.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB565.</remarks>
///
public static readonly Guid RGB565 =
new Guid( 0xE436EB7B, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// RGB 555, 16 bpp.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB555.</remarks>
///
public static readonly Guid RGB555 =
new Guid( 0xE436EB7C, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// RGB, 24 bpp.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB24.</remarks>
///
public static readonly Guid RGB24 =
new Guid( 0xE436Eb7D, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// RGB, 32 bpp, no alpha channel.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_RGB32.</remarks>
///
public static readonly Guid RGB32 =
new Guid( 0xE436EB7E, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// Data from AVI file.
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_Avi.</remarks>
///
public static readonly Guid Avi =
new Guid( 0xE436EB88, 0x524F, 0x11CE, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 );
/// <summary>
/// Advanced Streaming Format (ASF).
/// </summary>
///
/// <remarks>Equals to MEDIASUBTYPE_Asf.</remarks>
///
public static readonly Guid Asf =
new Guid( 0x3DB80F90, 0x9412, 0x11D1, 0xAD, 0xED, 0x00, 0x00, 0xF8, 0x75, 0x4B, 0x99 );
}
/// <summary>
/// DirectShow pin categories.
/// </summary>
///
[ComVisible( false )]
static internal class PinCategory
{
/// <summary>
/// Capture pin.
/// </summary>
///
/// <remarks>Equals to PIN_CATEGORY_CAPTURE.</remarks>
///
public static readonly Guid Capture =
new Guid( 0xFB6C4281, 0x0353, 0x11D1, 0x90, 0x5F, 0x00, 0x00, 0xC0, 0xCC, 0x16, 0xBA );
/// <summary>
/// Still image pin.
/// </summary>
///
/// <remarks>Equals to PIN_CATEGORY_STILL.</remarks>
///
public static readonly Guid StillImage =
new Guid( 0xFB6C428A, 0x0353, 0x11D1, 0x90, 0x5F, 0x00, 0x00, 0xC0, 0xCC, 0x16, 0xBA );
}
// Below GUIDs are used by ICaptureGraphBuilder::FindInterface().
[ComVisible( false )]
static internal class FindDirection
{
/// <summary>Equals to LOOK_UPSTREAM_ONLY.</summary>
public static readonly Guid UpstreamOnly =
new Guid( 0xAC798BE0, 0x98E3, 0x11D1, 0xB3, 0xF1, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5 );
/// <summary>Equals to LOOK_DOWNSTREAM_ONLY.</summary>
public static readonly Guid DownstreamOnly =
new Guid( 0xAC798BE1, 0x98E3, 0x11D1, 0xB3, 0xF1, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5 );
}
}

View File

@ -0,0 +1,102 @@
// AForge Video for Windows Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2007-2011
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow.Internals
{
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
/// <summary>
/// Some Win32 API used internally.
/// </summary>
///
internal static class Win32
{
/// <summary>
/// Supplies a pointer to an implementation of <b>IBindCtx</b> (a bind context object).
/// This object stores information about a particular moniker-binding operation.
/// </summary>
///
/// <param name="reserved">Reserved for future use; must be zero.</param>
/// <param name="ppbc">Address of <b>IBindCtx*</b> pointer variable that receives the
/// interface pointer to the new bind context object.</param>
///
/// <returns>Returns <b>S_OK</b> on success.</returns>
///
[DllImport( "ole32.dll" )]
public static extern
int CreateBindCtx( int reserved, out IBindCtx ppbc );
/// <summary>
/// Converts a string into a moniker that identifies the object named by the string.
/// </summary>
///
/// <param name="pbc">Pointer to the IBindCtx interface on the bind context object to be used in this binding operation.</param>
/// <param name="szUserName">Pointer to a zero-terminated wide character string containing the display name to be parsed. </param>
/// <param name="pchEaten">Pointer to the number of characters of szUserName that were consumed.</param>
/// <param name="ppmk">Address of <b>IMoniker*</b> pointer variable that receives the interface pointer
/// to the moniker that was built from <b>szUserName</b>.</param>
///
/// <returns>Returns <b>S_OK</b> on success.</returns>
///
[DllImport( "ole32.dll", CharSet = CharSet.Unicode )]
public static extern
int MkParseDisplayName( IBindCtx pbc, string szUserName,
ref int pchEaten, out IMoniker ppmk );
/// <summary>
/// Copy a block of memory.
/// </summary>
///
/// <param name="dst">Destination pointer.</param>
/// <param name="src">Source pointer.</param>
/// <param name="count">Memory block's length to copy.</param>
///
/// <returns>Return's the value of <b>dst</b> - pointer to destination.</returns>
///
[DllImport( "ntdll.dll", CallingConvention = CallingConvention.Cdecl )]
public static unsafe extern int memcpy(
byte* dst,
byte* src,
int count );
/// <summary>
/// Invokes a new property frame, that is, a property sheet dialog box.
/// </summary>
///
/// <param name="hwndOwner">Parent window of property sheet dialog box.</param>
/// <param name="x">Horizontal position for dialog box.</param>
/// <param name="y">Vertical position for dialog box.</param>
/// <param name="caption">Dialog box caption.</param>
/// <param name="cObjects">Number of object pointers in <b>ppUnk</b>.</param>
/// <param name="ppUnk">Pointer to the objects for property sheet.</param>
/// <param name="cPages">Number of property pages in <b>lpPageClsID</b>.</param>
/// <param name="lpPageClsID">Array of CLSIDs for each property page.</param>
/// <param name="lcid">Locale identifier for property sheet locale.</param>
/// <param name="dwReserved">Reserved.</param>
/// <param name="lpvReserved">Reserved.</param>
///
/// <returns>Returns <b>S_OK</b> on success.</returns>
///
[DllImport( "oleaut32.dll" )]
public static extern int OleCreatePropertyFrame(
IntPtr hwndOwner,
int x,
int y,
[MarshalAs( UnmanagedType.LPWStr )] string caption,
int cObjects,
[MarshalAs( UnmanagedType.Interface, ArraySubType = UnmanagedType.IUnknown )]
ref object ppUnk,
int cPages,
IntPtr lpPageClsID,
int lcid,
int dwReserved,
IntPtr lpvReserved );
}
}

View File

@ -0,0 +1,123 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2012
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow
{
/// <summary>
/// Specifies the physical type of pin (audio or video).
/// </summary>
public enum PhysicalConnectorType
{
/// <summary>
/// Default value of connection type. Physically it does not exist, but just either to specify that
/// connection type should not be changed (input) or was not determined (output).
/// </summary>
Default = 0,
/// <summary>
/// Specifies a tuner pin for video.
/// </summary>
VideoTuner = 1,
/// <summary>
/// Specifies a composite pin for video.
/// </summary>
VideoComposite,
/// <summary>
/// Specifies an S-Video (Y/C video) pin.
/// </summary>
VideoSVideo,
/// <summary>
/// Specifies an RGB pin for video.
/// </summary>
VideoRGB,
/// <summary>
/// Specifies a YRYBY (Y, RY, BY) pin for video.
/// </summary>
VideoYRYBY,
/// <summary>
/// Specifies a serial digital pin for video.
/// </summary>
VideoSerialDigital,
/// <summary>
/// Specifies a parallel digital pin for video.
/// </summary>
VideoParallelDigital,
/// <summary>
/// Specifies a SCSI (Small Computer System Interface) pin for video.
/// </summary>
VideoSCSI,
/// <summary>
/// Specifies an AUX (auxiliary) pin for video.
/// </summary>
VideoAUX,
/// <summary>
/// Specifies an IEEE 1394 pin for video.
/// </summary>
Video1394,
/// <summary>
/// Specifies a USB (Universal Serial Bus) pin for video.
/// </summary>
VideoUSB,
/// <summary>
/// Specifies a video decoder pin.
/// </summary>
VideoDecoder,
/// <summary>
/// Specifies a video encoder pin.
/// </summary>
VideoEncoder,
/// <summary>
/// Specifies a SCART (Peritel) pin for video.
/// </summary>
VideoSCART,
/// <summary>
/// Not used.
/// </summary>
VideoBlack,
/// <summary>
/// Specifies a tuner pin for audio.
/// </summary>
AudioTuner = 4096,
/// <summary>
/// Specifies a line pin for audio.
/// </summary>
AudioLine,
/// <summary>
/// Specifies a microphone pin.
/// </summary>
AudioMic,
/// <summary>
/// Specifies an AES/EBU (Audio Engineering Society/European Broadcast Union) digital pin for audio.
/// </summary>
AudioAESDigital,
/// <summary>
/// Specifies an S/PDIF (Sony/Philips Digital Interface Format) digital pin for audio.
/// </summary>
AudioSPDIFDigital,
/// <summary>
/// Specifies a SCSI pin for audio.
/// </summary>
AudioSCSI,
/// <summary>
/// Specifies an AUX pin for audio.
/// </summary>
AudioAUX,
/// <summary>
/// Specifies an IEEE 1394 pin for audio.
/// </summary>
Audio1394,
/// <summary>
/// Specifies a USB pin for audio.
/// </summary>
AudioUSB,
/// <summary>
/// Specifies an audio decoder pin.
/// </summary>
AudioDecoder
}
}

View File

@ -0,0 +1,5 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

View File

@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4214
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AForge.Video.DirectShow.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AForge.Video.DirectShow.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
internal static System.Drawing.Bitmap camera {
get {
object obj = ResourceManager.GetObject("camera", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="camera" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Icons\camera.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -0,0 +1,55 @@
// AForge Direct Show Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video.DirectShow
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// DirectShow filter categories.
/// </summary>
[ComVisible( false )]
public static class FilterCategory
{
/// <summary>
/// Audio input device category.
/// </summary>
///
/// <remarks>Equals to CLSID_AudioInputDeviceCategory.</remarks>
///
public static readonly Guid AudioInputDevice =
new Guid( 0x33D9A762, 0x90C8, 0x11D0, 0xBD, 0x43, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
/// <summary>
/// Video input device category.
/// </summary>
///
/// <remarks>Equals to CLSID_VideoInputDeviceCategory.</remarks>
///
public static readonly Guid VideoInputDevice =
new Guid( 0x860BB310, 0x5D01, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
/// <summary>
/// Video compressor category.
/// </summary>
///
/// <remarks>Equals to CLSID_VideoCompressorCategory.</remarks>
///
public static readonly Guid VideoCompressorCategory =
new Guid( 0x33D9A760, 0x90C8, 0x11D0, 0xBD, 0x43, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
/// <summary>
/// Audio compressor category
/// </summary>
///
/// <remarks>Equals to CLSID_AudioCompressorCategory.</remarks>
///
public static readonly Guid AudioCompressorCategory =
new Guid( 0x33D9A761, 0x90C8, 0x11D0, 0xBD, 0x43, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
}
}

View File

@ -0,0 +1,245 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2013
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using AForge.Video;
using AForge.Video.DirectShow.Internals;
/// <summary>
/// Capabilities of video device such as frame size and frame rate.
/// </summary>
public class VideoCapabilities
{
/// <summary>
/// Frame size supported by video device.
/// </summary>
public readonly Size FrameSize;
/// <summary>
/// Frame rate supported by video device for corresponding <see cref="FrameSize">frame size</see>.
/// </summary>
///
/// <remarks><para><note>This field is depricated - should not be used.
/// Its value equals to <see cref="AverageFrameRate"/>.</note></para>
/// </remarks>
///
[Obsolete( "No longer supported. Use AverageFrameRate instead." )]
public int FrameRate
{
get { return AverageFrameRate; }
}
/// <summary>
/// Average frame rate of video device for corresponding <see cref="FrameSize">frame size</see>.
/// </summary>
public readonly int AverageFrameRate;
/// <summary>
/// Maximum frame rate of video device for corresponding <see cref="FrameSize">frame size</see>.
/// </summary>
public readonly int MaximumFrameRate;
/// <summary>
/// Number of bits per pixel provided by the camera.
/// </summary>
public readonly int BitCount;
internal VideoCapabilities( ) { }
// Retrieve capabilities of a video device
static internal VideoCapabilities[] FromStreamConfig( IAMStreamConfig videoStreamConfig )
{
if ( videoStreamConfig == null )
throw new ArgumentNullException( "videoStreamConfig" );
// ensure this device reports capabilities
int count, size;
int hr = videoStreamConfig.GetNumberOfCapabilities( out count, out size );
if ( hr != 0 )
Marshal.ThrowExceptionForHR( hr );
if ( count <= 0 )
throw new NotSupportedException( "This video device does not report capabilities." );
if ( size > Marshal.SizeOf( typeof( VideoStreamConfigCaps ) ) )
throw new NotSupportedException( "Unable to retrieve video device capabilities. This video device requires a larger VideoStreamConfigCaps structure." );
// group capabilities with similar parameters
Dictionary<uint, VideoCapabilities> videocapsList = new Dictionary<uint, VideoCapabilities>( );
for ( int i = 0; i < count; i++ )
{
try
{
VideoCapabilities vc = new VideoCapabilities( videoStreamConfig, i );
uint key = ( ( (uint) vc.FrameSize.Height ) << 32 ) |
( ( (uint) vc.FrameSize.Width ) << 16 );
if ( !videocapsList.ContainsKey( key ) )
{
videocapsList.Add( key, vc );
}
else
{
if ( vc.BitCount > videocapsList[key].BitCount )
{
videocapsList[key] = vc;
}
}
}
catch
{
}
}
VideoCapabilities[] videocaps = new VideoCapabilities[videocapsList.Count];
videocapsList.Values.CopyTo( videocaps, 0 );
return videocaps;
}
// Retrieve capabilities of a video device
internal VideoCapabilities( IAMStreamConfig videoStreamConfig, int index )
{
AMMediaType mediaType = null;
VideoStreamConfigCaps caps = new VideoStreamConfigCaps( );
try
{
// retrieve capabilities struct at the specified index
int hr = videoStreamConfig.GetStreamCaps( index, out mediaType, caps );
if ( hr != 0 )
Marshal.ThrowExceptionForHR( hr );
if ( mediaType.FormatType == FormatType.VideoInfo )
{
VideoInfoHeader videoInfo = (VideoInfoHeader) Marshal.PtrToStructure( mediaType.FormatPtr, typeof( VideoInfoHeader ) );
FrameSize = new Size( videoInfo.BmiHeader.Width, videoInfo.BmiHeader.Height );
BitCount = videoInfo.BmiHeader.BitCount;
AverageFrameRate = (int) ( 10000000 / videoInfo.AverageTimePerFrame );
MaximumFrameRate = (int) ( 10000000 / caps.MinFrameInterval );
}
else if ( mediaType.FormatType == FormatType.VideoInfo2 )
{
VideoInfoHeader2 videoInfo = (VideoInfoHeader2) Marshal.PtrToStructure( mediaType.FormatPtr, typeof( VideoInfoHeader2 ) );
FrameSize = new Size( videoInfo.BmiHeader.Width, videoInfo.BmiHeader.Height );
BitCount = videoInfo.BmiHeader.BitCount;
AverageFrameRate = (int) ( 10000000 / videoInfo.AverageTimePerFrame );
MaximumFrameRate = (int) ( 10000000 / caps.MinFrameInterval );
}
else
{
throw new ApplicationException( "Unsupported format found." );
}
// ignore 12 bpp formats for now, since it was noticed they cause issues on Windows 8
// TODO: proper fix needs to be done so ICaptureGraphBuilder2::RenderStream() does not fail
// on such formats
if ( BitCount <= 12 )
{
throw new ApplicationException( "Unsupported format found." );
}
}
finally
{
if ( mediaType != null )
mediaType.Dispose( );
}
}
/// <summary>
/// Check if the video capability equals to the specified object.
/// </summary>
///
/// <param name="obj">Object to compare with.</param>
///
/// <returns>Returns true if both are equal are equal or false otherwise.</returns>
///
public override bool Equals( object obj )
{
return Equals( obj as VideoCapabilities );
}
/// <summary>
/// Check if two video capabilities are equal.
/// </summary>
///
/// <param name="vc2">Second video capability to compare with.</param>
///
/// <returns>Returns true if both video capabilities are equal or false otherwise.</returns>
///
public bool Equals( VideoCapabilities vc2 )
{
if ( (object) vc2 == null )
{
return false;
}
return ( ( FrameSize == vc2.FrameSize ) && ( BitCount == vc2.BitCount ) );
}
/// <summary>
/// Get hash code of the object.
/// </summary>
///
/// <returns>Returns hash code ot the object </returns>
public override int GetHashCode( )
{
return FrameSize.GetHashCode( ) ^ BitCount;
}
/// <summary>
/// Equality operator.
/// </summary>
///
/// <param name="a">First object to check.</param>
/// <param name="b">Seconds object to check.</param>
///
/// <returns>Return true if both objects are equal or false otherwise.</returns>
public static bool operator ==( VideoCapabilities a, VideoCapabilities b )
{
// if both are null, or both are same instance, return true.
if ( object.ReferenceEquals( a, b ) )
{
return true;
}
// if one is null, but not both, return false.
if ( ( (object) a == null ) || ( (object) b == null ) )
{
return false;
}
return a.Equals( b );
}
/// <summary>
/// Inequality operator.
/// </summary>
///
/// <param name="a">First object to check.</param>
/// <param name="b">Seconds object to check.</param>
///
/// <returns>Return true if both objects are not equal or false otherwise.</returns>
public static bool operator !=( VideoCapabilities a, VideoCapabilities b )
{
return !( a == b );
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
// AForge Direct Show Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2012
// contacts@aforgenet.com
//
namespace AForge.Video.DirectShow
{
using System;
/// <summary>
/// Video input of a capture board.
/// </summary>
///
/// <remarks><para>The class is used to describe video input of devices like video capture boards,
/// which usually provide several inputs.</para>
/// </remarks>
///
public class VideoInput
{
/// <summary>
/// Index of the video input.
/// </summary>
public readonly int Index;
/// <summary>
/// Type of the video input.
/// </summary>
public readonly PhysicalConnectorType Type;
internal VideoInput( int index, PhysicalConnectorType type )
{
Index = index;
Type = type;
}
/// <summary>
/// Default video input. Used to specify that it should not be changed.
/// </summary>
public static VideoInput Default
{
get { return new VideoInput( -1, PhysicalConnectorType.Default ); }
}
}
}

View File

@ -0,0 +1,473 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2005-2011
// contacts@aforgenet.com
//
namespace AForge.Video
{
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
/// <summary>
/// Proxy video source for asynchronous processing of another nested video source.
/// </summary>
///
/// <remarks><para>The class represents a simple proxy, which wraps the specified <see cref="NestedVideoSource"/>
/// with the aim of asynchronous processing of received video frames. The class intercepts <see cref="NewFrame"/>
/// event from the nested video source and fires it to clients from its own thread, which is different from the thread
/// used by nested video source for video acquisition. This allows clients to perform processing of video frames
/// without blocking video acquisition thread, which continue to run and acquire next video frame while current is still
/// processed.</para>
///
/// <para>For example, lets suppose that it takes 100 ms for the nested video source to acquire single frame, so the original
/// frame rate is 10 frames per second. Also lets assume that we have an image processing routine, which also takes
/// 100 ms to process a single frame. If the acquisition and processing are done sequentially, then resulting
/// frame rate will drop to 5 frames per second. However, if doing both in parallel, then there is a good chance to
/// keep resulting frame rate equal (or close) to the original frame rate.</para>
///
/// <para>The class provides a bonus side effect - easer debugging of image processing routines, which are put into
/// <see cref="NewFrame"/> event handler. In many cases video source classes fire their <see cref="IVideoSource.NewFrame"/>
/// event from a try/catch block, which makes it very hard to spot error made in user's code - the catch block simply
/// hides exception raised in users code. The <see cref="AsyncVideoSource"/> does not have any try/catch blocks around
/// firing of <see cref="NewFrame"/> event, so always user gets exception in the case it comes from his code. At the same time
/// nested video source is not affected by the user's exception, since it runs in different thread.</para>
///
/// <para>Sample usage:</para>
/// <code>
/// // usage of AsyncVideoSource is the same as usage of any
/// // other video source class, so code change is very little
///
/// // create nested video source, for example JPEGStream
/// JPEGStream stream = new JPEGStream( "some url" );
/// // create async video source
/// AsyncVideoSource asyncSource = new AsyncVideoSource( stream );
/// // set NewFrame event handler
/// asyncSource.NewFrame += new NewFrameEventHandler( video_NewFrame );
/// // start the video source
/// asyncSource.Start( );
/// // ...
///
/// private void video_NewFrame( object sender, NewFrameEventArgs eventArgs )
/// {
/// // get new frame
/// Bitmap bitmap = eventArgs.Frame;
/// // process the frame
/// }
/// </code>
/// </remarks>
///
public class AsyncVideoSource : IVideoSource
{
private readonly IVideoSource nestedVideoSource = null;
private Bitmap lastVideoFrame = null;
private Thread imageProcessingThread = null;
private AutoResetEvent isNewFrameAvailable = null;
private AutoResetEvent isProcessingThreadAvailable = null;
// skip frames or not in the case if processing thread is busy
private bool skipFramesIfBusy = false;
// processed frames count
private int framesProcessed;
/// <summary>
/// New frame event.
/// </summary>
///
/// <remarks><para>Notifies clients about new available frame from video source.</para>
///
/// <para><note>This event is fired from a different thread other than the video acquisition thread created
/// by <see cref="NestedVideoSource"/>. This allows nested video frame to continue acquisition of the next
/// video frame while clients perform processing of the current video frame.</note></para>
///
/// <para><note>Since video source may have multiple clients, each client is responsible for
/// making a copy (cloning) of the passed video frame, because the video source disposes its
/// own original copy after notifying of clients.</note></para>
/// </remarks>
///
public event NewFrameEventHandler NewFrame;
/// <summary>
/// Video source error event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients about any type of errors occurred in
/// video source object, for example internal exceptions.</para>
///
/// <para><note>Unlike <see cref="NewFrame"/> event, this event is simply redirected to the corresponding
/// event of the <see cref="NestedVideoSource"/>, so it is fired from the thread of the nested video source.</note></para>
/// </remarks>
///
public event VideoSourceErrorEventHandler VideoSourceError
{
add { nestedVideoSource.VideoSourceError += value; }
remove { nestedVideoSource.VideoSourceError -= value; }
}
/// <summary>
/// Video playing finished event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients that the video playing has finished.</para>
///
/// <para><note>Unlike <see cref="NewFrame"/> event, this event is simply redirected to the corresponding
/// event of the <see cref="NestedVideoSource"/>, so it is fired from the thread of the nested video source.</note></para>
/// </remarks>
///
public event PlayingFinishedEventHandler PlayingFinished
{
add { nestedVideoSource.PlayingFinished += value; }
remove { nestedVideoSource.PlayingFinished -= value; }
}
/// <summary>
/// Nested video source which is the target for asynchronous processing.
/// </summary>
///
/// <remarks><para>The property is set through the class constructor.</para>
///
/// <para>All calls to this object are actually redirected to the nested video source. The only
/// exception is the <see cref="NewFrame"/> event, which is handled differently. This object gets
/// <see cref="IVideoSource.NewFrame"/> event from the nested class and then fires another
/// <see cref="NewFrame"/> event, but from a different thread.</para>
/// </remarks>
///
public IVideoSource NestedVideoSource
{
get { return nestedVideoSource; }
}
/// <summary>
/// Specifies if the object should skip frames from the nested video source when it is busy.
/// </summary>
///
/// <remarks><para>Specifies if the object should skip frames from the nested video source
/// in the case if it is still busy processing the previous video frame in its own thread.</para>
///
/// <para>Default value is set to <see langword="false"/>.</para></remarks>
///
public bool SkipFramesIfBusy
{
get { return skipFramesIfBusy; }
set { skipFramesIfBusy = value; }
}
/// <summary>
/// Video source string.
/// </summary>
///
/// <remarks><para>The property is redirected to the corresponding property of <see cref="NestedVideoSource"/>,
/// so check its documentation to find what it means.</para></remarks>
///
public string Source
{
get { return nestedVideoSource.Source; }
}
/// <summary>
/// Received frames count.
/// </summary>
///
/// <remarks><para>Number of frames the <see cref="NestedVideoSource">nested video source</see> received from
/// the moment of the last access to the property.</para>
/// </remarks>
///
public int FramesReceived
{
get { return nestedVideoSource.FramesReceived; }
}
/// <summary>
/// Received bytes count.
/// </summary>
///
/// <remarks><para>Number of bytes the <see cref="NestedVideoSource">nested video source</see> received from
/// the moment of the last access to the property.</para></remarks>
///
public long BytesReceived
{
get { return nestedVideoSource.BytesReceived; }
}
/// <summary>
/// Processed frames count.
/// </summary>
///
/// <remarks><para>The property keeps the number of processed video frames since the last access to this property.
/// </para>
///
/// <para>The value of this property equals to <see cref="FramesReceived"/> in most cases if the
/// <see cref="SkipFramesIfBusy"/> property is set to <see langword="false"/> - every received frame gets processed
/// sooner or later. However, if the <see cref="SkipFramesIfBusy"/> property is set to <see langword="true"/>,
/// then value of this property may be lower than the value of the <see cref="FramesReceived"/> property, which
/// means that nested video source performs acquisition faster than client perform processing of the received frame
/// and some frame are skipped from processing.</para>
/// </remarks>
///
public int FramesProcessed
{
get
{
int frames = framesProcessed;
framesProcessed = 0;
return frames;
}
}
/// <summary>
/// State of the video source.
/// </summary>
///
/// <remarks><para>Current state of the video source object - running or not.</para></remarks>
///
public bool IsRunning
{
get
{
bool isRunning = nestedVideoSource.IsRunning;
if ( !isRunning )
{
Free( );
}
return isRunning;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="AsyncVideoSource"/> class.
/// </summary>
///
/// <param name="nestedVideoSource">Nested video source which is the target for asynchronous processing.</param>
///
public AsyncVideoSource( IVideoSource nestedVideoSource )
{
this.nestedVideoSource = nestedVideoSource;
}
/// <summary>
/// Initializes a new instance of the <see cref="AsyncVideoSource"/> class.
/// </summary>
///
/// <param name="nestedVideoSource">Nested video source which is the target for asynchronous processing.</param>
/// <param name="skipFramesIfBusy">Specifies if the object should skip frames from the nested video source
/// in the case if it is still busy processing the previous video frame.</param>
///
public AsyncVideoSource( IVideoSource nestedVideoSource, bool skipFramesIfBusy )
{
this.nestedVideoSource = nestedVideoSource;
this.skipFramesIfBusy = skipFramesIfBusy;
}
/// <summary>
/// Start video source.
/// </summary>
///
/// <remarks><para>Starts the nested video source and returns execution to caller. This object creates
/// an extra thread which is used to fire <see cref="NewFrame"/> events, so the image processing could be
/// done on another thread without blocking video acquisition thread.</para></remarks>
///
public void Start( )
{
if ( !IsRunning )
{
framesProcessed = 0;
// create all synchronization events
isNewFrameAvailable = new AutoResetEvent( false );
isProcessingThreadAvailable = new AutoResetEvent( true );
// create image processing thread
imageProcessingThread = new Thread( new ThreadStart( imageProcessingThread_Worker ) );
imageProcessingThread.Start( );
// start the nested video source
nestedVideoSource.NewFrame += new NewFrameEventHandler( nestedVideoSource_NewFrame );
nestedVideoSource.Start( );
}
}
/// <summary>
/// Signal video source to stop its work.
/// </summary>
///
/// <remarks><para>Signals video source to stop its background thread, stop to
/// provide new frames and free resources.</para></remarks>
///
public void SignalToStop( )
{
nestedVideoSource.SignalToStop( );
}
/// <summary>
/// Wait for video source has stopped.
/// </summary>
///
/// <remarks><para>Waits for video source stopping after it was signalled to stop using
/// <see cref="SignalToStop"/> method.</para></remarks>
///
public void WaitForStop( )
{
nestedVideoSource.WaitForStop( );
Free( );
}
/// <summary>
/// Stop video source.
/// </summary>
///
/// <remarks><para>Stops nested video source by calling its <see cref="IVideoSource.Stop"/> method.
/// See documentation of the particular video source for additional details.</para></remarks>
///
public void Stop( )
{
nestedVideoSource.Stop( );
Free( );
}
private void Free( )
{
if ( imageProcessingThread != null )
{
nestedVideoSource.NewFrame -= new NewFrameEventHandler( nestedVideoSource_NewFrame );
// make sure processing thread does nothing
isProcessingThreadAvailable.WaitOne( );
// signal worker thread to stop and wait for it
lastVideoFrame = null;
isNewFrameAvailable.Set( );
imageProcessingThread.Join( );
imageProcessingThread = null;
// release events
isNewFrameAvailable.Close( );
isNewFrameAvailable = null;
isProcessingThreadAvailable.Close( );
isProcessingThreadAvailable = null;
}
}
// New frame from nested video source
private void nestedVideoSource_NewFrame( object sender, NewFrameEventArgs eventArgs )
{
// don't even try doing something if there are no clients
if ( NewFrame == null )
return;
if ( skipFramesIfBusy )
{
if ( !isProcessingThreadAvailable.WaitOne( 0, false ) )
{
// return in the case if image processing thread is still busy and
// we are allowed to skip frames
return;
}
}
else
{
// make sure image processing thread is available in the case we cannot skip frames
isProcessingThreadAvailable.WaitOne( );
}
// pass the image to processing frame and exit
lastVideoFrame = CloneImage( eventArgs.Frame );
isNewFrameAvailable.Set( );
}
private void imageProcessingThread_Worker( )
{
while ( true )
{
// wait for new frame to process
isNewFrameAvailable.WaitOne( );
// if it is null, then we need to exit
if ( lastVideoFrame == null )
{
break;
}
if ( NewFrame != null )
{
NewFrame( this, new NewFrameEventArgs( lastVideoFrame ) );
}
lastVideoFrame.Dispose( );
lastVideoFrame = null;
framesProcessed++;
// we are free now for new image
isProcessingThreadAvailable.Set( );
}
}
// Note: image cloning is taken from AForge.Imaging.Image.Clone() to avoid reference,
// which may be unwanted
private static Bitmap CloneImage( Bitmap source )
{
// lock source bitmap data
BitmapData sourceData = source.LockBits(
new Rectangle( 0, 0, source.Width, source.Height ),
ImageLockMode.ReadOnly, source.PixelFormat );
// create new image
Bitmap destination = CloneImage( sourceData );
// unlock source image
source.UnlockBits( sourceData );
//
if (
( source.PixelFormat == PixelFormat.Format1bppIndexed ) ||
( source.PixelFormat == PixelFormat.Format4bppIndexed ) ||
( source.PixelFormat == PixelFormat.Format8bppIndexed ) ||
( source.PixelFormat == PixelFormat.Indexed ) )
{
ColorPalette srcPalette = source.Palette;
ColorPalette dstPalette = destination.Palette;
int n = srcPalette.Entries.Length;
// copy pallete
for ( int i = 0; i < n; i++ )
{
dstPalette.Entries[i] = srcPalette.Entries[i];
}
destination.Palette = dstPalette;
}
return destination;
}
private static Bitmap CloneImage( BitmapData sourceData )
{
// get source image size
int width = sourceData.Width;
int height = sourceData.Height;
// create new image
Bitmap destination = new Bitmap( width, height, sourceData.PixelFormat );
// lock destination bitmap data
BitmapData destinationData = destination.LockBits(
new Rectangle( 0, 0, width, height ),
ImageLockMode.ReadWrite, destination.PixelFormat );
AForge.SystemTools.CopyUnmanagedMemory( destinationData.Scan0, sourceData.Scan0, height * sourceData.Stride );
// unlock destination image
destination.UnlockBits( destinationData );
return destination;
}
}
}

View File

@ -0,0 +1,91 @@
// AForge Video Library
// AForge.NET framework
//
// Copyright © Andrew Kirillov, 2007-2008
// andrew.kirillov@gmail.com
//
namespace AForge.Video
{
using System;
/// <summary>
/// Some internal utilities for handling arrays.
/// </summary>
///
internal static class ByteArrayUtils
{
/// <summary>
/// Check if the array contains needle at specified position.
/// </summary>
///
/// <param name="array">Source array to check for needle.</param>
/// <param name="needle">Needle we are searching for.</param>
/// <param name="startIndex">Start index in source array.</param>
///
/// <returns>Returns <b>true</b> if the source array contains the needle at
/// the specified index. Otherwise it returns <b>false</b>.</returns>
///
public static bool Compare( byte[] array, byte[] needle, int startIndex )
{
int needleLen = needle.Length;
// compare
for ( int i = 0, p = startIndex; i < needleLen; i++, p++ )
{
if ( array[p] != needle[i] )
{
return false;
}
}
return true;
}
/// <summary>
/// Find subarray in the source array.
/// </summary>
///
/// <param name="array">Source array to search for needle.</param>
/// <param name="needle">Needle we are searching for.</param>
/// <param name="startIndex">Start index in source array.</param>
/// <param name="sourceLength">Number of bytes in source array, where the needle is searched for.</param>
///
/// <returns>Returns starting position of the needle if it was found or <b>-1</b> otherwise.</returns>
///
public static int Find( byte[] array, byte[] needle, int startIndex, int sourceLength )
{
int needleLen = needle.Length;
int index;
while ( sourceLength >= needleLen )
{
// find needle's starting element
index = Array.IndexOf( array, needle[0], startIndex, sourceLength - needleLen + 1 );
// if we did not find even the first element of the needls, then the search is failed
if ( index == -1 )
return -1;
int i, p;
// check for needle
for ( i = 0, p = index; i < needleLen; i++, p++ )
{
if ( array[p] != needle[i] )
{
break;
}
}
if ( i == needleLen )
{
// needle was found
return index;
}
// continue to search for needle
sourceLength -= ( index - startIndex + 1 );
startIndex = index + 1;
}
return -1;
}
}
}

View File

@ -0,0 +1,31 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2005-2011
// contacts@aforgenet.com
//
namespace AForge.Video
{
using System;
/// <summary>
/// Video related exception.
/// </summary>
///
/// <remarks><para>The exception is thrown in the case of some video related issues, like
/// failure of initializing codec, compression, etc.</para></remarks>
///
public class VideoException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="VideoException"/> class.
/// </summary>
///
/// <param name="message">Exception's message.</param>
///
public VideoException( string message ) :
base( message ) { }
}
}

View File

@ -0,0 +1,126 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © Andrew Kirillov, 2005-2009
// andrew.kirillov@aforgenet.com
//
namespace AForge.Video
{
using System;
/// <summary>
/// Video source interface.
/// </summary>
///
/// <remarks>The interface describes common methods for different type of video sources.</remarks>
///
public interface IVideoSource
{
/// <summary>
/// New frame event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients about new available video frame.</para>
///
/// <para><note>Since video source may have multiple clients, each client is responsible for
/// making a copy (cloning) of the passed video frame, but video source is responsible for
/// disposing its own original copy after notifying of clients.</note></para>
/// </remarks>
///
event NewFrameEventHandler NewFrame;
/// <summary>
/// Video source error event.
/// </summary>
///
/// <remarks>This event is used to notify clients about any type of errors occurred in
/// video source object, for example internal exceptions.</remarks>
///
event VideoSourceErrorEventHandler VideoSourceError;
/// <summary>
/// Video playing finished event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients that the video playing has finished.</para>
/// </remarks>
///
event PlayingFinishedEventHandler PlayingFinished;
/// <summary>
/// Video source.
/// </summary>
///
/// <remarks>The meaning of the property depends on particular video source.
/// Depending on video source it may be a file name, URL or any other string
/// describing the video source.</remarks>
///
string Source { get; }
/// <summary>
/// Received frames count.
/// </summary>
///
/// <remarks>Number of frames the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
int FramesReceived { get; }
/// <summary>
/// Received bytes count.
/// </summary>
///
/// <remarks>Number of bytes the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
long BytesReceived { get; }
/// <summary>
/// State of the video source.
/// </summary>
///
/// <remarks>Current state of video source object - running or not.</remarks>
///
bool IsRunning { get; }
/// <summary>
/// Start video source.
/// </summary>
///
/// <remarks>Starts video source and return execution to caller. Video source
/// object creates background thread and notifies about new frames with the
/// help of <see cref="NewFrame"/> event.</remarks>
///
void Start( );
/// <summary>
/// Signal video source to stop its work.
/// </summary>
///
/// <remarks>Signals video source to stop its background thread, stop to
/// provide new frames and free resources.</remarks>
///
void SignalToStop( );
/// <summary>
/// Wait for video source has stopped.
/// </summary>
///
/// <remarks>Waits for video source stopping after it was signalled to stop using
/// <see cref="SignalToStop"/> method.</remarks>
///
void WaitForStop( );
/// <summary>
/// Stop video source.
/// </summary>
///
/// <remarks>Stops video source aborting its thread.</remarks>
///
void Stop( );
}
}

View File

@ -0,0 +1,587 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2005-2011
// contacts@aforgenet.com
//
namespace AForge.Video
{
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Net;
using System.Security;
/// <summary>
/// JPEG video source.
/// </summary>
///
/// <remarks><para>The video source constantly downloads JPEG files from the specified URL.</para>
///
/// <para>Sample usage:</para>
/// <code>
/// // create JPEG video source
/// JPEGStream stream = new JPEGStream( "some url" );
/// // set NewFrame event handler
/// stream.NewFrame += new NewFrameEventHandler( video_NewFrame );
/// // start the video source
/// stream.Start( );
/// // ...
/// // signal to stop
/// stream.SignalToStop( );
/// // ...
///
/// private void video_NewFrame( object sender, NewFrameEventArgs eventArgs )
/// {
/// // get new frame
/// Bitmap bitmap = eventArgs.Frame;
/// // process the frame
/// }
/// </code>
///
/// <para><note>Some cameras produce HTTP header, which does not conform strictly to
/// standard, what leads to .NET exception. To avoid this exception the <b>useUnsafeHeaderParsing</b>
/// configuration option of <b>httpWebRequest</b> should be set, what may be done using application
/// configuration file.</note></para>
/// <code>
/// &lt;configuration&gt;
/// &lt;system.net&gt;
/// &lt;settings&gt;
/// &lt;httpWebRequest useUnsafeHeaderParsing="true" /&gt;
/// &lt;/settings&gt;
/// &lt;/system.net&gt;
/// &lt;/configuration&gt;
/// </code>
/// </remarks>
///
public class JPEGStream : IVideoSource
{
// URL for JPEG files
private string source;
// login and password for HTTP authentication
private string login = null;
private string password = null;
// proxy information
private IWebProxy proxy = null;
// received frames count
private int framesReceived;
// recieved byte count
private long bytesReceived;
// use separate HTTP connection group or use default
private bool useSeparateConnectionGroup = false;
// prevent cashing or not
private bool preventCaching = true;
// frame interval in milliseconds
private int frameInterval = 0;
// timeout value for web request
private int requestTimeout = 10000;
// if we should use basic authentication when connecting to the video source
private bool forceBasicAuthentication = false;
// buffer size used to download JPEG image
private const int bufferSize = 1024 * 1024;
// size of portion to read at once
private const int readSize = 1024;
private Thread thread = null;
private ManualResetEvent stopEvent = null;
/// <summary>
/// New frame event.
/// </summary>
///
/// <remarks><para>Notifies clients about new available frame from video source.</para>
///
/// <para><note>Since video source may have multiple clients, each client is responsible for
/// making a copy (cloning) of the passed video frame, because the video source disposes its
/// own original copy after notifying of clients.</note></para>
/// </remarks>
///
public event NewFrameEventHandler NewFrame;
/// <summary>
/// Video source error event.
/// </summary>
///
/// <remarks>This event is used to notify clients about any type of errors occurred in
/// video source object, for example internal exceptions.</remarks>
///
public event VideoSourceErrorEventHandler VideoSourceError;
/// <summary>
/// Video playing finished event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients that the video playing has finished.</para>
/// </remarks>
///
public event PlayingFinishedEventHandler PlayingFinished;
/// <summary>
/// Use or not separate connection group.
/// </summary>
///
/// <remarks>The property indicates to open web request in separate connection group.</remarks>
///
public bool SeparateConnectionGroup
{
get { return useSeparateConnectionGroup; }
set { useSeparateConnectionGroup = value; }
}
/// <summary>
/// Use or not caching.
/// </summary>
///
/// <remarks>If the property is set to <b>true</b>, then a fake random parameter will be added
/// to URL to prevent caching. It's required for clients, who are behind proxy server.</remarks>
///
public bool PreventCaching
{
get { return preventCaching; }
set { preventCaching = value; }
}
/// <summary>
/// Frame interval.
/// </summary>
///
/// <remarks>The property sets the interval in milliseconds betwen frames. If the property is
/// set to 100, then the desired frame rate will be 10 frames per second. Default value is 0 -
/// get new frames as fast as possible.</remarks>
///
public int FrameInterval
{
get { return frameInterval; }
set { frameInterval = value; }
}
/// <summary>
/// Video source.
/// </summary>
///
/// <remarks>URL, which provides JPEG files.</remarks>
///
public virtual string Source
{
get { return source; }
set { source = value; }
}
/// <summary>
/// Login value.
/// </summary>
///
/// <remarks>Login required to access video source.</remarks>
///
public string Login
{
get { return login; }
set { login = value; }
}
/// <summary>
/// Password value.
/// </summary>
///
/// <remarks>Password required to access video source.</remarks>
///
public string Password
{
get { return password; }
set { password = value; }
}
/// <summary>
/// Gets or sets proxy information for the request.
/// </summary>
///
/// <remarks><para>The local computer or application config file may specify that a default
/// proxy to be used. If the Proxy property is specified, then the proxy settings from the Proxy
/// property overridea the local computer or application config file and the instance will use
/// the proxy settings specified. If no proxy is specified in a config file
/// and the Proxy property is unspecified, the request uses the proxy settings
/// inherited from Internet Explorer on the local computer. If there are no proxy settings
/// in Internet Explorer, the request is sent directly to the server.
/// </para></remarks>
///
public IWebProxy Proxy
{
get { return proxy; }
set { proxy = value; }
}
/// <summary>
/// Received frames count.
/// </summary>
///
/// <remarks>Number of frames the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public int FramesReceived
{
get
{
int frames = framesReceived;
framesReceived = 0;
return frames;
}
}
/// <summary>
/// Received bytes count.
/// </summary>
///
/// <remarks>Number of bytes the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public long BytesReceived
{
get
{
long bytes = bytesReceived;
bytesReceived = 0;
return bytes;
}
}
/// <summary>
/// Request timeout value.
/// </summary>
///
/// <remarks><para>The property sets timeout value in milliseconds for web requests.</para>
///
/// <para>Default value is set <b>10000</b> milliseconds.</para></remarks>
///
public int RequestTimeout
{
get { return requestTimeout; }
set { requestTimeout = value; }
}
/// <summary>
/// State of the video source.
/// </summary>
///
/// <remarks>Current state of video source object - running or not.</remarks>
///
public bool IsRunning
{
get
{
if ( thread != null )
{
// check thread status
if ( thread.Join( 0 ) == false )
return true;
// the thread is not running, free resources
Free( );
}
return false;
}
}
/// <summary>
/// Force using of basic authentication when connecting to the video source.
/// </summary>
///
/// <remarks><para>For some IP cameras (TrendNET IP cameras, for example) using standard .NET's authentication via credentials
/// does not seem to be working (seems like camera does not request for authentication, but expects corresponding headers to be
/// present on connection request). So this property allows to force basic authentication by adding required HTTP headers when
/// request is sent.</para>
///
/// <para>Default value is set to <see langword="false"/>.</para>
/// </remarks>
///
public bool ForceBasicAuthentication
{
get { return forceBasicAuthentication; }
set { forceBasicAuthentication = value; }
}
/// <summary>
/// Initializes a new instance of the <see cref="JPEGStream"/> class.
/// </summary>
///
public JPEGStream( ) { }
/// <summary>
/// Initializes a new instance of the <see cref="JPEGStream"/> class.
/// </summary>
///
/// <param name="source">URL, which provides JPEG files.</param>
///
public JPEGStream( string source )
{
this.source = source;
}
/// <summary>
/// Start video source.
/// </summary>
///
/// <remarks>Starts video source and return execution to caller. Video source
/// object creates background thread and notifies about new frames with the
/// help of <see cref="NewFrame"/> event.</remarks>
///
/// <exception cref="ArgumentException">Video source is not specified.</exception>
///
public void Start( )
{
if ( !IsRunning )
{
// check source
if ( ( source == null ) || ( source == string.Empty ) )
throw new ArgumentException( "Video source is not specified." );
framesReceived = 0;
bytesReceived = 0;
// create events
stopEvent = new ManualResetEvent( false );
// create and start new thread
thread = new Thread( new ThreadStart( WorkerThread ) );
thread.Name = source; // mainly for debugging
thread.Start( );
}
}
/// <summary>
/// Signal video source to stop its work.
/// </summary>
///
/// <remarks>Signals video source to stop its background thread, stop to
/// provide new frames and free resources.</remarks>
///
public void SignalToStop( )
{
// stop thread
if ( thread != null )
{
// signal to stop
stopEvent.Set( );
}
}
/// <summary>
/// Wait for video source has stopped.
/// </summary>
///
/// <remarks>Waits for source stopping after it was signalled to stop using
/// <see cref="SignalToStop"/> method.</remarks>
///
public void WaitForStop( )
{
if ( thread != null )
{
// wait for thread stop
thread.Join( );
Free( );
}
}
/// <summary>
/// Stop video source.
/// </summary>
///
/// <remarks><para>Stops video source aborting its thread.</para>
///
/// <para><note>Since the method aborts background thread, its usage is highly not preferred
/// and should be done only if there are no other options. The correct way of stopping camera
/// is <see cref="SignalToStop">signaling it stop</see> and then
/// <see cref="WaitForStop">waiting</see> for background thread's completion.</note></para>
/// </remarks>
///
public void Stop( )
{
if ( this.IsRunning )
{
stopEvent.Set( );
thread.Abort( );
WaitForStop( );
}
}
/// <summary>
/// Free resource.
/// </summary>
///
private void Free( )
{
thread = null;
// release events
stopEvent.Close( );
stopEvent = null;
}
// Worker thread
private void WorkerThread( )
{
// buffer to read stream
byte[] buffer = new byte[bufferSize];
// HTTP web request
HttpWebRequest request = null;
// web responce
WebResponse response = null;
// stream for JPEG downloading
Stream stream = null;
// random generator to add fake parameter for cache preventing
Random rand = new Random( (int) DateTime.Now.Ticks );
// download start time and duration
DateTime start;
TimeSpan span;
while ( !stopEvent.WaitOne( 0, false ) )
{
int read, total = 0;
try
{
// set dowbload start time
start = DateTime.Now;
// create request
if ( !preventCaching )
{
// request without cache prevention
request = (HttpWebRequest) WebRequest.Create( source );
}
else
{
// request with cache prevention
request = (HttpWebRequest) WebRequest.Create( source + ( ( source.IndexOf( '?' ) == -1 ) ? '?' : '&' ) + "fake=" + rand.Next( ).ToString( ) );
}
// set proxy
if ( proxy != null )
{
request.Proxy = proxy;
}
// set timeout value for the request
request.Timeout = requestTimeout;
// set login and password
if ( ( login != null ) && ( password != null ) && ( login != string.Empty ) )
request.Credentials = new NetworkCredential( login, password );
// set connection group name
if ( useSeparateConnectionGroup )
request.ConnectionGroupName = GetHashCode( ).ToString( );
// force basic authentication through extra headers if required
if ( forceBasicAuthentication )
{
string authInfo = string.Format( "{0}:{1}", login, password );
authInfo = Convert.ToBase64String( Encoding.Default.GetBytes( authInfo ) );
request.Headers["Authorization"] = "Basic " + authInfo;
}
// get response
response = request.GetResponse( );
// get response stream
stream = response.GetResponseStream( );
stream.ReadTimeout = requestTimeout;
// loop
while ( !stopEvent.WaitOne( 0, false ) )
{
// check total read
if ( total > bufferSize - readSize )
{
total = 0;
}
// read next portion from stream
if ( ( read = stream.Read( buffer, total, readSize ) ) == 0 )
break;
total += read;
// increment received bytes counter
bytesReceived += read;
}
if ( !stopEvent.WaitOne( 0, false ) )
{
// increment frames counter
framesReceived++;
// provide new image to clients
if ( NewFrame != null )
{
Bitmap bitmap = (Bitmap) Bitmap.FromStream( new MemoryStream( buffer, 0, total ) );
// notify client
NewFrame( this, new NewFrameEventArgs( bitmap ) );
// release the image
bitmap.Dispose( );
bitmap = null;
}
}
// wait for a while ?
if ( frameInterval > 0 )
{
// get download duration
span = DateTime.Now.Subtract( start );
// miliseconds to sleep
int msec = frameInterval - (int) span.TotalMilliseconds;
if ( ( msec > 0 ) && ( stopEvent.WaitOne( msec, false ) ) )
break;
}
}
catch ( ThreadAbortException )
{
break;
}
catch ( Exception exception )
{
// provide information to clients
if ( VideoSourceError != null )
{
VideoSourceError( this, new VideoSourceErrorEventArgs( exception.Message ) );
}
// wait for a while before the next try
Thread.Sleep( 250 );
}
finally
{
// abort request
if ( request != null)
{
request.Abort( );
request = null;
}
// close response stream
if ( stream != null )
{
stream.Close( );
stream = null;
}
// close response
if ( response != null )
{
response.Close( );
response = null;
}
}
// need to stop ?
if ( stopEvent.WaitOne( 0, false ) )
break;
}
if ( PlayingFinished != null )
{
PlayingFinished( this, ReasonToFinishPlaying.StoppedByUser );
}
}
}
}

View File

@ -0,0 +1,704 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2005-2011
// contacts@aforgenet.com
//
namespace AForge.Video
{
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Net;
using System.Security;
/// <summary>
/// MJPEG video source.
/// </summary>
///
/// <remarks><para>The video source downloads JPEG images from the specified URL, which represents
/// MJPEG stream.</para>
///
/// <para>Sample usage:</para>
/// <code>
/// // create MJPEG video source
/// MJPEGStream stream = new MJPEGStream( "some url" );
/// // set event handlers
/// stream.NewFrame += new NewFrameEventHandler( video_NewFrame );
/// // start the video source
/// stream.Start( );
/// // ...
/// </code>
///
/// <para><note>Some cameras produce HTTP header, which does not conform strictly to
/// standard, what leads to .NET exception. To avoid this exception the <b>useUnsafeHeaderParsing</b>
/// configuration option of <b>httpWebRequest</b> should be set, what may be done using application
/// configuration file.</note></para>
/// <code>
/// &lt;configuration&gt;
/// &lt;system.net&gt;
/// &lt;settings&gt;
/// &lt;httpWebRequest useUnsafeHeaderParsing="true" /&gt;
/// &lt;/settings&gt;
/// &lt;/system.net&gt;
/// &lt;/configuration&gt;
/// </code>
/// </remarks>
///
public class MJPEGStream : IVideoSource
{
// URL for MJPEG stream
private string source;
// login and password for HTTP authentication
private string login = null;
private string password = null;
// proxy information
private IWebProxy proxy = null;
// received frames count
private int framesReceived;
// recieved byte count
private long bytesReceived;
// use separate HTTP connection group or use default
private bool useSeparateConnectionGroup = true;
// timeout value for web request
private int requestTimeout = 10000;
// if we should use basic authentication when connecting to the video source
private bool forceBasicAuthentication = false;
// buffer size used to download MJPEG stream
private const int bufSize = 1024 * 1024;
// size of portion to read at once
private const int readSize = 1024;
private Thread thread = null;
private ManualResetEvent stopEvent = null;
private ManualResetEvent reloadEvent = null;
private string userAgent = "Mozilla/5.0";
/// <summary>
/// New frame event.
/// </summary>
///
/// <remarks><para>Notifies clients about new available frame from video source.</para>
///
/// <para><note>Since video source may have multiple clients, each client is responsible for
/// making a copy (cloning) of the passed video frame, because the video source disposes its
/// own original copy after notifying of clients.</note></para>
/// </remarks>
///
public event NewFrameEventHandler NewFrame;
/// <summary>
/// Video source error event.
/// </summary>
///
/// <remarks>This event is used to notify clients about any type of errors occurred in
/// video source object, for example internal exceptions.</remarks>
///
public event VideoSourceErrorEventHandler VideoSourceError;
/// <summary>
/// Video playing finished event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients that the video playing has finished.</para>
/// </remarks>
///
public event PlayingFinishedEventHandler PlayingFinished;
/// <summary>
/// Use or not separate connection group.
/// </summary>
///
/// <remarks>The property indicates to open web request in separate connection group.</remarks>
///
public bool SeparateConnectionGroup
{
get { return useSeparateConnectionGroup; }
set { useSeparateConnectionGroup = value; }
}
/// <summary>
/// Video source.
/// </summary>
///
/// <remarks>URL, which provides MJPEG stream.</remarks>
///
public string Source
{
get { return source; }
set
{
source = value;
// signal to reload
if ( thread != null )
reloadEvent.Set( );
}
}
/// <summary>
/// Login value.
/// </summary>
///
/// <remarks>Login required to access video source.</remarks>
///
public string Login
{
get { return login; }
set { login = value; }
}
/// <summary>
/// Password value.
/// </summary>
///
/// <remarks>Password required to access video source.</remarks>
///
public string Password
{
get { return password; }
set { password = value; }
}
/// <summary>
/// Gets or sets proxy information for the request.
/// </summary>
///
/// <remarks><para>The local computer or application config file may specify that a default
/// proxy to be used. If the Proxy property is specified, then the proxy settings from the Proxy
/// property overridea the local computer or application config file and the instance will use
/// the proxy settings specified. If no proxy is specified in a config file
/// and the Proxy property is unspecified, the request uses the proxy settings
/// inherited from Internet Explorer on the local computer. If there are no proxy settings
/// in Internet Explorer, the request is sent directly to the server.
/// </para></remarks>
///
public IWebProxy Proxy
{
get { return proxy; }
set { proxy = value; }
}
/// <summary>
/// User agent to specify in HTTP request header.
/// </summary>
///
/// <remarks><para>Some IP cameras check what is the requesting user agent and depending
/// on it they provide video in different formats or do not provide it at all. The property
/// sets the value of user agent string, which is sent to camera in request header.
/// </para>
///
/// <para>Default value is set to "Mozilla/5.0". If the value is set to <see langword="null"/>,
/// the user agent string is not sent in request header.</para>
/// </remarks>
///
public string HttpUserAgent
{
get { return userAgent; }
set { userAgent = value; }
}
/// <summary>
/// Received frames count.
/// </summary>
///
/// <remarks>Number of frames the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public int FramesReceived
{
get
{
int frames = framesReceived;
framesReceived = 0;
return frames;
}
}
/// <summary>
/// Received bytes count.
/// </summary>
///
/// <remarks>Number of bytes the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public long BytesReceived
{
get
{
long bytes = bytesReceived;
bytesReceived = 0;
return bytes;
}
}
/// <summary>
/// Request timeout value.
/// </summary>
///
/// <remarks>The property sets timeout value in milliseconds for web requests.
/// Default value is 10000 milliseconds.</remarks>
///
public int RequestTimeout
{
get { return requestTimeout; }
set { requestTimeout = value; }
}
/// <summary>
/// State of the video source.
/// </summary>
///
/// <remarks>Current state of video source object - running or not.</remarks>
///
public bool IsRunning
{
get
{
if ( thread != null )
{
// check thread status
if ( thread.Join( 0 ) == false )
return true;
// the thread is not running, so free resources
Free( );
}
return false;
}
}
/// <summary>
/// Force using of basic authentication when connecting to the video source.
/// </summary>
///
/// <remarks><para>For some IP cameras (TrendNET IP cameras, for example) using standard .NET's authentication via credentials
/// does not seem to be working (seems like camera does not request for authentication, but expects corresponding headers to be
/// present on connection request). So this property allows to force basic authentication by adding required HTTP headers when
/// request is sent.</para>
///
/// <para>Default value is set to <see langword="false"/>.</para>
/// </remarks>
///
public bool ForceBasicAuthentication
{
get { return forceBasicAuthentication; }
set { forceBasicAuthentication = value; }
}
/// <summary>
/// Initializes a new instance of the <see cref="MJPEGStream"/> class.
/// </summary>
///
public MJPEGStream( ) { }
/// <summary>
/// Initializes a new instance of the <see cref="MJPEGStream"/> class.
/// </summary>
///
/// <param name="source">URL, which provides MJPEG stream.</param>
///
public MJPEGStream( string source )
{
this.source = source;
}
/// <summary>
/// Start video source.
/// </summary>
///
/// <remarks>Starts video source and return execution to caller. Video source
/// object creates background thread and notifies about new frames with the
/// help of <see cref="NewFrame"/> event.</remarks>
///
/// <exception cref="ArgumentException">Video source is not specified.</exception>
///
public void Start( )
{
if ( !IsRunning )
{
// check source
if ( ( source == null ) || ( source == string.Empty ) )
throw new ArgumentException( "Video source is not specified." );
framesReceived = 0;
bytesReceived = 0;
// create events
stopEvent = new ManualResetEvent( false );
reloadEvent = new ManualResetEvent( false );
// create and start new thread
thread = new Thread( new ThreadStart( WorkerThread ) );
thread.Name = source;
thread.Start( );
}
}
/// <summary>
/// Signal video source to stop its work.
/// </summary>
///
/// <remarks>Signals video source to stop its background thread, stop to
/// provide new frames and free resources.</remarks>
///
public void SignalToStop( )
{
// stop thread
if ( thread != null )
{
// signal to stop
stopEvent.Set( );
}
}
/// <summary>
/// Wait for video source has stopped.
/// </summary>
///
/// <remarks>Waits for source stopping after it was signalled to stop using
/// <see cref="SignalToStop"/> method.</remarks>
///
public void WaitForStop( )
{
if ( thread != null )
{
// wait for thread stop
thread.Join( );
Free( );
}
}
/// <summary>
/// Stop video source.
/// </summary>
///
/// <remarks><para>Stops video source aborting its thread.</para>
///
/// <para><note>Since the method aborts background thread, its usage is highly not preferred
/// and should be done only if there are no other options. The correct way of stopping camera
/// is <see cref="SignalToStop">signaling it stop</see> and then
/// <see cref="WaitForStop">waiting</see> for background thread's completion.</note></para>
/// </remarks>
///
public void Stop( )
{
if ( this.IsRunning )
{
stopEvent.Set( );
thread.Abort( );
WaitForStop( );
}
}
/// <summary>
/// Free resource.
/// </summary>
///
private void Free( )
{
thread = null;
// release events
stopEvent.Close( );
stopEvent = null;
reloadEvent.Close( );
reloadEvent = null;
}
// Worker thread
private void WorkerThread( )
{
// buffer to read stream
byte[] buffer = new byte[bufSize];
// JPEG magic number
byte[] jpegMagic = new byte[] { 0xFF, 0xD8, 0xFF };
int jpegMagicLength = 3;
ASCIIEncoding encoding = new ASCIIEncoding( );
while ( !stopEvent.WaitOne( 0, false ) )
{
// reset reload event
reloadEvent.Reset( );
// HTTP web request
HttpWebRequest request = null;
// web responce
WebResponse response = null;
// stream for MJPEG downloading
Stream stream = null;
// boundary betweeen images (string and binary versions)
byte[] boundary = null;
string boudaryStr = null;
// length of boundary
int boundaryLen;
// flag signaling if boundary was checked or not
bool boundaryIsChecked = false;
// read amounts and positions
int read, todo = 0, total = 0, pos = 0, align = 1;
int start = 0, stop = 0;
// align
// 1 = searching for image start
// 2 = searching for image end
try
{
// create request
request = (HttpWebRequest) WebRequest.Create( source );
// set user agent
if ( userAgent != null )
{
request.UserAgent = userAgent;
}
// set proxy
if ( proxy != null )
{
request.Proxy = proxy;
}
// set timeout value for the request
request.Timeout = requestTimeout;
// set login and password
if ( ( login != null ) && ( password != null ) && ( login != string.Empty ) )
request.Credentials = new NetworkCredential( login, password );
// set connection group name
if ( useSeparateConnectionGroup )
request.ConnectionGroupName = GetHashCode( ).ToString( );
// force basic authentication through extra headers if required
if ( forceBasicAuthentication )
{
string authInfo = string.Format( "{0}:{1}", login, password );
authInfo = Convert.ToBase64String( Encoding.Default.GetBytes( authInfo ) );
request.Headers["Authorization"] = "Basic " + authInfo;
}
// get response
response = request.GetResponse( );
// check content type
string contentType = response.ContentType;
string[] contentTypeArray = contentType.Split( '/' );
// "application/octet-stream"
if ( ( contentTypeArray[0] == "application" ) && ( contentTypeArray[1] == "octet-stream" ) )
{
boundaryLen = 0;
boundary = new byte[0];
}
else if ( ( contentTypeArray[0] == "multipart" ) && ( contentType.Contains( "mixed" ) ) )
{
// get boundary
int boundaryIndex = contentType.IndexOf( "boundary", 0 );
if ( boundaryIndex != -1 )
{
boundaryIndex = contentType.IndexOf( "=", boundaryIndex + 8 );
}
if ( boundaryIndex == -1 )
{
// try same scenario as with octet-stream, i.e. without boundaries
boundaryLen = 0;
boundary = new byte[0];
}
else
{
boudaryStr = contentType.Substring( boundaryIndex + 1 );
// remove spaces and double quotes, which may be added by some IP cameras
boudaryStr = boudaryStr.Trim( ' ', '"' );
boundary = encoding.GetBytes( boudaryStr );
boundaryLen = boundary.Length;
boundaryIsChecked = false;
}
}
else
{
throw new Exception( "Invalid content type." );
}
// get response stream
stream = response.GetResponseStream( );
stream.ReadTimeout = requestTimeout;
// loop
while ( ( !stopEvent.WaitOne( 0, false ) ) && ( !reloadEvent.WaitOne( 0, false ) ) )
{
// check total read
if ( total > bufSize - readSize )
{
total = pos = todo = 0;
}
// read next portion from stream
if ( ( read = stream.Read( buffer, total, readSize ) ) == 0 )
throw new ApplicationException( );
total += read;
todo += read;
// increment received bytes counter
bytesReceived += read;
// do we need to check boundary ?
if ( ( boundaryLen != 0 ) && ( !boundaryIsChecked ) )
{
// some IP cameras, like AirLink, claim that boundary is "myboundary",
// when it is really "--myboundary". this needs to be corrected.
pos = ByteArrayUtils.Find( buffer, boundary, 0, todo );
// continue reading if boudary was not found
if ( pos == -1 )
continue;
for ( int i = pos - 1; i >= 0; i-- )
{
byte ch = buffer[i];
if ( ( ch == (byte) '\n' ) || ( ch == (byte) '\r' ) )
{
break;
}
boudaryStr = (char) ch + boudaryStr;
}
boundary = encoding.GetBytes( boudaryStr );
boundaryLen = boundary.Length;
boundaryIsChecked = true;
}
// search for image start
if ( ( align == 1 ) && ( todo >= jpegMagicLength ) )
{
start = ByteArrayUtils.Find( buffer, jpegMagic, pos, todo );
if ( start != -1 )
{
// found JPEG start
pos = start + jpegMagicLength;
todo = total - pos;
align = 2;
}
else
{
// delimiter not found
todo = jpegMagicLength - 1;
pos = total - todo;
}
}
// search for image end ( boundaryLen can be 0, so need extra check )
while ( ( align == 2 ) && ( todo != 0 ) && ( todo >= boundaryLen ) )
{
stop = ByteArrayUtils.Find( buffer,
( boundaryLen != 0 ) ? boundary : jpegMagic,
pos, todo );
if ( stop != -1 )
{
pos = stop;
todo = total - pos;
// increment frames counter
framesReceived ++;
// image at stop
if ( ( NewFrame != null ) && ( !stopEvent.WaitOne( 0, false ) ) )
{
Bitmap bitmap = (Bitmap) Bitmap.FromStream ( new MemoryStream( buffer, start, stop - start ) );
// notify client
NewFrame( this, new NewFrameEventArgs( bitmap ) );
// release the image
bitmap.Dispose( );
bitmap = null;
}
// shift array
pos = stop + boundaryLen;
todo = total - pos;
Array.Copy( buffer, pos, buffer, 0, todo );
total = todo;
pos = 0;
align = 1;
}
else
{
// boundary not found
if ( boundaryLen != 0 )
{
todo = boundaryLen - 1;
pos = total - todo;
}
else
{
todo = 0;
pos = total;
}
}
}
}
}
catch ( ApplicationException )
{
// do nothing for Application Exception, which we raised on our own
// wait for a while before the next try
Thread.Sleep( 250 );
}
catch ( ThreadAbortException )
{
break;
}
catch ( Exception exception )
{
// provide information to clients
if ( VideoSourceError != null )
{
VideoSourceError( this, new VideoSourceErrorEventArgs( exception.Message ) );
}
// wait for a while before the next try
Thread.Sleep( 250 );
}
finally
{
// abort request
if ( request != null)
{
request.Abort( );
request = null;
}
// close response stream
if ( stream != null )
{
stream.Close( );
stream = null;
}
// close response
if ( response != null )
{
response.Close( );
response = null;
}
}
// need to stop ?
if ( stopEvent.WaitOne( 0, false ) )
break;
}
if ( PlayingFinished != null )
{
PlayingFinished( this, ReasonToFinishPlaying.StoppedByUser );
}
}
}
}

View File

@ -0,0 +1,396 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2005-2012
// contacts@aforgenet.com
//
// Copyright © César Souza, 2012
// cesarsouza@gmail.com
//
namespace AForge.Video
{
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
/// <summary>
/// Screen capture video source.
/// </summary>
///
/// <remarks><para>The video source constantly captures the desktop screen.</para>
///
/// <para>Sample usage:</para>
/// <code>
/// // get entire desktop area size
/// Rectangle screenArea = Rectangle.Empty;
/// foreach ( System.Windows.Forms.Screen screen in
/// System.Windows.Forms.Screen.AllScreens )
/// {
/// screenArea = Rectangle.Union( screenArea, screen.Bounds );
/// }
///
/// // create screen capture video source
/// ScreenCaptureStream stream = new ScreenCaptureStream( screenArea );
///
/// // set NewFrame event handler
/// stream.NewFrame += new NewFrameEventHandler( video_NewFrame );
///
/// // start the video source
/// stream.Start( );
///
/// // ...
/// // signal to stop
/// stream.SignalToStop( );
/// // ...
///
/// private void video_NewFrame( object sender, NewFrameEventArgs eventArgs )
/// {
/// // get new frame
/// Bitmap bitmap = eventArgs.Frame;
/// // process the frame
/// }
/// </code>
/// </remarks>
///
public class ScreenCaptureStream : IVideoSource
{
private Rectangle region;
// frame interval in milliseconds
private int frameInterval = 100;
// received frames count
private int framesReceived;
private Thread thread = null;
private ManualResetEvent stopEvent = null;
/// <summary>
/// New frame event.
/// </summary>
///
/// <remarks><para>Notifies clients about new available frame from video source.</para>
///
/// <para><note>Since video source may have multiple clients, each client is responsible for
/// making a copy (cloning) of the passed video frame, because the video source disposes its
/// own original copy after notifying of clients.</note></para>
/// </remarks>
///
public event NewFrameEventHandler NewFrame;
/// <summary>
/// Video source error event.
/// </summary>
///
/// <remarks>This event is used to notify clients about any type of errors occurred in
/// video source object, for example internal exceptions.</remarks>
///
public event VideoSourceErrorEventHandler VideoSourceError;
/// <summary>
/// Video playing finished event.
/// </summary>
///
/// <remarks><para>This event is used to notify clients that the video playing has finished.</para>
/// </remarks>
///
public event PlayingFinishedEventHandler PlayingFinished;
/// <summary>
/// Video source.
/// </summary>
///
public virtual string Source
{
get { return "Screen Capture"; }
}
/// <summary>
/// Gets or sets the screen capture region.
/// </summary>
///
/// <remarks><para>This property specifies which region (rectangle) of the screen to capture. It may cover multiple displays
/// if those are available in the system.</para>
///
/// <para><note>The property must be set before starting video source to have any effect.</note></para>
/// </remarks>
///
public Rectangle Region
{
get { return region; }
set { region = value; }
}
/// <summary>
/// Time interval between making screen shots, ms.
/// </summary>
///
/// <remarks><para>The property specifies time interval in milliseconds between consequent screen captures.
/// Expected frame rate of the stream should be approximately 1000/FrameInteval.</para>
///
/// <para>If the property is set to 0, then the stream will capture screen as fast as the system allows.</para>
///
/// <para>Default value is set to <b>100</b>.</para>
/// </remarks>
///
public int FrameInterval
{
get { return frameInterval; }
set { frameInterval = Math.Max( 0, value ); }
}
/// <summary>
/// Received frames count.
/// </summary>
///
/// <remarks>Number of frames the video source provided from the moment of the last
/// access to the property.
/// </remarks>
///
public int FramesReceived
{
get
{
int frames = framesReceived;
framesReceived = 0;
return frames;
}
}
/// <summary>
/// Received bytes count.
/// </summary>
///
/// <remarks><para><note>The property is not implemented for this video source and always returns 0.</note></para>
/// </remarks>
///
public long BytesReceived
{
get { return 0; }
}
/// <summary>
/// State of the video source.
/// </summary>
///
/// <remarks>Current state of video source object - running or not.</remarks>
///
public bool IsRunning
{
get
{
if ( thread != null )
{
// check thread status
if ( thread.Join( 0 ) == false )
return true;
// the thread is not running, free resources
Free( );
}
return false;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ScreenCaptureStream"/> class.
/// </summary>
///
/// <param name="region">Screen's rectangle to capture (the rectangle may cover multiple displays).</param>
///
public ScreenCaptureStream( Rectangle region )
{
this.region = region;
}
/// <summary>
/// Initializes a new instance of the <see cref="ScreenCaptureStream"/> class.
/// </summary>
///
/// <param name="region">Screen's rectangle to capture (the rectangle may cover multiple displays).</param>
/// <param name="frameInterval">Time interval between making screen shots, ms.</param>
///
public ScreenCaptureStream( Rectangle region, int frameInterval )
{
this.region = region;
this.FrameInterval = frameInterval;
}
/// <summary>
/// Start video source.
/// </summary>
///
/// <remarks>Starts video source and return execution to caller. Video source
/// object creates background thread and notifies about new frames with the
/// help of <see cref="NewFrame"/> event.</remarks>
///
/// <exception cref="ArgumentException">Video source is not specified.</exception>
///
public void Start( )
{
if ( !IsRunning )
{
framesReceived = 0;
// create events
stopEvent = new ManualResetEvent( false );
// create and start new thread
thread = new Thread( new ThreadStart( WorkerThread ) );
thread.Name = Source; // mainly for debugging
thread.Start( );
}
}
/// <summary>
/// Signal video source to stop its work.
/// </summary>
///
/// <remarks>Signals video source to stop its background thread, stop to
/// provide new frames and free resources.</remarks>
///
public void SignalToStop( )
{
// stop thread
if ( thread != null )
{
// signal to stop
stopEvent.Set( );
}
}
/// <summary>
/// Wait for video source has stopped.
/// </summary>
///
/// <remarks>Waits for source stopping after it was signalled to stop using
/// <see cref="SignalToStop"/> method.</remarks>
///
public void WaitForStop( )
{
if ( thread != null )
{
// wait for thread stop
thread.Join( );
Free( );
}
}
/// <summary>
/// Stop video source.
/// </summary>
///
/// <remarks><para>Stops video source aborting its thread.</para>
///
/// <para><note>Since the method aborts background thread, its usage is highly not preferred
/// and should be done only if there are no other options. The correct way of stopping camera
/// is <see cref="SignalToStop">signaling it stop</see> and then
/// <see cref="WaitForStop">waiting</see> for background thread's completion.</note></para>
/// </remarks>
///
public void Stop( )
{
if ( this.IsRunning )
{
stopEvent.Set( );
thread.Abort( );
WaitForStop( );
}
}
/// <summary>
/// Free resource.
/// </summary>
///
private void Free( )
{
thread = null;
// release events
stopEvent.Close( );
stopEvent = null;
}
// Worker thread
private void WorkerThread( )
{
int width = region.Width;
int height = region.Height;
int x = region.Location.X;
int y = region.Location.Y;
Size size = region.Size;
Bitmap bitmap = new Bitmap( width, height, PixelFormat.Format32bppArgb );
Graphics graphics = Graphics.FromImage( bitmap );
// download start time and duration
DateTime start;
TimeSpan span;
while ( !stopEvent.WaitOne( 0, false ) )
{
// set dowbload start time
start = DateTime.Now;
try
{
// capture the screen
graphics.CopyFromScreen( x, y, 0, 0, size, CopyPixelOperation.SourceCopy );
// increment frames counter
framesReceived++;
// provide new image to clients
if ( NewFrame != null )
{
// notify client
NewFrame( this, new NewFrameEventArgs( bitmap ) );
}
// wait for a while ?
if ( frameInterval > 0 )
{
// get download duration
span = DateTime.Now.Subtract( start );
// miliseconds to sleep
int msec = frameInterval - (int) span.TotalMilliseconds;
if ( ( msec > 0 ) && ( stopEvent.WaitOne( msec, false ) ) )
break;
}
}
catch ( ThreadAbortException )
{
break;
}
catch ( Exception exception )
{
// provide information to clients
if ( VideoSourceError != null )
{
VideoSourceError( this, new VideoSourceErrorEventArgs( exception.Message ) );
}
// wait for a while before the next try
Thread.Sleep( 250 );
}
// need to stop ?
if ( stopEvent.WaitOne( 0, false ) )
break;
}
// release resources
graphics.Dispose( );
bitmap.Dispose( );
if ( PlayingFinished != null )
{
PlayingFinished( this, ReasonToFinishPlaying.StoppedByUser );
}
}
}
}

View File

@ -0,0 +1,164 @@
// AForge Core Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2007-2011
// contacts@aforgenet.com
//
namespace AForge
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Set of systems tools.
/// </summary>
///
/// <remarks><para>The class is a container of different system tools, which are used
/// across the framework. Some of these tools are platform specific, so their
/// implementation is different on different platform, like .NET and Mono.</para>
/// </remarks>
///
public static class SystemTools
{
/// <summary>
/// Copy block of unmanaged memory.
/// </summary>
///
/// <param name="dst">Destination pointer.</param>
/// <param name="src">Source pointer.</param>
/// <param name="count">Memory block's length to copy.</param>
///
/// <returns>Return's value of <paramref name="dst"/> - pointer to destination.</returns>
///
/// <remarks><para>This function is required because of the fact that .NET does
/// not provide any way to copy unmanaged blocks, but provides only methods to
/// copy from unmanaged memory to managed memory and vise versa.</para></remarks>
///
public static IntPtr CopyUnmanagedMemory( IntPtr dst, IntPtr src, int count )
{
unsafe
{
CopyUnmanagedMemory( (byte*) dst.ToPointer( ), (byte*) src.ToPointer( ), count );
}
return dst;
}
/// <summary>
/// Copy block of unmanaged memory.
/// </summary>
///
/// <param name="dst">Destination pointer.</param>
/// <param name="src">Source pointer.</param>
/// <param name="count">Memory block's length to copy.</param>
///
/// <returns>Return's value of <paramref name="dst"/> - pointer to destination.</returns>
///
/// <remarks><para>This function is required because of the fact that .NET does
/// not provide any way to copy unmanaged blocks, but provides only methods to
/// copy from unmanaged memory to managed memory and vise versa.</para></remarks>
///
public static unsafe byte* CopyUnmanagedMemory( byte* dst, byte* src, int count )
{
#if !MONO
return memcpy( dst, src, count );
#else
int countUint = count >> 2;
int countByte = count & 3;
uint* dstUint = (uint*) dst;
uint* srcUint = (uint*) src;
while ( countUint-- != 0 )
{
*dstUint++ = *srcUint++;
}
byte* dstByte = (byte*) dstUint;
byte* srcByte = (byte*) srcUint;
while ( countByte-- != 0 )
{
*dstByte++ = *srcByte++;
}
return dst;
#endif
}
/// <summary>
/// Fill memory region with specified value.
/// </summary>
///
/// <param name="dst">Destination pointer.</param>
/// <param name="filler">Filler byte's value.</param>
/// <param name="count">Memory block's length to fill.</param>
///
/// <returns>Return's value of <paramref name="dst"/> - pointer to destination.</returns>
///
public static IntPtr SetUnmanagedMemory( IntPtr dst, int filler, int count )
{
unsafe
{
SetUnmanagedMemory( (byte*) dst.ToPointer( ), filler, count );
}
return dst;
}
/// <summary>
/// Fill memory region with specified value.
/// </summary>
///
/// <param name="dst">Destination pointer.</param>
/// <param name="filler">Filler byte's value.</param>
/// <param name="count">Memory block's length to fill.</param>
///
/// <returns>Return's value of <paramref name="dst"/> - pointer to destination.</returns>
///
public static unsafe byte* SetUnmanagedMemory( byte* dst, int filler, int count )
{
#if !MONO
return memset( dst, filler, count );
#else
int countUint = count >> 2;
int countByte = count & 3;
byte fillerByte = (byte) filler;
uint fiilerUint = (uint) filler | ( (uint) filler << 8 ) |
( (uint) filler << 16 );// |
//( (uint) filler << 24 );
uint* dstUint = (uint*) dst;
while ( countUint-- != 0 )
{
*dstUint++ = fiilerUint;
}
byte* dstByte = (byte*) dstUint;
while ( countByte-- != 0 )
{
*dstByte++ = fillerByte;
}
return dst;
#endif
}
#if !MONO
// Win32 memory copy function
[DllImport( "ntdll.dll", CallingConvention = CallingConvention.Cdecl )]
private static unsafe extern byte* memcpy(
byte* dst,
byte* src,
int count );
// Win32 memory set function
[DllImport( "ntdll.dll", CallingConvention = CallingConvention.Cdecl )]
private static unsafe extern byte* memset(
byte* dst,
int filler,
int count );
#endif
}
}

View File

@ -0,0 +1,125 @@
// AForge Video Library
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
// Copyright © AForge.NET, 2009-2011
// contacts@aforgenet.com
//
namespace AForge.Video
{
using System;
/// <summary>
/// Delegate for new frame event handler.
/// </summary>
///
/// <param name="sender">Sender object.</param>
/// <param name="eventArgs">Event arguments.</param>
///
public delegate void NewFrameEventHandler( object sender, NewFrameEventArgs eventArgs );
/// <summary>
/// Delegate for video source error event handler.
/// </summary>
///
/// <param name="sender">Sender object.</param>
/// <param name="eventArgs">Event arguments.</param>
///
public delegate void VideoSourceErrorEventHandler( object sender, VideoSourceErrorEventArgs eventArgs );
/// <summary>
/// Delegate for playing finished event handler.
/// </summary>
///
/// <param name="sender">Sender object.</param>
/// <param name="reason">Reason of finishing video playing.</param>
///
public delegate void PlayingFinishedEventHandler( object sender, ReasonToFinishPlaying reason );
/// <summary>
/// Reason of finishing video playing.
/// </summary>
///
/// <remarks><para>When video source class fire the <see cref="IVideoSource.PlayingFinished"/> event, they
/// need to specify reason of finishing video playing. For example, it may be end of stream reached.</para></remarks>
///
public enum ReasonToFinishPlaying
{
/// <summary>
/// Video playing has finished because it end was reached.
/// </summary>
EndOfStreamReached,
/// <summary>
/// Video playing has finished because it was stopped by user.
/// </summary>
StoppedByUser,
/// <summary>
/// Video playing has finished because the device was lost (unplugged).
/// </summary>
DeviceLost,
/// <summary>
/// Video playing has finished because of some error happened the video source (camera, stream, file, etc.).
/// A error reporting event usually is fired to provide error information.
/// </summary>
VideoSourceError
}
/// <summary>
/// Arguments for new frame event from video source.
/// </summary>
///
public class NewFrameEventArgs : EventArgs
{
private System.Drawing.Bitmap frame;
/// <summary>
/// Initializes a new instance of the <see cref="NewFrameEventArgs"/> class.
/// </summary>
///
/// <param name="frame">New frame.</param>
///
public NewFrameEventArgs( System.Drawing.Bitmap frame )
{
this.frame = frame;
}
/// <summary>
/// New frame from video source.
/// </summary>
///
public System.Drawing.Bitmap Frame
{
get { return frame; }
}
}
/// <summary>
/// Arguments for video source error event from video source.
/// </summary>
///
public class VideoSourceErrorEventArgs : EventArgs
{
private string description;
/// <summary>
/// Initializes a new instance of the <see cref="VideoSourceErrorEventArgs"/> class.
/// </summary>
///
/// <param name="description">Error description.</param>
///
public VideoSourceErrorEventArgs( string description )
{
this.description = description;
}
/// <summary>
/// Video source error description.
/// </summary>
///
public string Description
{
get { return description; }
}
}
}

View File

@ -12,7 +12,8 @@ using System.Collections.Generic;
using xClient.Core.Data;
using xClient.Core.Recovery.Browsers;
using xClient.Core.Recovery.FtpClients;
using AForge.Video.DirectShow;
using AForge.Video;
namespace xClient.Core.Commands
{
/* THIS PARTIAL CLASS SHOULD CONTAIN METHODS THAT HANDLE SURVEILLANCE COMMANDS. */

View File

@ -0,0 +1,84 @@
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using xClient.Core.Helper;
using System.Drawing.Imaging;
using System.Threading;
using xClient.Core.Networking;
using xClient.Core.Utilities;
using xClient.Enums;
using System.Collections.Generic;
using xClient.Core.Data;
using xClient.Core.Recovery.Browsers;
using xClient.Core.Recovery.FtpClients;
using AForge.Video.DirectShow;
using AForge.Video;
namespace xClient.Core.Commands
{
/* THIS PARTIAL CLASS SHOULD CONTAIN METHODS THAT HANDLE WEBCAM COMMANDS. */
public static partial class CommandHandler
{
public static bool webcamStarted = false;
public static bool needsCapture = false;
public static Client _client;
public static int webcam;
public static VideoCaptureDevice FinalVideo;
public static void HandleGetWebcams(Packets.ServerPackets.GetWebcams command, Client client)
{
List<string> result = new List<string>();
FilterInfoCollection VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
{
result.Add(VideoCaptureDevice.Name);
}
if (result.Count > 0)
new Packets.ClientPackets.GetWebcamsResponse(result).Execute(client);
}
public static void HandleGetWebcam(Packets.ServerPackets.GetWebcam command, Client client)
{
_client = client;
needsCapture = true;
webcam = command.Webcam;
if (!webcamStarted)
{
FilterInfoCollection VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[command.Webcam].MonikerString);
FinalVideo.NewFrame += FinalVideo_NewFrame;
FinalVideo.Start();
webcamStarted = true;
}
}
public static void HandleDoWebcamStop(Packets.ServerPackets.DoWebcamStop command, Client client)
{
needsCapture = false;
webcamStarted = false;
FinalVideo.NewFrame -= FinalVideo_NewFrame;
FinalVideo.Stop();
}
private static void FinalVideo_NewFrame(object sender, NewFrameEventArgs e)
{
if (!webcamStarted)
FinalVideo.Stop();
if (needsCapture)
{
byte[] imagegeBytes = new byte[0];
Bitmap image = (Bitmap)e.Frame.Clone();
using (MemoryStream stream = new MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
new Packets.ClientPackets.GetWebcamResponse(stream.ToArray(), webcam).Execute(_client);
stream.Close();
}
needsCapture = false;
}
}
}
}

View File

@ -30,6 +30,7 @@ namespace xClient.Core.Networking
typeof (Packets.ServerPackets.DoClientDisconnect),
typeof (Packets.ServerPackets.DoClientReconnect),
typeof (Packets.ServerPackets.DoClientUninstall),
typeof (Packets.ServerPackets.DoWebcamStop),
typeof (Packets.ServerPackets.DoAskElevate),
typeof (Packets.ServerPackets.DoDownloadAndExecute),
typeof (Packets.ServerPackets.DoUploadAndExecute),
@ -47,6 +48,8 @@ namespace xClient.Core.Networking
typeof (Packets.ServerPackets.DoShowMessageBox),
typeof (Packets.ServerPackets.DoClientUpdate),
typeof (Packets.ServerPackets.GetMonitors),
typeof (Packets.ServerPackets.GetWebcams),
typeof (Packets.ServerPackets.GetWebcam),
typeof (Packets.ServerPackets.DoShellExecute),
typeof (Packets.ServerPackets.DoPathRename),
typeof (Packets.ServerPackets.DoPathDelete),
@ -80,6 +83,8 @@ namespace xClient.Core.Networking
typeof (Packets.ClientPackets.DoDownloadFileResponse),
typeof (Packets.ClientPackets.GetSystemInfoResponse),
typeof (Packets.ClientPackets.GetMonitorsResponse),
typeof (Packets.ClientPackets.GetWebcamsResponse),
typeof (Packets.ClientPackets.GetWebcamResponse),
typeof (Packets.ClientPackets.DoShellExecuteResponse),
typeof (Packets.ClientPackets.GetStartupItemsResponse),
typeof (Packets.ClientPackets.GetKeyloggerLogsResponse),

View File

@ -0,0 +1,28 @@
using System;
using System.Drawing;
using xClient.Core.Networking;
namespace xClient.Core.Packets.ClientPackets
{
[Serializable]
public class GetWebcamResponse : IPacket
{
public byte[] Image { get; set; }
public int Webcam { get; set; }
public GetWebcamResponse()
{
}
public GetWebcamResponse(byte[] image, int webcam)
{
this.Image = image;
this.Webcam = webcam;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using xClient.Core.Networking;
namespace xClient.Core.Packets.ClientPackets
{
[Serializable]
public class GetWebcamsResponse : IPacket
{
public List<string> Names { get; set; }
public GetWebcamsResponse()
{
}
public GetWebcamsResponse(List<string> names)
{
this.Names = names;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -9,7 +9,6 @@ namespace xClient.Core.Packets
public static void HandlePacket(Client client, IPacket packet)
{
var type = packet.GetType();
if (type == typeof(ServerPackets.DoDownloadAndExecute))
{
CommandHandler.HandleDoDownloadAndExecute((ServerPackets.DoDownloadAndExecute)packet,
@ -39,6 +38,10 @@ namespace xClient.Core.Packets
{
CommandHandler.HandleGetDesktop((ServerPackets.GetDesktop)packet, client);
}
else if (type == typeof(ServerPackets.GetWebcam))
{
CommandHandler.HandleGetWebcam((ServerPackets.GetWebcam)packet, client);
}
else if (type == typeof(ServerPackets.GetProcesses))
{
CommandHandler.HandleGetProcesses((ServerPackets.GetProcesses)packet, client);
@ -47,6 +50,10 @@ namespace xClient.Core.Packets
{
CommandHandler.HandleDoProcessKill((ServerPackets.DoProcessKill)packet, client);
}
else if (type == typeof(ServerPackets.DoWebcamStop))
{
CommandHandler.HandleDoWebcamStop((ServerPackets.DoWebcamStop)packet, client);
}
else if (type == typeof(ServerPackets.DoProcessStart))
{
CommandHandler.HandleDoProcessStart((ServerPackets.DoProcessStart)packet, client);
@ -91,6 +98,10 @@ namespace xClient.Core.Packets
{
CommandHandler.HandleDoClientUpdate((ServerPackets.DoClientUpdate)packet, client);
}
else if (type == typeof(ServerPackets.GetWebcams))
{
CommandHandler.HandleGetWebcams((ServerPackets.GetWebcams)packet, client);
}
else if (type == typeof(ServerPackets.GetMonitors))
{
CommandHandler.HandleGetMonitors((ServerPackets.GetMonitors)packet, client);

View File

@ -0,0 +1,18 @@
using System;
using xClient.Core.Networking;
namespace xClient.Core.Packets.ServerPackets
{
[Serializable]
public class DoWebcamStop : IPacket
{
public DoWebcamStop()
{
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using xClient.Core.Networking;
namespace xClient.Core.Packets.ServerPackets
{
[Serializable]
public class GetWebcam : IPacket
{
public int Webcam { get; set; }
public GetWebcam()
{
}
public GetWebcam(int webcam)
{
this.Webcam = webcam;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using xClient.Core.Networking;
namespace xClient.Core.Packets.ServerPackets
{
[Serializable]
public class GetWebcams : IPacket
{
public GetWebcams()
{
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Drawing;
using System.Threading;
using xServer.Core.Data;
using xServer.Core.Helper;
@ -172,5 +173,35 @@ namespace xServer.Core.Commands
client.Value.FrmRdp.AddMonitors(packet.Number);
}
public static void HandleGetWebcamsResponse(Client client, GetWebcamsResponse packet)
{
if (client.Value == null || client.Value.FrmWebcam == null)
return;
client.Value.FrmWebcam.AddWebcams(packet.Names);
}
public static void HandleGetWebcamResponse(Client client, GetWebcamResponse packet)
{
if (client.Value == null || client.Value.FrmWebcam == null
|| client.Value.FrmWebcam.IsDisposed
|| client.Value.FrmWebcam.Disposing)
return;
if (packet.Image == null)
return;
using (MemoryStream ms = new MemoryStream(packet.Image))
{
Bitmap img = new Bitmap(ms);
client.Value.FrmWebcam.UpdateImage(img);
}
if (client.Value != null && client.Value.FrmWebcam != null && client.Value.FrmWebcam.IsStarted)
{
new GetWebcam(packet.Webcam).Execute(client);
}
}
}
}

View File

@ -77,6 +77,7 @@ namespace xServer.Core.Networking
typeof (Packets.ServerPackets.DoClientDisconnect),
typeof (Packets.ServerPackets.DoClientReconnect),
typeof (Packets.ServerPackets.DoClientUninstall),
typeof (Packets.ServerPackets.DoWebcamStop),
typeof (Packets.ServerPackets.DoAskElevate),
typeof (Packets.ServerPackets.DoDownloadAndExecute),
typeof (Packets.ServerPackets.DoUploadAndExecute),
@ -94,6 +95,8 @@ namespace xServer.Core.Networking
typeof (Packets.ServerPackets.DoShowMessageBox),
typeof (Packets.ServerPackets.DoClientUpdate),
typeof (Packets.ServerPackets.GetMonitors),
typeof (Packets.ServerPackets.GetWebcams),
typeof (Packets.ServerPackets.GetWebcam),
typeof (Packets.ServerPackets.DoShellExecute),
typeof (Packets.ServerPackets.DoPathRename),
typeof (Packets.ServerPackets.DoPathDelete),
@ -127,6 +130,8 @@ namespace xServer.Core.Networking
typeof (Packets.ClientPackets.DoDownloadFileResponse),
typeof (Packets.ClientPackets.GetSystemInfoResponse),
typeof (Packets.ClientPackets.GetMonitorsResponse),
typeof (Packets.ClientPackets.GetWebcamsResponse),
typeof (Packets.ClientPackets.GetWebcamResponse),
typeof (Packets.ClientPackets.DoShellExecuteResponse),
typeof (Packets.ClientPackets.GetStartupItemsResponse),
typeof (Packets.ClientPackets.GetKeyloggerLogsResponse),

View File

@ -25,6 +25,7 @@ namespace xServer.Core.Networking
public string DownloadDirectory { get; set; }
public FrmRemoteDesktop FrmRdp { get; set; }
public FrmRemoteWebcam FrmWebcam { get; set; }
public FrmTaskManager FrmTm { get; set; }
public FrmFileManager FrmFm { get; set; }
public FrmRegistryEditor FrmRe { get; set; }

View File

@ -0,0 +1,29 @@
using System;
using System.Drawing;
using xServer.Core.Networking;
namespace xServer.Core.Packets.ClientPackets
{
[Serializable]
public class GetWebcamResponse : IPacket
{
public byte[] Image { get; set; }
public int Webcam { get; set; }
public GetWebcamResponse()
{
}
public GetWebcamResponse(byte[] image, int webcam)
{
this.Image = image;
this.Webcam = webcam;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using xServer.Core.Networking;
namespace xServer.Core.Packets.ClientPackets
{
[Serializable]
public class GetWebcamsResponse : IPacket
{
public List<string> Names { get; set; }
public GetWebcamsResponse()
{
}
public GetWebcamsResponse(List<string> names)
{
this.Names = names;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -52,6 +52,14 @@ namespace xServer.Core.Packets
{
CommandHandler.HandleGetMonitorsResponse(client, (ClientPackets.GetMonitorsResponse)packet);
}
else if (type == typeof(ClientPackets.GetWebcamsResponse))
{
CommandHandler.HandleGetWebcamsResponse(client, (ClientPackets.GetWebcamsResponse)packet);
}
else if (type == typeof(ClientPackets.GetWebcamResponse))
{
CommandHandler.HandleGetWebcamResponse(client, (ClientPackets.GetWebcamResponse)packet);
}
else if (type == typeof(ClientPackets.DoShellExecuteResponse))
{
CommandHandler.HandleDoShellExecuteResponse(client,

View File

@ -0,0 +1,18 @@
using System;
using xServer.Core.Networking;
namespace xServer.Core.Packets.ServerPackets
{
[Serializable]
public class DoWebcamStop : IPacket
{
public DoWebcamStop()
{
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using xServer.Core.Networking;
namespace xServer.Core.Packets.ServerPackets
{
[Serializable]
public class GetWebcam : IPacket
{
public int Webcam { get; set; }
public GetWebcam()
{
}
public GetWebcam(int webcam)
{
this.Webcam = webcam;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using xServer.Core.Networking;
namespace xServer.Core.Packets.ServerPackets
{
[Serializable]
public class GetWebcams : IPacket
{
public GetWebcams()
{
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -86,6 +86,7 @@ namespace xServer.Forms
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.builderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.remoteWebcamToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip.SuspendLayout();
this.tableLayoutPanel.SuspendLayout();
this.statusStrip.SuspendLayout();
@ -113,7 +114,7 @@ namespace xServer.Forms
this.uninstallToolStripMenuItem});
this.connectionToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("connectionToolStripMenuItem.Image")));
this.connectionToolStripMenuItem.Name = "connectionToolStripMenuItem";
this.connectionToolStripMenuItem.Size = new System.Drawing.Size(149, 22);
this.connectionToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.connectionToolStripMenuItem.Text = "Connection";
//
// updateToolStripMenuItem
@ -164,7 +165,7 @@ namespace xServer.Forms
this.actionsToolStripMenuItem});
this.systemToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("systemToolStripMenuItem.Image")));
this.systemToolStripMenuItem.Name = "systemToolStripMenuItem";
this.systemToolStripMenuItem.Size = new System.Drawing.Size(149, 22);
this.systemToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.systemToolStripMenuItem.Text = "System";
//
// systemInformationToolStripMenuItem
@ -210,7 +211,7 @@ namespace xServer.Forms
// connectionsToolStripMenuItem
//
this.connectionsToolStripMenuItem.Name = "connectionsToolStripMenuItem";
this.connectionsToolStripMenuItem.Size = new System.Drawing.Size(178, 22);
this.connectionsToolStripMenuItem.Size = new System.Drawing.Size(211, 22);
this.connectionsToolStripMenuItem.Text = "TCP Connections";
this.connectionsToolStripMenuItem.Click += new System.EventHandler(this.connectionsToolStripMenuItem_Click);
//
@ -282,11 +283,12 @@ namespace xServer.Forms
//
this.surveillanceToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.remoteDesktopToolStripMenuItem,
this.remoteWebcamToolStripMenuItem,
this.passwordRecoveryToolStripMenuItem,
this.keyloggerToolStripMenuItem});
this.surveillanceToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("surveillanceToolStripMenuItem.Image")));
this.surveillanceToolStripMenuItem.Name = "surveillanceToolStripMenuItem";
this.surveillanceToolStripMenuItem.Size = new System.Drawing.Size(149, 22);
this.surveillanceToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.surveillanceToolStripMenuItem.Text = "Surveillance";
//
// remoteDesktopToolStripMenuItem
@ -321,7 +323,7 @@ namespace xServer.Forms
this.showMessageboxToolStripMenuItem});
this.miscellaneousToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("miscellaneousToolStripMenuItem.Image")));
this.miscellaneousToolStripMenuItem.Name = "miscellaneousToolStripMenuItem";
this.miscellaneousToolStripMenuItem.Size = new System.Drawing.Size(149, 22);
this.miscellaneousToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.miscellaneousToolStripMenuItem.Text = "Miscellaneous";
//
// remoteExecuteToolStripMenuItem
@ -369,14 +371,13 @@ namespace xServer.Forms
// lineToolStripMenuItem
//
this.lineToolStripMenuItem.Name = "lineToolStripMenuItem";
this.lineToolStripMenuItem.Size = new System.Drawing.Size(146, 6);
this.lineToolStripMenuItem.Size = new System.Drawing.Size(149, 6);
//
// selectAllToolStripMenuItem
//
this.selectAllToolStripMenuItem.Name = "selectAllToolStripMenuItem";
this.selectAllToolStripMenuItem.Size = new System.Drawing.Size(149, 22);
this.selectAllToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.selectAllToolStripMenuItem.Text = "Select All";
this.selectAllToolStripMenuItem.Click += new System.EventHandler(this.selectAllToolStripMenuItem_Click);
//
// imgFlags
//
@ -796,6 +797,13 @@ namespace xServer.Forms
this.aboutToolStripMenuItem.Text = "About";
this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
//
// remoteWebcamToolStripMenuItem
//
this.remoteWebcamToolStripMenuItem.Name = "remoteWebcamToolStripMenuItem";
this.remoteWebcamToolStripMenuItem.Size = new System.Drawing.Size(175, 22);
this.remoteWebcamToolStripMenuItem.Text = "Remote Webcam";
this.remoteWebcamToolStripMenuItem.Click += new System.EventHandler(this.remoteWebcamToolStripMenuItem_Click);
//
// FrmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -878,6 +886,7 @@ namespace xServer.Forms
private System.Windows.Forms.ToolStripStatusLabel listenToolStripStatusLabel;
private System.Windows.Forms.ToolStripMenuItem elevateClientPermissionsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem connectionsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem remoteWebcamToolStripMenuItem;
}
}

View File

@ -692,7 +692,19 @@ namespace xServer.Forms
frmRDP.Show();
}
}
private void remoteWebcamToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Client c in GetSelectedClients())
{
if (c.Value.FrmWebcam != null)
{
c.Value.FrmWebcam.Focus();
return;
}
FrmRemoteWebcam FrmWebcam = new FrmRemoteWebcam(c);
FrmWebcam.Show();
}
}
private void passwordRecoveryToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Client c in GetSelectedClients())
@ -835,10 +847,7 @@ namespace xServer.Forms
#endregion
private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
{
lstClients.SelectAllItems();
}
#endregion
@ -890,5 +899,7 @@ namespace xServer.Forms
}
#endregion
}
}

View File

@ -405,7 +405,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADY
sQAAAk1TRnQBSQFMAgEB+AEAAaABCAGgAQgBEAEAAQsBAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
sQAAAk1TRnQBSQFMAgEB+AEAAbgBCAG4AQgBEAEAAQsBAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAAbUBAgIAAQEBAAEIBQABQAGtGAABgAIAAYADAAKAAQABgAMAAYABAAGAAQACgAIAA8ABAAHA
AdwBwAEAAfABygGmAQABMwUAATMBAAEzAQABMwEAAjMCAAMWAQADHAEAAyIBAAMpAQADVQEAA00BAANC
AQADOQEAAYABfAH/AQACUAH/AQABkwEAAdYBAAH/AewBzAEAAcYB1gHvAQAB1gLnAQABkAGpAa0CAAH/

158
Server/Forms/FrmRemoteWebcam.Designer.cs generated Normal file
View File

@ -0,0 +1,158 @@
namespace xServer.Forms
{
partial class FrmRemoteWebcam
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmRemoteWebcam));
this.btnShow = new System.Windows.Forms.Button();
this.panelTop = new System.Windows.Forms.Panel();
this.cbWebcams = new System.Windows.Forms.ComboBox();
this.btnHide = new System.Windows.Forms.Button();
this.btnStart = new System.Windows.Forms.Button();
this.btnStop = new System.Windows.Forms.Button();
this.picWebcam = new xServer.Controls.RapidPictureBox();
this.panelTop.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picWebcam)).BeginInit();
this.SuspendLayout();
//
// btnShow
//
this.btnShow.Location = new System.Drawing.Point(389, 84);
this.btnShow.Name = "btnShow";
this.btnShow.Size = new System.Drawing.Size(54, 19);
this.btnShow.TabIndex = 10;
this.btnShow.TabStop = false;
this.btnShow.Text = "Show";
this.btnShow.UseVisualStyleBackColor = true;
this.btnShow.Visible = false;
this.btnShow.Click += new System.EventHandler(this.btnShow_Click);
//
// panelTop
//
this.panelTop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelTop.Controls.Add(this.cbWebcams);
this.panelTop.Controls.Add(this.btnHide);
this.panelTop.Controls.Add(this.btnStart);
this.panelTop.Controls.Add(this.btnStop);
this.panelTop.Location = new System.Drawing.Point(330, 0);
this.panelTop.Name = "panelTop";
this.panelTop.Size = new System.Drawing.Size(181, 76);
this.panelTop.TabIndex = 9;
//
// cbWebcams
//
this.cbWebcams.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cbWebcams.FormattingEnabled = true;
this.cbWebcams.Location = new System.Drawing.Point(15, 30);
this.cbWebcams.Name = "cbWebcams";
this.cbWebcams.Size = new System.Drawing.Size(149, 21);
this.cbWebcams.TabIndex = 8;
this.cbWebcams.TabStop = false;
//
// btnHide
//
this.btnHide.Location = new System.Drawing.Point(57, 54);
this.btnHide.Name = "btnHide";
this.btnHide.Size = new System.Drawing.Size(54, 19);
this.btnHide.TabIndex = 7;
this.btnHide.TabStop = false;
this.btnHide.Text = "Hide";
this.btnHide.UseVisualStyleBackColor = true;
this.btnHide.Click += new System.EventHandler(this.btnHide_Click);
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(15, 5);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(68, 23);
this.btnStart.TabIndex = 1;
this.btnStart.TabStop = false;
this.btnStart.Text = "Start";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// btnStop
//
this.btnStop.Enabled = false;
this.btnStop.Location = new System.Drawing.Point(96, 5);
this.btnStop.Name = "btnStop";
this.btnStop.Size = new System.Drawing.Size(68, 23);
this.btnStop.TabIndex = 2;
this.btnStop.TabStop = false;
this.btnStop.Text = "Stop";
this.btnStop.UseVisualStyleBackColor = true;
this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
//
// picWebcam
//
this.picWebcam.BackColor = System.Drawing.Color.Black;
this.picWebcam.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.picWebcam.Cursor = System.Windows.Forms.Cursors.Default;
this.picWebcam.Dock = System.Windows.Forms.DockStyle.Fill;
this.picWebcam.GetImageSafe = null;
this.picWebcam.Location = new System.Drawing.Point(0, 0);
this.picWebcam.Name = "picWebcam";
this.picWebcam.Running = false;
this.picWebcam.Size = new System.Drawing.Size(794, 562);
this.picWebcam.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picWebcam.TabIndex = 1;
this.picWebcam.TabStop = false;
//
// FrmRemoteWebcam
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(794, 562);
this.Controls.Add(this.btnShow);
this.Controls.Add(this.panelTop);
this.Controls.Add(this.picWebcam);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(480, 320);
this.Name = "FrmRemoteWebcam";
this.Text = "FrmRemoteWebcam []";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmRemoteWebcam_FormClosing);
this.Load += new System.EventHandler(this.FrmRemoteWebcam_Load);
this.Resize += new System.EventHandler(this.FrmRemoteWebcam_Resize);
this.panelTop.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picWebcam)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Controls.RapidPictureBox picWebcam;
private System.Windows.Forms.Button btnShow;
private System.Windows.Forms.Panel panelTop;
private System.Windows.Forms.ComboBox cbWebcams;
private System.Windows.Forms.Button btnHide;
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Button btnStop;
}
}

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using xServer.Core.Helper;
using xServer.Core.Networking;
using xServer.Core.Utilities;
using xServer.Enums;
namespace xServer.Forms
{
public partial class FrmRemoteWebcam : Form
{
public bool IsStarted { get; private set; }
private readonly Client _connectClient;
public FrmRemoteWebcam(Client c)
{
_connectClient = c;
_connectClient.Value.FrmWebcam = this;
InitializeComponent();
}
private void btnShow_Click(object sender, EventArgs e)
{
panelTop.Visible = true;
btnShow.Visible = false;
btnHide.Visible = true;
this.ActiveControl = picWebcam;
}
private void btnHide_Click(object sender, EventArgs e)
{
panelTop.Visible = false;
btnShow.Visible = true;
btnHide.Visible = false;
this.ActiveControl = picWebcam;
}
private void FrmRemoteWebcam_Load(object sender, EventArgs e)
{
this.Text = WindowHelper.GetWindowTitle("Remote Webcam", _connectClient);
panelTop.Left = (this.Width / 2) - (panelTop.Width / 2);
btnHide.Left = (panelTop.Width / 2) - (btnHide.Width / 2);
btnShow.Location = new Point(377, 0);
btnShow.Left = (this.Width / 2) - (btnShow.Width / 2);
if (_connectClient.Value != null)
new Core.Packets.ServerPackets.GetWebcams().Execute(_connectClient);
}
public void AddWebcams(List<string> names)
{
try
{
cbWebcams.Invoke((MethodInvoker)delegate
{
for (int i = 0; i < names.Count; i++)
cbWebcams.Items.Add(string.Format("{0}",names[i]));
cbWebcams.SelectedIndex = 0;
});
}
catch (InvalidOperationException)
{
}
}
public void UpdateImage(Bitmap bmp, bool cloneBitmap = false)
{
picWebcam.Image = new Bitmap(bmp, picWebcam.Width, picWebcam.Height);
}
private void btnStart_Click(object sender, EventArgs e)
{
if (cbWebcams.Items.Count == 0)
{
MessageBox.Show("No webcam detected.\nPlease wait till the client sends a list with available webcams.",
"Starting failed", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
ToggleControls(false);
this.ActiveControl = picWebcam;
new Core.Packets.ServerPackets.GetWebcam(cbWebcams.SelectedIndex).Execute(_connectClient);
}
public void ToggleControls(bool state)
{
IsStarted = !state;
cbWebcams.Enabled = btnStart.Enabled = state;
btnStop.Enabled = !state;
}
private void FrmRemoteWebcam_FormClosing(object sender, FormClosingEventArgs e)
{
if (_connectClient.Value != null)
_connectClient.Value.FrmWebcam = null;
}
private void FrmRemoteWebcam_Resize(object sender, EventArgs e)
{
panelTop.Left = (this.Width / 2) - (panelTop.Width / 2);
btnShow.Left = (this.Width / 2) - (btnShow.Width / 2);
}
private void btnStop_Click(object sender, EventArgs e)
{
ToggleControls(true);
this.ActiveControl = picWebcam;
new Core.Packets.ServerPackets.DoWebcamStop().Execute(_connectClient);
}
}
}

View File

@ -0,0 +1,659 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAQAEBAAAAAAIABoBAAARgAAACAgAAAAACAAqBAAAK4EAAAwMAAAAAAgAKglAABWFQAAQEAAAAAA
IAAoQgAA/joAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8B////Af//
/wH///8B////Af///wE/LyhBOSkiyzkpIslBMSo9////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////AUg4MSE6KiOrNycg/T4uJ/87KyT/Nycg/TsrJKdKOjMf////Af///wH///8B////Af//
/wH///8BXExFCzsrJIE3JyD1OSki/zkpIv9PQDr/Szs1/zkpIv84KCH/Nycg8zsrJH0/LygL////Af//
/wH///8BPCwlVTcnIOE4KCH/OCgh/zcnIP81JR7/YVRP/1pMRv82Jh//OCgh/zgoIf84KCH/OCgh3zws
JVH///8BWUlCJTcnIPc4KCH/QzQt/4B1cP+Dd3L/fnJt/6uioP+jmpb/bF9Z/2pcVf9jVU7/PCwl/zgo
If84KCHza1tUH1NDPCs3JyD7eGtm/4J2cv87KyT/MSEa/z8vKP+vpqL/q6Ke/z0tJ/82JyD/NSUe/1pL
Rf9QQDr/OCgh9W5eVyNTQzwrNiYf+4h8eP83JyD/YFBJ/7yspf+woZv/iXt1/41+d/+Gdm7/bl5X/0Ex
Kv84KCH/U0M8/zUlHvVuXlcjU0M8KzcnIPs1JB3/c2Nc/5CAef/IuLH/qaGf//7+/v/+/v7/3dXR/6ub
lP/Nvbb/WUlC/04+N/84KCH1bl5XI1NDPCs4KCH7OCgh/35uZ/+Tg3z/hHRu/5SIg//9/f3//v39/97S
zP9pWVP/0sK7/1dHQP83JyD/OSki9W5eVyNTQzwrOCgh+zkpIv82Jh//YFBJ/5mJgv+zopv/6+bj/9vW
1P9pWFH/eGhi/0w8Nf83JyD/OSki/zkpIvVuXlcjU0M8KzgoIfs5KSL/OCgh/zwsJf84KCH/NiYf/5GI
hP+MgX3/Nycg/zgoIf9aTEb/WUtG/zkpIv85KSL1bl5XI1ZGPyc4KCH5OCgh/zgoIf+upqP/TT85/zgo
If9uYl3/aVxX/zgoIf84KCH/kIaC/5CGgv84KCH/OCgh83BgWSGHd3ADPi4nYTgoIek4KCH/Sjs0/zUl
Hv84KCH/WUtF/1FDPf9BMSr/loyI/zsrJP88LCX/OSki5z4uJ13///8B////Af///wFKOjMROyskjTgo
Ifk4KCH/OSki/0Y2L/9DMyz/OCgh/zUlHv84KCH5Oioji1NDPA////8B////Af///wH///8B////Af//
/wFGNi8pOCghtTgoIf84KCH/OCgh/zcnIP06KiOxQTEqJ////wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wE8LCVJOCgh0zgoIdE+LidH////Af///wH///8B////Af///wH///8BAAD//wAA
//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//ygA
AAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAD///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8Bbl5XBUY2L105KSLTOioj0U09NlVWRj8D////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AU8/ODs6KiPBNSUe/zkpIv83JyD/NCQd/Toq
I7tZSUI1////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AWtbVB8+LiedNiYf9zcnIP85KSL/OSki/zcn
IP83JyD/NiYf/zUlHvVCMiubZVVOGf///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AVJCOwlHNzB3Nycg7zYmH/85KSL/OCgh/zkp
Iv9NPTb/RTUu/zgoIf84KCH/OCgh/zYmH/83JyDrSTkycWNTTAf///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AUs7NANPPzhROCgh1zUlHv85KSL/OSki/zkp
Iv85KSL/OSki/1xNRv9XR0D/OSki/zkpIv85KSL/OSki/zgoIf80JB3/Oioj0UExKkVgUEkD////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wFcTEUtPS0mtTMjHP04KCH/OCgh/zkp
Iv85KSL/OSki/zkpIv83KCH/cGNe/2FUT/85KSL/OSki/zkpIv85KSL/OSki/zgoIf84KCH/NSUe/UAw
KbE/Lygn////Af///wH///8B////Af///wH///8B////Af///wFUQzwVQTEqkzMjHPU3JyD/OCgh/zkp
Iv85KSL/OSki/zkpIv85KSL/OCgh/zMjHP+Ngnz/eGtl/zYmH/85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/Nycg/zUlHvNAMCmNTz84E////wH///8B////Af///wGyopsDSTkyVTUlHuU1JR7/OSki/zgo
If84KCH/OCgh/zgoIf83JyD/NSUe/zQkHf8xIBn/JRYQ/56Wk/+Sh4P/KRgS/zMiG/81JR7/Nycf/zgo
If84KCH/OCgh/zkpIv85KSL/OCgh/zYmH/83JyDjRjYvTf///wH///8B////AWNTTD82Jh/pOCgh/zkp
Iv85KSL/OSki/zUkHf8sHBT/OSkh/1pKRP+He3b/pp6a/7KrqP+1ran/6eXk/+Da2P+upJ//opiU/46B
fP9uYFr/Szw2/zMjHP8xIBn/OCgh/zkpIv85KSL/OSki/zgoIf81JR7haFhRM////wH///8BUUE6VTgo
IfU4KCH/OSki/zYmH/8vHRb/cWRf/8K7uP/Y09H/raWh/4B0b/9cTEb/RDQs/yoZFP/k4N7/2NPR/ykX
D/85KSL/SToz/2ZXUP+JfHb/npGL/4t/ev9QQTr/Lh4W/zkpIv84KCH/OSki/zgoIe1uXldF////Af//
/wFTQzxTNycg9TgoIf8wIBj/X09J/9rW1P+upqL/UUI7/y0cFP8sHBT/MyMc/zkpIv87KyT/SDgw//n4
9//18/P/PCwl/zssJf85KSP/OSki/zIiG/8sHBT/OCgg/21gWf+UiIL/Py8n/zYnIP85KSL/OCgh625e
V0P///8B////AVNDPFM3JyD1NSUf/21fWf/k4N//U0M8/y0cFP83Jh//OCgh/zIiG/8zIxz/Py8o/0k4
Mv+HeXX/9e7r//n08f+CdXH/Rzcw/zoqI/84KCH/OCgh/zcnIP85KSL/NCQd/zIhGv+JeXP/RDQt/zkp
Iv84KCHrbl5XQ////wH///8BU0M8UzgoIfUzIhv/4dzb/1JCPf82Jh//OCgh/zYmH/9AMCn/lYV+/8Cw
qf/Pv7j/3c3G/8Gxqv+Id3H/X05H/1REPv9MPDX/Oioj/zEhGv8vHxj/NCQd/zgoIf85KSL/OSki/y4e
F/+Ab2n/MyMc/zgoIetuXldD////Af///wFTQzxTOCgh9TYnIP+7sq//MSAZ/zcnIP82Jh//Pi4n/8y8
tf/QwLn/zLy1/8W1rv9RQj//UUM+/4yAfP+6raj/x7ix/8a1rf/Lu7T/uqqj/56Oh/9nV1D/MyMc/zcn
IP84KCH/Lx8Y/3FhWv8xIRr/OCgh625eV0P///8B////AVNDPFM3JyD1OCgh/y0cFP85KSL/QjIr/3Zm
X/9pWVL/1cW+/8y8tf/Ovrf/RTg0/8rEwf/+/f3///7+///////+/f3/7+jl/6SUjP/Nvbb/0MC5/9XF
vv/EtK3/Rzcw/zYmH/9FNS7/X09I/zgoIf84KCHrbl5XQ////wH///8BU0M8UzcnIPU4KCH/OCgh/zUl
Hv9tXVb/p5eQ/zgoIf/Lu7T/z7+4/7ioof+WjIj///7+///+/v/////////////+/v//////4dnV/1FA
Ov+/r6j/zb22/86+t/+snJX/PS0m/19PSP80JB3/OSki/zgoIetuXldD////Af///wFTQzxTNycg9Tgo
If85KSL/Nycg/1lJQv/czMX/eWli/zUlIP+Ccmz/t6eg/6KTjP/39vX///////////////////////z5
+f/YycL/fm5n/2JSTP/Vxb7/zb22/6ublP8xIRr/NSUe/zgoIf85KSL/OCgh625eV0P///8B////AVND
PFM3JyD1OCgh/zkpIv85KSL/MCAZ/5SEff/ezsf/wbGq/39vaf9aSkT/Tz84/2lZUv/6+fj///7+///+
/v/8+/r/0MC5/9TFvv9BMSv/hHRt/9fHwP/Pv7j/Sjoz/zcnIP84KCH/OCgh/zkpIv84KCHrbl5XQ///
/wH///8BU0M8UzcnIPU4KCH/OSki/zkpIv84KCH/MCAZ/2ZWT/+1pZ7/2srD/97Ox//by8T/08K6/+/o
5P///v7///7+//Lr5/+9rKX/Tz84/29gW//UxL3/kIB5/zsrJP82Jh//OCgh/zkpIv85KSL/OSki/zgo
IetuXldD////Af///wFTQzxTNycg9TgoIf85KSL/OSki/zgoIf84KCH/NSUe/zAgGf9ENC3/ZlZP/4V1
bv+YiIH/vrKt//////////7/fnBs/zQkHf9jU03/ZVVO/zkpIv8wIBn/NiYf/zYmH/84KCH/OSki/zkp
Iv85KSL/OCgh625eV0P///8B////AVNDPFM3JyD1OCgh/zkpIv85KSL/OSki/zkpIv85KSL/OCgh/zgo
If83JyD/NCQd/zMjHP8+Lin/9/b2//Py8f84JyD/OCgh/zYmH/83JyD/OCgh/zgoIf9PQDr/Tj44/zkp
Iv85KSL/OSki/zkpIv84KCHrbl5XQ////wH///8BU0M8UzcnIPU4KCH/OSki/zkpIv85KSL/OCgh/zgp
If9HNjD/Nych/zgoIf84KCH/OCgh/y0cFP/k4N7/2NPR/ysaE/84KCH/OCgh/zkpIv85KSL/KxsV/7Sr
qf+1rKr/KxsV/zkpIv85KSL/OSki/zgoIetuXldD////Af///wFRQTpVNycg9TgoIf85KSL/OSki/zkp
Iv84KCH/TkA8/9jRzv9AMy7/Nycg/zkpIv84KCH/KhkS/8C4tf+yqqb/LR0W/zkpIv85KSL/OSki/zUl
Hv9wYlv//v39//79/f9vYVv/NSUe/zkpIv85KSL/OCgh7W1dVkX///8B////AVpKQ0U3JyDtOSki/zkp
Iv84KCH/OSki/zcnIP+nnZj/7uvp/46EgP8xIBn/OSki/zkpIv8vHxj/oJeU/5SJhP8xIRv/OSki/zYm
H/8+Lif/NSQd/ywcFv+nnpr/p56a/ywcFv85KSL/OSki/zkpIv83JyDlc2NcOf///wH///8Bh3dwBUU1
Lmc3JyDzNycg/zgoIf85KSL/OCgh/zEgGv+Ngn3/LBsV/zkpIv85KSL/OSki/zMjHP+Lf3r/dWlk/zYn
IP86KiP/U0Q///n49/91Z2L/MyMc/0o6M/9IODL/OSki/zkpIv83JyD/NCQd70o6M1+jk4wD////Af//
/wH///8B////AVVFPiU/LyipNiYf+zgoIf84KCH/OCgh/zEhGv85KSL/OCgh/zkpIv84KCH/OCgh/29i
Xf9hU0//Oioj/zkpIv89LCX/n5aS/0o8Nf84KCH/NyYg/zYmH/84KCH/NSUe+UIyK6NeTkch////Af//
/wH///8B////Af///wH///8B////Af///wFJOTJBOyskyTQkHf85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/W0tF/1ZHQP85KSL/OSki/zgpIv8uHhb/Nycg/zkpIv85KSL/NSUe/zsrJMdSQjs7////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wFpWVIHSjozZTcnIOc3JyD/OCgh/zgo
If85KSL/OSki/zkpIv9LOzT/RjYv/zgoIf85KSL/OCgh/zcnIP84KCH/Nycg/zoqI+VFNS5deGhhBf//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BTz84E0Q0
LY00JB31NiYf/zkpIv85KSL/OSki/zkpIv83JyD/OCgh/zkpIv84KCH/Nycg/zgoIfM+LyiFWEhBEf//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////AUExKi0/LyizNSUe+zgoIf84KCH/OCgh/zgoIf84KCH/OCgh/zQkHfs+LierSDgyKf//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////AV1NRgNBMSpHOiojzzMjHP84KCH/OCgh/zQkHf86KiPNRzcwQ///
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wFVRT4JSjozbzYmH+E4KCHfQjIraUg4
MQn///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAoAAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAA////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wFuXlYDUEA5Kz8vKHs8LCXNPy8oyUY2L3NURD0lVkY/A////wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////AUU1LhVGNi9ZPS0mwzQkHfc2Jh//NSUe/zYmH/U7KyS7RTUuT0o6MxP///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8BV0dAQz4uJ6M2Jh/nNSUe/zgoIf85KSH/Nycg/zcnIP82Jh/9Nycg40U1
Lp1VRT45////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8Ba1tUCVNDPDVDMyyNOSki7zMjHP83JyD/OSki/zkpIv84KCH/Nycg/zgo
If83JyD/NiYf/zIiG/83JyDpRTUui1hIQTFjU0wH////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wFeTkcbRDQteT0tJs81JR75NSUe/zgoIf83KCH/OSki/zYm
H/9JOTL/Py8o/zYmH/83JyD/Nycg/zcnIP82Jh//NSUe+TwsJcdCMitxaFdRF////wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8BUkI6B1JCO0lAMCmzNSUe8zYmH/84KCH/OSki/zgo
If84KCH/OCgh/zEhGv9jU0z/WEhB/zIiG/84KCH/OCgh/zgoIf84KCH/OCgh/zYmH/82Jh/xQDApr1pK
Q0NjU0wF////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AVREPQ1TQzw5QDApsTMjHPM1JR7/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OCgh/y0dFv94aWL/cF9Y/y0dFv85KSL/OSki/zkoIf85KSL/OSki/zko
If84KCH/NCQd/zMjHPFFNS6pRTUuMUc3MAv///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wGAb2gDUUE6LzwsJYM6KiPXNSUe/zcn
IP84KCH/OSkh/zkpIv85KCH/OSkh/zkpIv85KCH/OCki/ysaE/+He3b/f3Bq/ysaFP84KCH/OCgi/zkp
Iv85KCH/OCgi/zkpIv84KCH/OCgh/zcnIP80JB3/NiYfz0ExKntcTEUr////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AVhIQQ9cTEVVPCwlzTQk
HfM2Jh//OCgh/zgoIf84KCH/OSkh/zgoIf85KSH/OSkh/zgoIf85KSH/Nycg/ysbE/+dk4//h3x4/ygY
Ef85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OCgh/zgoIf84KCH/Nycg/zYmH/M8LCXJPCwlTVJD
Owv///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wFUQzwRTDw1Vzkp
IrswIBn3NSUe/zgoIf84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv84KCH/NiYf/y8f
F/+3rqr/m5KN/ywbFP83KCH/OSki/zkoIf85KSL/OSki/zkoIf85KSL/OSki/zkoIf85KSL/OSki/zkp
Iv81JR7/NCQd9z8vKLdGNi9PTz83D////wH///8B////Af///wH///8B////Af///wH///8BXExFB0s7
NDc7KySPOSki6zUlHv03JyD/OCgh/zgoIf84KCH/OSkh/zkpIv85KCH/OCgh/zgoIf84KCH/OSkh/zkp
Iv84KCH/NSQd/zQjHP/Dvbn/sqii/zEgGP82JiD/OCgh/zgoIf84KCH/OCgh/zgoIf84KCH/OCgh/zkp
Iv85KCH/OCgi/zkpIv85KSL/Nycg/zUlHv02Jh/lPy8oiUg4MTNFNS0F////Af///wH///8B////Af//
/wGyopsFWkpDVTMjHM80JB33NiYf/zgoIf85KSL/OCgh/zkpIv84KCH/Nycg/zgoIf84KCH/Nycg/zUl
Hf80JBz/MiIb/zAfGP8sHBT/JhYQ/y8iHv/KxsT/wLq3/ykZFP8oGBH/Lx8Y/zIiG/80JB3/NiYe/zcn
IP84KCH/OCgh/zcnIP84KCH/OSki/zkpIv85KSL/OCgh/zgoIf83JyD/NiYf9zcnIMlPPzhJWUpDA///
/wH///8B////Af///wFuXldRPi4n1TAgGf84KCH/OSki/zkpIv85KSL/OSki/zkpIv82Jh//MSEa/zAg
GP81JR3/Pi0m/0s7Nf9kVU7/d2tl/4Z8d/+TiIT/m5CL/7Cmov/u7Or/5+Ti/6CTj/+TiIT/gnZx/3Nm
YP9lVlD/Tj84/0Q0Lf86KiT/MyMc/zIiG/81JR3/OCgh/zkpIv85KSL/OSki/zkoIf85KSL/OCgh/zMj
HP85KSLLYFBJQf///wH///8B////Af///wFSQjt/Oysk8TUlHv84KCH/OSki/zkpIv86KiP/NSUe/y4d
Ff8wHhf/Tj44/3VoY/+gl5T/wbq3/8vFw//W0M7/z8nG/721sv+ooZ7/lIuI/7CopP/18/P/8O3s/6SY
k/+ShoD/mY6J/6CXkv+mnJf/r6Sf/6memP+bjoj/fG5p/1lJQ/88LCX/Lx8Y/zMiG/85KSL/OCgi/zkp
Iv85KCH/OCgh/zIiG/8/Lyjjb19YZf///wH///8B////Af///wFSQjt/Oysk8TQkHf83KCH/OSki/zop
Iv8wHxj/KhgQ/1lKRP+imJT/3NnX/9/b2f/Iwr//kYeC/2tdV/9SRD3/Py4o/zgnH/8yIRn/IRAN/3tu
af/z8fD/7evq/2xeWP8lFA3/Lx8Y/zAfGP82Jh//QTAp/1BAOv9sXVb/in13/6GVj/+lmpX/cGNd/zsr
JP8pGBD/OCgh/zkpIv84KCH/OSki/zMjHP8/LyjjbV5XZ////wH///8B////Af///wFTQzx9Oysk8TQk
Hf84KCH/NSUe/y4cFf9RQDn/v7i1/+bj4v/Gwb7/dmlk/z8vKP8qGBD/JhQN/ykZEv8yIhv/OSki/zoq
I/88LCX/MyIZ/6qgnP/7+vr/+fj4/5mPjP8uHhf/PCwl/zoqI/85KSP/OSki/zUlHv8rGxT/JhUN/y8e
F/9GNi//gHNt/5+Uj/9+cWv/NiYe/zIiG/84KCH/OSki/zMjHP8+Lifjbl5XZf///wH///8B////Af//
/wFTQzx9Oysk8TQkHf84KCH/MCAZ/3BiXP/X0s//zMbD/3dqZP89LCX/KhkS/y8eF/81JR7/OSki/zkp
Iv83JyD/MyMc/zEhGv8tHBb/OCkl/83HxP/+/v7//f39/763tP8yIx//MiIb/zUlHv84KCH/OCgi/zkp
Iv85KSL/OCgh/zUkHf8vHhf/MB4X/0U1Lv98bmj/kIF6/0Y2L/8zIxz/OSki/zMjHP8+LifjbV5XZf//
/wH///8B////Af///wFTQzx9Oysk8TQkHf8yIRv/YVJL/+Hd2v/JwsD/QzIr/y0cFf8zIhv/Nycg/zgo
If83JyD/MSEa/ywcFf80JB3/RTUu/1VFPv9dTUb/f3Br/9/Uz//w5eD/9Ovm/+Tc2P9+b2r/WEhB/0g4
Mf85KSL/OCgh/zcnIP84KCH/Nycg/zcnIP85KSL/Nycg/zQjHP8xIBn/YlNM/4t7dP89LSb/OCgh/zMj
HP8+Lifjbl5XZf///wH///8B////Af///wFTQzx9Oysk8TMjHP8uHRb/ysK//8zGxP9ALyj/MSEa/zkp
Iv84KCH/Nycg/zMjHP85KSL/bFxV/5uLhP+3p6D/y7u0/9XFvv/fz8j/2cnC/7yrpP+jkov/g3Fq/3Ff
WP9uXlj/X09I/1FBOv84KCH/MiIb/zEhGv8zIxz/NiYf/zcnIP84KCH/OSki/zkoIf85KSL/Lh4X/2VV
Tv9zYlz/MiIb/zMjHP8+Lifjbl5XZf///wH///8B////Af///wFTQzx9Oysk8TAgGf87KyT/8/Hw/5eM
iP8pGRP/Oioj/zcnH/82Jh//NCQd/0U1Lv+djYb/08O8/9fHwP/Swrv/1MS9/9PDu/+mlpD/YlNN/0Q2
Mv9AMCv/Szoy/1dGP/9iUUv/bl5X/3JjW/9yYlv/ZVVO/1ZGP/9DMyz/MCAZ/y4eF/81JR7/OSki/zkp
Iv84KCH/NCQd/0MyLP+AcGn/KxsU/zQkHf8+LifjbV5XZf///wH///8B////Af///wFTQzx9Oysk8TIj
G/83JyD/pJiT/2ZYUf8yIRr/OCgh/zQkHf84KCH/OCgh/5WFfv/Wxr//zb63/8y8tf/Ovrf/yrqz/25g
W/8wIh//YFNO/5eMif+8sq7/2M7K/97Tzv/ZysP/z762/9PCu//Xx8D/zLy1/8a2r/+1pZ7/jHx1/1dH
QP8wIBn/NCQd/zkpIv84KCH/NSUe/0IyK/94aGH/LR0W/zQkHf8+Lifjbl5XZf///wH///8B////Af//
/wFTQzx9Oysk8TQkHf83JyD/KBYP/zEhGf86KiP/NCQd/3RkXf9aSkP/Szs0/8OzrP/Pv7j/zLy1/86+
t//Swrv/WUtG/1JHRP/IwL3//Pz7///+/v///v7///////7+/v/8+/v/7+fj/8O0rv+vnpf/0cK7/9HB
uv/Swrv/2cnC/9bGv/+pmZL/QTEq/zMjHP84KCH/MyMc/2hYUf9WRj//Nycg/zMjHP8+Lifjbl5XZf//
/wH///8B////Af///wFTQzx9Oysk8TQkHf83KCD/NiYf/zgoIf82Jh//QjIr/7Kim/9nV1D/QDAp/7mp
ov/Tw7z/y7u0/9PDvP+vn5j/Rzo0/9DLyP/+/f3///7+///+/v/+/v7////////+/v/+/v7//v7+/+vm
5P+cjYf/e2tk/8Gxqv/QwLn/y7u0/9DAuf/aysP/nIyF/zkpIv8wIBn/XU1G/2lZUv84KCH/OSki/zMj
HP8+LifjbV5XZf///wH///8B////Af///wFTQzx9Oysk8TQkHf84KCH/OCgh/zkpIv8xIRr/UUE6/8m5
sv+Whn//JhYP/3NjXP/Rwbr/1MO8/9bFv/+nl4//bmFc//v5+f///v7///7+//7+/v/////////////+
/v///v7///////79/f/g1M7/YE9J/11NR//Gtq//z7+4/8y8tf/Ovrf/x7ew/1ZGP/9VRT7/W0tE/zkp
Iv82Jh//OSki/zMjHP8+Lifjbl5XZf///wH///8B////Af///wFSQzx9Oysk8TQkHf84KCH/OSki/zkp
Iv81JR7/Rzcw/7urpP/ZycL/cmJb/y4eF/9JOTP/nIyF/7+vqP/MvLX/koJ8/9XPzP/9/Pz/////////
/////////////////////////v39//Hq5//Xx8D/oZGK/ywcGP+IeHL/2cnC/8y8tf/Nvbb/x7ew/1dH
QP85KSL/MiIb/zcnIP83KCH/OSki/zMjHP8+LifjbV1XZf///wH///8B////Af///wFSQzx9Oysk8TQk
Hf84KCH/OSki/zkpIv85KSL/MyMc/4R0bf/XxsD/zr63/5eHgf9XR0L/OSoj/0Q1MP9cTEb/cmFa/3xu
aP/DvLn///////7+/v///////v7+////////////7ufk/9TFvv/Xx8D/jX12/ygYEf+BcWr/2cnC/829
t//aysP/no6H/zkpIv8zIxz/Nycg/zgoIf84KCH/OSki/zMjHP8+LifjbV1WZf///wH///8B////Af//
/wFSQzx9Oysk8TQkHf84KCH/OSki/zkpIv85KSL/NSUe/zwsJf+Whn//3s7H/93Nxv/Lu7T/qZmS/4x8
df9yYlz/X09I/08+N/9zY1v/9PLw///+/v///v7///7+//7+/v/49fT/zb22/9PDu//Nvbb/QzMt/zYm
IP+tnZb/2cnC/9vLxP+8rKX/RjYv/zIiG/84KCH/OCgh/zgoIf84KCH/OSki/zMjHP8+LifjbV1XZf//
/wH///8B////Af///wFSQzx9Oysk8TQkHf84KCH/OSki/zkpIv85KSL/OCgh/zQkHf8uHhf/cWFa/7Gh
mv/Nvbb/3c3G/97Ox//dzcb/3MzF/9jIwf/OvbX/6uHc//7+/v///v7///7+///+/f/r4dz/z722/62d
lv9NPTb/PS4r/6aWj//czMX/uKih/3trZP84KCH/MiIb/zgoIf84KCH/OSki/zkpIv85KSH/OSki/zMj
HP8+LifjbV1XZf///wH///8B////Af///wFSQzx9Oysk8TQkHf84KCH/OSki/zkpIv85KSL/OCgh/zgo
If81JR7/Lh4X/0AwKf9kVE3/kIB5/6+fmP/Bsar/z7+4/9TEvf/RwLn/5NfR//37+v///////v7+//f1
9P++r6n/cF9Z/0c3MP9SQjv/nY2G/6eXkP95aWL/RjYv/y8fGP8yIhv/OCgh/zgoIf84KCH/OCgh/zkp
Iv85KSL/OSki/zMjHP8+LifjbV1WZf///wH///8B////Af///wFSQzx9Oysk8TQkHf84KCH/OSki/zkp
Iv85KSL/OCgh/zgoIf84KCH/Nycg/zQkHf8yIhv/OCgh/z8vKP9PPzj/YlJL/3NjXf99bWX/koN8/+jk
4v/////////+/9LNyv9IODX/MiEb/009Nv9dTUb/Tj43/zwsJf8zIxz/MiIb/zYmH/80JB3/NCQd/zco
IP84KCH/OSki/zkpIf85KSH/OSki/zMjHP8+LifjbV1XZf///wH///8B////Af///wFSQzx9Oysk8TQk
Hf84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zgoIf85KSL/OCgh/zcnIP82Jh//MyMc/zAg
Gf8wIBj/KhoY/7Copf/8+/v/+vn5/6GXk/8uHRX/OSoj/zQkHf81JR7/NiYf/zcnIP84KCH/OCgh/zEh
G/9WRj//VUU+/zEhGv84KCH/OSki/zkpIv85KSH/OSki/zMjHP8+LifjbV1XZf///wH///8B////Af//
/wFSQzx9Oysk8TQkHf84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zMjHP8xIBn/Oioj/zkp
Iv84KCH/OCgh/zgnIP85KSL/LBsU/5GHgv/39vb/9PLx/4N3cv8tHBX/OCgh/zcnIP84KCH/OCgh/zkp
Iv85KSL/NSUe/ycWEP+hl5P/oJWS/ygXEv82Jh//OSki/zkpIv85KSL/OSki/zMjHP8+LifjbV1WZf//
/wH///8B////Af///wFSQzx9Oysk8TQkHf84KCH/OSki/zkpIv85KSL/OSki/zkpIv84KCH/OCgh/0o6
M/9TQz3/NSUe/zgoIf84KCH/OCgh/zgoIf84KCH/Lx4X/3NmYP/v7ez/6Obl/2FTTv8xIRr/OCgh/zgo
If84KCH/OSki/zkpIf85KSL/Lx8X/1xMSP/g3Nv/4Nzb/1pLR/8vHxn/Oioj/zkpIf85KSH/OSki/zMj
HP8+LifjbV1XZf///wH///8B////Af///wFSQjt/Oysk8TQkHf84KCH/OSki/zkpIv85KSL/OSki/zkp
Iv84KCH/MyUg/5iPjP/Bubb/Jxwa/zYlH/84KCH/OSki/zkpIv84KCH/MSEa/1JCPP/g3Nr/2NPR/0o5
M/80Ixz/OSki/zkpIv85KSH/OSki/zkpIv8xIRr/VkU//9jU0f/+/v7//v7+/9fSz/9WR0D/MSEa/zkp
Iv85KSH/OSki/zMjHP8+LifjbV1WZ////wH///8B////Af///wFSQjuBOysk8zUlHf84KCH/OSki/zkp
Iv85KSL/OSki/zYmH/84KCD/raOe/+Dc2f/s6ej/rKOg/1JDPf8yIhv/OCki/zgpIf85KSL/MyMc/0Q0
LP/Tz83/ysTC/zoqI/80JB3/OCgh/zkpIv85KSL/MiIb/zUlHf82Jh//PCsl/5GGgv/w7u3/8O7t/5CF
gv88LCX/Nycg/zkpIv85KSL/OSki/zMjHP89LSblbFxVaf///wH///8B////Af///wFgUElbPCwl3TMj
HP84KCH/OSki/zgoIf84KCH/OSki/zcnIP84KCH/fG9p/8O7uP/b2NX/d2tm/0c4Mf81JB3/OSgi/zkp
Iv85KSL/NCQd/zcmH//HwsD/u7Ov/zMhGv82Jh//OSki/zkpIv8zIhv/Rzcv/z4uJv80Ixz/NCQd/zQj
Hf/AuLX/wLm1/zQjHf8zJB3/OSki/zkpIf85KSH/OCgh/zEhGv8/LyjTeGhhTf///wH///8B////Af//
/wGHd28LUEA5ZTMjHN02Jh/9OCgh/zgoIf84KCH/OCki/zkpIv84KCH/KxoU/3ptaP+dlZD/IRAL/zUk
Hf85KSL/OSki/zkpIv85KSL/NiYf/zEfGP+7sq7/oZiU/y4dFf83JyD/OSki/y4eF/9iU03/9fLx/9HM
yf9MPDX/MiIb/y4eF/9qWlP/aFhR/y0dFv85KSL/OSki/zkpIv83JyD/NSUe+zQkHddaSkNdo5OMB///
/wH///8B////Af///wH///8BXk5HC0w8NU8/LyirNycg8TUlHv83JyD/OSgh/zkpIv84KCH/Nygh/zsr
JP89LSb/OCgh/zgoIf84KCH/OSki/zkpIv84KCH/Nycg/y0cFf+poJz/joSB/yoZEv85KSL/OSki/ywc
Fv9tX1v/8vHw/9nU0v9URT7/MCAZ/zgoIf84KCH/OCgh/zcnIP84KCH/OCgh/zQkHf82Jh/xQDAppUMz
LEVYSEEJ////Af///wH///8B////Af///wH///8B////AWVVTgVTQzwZRjYvcT8vKNM2Jh/7Nycg/zgo
If84KCH/OCgh/zcnIP82Jh//OSki/zgoIf84KCH/OSki/zkpIv84KCH/OCgh/ysZEv+Rh4P/hHhy/yoZ
Ev85KSL/OSki/zcnIP85KSH/eGtm/2RXUf83JyD/OSki/zkpIv83JyD/Nycg/zgoIf83JyD/NSUe+0Ex
Ks1LOzRpXk5HF19PSAP///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AVBA
OR1HNzBxNiYf2TQkHfk2Jh//OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/ywc
Ff97bGb/c2Rd/y4dFv84KCH/OSki/zkpIv84KCH/KBgQ/y0dFf85KSH/OSki/zkpIv85KSL/Nycg/zQk
Hfk1JR7XUEA5aV5ORxn///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wFPPzcDUEA5Q0AwKZk3JyDnNSUe/zgoIf85KSL/OCgh/zgoIf84KCH/OSki/zkp
Iv85KSL/OCgh/y8fGP9tXFX/Y1NM/zAgGf84KCH/OSki/zkpIv84KCH/OCki/zkpIv85KSL/OSki/zgo
If80JB3/OCgh4UExKpVURD09Xk5IA////wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8BaFlSA1JCOxNXR0BPPS0myzUlHv02Jh//OCgh/zgo
If84KCH/OSki/zkpIv85KSL/OSki/zQkHf9WRj//Tj43/zMjHP83JyD/OSki/zkpIv84KCH/Nycg/zcn
IP84KCH/Nycg/zUlHv1ENC3HRzcwRVZGPxN4aGED////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BTz84EUQ0
LWM9LSbHNCQd9zcnIP84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Nycg/zgoIP84KCH/OSki/zko
Iv84KCH/Nycg/zcnIP82Jh/3OiojwUQ1Ll9ZSUIP////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////AVlJQgNtXVYrNycgjzYmH901JR77OCgh/zkpIv85KSL/OCgh/zkpIv84KCH/Nycg/zgo
If84KCH/OSki/zkpIv83JyD/NCQd+zcnINdENC2LWUlCJf///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8BRTUuD0o6M0VCMiupNCQd+TQkHf84KCH/OCgh/zcn
IP84KCH/OCgh/zgoIf84KCH/OSki/zIiG/81JR73SDgxoT8vKT1TQzwP////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wFdTUYFPy8oUT0t
JrU0JB3vNCQd/zcnIP84KCH/OCgh/zgoIf82Jh//NCQd7T4uJ7FHNzBNeWliA////wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8BXk1HA2hYUR8+LidtOSki0zQkHfs3JyD/Nycg/zUlHvs1JR7NPy8oaXNjXB1uXlYD////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wFVRT4HVEQ9NUExKpU2Jh/ZNycg2Uc3MJFIODExSDcxB///
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8BAAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//KAAAAEAAAACAAAAAAQAgAAAA
AAAAQgAAAAAAAAAAAAAAAAAAAAAAAP///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8BRTUuJ0w8NX8+LifRQjIrzVFBOndgUEkf////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wFuXlcRZ1dQazgoIeMxIRr/NSUe/zUlHv8vHxj/RTUu21xM
RV1WRj8H////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AVxMRQdENC1LRDQtxTIiG/8yIhv/OSki/zkp
Iv84KCH/OCgh/zAgGf8xIRr5RTUutUg4MUd7a2QF////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AWdXUD1HNzCnOCgh8zIi
G/82Jh//Oioj/zkpIv85KSL/Nycg/zgoIf86KiP/OCgh/zQkHf83JyDvXExFm04+NzH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BY1NMI009
NoNBMSrjMCAZ/zUlHv85KSL/Oioj/zkpIv86KiP/NSUe/zYmH/84KCH/OSki/zgoIf83JyD/MyMc/y8f
GP88LCXZTj43gXFhWiH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wFuXlcNa1tUaz8vKM8yIhv/MCAZ/zkpIv83JyD/OCgh/zkpIv85KSL/OCgh/0AwKf85KSL/Nycg/zcn
IP83JyD/Nycg/zgoIf83JyD/NCQd/zMjHP9GNi/LZlZPW08/OAX///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////AWJSSwNeTkdDQjIrvTQkHf8yIhv/Nycg/zoqI/85KSL/OSki/zgoIf85KSL/Oioj/zAg
Gf9gUEn/TT02/zEhGv85KSL/OCgh/zgoIf83JyD/OSki/zgoIf82Jh//MiIb/zEhGvtENC23aFhRPf//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////AVJCOyNSQjuhOioj8zMjHP82Jh//OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OCgh/zkpIv8nFxD/f25n/3BgWf8pGRL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv83JyD/NCQd/zgoIfFZSUKXY1NMGf///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8BdmZfF1FBOn04KCHhLx8Y/zcnIP85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zgoIf87KyT/IhIL/5KCe/+GdW7/IxMM/zoqI/85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zkpIv81JR7/LBwV/zkpItlhUUpxalpTD////wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wFLOzQLVkY/XUg4Mc0zIxz/NCQd/zgo
If85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv84KCH/Oysk/x0MBf+glI7/l4iB/x8P
CP86KiP/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv84KCH/OCgh/zoqI/8zIxz/MyMc/z0t
Jr1ENC1JYFBJC////wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AYBwaQVeTkc/RDQtqy0d
FvswIBn/Nycg/zkpIv84KCH/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkq
I/8bCQH/tq6r/6qdmP8ZCAH/Oysk/zgoIf85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zgo
If85KSL/OSki/zYmH/8xIRr/NSUe+VFBOqFnV1A3QDApA////wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AVhI
QSVdTUaJPCwl7zIiG/83JyD/Oioj/zkpIv85KSL/OSki/zgoIf85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zgoIf81Jh//JBIK/8zFwv+tpqT/FwUA/zoqI/85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv84KCH/OSki/zgoIf85KSL/Oioj/zYmH/8yIhv/PCwl6zsrJH1TQzwd////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8Bf29oFUk5MnE3JyDZLBwV/zMjHP85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/MCEa/y4cFP/h29j/vri2/yEPBv82JyD/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv86KiP/OSki/zIi
G/8yIhv/PS0m01ZGP21oWFEP////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8BVEM8U0o6M8szIxz7MyMc/zcnIP86KiP/OCgh/zgoIf85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv84KCH/OCgh/ysbFP86Jx//7urn/9LL
x/8vHBP/MSEb/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv86KiP/OCgh/zIiG/83JyD5Pi4nvU8/OEv///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wFcTEUvRzcwqTEhGvEwIBn/NiYf/zkpIv85KSL/OCgh/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OCgh/zgoIf85KSL/OSki/zkpIv85KSL/OSki/zoq
I/8oFg//QzQu//Hw7//m39v/Oicf/y0dFf86KiT/OSki/zgoIf84KCH/OSki/zkpIv84KCH/OCgh/zkp
Iv84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zgoIf84KCH/NCQd/zIiG/84KCHvSTkyoUU1
Lif///8B////Af///wH///8B////Af///wH///8B////AbKimweGdm9HMiIb3y8fGP82Jh//OCgh/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zgoIf83JyD/OCgh/zkpIv84KCH/Nycg/zUlHv80JBz/MiIb/zEh
Gv8vHhf/KxoT/ycXD/8pFxD/CgEA/1BDPv/29PP/8e/u/zkpJP8TAwH/KhkR/ywbFP8wHxj/MiEa/zQk
HP81JR3/NiYf/zgoIf85KSL/OCgi/zgoIf83JyD/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OCgh/y0dFv8/LyjVZlZPN1lKQwX///8B////Af///wH///8B////Af///wF/b2hZSzs0uyYW
D/85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zoqI/85KSL/Nycg/zMjHP8xIRr/LR0V/yYV
Df8kEQr/Lx4W/z4sJP9HNy//VUdA/2lcVv93aWP/gHFs/4R3cv+2qqT//Pv7//n49/+cjon/dWdi/3lt
aP9mWVP/UkQ+/0g3MP8+LCX/Lh0V/ycWD/8rGxP/Lh4Y/zEhGv80JB3/OCgh/zkpIv86KiP/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zgoIf85KSL/Lh4X/zwsJbFWRj9H////Af///wH///8B////Af//
/wH///8BVUU+pT4uJ+sxIRr/OSki/zgoIf85KSL/OSki/zkpIv85KSL/Oioj/zsrJP81JR7/LBsU/yQT
DP8lEwv/NCMb/1NDPf+Bcmz/nZOP/8K9uv/u5uT///38///////6+fj/8fDw/+zr6v/k4d//9PPz////
/////v7/7uXi/+HZ1f/p4+D/597b/+ro5v/j29f/0cnE/7uyrv+qnpn/gHNs/1ZHQf8+LSb/KxsU/ygX
EP8rGxP/NCQd/zoqJP86KiP/OSki/zkpIv85KSL/OSki/zkpIv84KCH/OSki/ysbFP9HNzDVcmJbgf//
/wH///8B////Af///wH///8B////AVBAOa0/LyjvMyMc/zgoIf84KCH/OSki/zkpIv86KiP/PCwl/zQk
Hv8lFAz/IxEJ/zclHf9rXFX/opiU/9zW0////////v////Du7f/d2Nb/xL+9/6edmf+LfHf/cGNd/1lL
RP9ENTL/LxoT/7yyrv////////7+/5+UkP8kEAj/RzUu/0o5M/9SQz7/Y1ZR/39zbf+ilpD/t6yn/8W8
t//c0Mv/yr+8/6WZk/9sXVf/RTUv/ysbFP8lEwz/MyMc/zsrJP85KSL/OSki/zkpIv85KSL/OSki/zoq
I/8sHBX/Rzcw3W5eV43///8B////Af///wH///8B////Af///wFTQzynPy8o6zEhGv84KCH/OCgh/zkp
Iv86KSL/Oysk/ygXEP8fDAT/RDIr/5OJhf/Z1NH///////z7+//Z1NL/r6ai/3ttZ/9LOzT/OSYe/yYV
DP8fDAX/IA4G/yIQCP8lEgr/EwIA/yQTDf/W0M3////////////EvLn/GwgA/x4PCP8nFxD/IhEJ/yIQ
Cf8hDwf/Hw0F/yAOB/83JR//Tz84/21fWP+cjoj/ua+q/8W8uP+Zjoj/WElC/ykZEv8jEQn/OCgh/zoq
I/84KCH/OSki/zkpIv86KiP/LBwV/0c3MNluXleH////Af///wH///8B////Af///wH///8BU0M8pz8v
KO0xIRr/OCgh/zgoIf84KCH/Nycg/x4LBf82JBv/l42I/+rn5v//////5+Ti/6Sbl/9dTkj/NCMc/yQR
Cf8gDQb/IBAI/ycXEP8zIxz/OSki/zoqI/86KyT/PS0m/yQTCv9ZSED/7Ono////////////5OHg/0Ex
Kv8mFg//PS0m/zssJf87KyT/Oiok/zkqI/85KSL/MCAZ/yMTDP8fDQX/IxIL/zopIv9ZSkT/kYV+/761
sf+pnpr/VUdA/x4OBv8xIRr/Oysk/zkpIv85KSL/Oioj/y0dFv9GNi/Zbl5Xh////wH///8B////Af//
/wH///8B////AVNDPKc/LyjtMSEa/zgoIf84KCH/Nicg/xwKAv9VQjv/1M3J///////q5eT/k4iC/0Av
KP8iEQn/IQ8H/ygYEf80JB3/OCgh/zsrJP87KyT/Oioj/zoqI/86KiP/Oysk/z0sJf8fDQX/hnhy//v5
+P////////////Lv7/9qWlP/IRAI/z0tJv86KiP/OSki/zkpIv85KSL/OSki/zoqI/87KyT/Oioj/zcn
IP8sHBT/IhEJ/ycVDv9BMSr/hnp0/8zCvf+KenP/IxMM/y0eF/86KiP/OSki/zoqI/8tHRb/RjYv2W5e
V4f///8B////Af///wH///8B////Af///wFTQzynPy8o7TEhGv84KCH/OSoj/yISCv9gT0j/8u7s////
//+/tbH/QzIq/x4MBP8oFg//MiEa/zkpIv87KyT/OSki/zkpIv86KiP/Nycg/zMjHP8vHxj/KhoT/ycX
EP8bCgb/DwAA/7euqv//////////////////////n5WR/w0AAP8oGBH/Lh4X/zUlHv85KSL/OSki/zkp
Iv85KSL/OSki/zgoIf84KCH/OSki/zoqI/81JB3/KxoT/yMRCv9HNjD/uKmi/56OiP8rGhP/MiIc/zkp
Iv86KiP/LR0W/0Y2L9luXleH////Af///wH///8B////Af///wH///8BU0M8pz8vKO0xIRr/OSki/y0c
Fv9JNzD/6uXi//////+hlpL/JRIK/yUTDP81JR7/OSki/zkpIv84KCH/OCgh/zcnIP8yIhv/JhYP/ysb
FP84KCH/SDgx/1xMRf9uXlf/dGRd/4NzbP/Uxr//7uLc/+rb1f/u4Nn/+vPv/93Szf+CcGn/bFxV/11N
Rv9ENC3/Nycg/zgoIf84KCH/Nycg/zgoIf84KCH/Nycg/zgoIf85KSL/OSki/zoqI/84JyD/KRgR/yoa
E/+llpD/jHt0/yoZEv84KCH/Oioj/y0dFv9GNi/Zbl5Xh////wH///8B////Af///wH///8B////AVND
PKc/LyjtMSEa/zcnIP8mFA3/qJyX//////+3rar/Iw8H/yoZEv87KyT/OSki/zgoIf84KCH/OSki/zIi
G/8oGBH/QDAp/3BgWf+YiIH/sqKb/8e3sP/QwLn/18fA/+TUzf/s3db/387G/8+8tf/Ar6j/qZiQ/5F+
d/+Jd3D/iHly/3NjXP9rW1T/Tj43/zIiG/8yIhv/NCQd/zUlHv83JyD/OSki/zkpIv84KCH/OCgh/zkp
Iv85KSL/OSki/zoqI/8qGhP/NCQc/6ublf9ZSUP/MiIb/zoqI/8tHRb/RjYv2W5eV4f///8B////Af//
/wH///8B////Af///wFTQzynPy8o7TIiG/8wIBn/Py4m//Dt7P/v6+r/V0Q//xoKBP89LSb/OSki/zkp
Iv85KSL/OSki/y4eF/8tHRb/e2tk/8W1rv/i0sv/4dHK/9jIwf/Tw7z/1cW+/9/PyP/bysP/t6eg/4N0
bv9aS0b/OSki/yUUDf8gEAn/Hw8J/yERDf8qGhP/KxsT/zQkHf83JyD/MiIb/ywcFf8oGBH/KhoT/y0d
Fv8zIxz/OCgh/zoqI/85KSL/OSki/zkpIv84KCH/PS0m/x8OB/9zYlv/iXly/ygYEf87KyT/LR0W/0Y2
L9luXleH////Af///wH///8B////Af///wH///8BU0M8pz8vKO0yIhv/Lx8X/0ExK////v7/4d3c/zgl
Hf8mFhD/Oioj/zkpIv8xIRr/NiYf/zUlHv8sHBX/kIB5/+nZ0v/ezsf/zr63/8u7tP/KurP/0sK7/+LS
yv+4p5//WktG/x8PCf8SAgD/JBgX/0o4Mv9sW1P/hnRs/5qIgP+nlo7/sqGa/7amn/+3p6D/rZ2W/5+P
iP+Pf3j/eGhh/1VFPv82Jh//KBgR/ycXEP81JR7/Oioj/zkpIv85KSL/OSki/zoqI/8jEwz/WUlC/4t7
dP8lFQ7/Oysk/y0dFv9GNi/Zbl5Xh////wH///8B////Af///wH///8B////AVNDPKc/LyjtMSEa/zYn
IP81JR7/inp1/4R2bv8wHxn/NiYf/zsrJP8wIBn/OCgh/zsrJP8qGhP/bV1W/+TUzf/UxL3/ybmy/829
tv/MvLX/0sK7/9vLxP+HeHH/GAwL/xsNDP9mWVX/raKd/9bNyv/s49//+vLv//z18v/16uX/6dnS/9vJ
wf/VxLz/5NTN/+XWz//dzcb/38/I/9vLxP/QwLn/t6eg/4d3cP9JOTL/JxcQ/zAgGf87KyT/OCgh/zgo
If89LSb/IhIL/2ZWT/98bGX/KhoT/zsrJP8tHRb/RjYv2W5eV4f///8B////Af///wH///8B////Af//
/wFTQzynPy8o7TEhGv85KSL/Nycg/yQRCf8mFQ3/OCki/zwsJf8vHxj/PCwl/419dv9HNzD/LR0W/6OT
jP/j08z/ybmy/829tv/Nvbb/zb22/93Nxv+FdnD/CgAA/11QS//VzMj/+/r5////////////////////
//////////7///v5+P/z6+f/z764/6qYkP/Ht7D/4NHK/9DAuf/Nvbb/2MjB/97Ox//fz8j/zr63/4R0
bf8vHxj/Lx8Y/zoqI/88LCX/Lh4X/zMjHP+Pf3j/Tj43/zUlHv86KiP/LR0W/0Y2L9luXleH////Af//
/wH///8B////Af///wH///8BU0M8pz8vKO0xIRr/OCgh/zgoIf81JB7/NiYf/zkpIv85KSL/IxMM/3xs
Zf/JubL/PS0m/y4eF/+pmZL/4tLL/8m5sv/Nvbb/zLy1/9fHwP+4qKH/IxQO/2RYU//59fP/////////
/////v7////////+/v////////////////////////////z5+P+4qaL/alhR/6KSi//j08z/1cW+/8i4
sf/Lu7T/z7+4/9zMxf/l1c7/k4N8/ywcFf82Jh//Lh4X/yoaE/+JeXL/dGRd/ywcFf85KSL/Oioj/y0d
Fv9GNi/Zbl5Xh////wH///8B////Af///wH///8B////AVNDPKc/LyjtMSEa/zgoIf84KCH/OCgh/zkp
Iv85KSL/MyMc/ywcFf+omJH/3c3G/0k5Mv8fDwj/dmZf/+XVzv/Tw7z/y7u0/8u7tP/h0cr/inpy/y8f
GP/m4N3////////+/v///v7//////////////////////////////v7/////////////////+/n4/6eX
kP81JR7/dGRd/9nJwv/Vxb7/y7u0/8y8tf/Lu7T/1cW+/97Ox/9pWVL/GwsE/zkpIv96amP/eWli/zEh
Gv80JB3/OSki/zoqI/8tHRb/RjYv2W5eV4f///8B////Af///wH///8B////Af///wFTQzynPy8o7TEh
Gv84KCH/OSki/zkpIv85KSL/Oioj/y4eF/81JR7/rZ2W/+vb1P+MfHX/Hg4H/y0dFv+Tg3z/5NTN/9rK
w//Ovbb/38/I/5iIgP9GNzD//vz7////////////////////////////////////////////////////
//////////////79/f/m19D/hnVu/xUFAP91ZV7/2srD/9LCu//MvLX/zb22/829tv/ezsf/jHx1/zAg
Gf9yYlv/XU1G/y4eF/8yIhv/Oioj/zkpIv86KiP/LR0W/0Y2L9luXleH////Af///wH///8B////Af//
/wH///8BU0M8pz8vKO0xIRr/OCgh/zkpIv85KSL/OSki/zoqI/8yIhv/MCAZ/6KSi//j08z/1cW+/21d
Vv8bCwT/IhIL/2xcVf+4qKH/2MfA/+DQyf/dzMb/eGZf/7qxrf//////////////////////////////
///////////////////////////////////u5eH/08G5/8W1rf80JB//JRUU/7Ghmv/dzcb/zLy1/829
tv/Nvbb/38/I/419dv8vHxj/QTEq/zAgGf82Jh//OCgh/zgoIf85KSL/Oioj/y0dFv9GNi/Zbl5Xh///
/wH///8B////Af///wH///8B////AVNDPKc/LyjtMSEa/zgoIf85KSL/OSki/zkpIv85KSL/OSki/yUV
Dv9tXVb/3s7H/9zMxf/UxL3/iHhx/zUlIP8SAgD/JhYO/1VGQf99bWf/o5OM/7emn/+fj4j/493a//7+
/v/////////////////////////////////////////////////z6uf/0L+4/9DAuf/Ht7D/OSki/x8P
CP+UhH3/3s7H/86+t//Lu7T/0sK7/93Nxv9kVE3/IREK/zYmH/83JyD/OCgh/zgoIf84KCH/OSki/zoq
I/8tHRb/RjYv2W5eV4f///8B////Af///wH///8B////Af///wFTQzynPy8o7TEhGv84KCH/OSki/zkp
Iv85KSL/OSki/zoqI/8xIRr/KxsU/52Nhv/j08z/28vE/+HRyv/Bsar/hXVu/0w8NP8jFhP/HQ4J/yER
Cv8yIhv/Nycf/zooIP+sop3////////////////////////////////////////////r4d3/x7Sr/8i3
sP/n19D/loZ//yAQCf8rGxT/rZ2W/93Nxv/KurP/1cW+/+nZ0v+aioP/KhoT/zUlHv84KCH/Nycg/zgo
If84KCH/OSki/zkpIv86KiP/LR0W/0Y2L9luXleH////Af///wH///8B////Af///wH///8BU0M8pz8v
KO0xIRr/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/Oysk/ywcFf80JB3/nY2G/97Ox//h0cr/4dHK/93N
xv/Rwbr/vayl/6STjP+Hd3H/cmJb/2NTTf9MOTL/dGNa/+3o5v////////7+///+/v///v7/////////
///07+z/x7Wt/8e3r//n2dL/va2m/zwsJf8UBAD/Y1NM/9XFvv/YyMH/38/I/+HRyv+fj4j/NiYf/y4e
F/86KiP/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/Oioj/y0dFv9GNi/Zbl5Xh////wH///8B////Af//
/wH///8B////AVNDPKc/LyjtMSEa/zgoIf85KSL/OSki/zkpIv85KSL/OSki/zgoIf86KiP/LBwV/y0d
Fv92Zl//wrKr/9zMxf/g0Mn/5NTN/+DQyf/by8T/3MzF/93Nxv/ZycL/1sa//8m4r//m29b/////////
/////v7//////////////v3/49fS/9fEvf/l1c7/taWd/z4uJ/8OAAD/U0M8/9PDvP/u3tf/3MzF/72t
pv9vX1j/LBwV/y0dFv86KiP/Nycg/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zoqI/8tHRb/RjYv2W5e
V4f///8B////Af///wH///8B////Af///wFTQzynPy8o7TEhGv84KCH/OSki/zkpIv85KSL/OSki/zkp
Iv84KCH/OSki/zoqI/8wIBn/JRUO/z0tJv9zY1z/p5eQ/8q6s//czMX/5NTN/+DQyf/dzcb/3MzF/9vL
xP/SwLj/3c3G//z5+P/////////////+/v////////78/+rZ0f+/rab/e2xk/yUVEP8kFA3/fm5n/+DQ
yf/i0sv/rZ2W/3JiW/83JyD/JBQN/y8fGP85KSL/OCgh/zgoIf85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv86KiP/LR0W/0Y2L9luXleH////Af///wH///8B////Af///wH///8BU0M8pz8vKO0xIRr/OCgh/zkp
Iv85KSL/OSki/zkpIv85KSL/OCgh/zgoIf84KCH/OSki/zUlHv8sHBX/KBgR/zAgGf9KOjP/bl5X/49/
eP+pmZL/v6+o/8q6s//Swrv/zr63/93MxP/89/X//////////////////////+Pc2f9xXlb/NyYg/yoa
E/9SQjz/kIB5/6yclf+Le3T/UkI7/zEhGv8oGBH/LR0W/zYmH/86KiP/OCgh/zgoIf84KCH/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/Oioj/y0dFv9GNi/Zbl5Xh////wH///8B////Af///wH///8B////AVND
PKc/LyjtMSEa/zgoIf85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Oioj/zYm
H/80JB3/MSEa/yoaE/8rGxT/Nycg/z8vKP9OPjf/Xk5I/2NTS/9eTET/xLu3////////////////////
/v+ShoH/EgAA/ysbFP9FNS7/X09I/04+N/82Jh//KRkS/y4eF/8zIxz/NSUe/zcnIP85KSL/MSEa/zIi
G/85KSL/Nycg/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zoqI/8tHRb/RjYv2W5eV4f///8B////Af//
/wH///8B////Af///wFTQzynPy8o7TEhGv84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/Oioj/zkpIv84KCH/NiYf/zUlHv8zIxz/MCAZ/y0dFv8tHRX/EAAA/3dp
ZP/49vX////////////v7Ov/YFBJ/yAOBv87LCX/NSUe/zIiG/81JR7/NSUe/zcnIP84KCH/OSki/zgo
If85KSL/MSEa/049Nf9OPTX/MCAZ/zkpIv84KCH/OSki/zkpIv85KSL/OSki/zkpIv86KiP/LR0W/0Y2
L9luXleH////Af///wH///8B////Af///wH///8BU0M8pz8vKO0xIRr/OCgh/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Nycg/zgoIf85KSL/OSki/zkpIv84KCH/OCgh/zgo
If84KCH/Oiok/yMRCf9PQTr/6efm////////////4t7c/z4sJP8lFQ7/Oioj/zcnIP85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv84KCH/Oioj/xUEAf+rnpn/ppmU/xUEAf86KyP/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/Oioj/y0dFv9GNi/Zbl5Xh////wH///8B////Af///wH///8B////AVNDPKc/LyjtMSEa/zgo
If85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv86KiP/OCki/yYVDv8sGhP/PCwl/zoq
I/85KSL/OSki/zgoIf84KCH/OCgh/zoqI/8oGRH/NCEZ/9vV0v///////////8W9uf8pFw//MSEa/zkp
Iv84KCH/Nycg/zgoIf85KSL/OSki/zkpIv85KSL/Oioj/xwMB/8zHxj/7ero/+7q6f82Ixz/HQwJ/zss
JP86KiP/OSki/zkpIv85KSL/OSki/zoqI/8tHRb/RjYv2W5eV4f///8B////Af///wH///8B////Af//
/wFTQzynPy8o7TEhGv84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv84KCH/Nycg/zoq
Iv9tXVj/Xk5I/zIiHP83JyD/OCgh/zgoIf85KSL/OCgh/zgoIf85KSL/NSUe/yQSCf+3rqv/////////
//+dko7/GQcA/zsrJP84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Oioj/zAhGP8pFxL/s6el////
////////saek/yQSDv8yIhv/Oysk/zkpIv85KSL/OSki/zkpIv86KiP/LR0W/0Y2L9luXleH////Af//
/wH///8B////Af///wH///8BU0M8pz8vKOsxIRr/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv86KiP/OCgh/xsLBf8nHh3/7+bh/6efnP8GAAD/JxUQ/zsrJP85KSL/OSki/zkpIv85KSL/OCgh/zoq
I/8YBgD/kYR///7+/f/7+fn/f29p/xwLBP88LCX/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Oioj/y4e
F/85Jh//u7Ou//////////////////////+4r6v/PCoi/y4eF/86KiP/OSki/zkpIv85KSL/Oioj/y0d
Fv9GNi/Zbl5Xh////wH///8B////Af///wH///8B////AVFBOqs+LifvMSEa/zgoIf85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/NiYf/zkpIf9tXlj/iXx4//z38//Pysj/e2xm/1pLRP8yIRr/Nycg/zkp
Iv85KSL/OSki/zkpIv86KiP/HQsE/3hoYP/6+fn/9fTz/1xNRv8jEgv/Oisk/zkpIv85KSL/OSki/zkp
Iv86KiP/Oioj/zsrJP8xIRr/MR8Y/52Qiv/7+vn////////////7+fn/m4+I/zAfF/8yIhv/Oioj/zkp
Iv85KSL/OSki/zoqI/8tHRb/RjYv221dVov///8B////Af///wH///8B////Af///wFTQzyrPy8o7zIi
G/85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Oioj/zIiG/88KiL/4NfT/////////v3///7+////
//+bko7/JBIL/zQjHP85KSL/OSki/zkpIv85KSL/Oioj/yQTC/9ZS0X/9fT0//Hv7v9DMiv/JxcQ/zoq
I/85KSL/OSki/zoqI/85KSL/KxsU/yoZEv82Jh7/Oysl/zMjHP8aCAX/lIiD//79/P/9/fz/koeD/xkH
BP80JR3/Oysk/zkpIv85KSL/OSki/zkpIv87KyT/LR0W/0MzLNtsXFWL////Af///wH///8B////Af//
/wH///8BaFhRaUU1LscsHBX/Oioj/zgoIf85KSL/OSki/zgoIf85KSL/OSki/zkpIv83JyD/OSoj/1RF
Pv9pWlP/9/Hv/8O/vP9WR0D/Szs0/zQkHP84KCH/OSki/zkpIv85KSL/OSki/zkpIv8oFxD/QjEq//Hv
7//j3tr/OSYe/ywcFv86KiP/OSki/zkpIv86KyT/Lh0V/1A/N/9WR0D/MB8X/zMjHP87KyT/KhoU/ygV
Dv/k3tv/5N7b/yoXEP8oGRP/Oysk/zkpIv85KSL/OSki/zkpIv84KCH/Oioj/ygYEf9MPDW7f29oWf//
/wH///8B////Af///wH///8B////AYd3cBNrW1RdLx8Y7TAgGf84KCH/OSki/zkpIv84KCH/OCgh/zkp
Iv85KSL/OSki/zgoIf8lEw3/MB4c/+fg2/+noZ7/FQMA/y4dFv86KiP/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/LBwV/zglHf/s5uP/z8nG/y0bEv8yIhv/OSki/zkpIv87KyP/JhYQ/2dXUP/v6+n/+vn3/5iM
iP8qGBD/MiMc/zsrJP8bCwT/mImC/5WFf/8ZCQP/PCwl/zkpIv85KSL/OSki/zoqI/85KSL/Nycg/zAg
Gf81JR7nf29oUaOTjA3///8B////Af///wH///8B////Af///wH///8B////AV5OR1FDMyzRNSUe/zYm
H/83JyD/Oioj/zgoIf85KSL/OSki/zkpIv84KCH/Nycg/zgoIf9XSEL/T0A5/zUlHv85KSL/OCgh/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zEhGv8tGxP/3tfV/7u1s/8gDQX/Nygh/zkpIv85KSL/PCwl/xYE
Af+qoZ7////////////X0s//Oygh/ycXEP86KiP/NCUe/0IxKf9DMiv/MiMc/zkpIv85KSL/OSki/zoq
I/83JyD/MyMc/zQkHf06KiPDWEhBQf///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8BZVVOGVJCO307KyTbMCAZ/zQkHf84KCH/OSki/zkpIv85KSL/OSki/zkpIv83KCH/JhYO/ywb
FP87KyT/OSki/zgoIf85KSL/OSki/zkpIv85KSL/OCgh/zgoIf82Jh//IxAI/8zGw/+uqKb/FgQA/zsr
JP85KSL/OSki/zorJP8nFg//ZlZQ/+Tg3v/v7ez/n5WQ/yoZEf80JB3/OSki/zopIv8wIBr/MCAZ/zoq
I/84KCH/OSki/zkpIv8zIxz/Lh4X/z4uJ9deTkdzX09IE////wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8BUEA5L1lJQps4KCHtNSUe/zYmH/85KSL/OCgh/zgo
If84KCH/OSki/zsrJP86KiP/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv84KCH/Oioj/xsI
Av+yqqf/ppqU/xoJAv87KyT/OSki/zkpIv85KSL/Oysk/y0cFP9SQjv/WUlD/y8fF/8zIxz/Oysk/zkp
Iv85KSL/OSki/zkpIv84KCH/OSki/zYmH/8zIxz/OSki52RUTZFeTkcn////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wGBcWoFTj43SUc3
MK80JB31Lx8Y/zYmH/85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zsrJP8dDAX/npGL/5OFfv8gDwj/Oysk/zgoIf85KSL/OSki/zoqI/83KCH/IxML/yMR
Cf8xIRn/PCwl/zkpIv85KSL/OSki/zkpIv85KSL/Nycg/y4eF/8yIhv1Tz84o1tLRD+VhX4F////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wFPPzgJVUU+X0g4MdUwIBn/MSEa/zsrJP85KSL/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zgoIf86KiP/IxMM/5B/eP+Ccmv/JRYP/zoqI/84KCH/OSki/zkp
Iv85KSL/OSki/zkqI/86KiP/OSki/zkpIv85KSL/OSki/zkpIv85KSL/NSUe/zAgGf9JOTLPXExFV19P
SAf///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wFpWVIbTj43dz0tJu0vHxj/OCgh/zkp
Iv85KSL/OSki/zgoIf84KCH/OSki/zkpIv85KSL/OSki/zkpIv85KSL/Oioj/ygYEf96amP/bl5X/yoa
E/85KSL/OCgh/zkpIv85KSL/OSki/zgoIf84KCH/OCgh/zkpIv85KSL/OSki/zkpIv84KCH/Lh4X/zsr
JN1RQTpzeGhhE////wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AVRE
PQOIeHEvSjozozUlHvs0JB3/NiYf/zgoIf84KCH/OCgh/zkpIv85KSL/OSki/zkpIv85KSL/OSki/zoq
I/8wIBn/XU1G/1FBOv8yIhv/Nycg/zgoIf85KSL/OSki/zkpIv84KCH/OCgh/zcnIP84KCH/OCgh/zcn
IP81JR7/NCQd+VtLRJ1dTUYjWkpDA////wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////AVFBOgVPPzhJQDApuzYmH/8zIxz/OSki/zkpIv85KSL/OSki/zkp
Iv85KSL/OSki/zkpIv85KSL/OSki/zsrJP83JyD/OSki/zcnIP85KSL/OSki/zkpIv85KSL/OCgh/zgo
If85KSL/Nycg/zMjHP81JR77Pi8ot1hIQUNmVk8D////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AVlJQgtuXldtNSUe1zEh
Gv8xIRr/OCgh/zoqI/85KSL/OSki/zkpIv85KSL/OSki/zoqI/82Jh//NiYf/zgoIf84KCH/OCgh/zkp
Iv85KSL/OSki/zkpIv81JR7/NiYf/zIiG/9HNzDTWkpDX0U1LgX///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////AVNDPCE9LSaPPS0m5TMjHP83JyD/Oioj/zoqI/85KSL/OSki/zgoIf85KSL/OSki/zgo
If84KCH/OSki/zgoIf85KSL/Oioj/zoqI/81JR7/MiIb/zoqI9tAMCqHcmJbHf///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////AWhYUTtGNjCrNCQd8zEhGv81JR7/Oioj/zkp
Iv83JyD/OCgh/zkpIv85KSL/OSki/zgoIf84KCH/Oysk/zMjHP8tHRb/OCgh71dHQKNJOTIt////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BXU1GBz4u
J09AMCm9NSUe/zIiG/84KCH/OSki/zgoIf85KSL/OSki/zgoIf86KiP/OSki/zEhGv8zIxz/RDQtt0o6
M0l5aWIF////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8BXk5HE2paU2U0JB3bKBgR/zMjHP85KSL/OCgh/zgoIf85KSL/MiIb/y4e
F/83JyDZdGRdX25eVw////8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BVUU+I2BQSY04KCHzLh4X/zoq
I/85KSL/MSEa/zkpIu9FNS5/SDgxH////wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8BYlJLOUU1Lq8yIhvXMiIb104+N6lqWlM1////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
/wH///8B////Af///wH///8B////Af///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
</value>
</data>
</root>

View File

@ -167,6 +167,8 @@
<Compile Include="Core\Packets\ClientPackets\GetCreateRegistryValueResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetDeleteRegistryKeyResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetDeleteRegistryValueResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetWebcamResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetWebcamsResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRegistryKeysResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRenameRegistryKeyResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRenameRegistryValueResponse.cs" />
@ -182,7 +184,10 @@
<Compile Include="Core\Packets\ServerPackets\DoLoadRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\DoRenameRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\DoRenameRegistryValue.cs" />
<Compile Include="Core\Packets\ServerPackets\DoWebcamStop.cs" />
<Compile Include="Core\Packets\ServerPackets\GetConnections.cs" />
<Compile Include="Core\Packets\ServerPackets\GetWebcam.cs" />
<Compile Include="Core\Packets\ServerPackets\GetWebcams.cs" />
<Compile Include="Core\Packets\ServerPackets\SetAuthenticationSuccess.cs" />
<Compile Include="Core\Registry\RegSeekerMatch.cs" />
<Compile Include="Core\Registry\RegValueData.cs" />
@ -277,6 +282,12 @@
<Compile Include="Enums\ShutdownAction.cs" />
<Compile Include="Enums\UserStatus.cs" />
<Compile Include="Enums\WordType.cs" />
<Compile Include="Forms\FrmRemoteWebcam.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\FrmRemoteWebcam.Designer.cs">
<DependentUpon>FrmRemoteWebcam.cs</DependentUpon>
</Compile>
<Compile Include="Forms\FrmAbout.cs">
<SubType>Form</SubType>
</Compile>
@ -445,6 +456,9 @@
</Compile>
<Compile Include="Core\Data\BuilderProfile.cs" />
<Compile Include="Core\Data\Settings.cs" />
<EmbeddedResource Include="Forms\FrmRemoteWebcam.resx">
<DependentUpon>FrmRemoteWebcam.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\FrmAbout.resx">
<DependentUpon>FrmAbout.cs</DependentUpon>
</EmbeddedResource>