diff --git a/Samples/Video/Player/MainForm.cs b/Samples/Video/Player/MainForm.cs
index 1d6c69d4..70ba1beb 100644
--- a/Samples/Video/Player/MainForm.cs
+++ b/Samples/Video/Player/MainForm.cs
@@ -128,7 +128,7 @@ private void OpenVideoSource( IVideoSource source )
CloseCurrentVideoSource( );
// start new video source
- videoSourcePlayer.VideoSource = source;
+ videoSourcePlayer.VideoSource = new AsyncVideoSource( source );
videoSourcePlayer.Start( );
// reset stop watch
diff --git a/Sources/Genetic/Chromosomes/ChromosomeBase.cs b/Sources/Genetic/Chromosomes/ChromosomeBase.cs
index 97fe1fb6..d989a50e 100644
--- a/Sources/Genetic/Chromosomes/ChromosomeBase.cs
+++ b/Sources/Genetic/Chromosomes/ChromosomeBase.cs
@@ -20,12 +20,12 @@ namespace AForge.Genetic
public abstract class ChromosomeBase : IChromosome
{
///
- /// Chromosome's fintess value.
+ /// Chromosome's fitness value.
///
protected double fitness = 0;
///
- /// Chromosome's fintess value.
+ /// Chromosome's fitness value.
///
///
/// Fitness value (usefulness) of the chromosome calculate by calling
diff --git a/Sources/Genetic/Chromosomes/DoubleArrayChromosome.cs b/Sources/Genetic/Chromosomes/DoubleArrayChromosome.cs
index 660ed483..67341438 100644
--- a/Sources/Genetic/Chromosomes/DoubleArrayChromosome.cs
+++ b/Sources/Genetic/Chromosomes/DoubleArrayChromosome.cs
@@ -112,7 +112,7 @@ public double[] Value
///
///
/// The property controls type of mutation, which is used more
- /// frequently. A radnom number is generated each time before doing mutation -
+ /// frequently. A random number is generated each time before doing mutation -
/// if the random number is smaller than the specified balance value, then one
/// mutation type is used, otherwse another. See method
/// for more information.
@@ -131,7 +131,7 @@ public double MutationBalancer
///
///
/// The property controls type of crossover, which is used more
- /// frequently. A radnom number is generated each time before doing crossover -
+ /// frequently. A random number is generated each time before doing crossover -
/// if the random number is smaller than the specified balance value, then one
/// crossover type is used, otherwse another. See method
/// for more information.
diff --git a/Sources/Genetic/Chromosomes/IChromosome.cs b/Sources/Genetic/Chromosomes/IChromosome.cs
index 0ea89492..cf56aab2 100644
--- a/Sources/Genetic/Chromosomes/IChromosome.cs
+++ b/Sources/Genetic/Chromosomes/IChromosome.cs
@@ -20,11 +20,11 @@ namespace AForge.Genetic
public interface IChromosome : IComparable
{
///
- /// Chromosome's fintess value.
+ /// Chromosome's fitness value.
///
///
/// The fitness value represents chromosome's usefulness - the greater the
- /// value, the more useful it.
+ /// value, the more useful it is.
///
double Fitness { get; }
diff --git a/Sources/Imaging/BlobCounterBase.cs b/Sources/Imaging/BlobCounterBase.cs
index 7e9bfdc4..00b27292 100644
--- a/Sources/Imaging/BlobCounterBase.cs
+++ b/Sources/Imaging/BlobCounterBase.cs
@@ -672,7 +672,6 @@ public Blob[] GetObjects( UnmanagedImage image, bool extractInOriginalSize )
( image.PixelFormat != PixelFormat.Format8bppIndexed ) &&
( image.PixelFormat != PixelFormat.Format32bppRgb ) &&
( image.PixelFormat != PixelFormat.Format32bppArgb ) &&
- ( image.PixelFormat != PixelFormat.Format32bppRgb ) &&
( image.PixelFormat != PixelFormat.Format32bppPArgb )
)
throw new UnsupportedImageFormatException( "Unsupported pixel format of the provided image." );
diff --git a/Sources/Video.DirectShow/Internals/CustomMarshalers.cs b/Sources/Video.DirectShow/Internals/CustomMarshalers.cs
new file mode 100644
index 00000000..6a270b6a
--- /dev/null
+++ b/Sources/Video.DirectShow/Internals/CustomMarshalers.cs
@@ -0,0 +1,127 @@
+// AForge Direct Show Library
+// AForge.NET framework
+//
+// Copyright © Andrew Kirillov, 2020
+// andrew.kirillov@gmail.com
+//
+// directshow.net library
+// directshownet.sourceforge.net
+//
+
+namespace AForge.Video.DirectShow.Internals
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ // Custom marshaller used to interop different Direct Show APIs
+ abstract internal class DSMarshaler : ICustomMarshaler
+ {
+ protected string cookie;
+ protected object obj;
+
+ public DSMarshaler( string cookie )
+ {
+ this.cookie = cookie;
+ }
+
+ // Called just before invoking the COM method. The returned IntPtr is what goes on the stack
+ // for the COM call. The input arg is the parameter that was passed to the method.
+ virtual public IntPtr MarshalManagedToNative( object managedObj )
+ {
+ this.obj = managedObj;
+
+ // create an appropriately sized buffer, blank it, and send it to the marshaler to make the COM call
+ int size = GetNativeDataSize( ) + 3;
+ IntPtr ptr = Marshal.AllocCoTaskMem( size );
+
+ for ( int x = 0; x < size / 4; x++ )
+ {
+ Marshal.WriteInt32( ptr, x * 4, 0 );
+ }
+
+ return ptr;
+ }
+
+ // Called just after invoking the COM method. The IntPtr is the same one that just got returned
+ // from MarshalManagedToNative. The return value is unused.
+ virtual public object MarshalNativeToManaged( IntPtr ptrNativeData )
+ {
+ return this.obj;
+ }
+
+ // Release the buffer
+ virtual public void CleanUpNativeData( IntPtr ptrNativeData )
+ {
+ if (ptrNativeData != IntPtr.Zero )
+ {
+ Marshal.FreeCoTaskMem( ptrNativeData );
+ }
+ }
+
+ // Release the managed object
+ virtual public void CleanUpManagedData( object managedObj )
+ {
+ this.obj = null;
+ }
+
+ // This routine is (apparently) never called by the marshaler. However it can be useful.
+ abstract public int GetNativeDataSize( );
+
+ // GetInstance is called by the marshaler in preparation to doing custom marshaling. The (optional)
+ // cookie is the value specified in MarshalCookie="asdf", or "" is none is specified.
+
+ // It is commented out in this abstract class, but MUST be implemented in derived classes
+ // public static ICustomMarshaler GetInstance(string cookie)
+ }
+
+ // Custom marshaller used for IEnumMediaTypes.Nex() as C# does not correctly marshal arrays of pointers
+ internal class EMTMarshaler : DSMarshaler
+ {
+ public EMTMarshaler( string cookie ) : base( cookie )
+ {
+ }
+
+ // Called just after invoking the COM method. The IntPtr is the same one that just got returned
+ // from MarshalManagedToNative. The return value is unused.
+ override public object MarshalNativeToManaged( IntPtr ptrNativeData )
+ {
+ AMMediaType[] emt = this.obj as AMMediaType[];
+
+ for ( int x = 0; x < emt.Length; x++ )
+ {
+ // copy in the value, and advance the pointer
+ IntPtr ptr = Marshal.ReadIntPtr( ptrNativeData, x * IntPtr.Size );
+ if ( ptr != IntPtr.Zero)
+ {
+ emt[x] = (AMMediaType) Marshal.PtrToStructure( ptr, typeof( AMMediaType ) );
+ }
+ else
+ {
+ emt[x] = null;
+ }
+ }
+
+ return null;
+ }
+
+ // The number of bytes to marshal out
+ override public int GetNativeDataSize( )
+ {
+ // get the array size
+ int len = ( (Array) this.obj ).Length;
+
+ // multiply that times the size of a pointer
+ int size = len * IntPtr.Size;
+
+ return size;
+ }
+
+ // This method is called by interop to create the custom marshaler. The (optional)
+ // cookie is the value specified in MarshalCookie="asdf", or "" is none is specified.
+ public static ICustomMarshaler GetInstance( string cookie )
+ {
+ return new EMTMarshaler( cookie );
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Sources/Video.DirectShow/Internals/IEnumMediaTypes.cs b/Sources/Video.DirectShow/Internals/IEnumMediaTypes.cs
new file mode 100644
index 00000000..67d52e2a
--- /dev/null
+++ b/Sources/Video.DirectShow/Internals/IEnumMediaTypes.cs
@@ -0,0 +1,68 @@
+// AForge Direct Show Library
+// AForge.NET framework
+//
+// Copyright © Andrew Kirillov, 2020
+// andrew.kirillov@gmail.com
+//
+
+namespace AForge.Video.DirectShow.Internals
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// This interface enumerates a pin's preferred media types.
+ ///
+ ///
+ [ComImport,
+ Guid( "89C31040-846B-11CE-97D3-00AA0055595A" ),
+ InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
+ internal interface IEnumMediaTypes
+ {
+ ///
+ /// Retrieves a specified number of media types.
+ ///
+ ///
+ /// The number of media types to retrieve.
+ /// Array of media types to fill in.
+ /// Receives the number of media types returned.
+ ///
+ /// Return's HRESULT error code.
+ ///
+ [PreserveSig]
+ int Next( [In] int cMediaTypes,
+ [In, Out, MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( EMTMarshaler ), SizeParamIndex = 0 )] AMMediaType[] mediaTypes,
+ [Out] out int typesFetched );
+
+ ///
+ /// Skips over a specified number of media types.
+ ///
+ ///
+ /// Number of media types to skip.
+ ///
+ /// Return's HRESULT error code.
+ ///
+ [PreserveSig]
+ int Skip( [In] int cMediaTypes );
+
+ ///
+ /// Resets the enumeration sequence to the beginning.
+ ///
+ ///
+ /// Return's HRESULT error code.
+ ///
+ [PreserveSig]
+ int Reset( );
+
+ ///
+ /// makes a copy of the enumerator.
+ ///
+ ///
+ /// Clone of the enumerator
+ ///
+ /// Return's HRESULT error code.
+ ///
+ [PreserveSig]
+ int Clone( [Out] out IEnumPins enumMediaTypes );
+ }
+}
\ No newline at end of file
diff --git a/Sources/Video.DirectShow/Internals/IPin.cs b/Sources/Video.DirectShow/Internals/IPin.cs
index ceed73f2..e340917b 100644
--- a/Sources/Video.DirectShow/Internals/IPin.cs
+++ b/Sources/Video.DirectShow/Internals/IPin.cs
@@ -125,12 +125,12 @@ internal interface IPin
/// Provides an enumerator for this pin's preferred media types.
///
///
- /// Address of a variable that receives a pointer to the IEnumMediaTypes interface.
+ /// Receives .
///
/// Return's HRESULT error code.
///
[PreserveSig]
- int EnumMediaTypes( IntPtr enumerator );
+ int EnumMediaTypes( [Out] out IEnumMediaTypes enumMediaTypes );
///
/// Provides an array of the pins to which this pin internally connects.
diff --git a/Sources/Video.DirectShow/Internals/Uuids.cs b/Sources/Video.DirectShow/Internals/Uuids.cs
index 8dc18745..f60aad11 100644
--- a/Sources/Video.DirectShow/Internals/Uuids.cs
+++ b/Sources/Video.DirectShow/Internals/Uuids.cs
@@ -256,6 +256,15 @@ static internal class MediaSubType
///
public static readonly Guid Asf =
new Guid( 0x3DB80F90, 0x9412, 0x11D1, 0xAD, 0xED, 0x00, 0x00, 0xF8, 0x75, 0x4B, 0x99 );
+
+ ///
+ /// Motion JPEG.
+ ///
+ ///
+ /// Equals to MEDIASUBTYPE_MJPG.
+ ///
+ public static readonly Guid MJpeg =
+ new Guid( 0x47504A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
}
///
diff --git a/Sources/Video.DirectShow/Video.DirectShow.csproj b/Sources/Video.DirectShow/Video.DirectShow.csproj
index cfebb5e7..7af331e3 100644
--- a/Sources/Video.DirectShow/Video.DirectShow.csproj
+++ b/Sources/Video.DirectShow/Video.DirectShow.csproj
@@ -68,6 +68,7 @@
+
@@ -76,6 +77,7 @@
+
diff --git a/Sources/Video.DirectShow/VideoCaptureDevice.cs b/Sources/Video.DirectShow/VideoCaptureDevice.cs
index 8b76c5a3..fe20f26c 100644
--- a/Sources/Video.DirectShow/VideoCaptureDevice.cs
+++ b/Sources/Video.DirectShow/VideoCaptureDevice.cs
@@ -2,8 +2,8 @@
// AForge.NET framework
// http://www.aforgenet.com/framework/
//
-// Copyright © AForge.NET, 2009-2013
-// contacts@aforgenet.com
+// Copyright © AForge.NET, 2009-2017
+// aforge.net@gmail.com
//
namespace AForge.Video.DirectShow
@@ -14,6 +14,7 @@ namespace AForge.Video.DirectShow
using System.Drawing.Imaging;
using System.Threading;
using System.Runtime.InteropServices;
+ using System.IO;
using AForge.Video;
using AForge.Video.DirectShow.Internals;
@@ -68,6 +69,11 @@ public class VideoCaptureDevice : IVideoSource
// provide snapshots or not
private bool provideSnapshots = false;
+ // JPEG encoding preference
+ private bool preferJpegEncoding = true;
+ // check if JPEG encoding is enabled
+ private bool jpegEncodingEnabled = false;
+
private Thread thread = null;
private ManualResetEvent stopEvent = null;
@@ -205,6 +211,45 @@ public bool ProvideSnapshots
set { provideSnapshots = value; }
}
+ ///
+ /// Specifies preference for JPEG encoding mode for video acquisition.
+ ///
+ ///
+ /// Many video devices can provide video frames encoded as JPEG image,
+ /// which increases frame rate (as transferring uncompressed RGB data over USB interface
+ /// is much slower). If device supports it, then we can instruct it to provide JPEG images.
+ /// If not, it is configured to provide RGB data.
+ ///
+ /// The property must be set before starting video device to take an effect.
+ ///
+ /// The event provides uncompressed image anyway.
+ /// This property is only affects internal mode of video acquisition.
+ ///
+ /// Default value of the property is set to , which should
+ /// be kept this way unless there is some strong reason otherwise.
+ ///
+ ///
+ public bool PreferJpegEncoding
+ {
+ get { return preferJpegEncoding; }
+ set { preferJpegEncoding = value; }
+ }
+
+ ///
+ /// Check if JPEG encoding is enabled for running device.
+ ///
+ ///
+ /// Specifies if video acquisition is configured to provide
+ /// JPEG encoded images.
+ ///
+ ///
+ ///
+ ///
+ public bool JpegEncodingEnabled
+ {
+ get { return JpegEncodingEnabled; }
+ }
+
///
/// New frame event.
///
@@ -1070,13 +1115,23 @@ private void WorkerThread( bool runGraph )
graph.AddFilter( videoGrabberBase, "grabber_video" );
graph.AddFilter( snapshotGrabberBase, "grabber_snapshot" );
- // set media type
- AMMediaType mediaType = new AMMediaType( );
- mediaType.MajorType = MediaType.Video;
- mediaType.SubType = MediaSubType.RGB24;
+ // check if we need and can do JPEG encoding
+ if ( preferJpegEncoding )
+ {
+ jpegEncodingEnabled = IsJpegEncodingAvailable( sourceBase );
+ }
- videoSampleGrabber.SetMediaType( mediaType );
- snapshotSampleGrabber.SetMediaType( mediaType );
+ // set media types
+ AMMediaType videoMediaType = new AMMediaType( );
+ videoMediaType.MajorType = MediaType.Video;
+ videoMediaType.SubType = ( jpegEncodingEnabled ) ? MediaSubType.MJpeg : MediaSubType.RGB24;
+
+ AMMediaType snapshotMediaType = new AMMediaType( );
+ snapshotMediaType.MajorType = MediaType.Video;
+ snapshotMediaType.SubType = MediaSubType.RGB24;
+
+ videoSampleGrabber.SetMediaType( videoMediaType );
+ snapshotSampleGrabber.SetMediaType( snapshotMediaType );
// get crossbar object to to allows configuring pins of capture card
captureGraph.FindInterface( FindDirection.UpstreamOnly, Guid.Empty, sourceBase, typeof( IAMCrossbar ).GUID, out crossbarObject );
@@ -1097,7 +1152,8 @@ private void WorkerThread( bool runGraph )
{
VideoControlFlags caps;
videoControl.GetCaps( pinStillImage, out caps );
- isSapshotSupported = ( ( caps & VideoControlFlags.ExternalTriggerEnable ) != 0 );
+ isSapshotSupported = ( ( ( caps & VideoControlFlags.ExternalTriggerEnable ) != 0 ) ||
+ ( ( caps & VideoControlFlags.Trigger ) != 0 ) );
}
}
@@ -1142,6 +1198,8 @@ private void WorkerThread( bool runGraph )
if ( runGraph )
{
+ AMMediaType mediaType = new AMMediaType( ); ;
+
// render capture pin
captureGraph.RenderStream( PinCategory.Capture, MediaType.Video, sourceBase, null, videoGrabberBase );
@@ -1313,6 +1371,62 @@ private void WorkerThread( bool runGraph )
{
PlayingFinished( this, reasonToStop );
}
+
+ jpegEncodingEnabled = false;
+ }
+
+ // Check if the filter can provide JPEG encoded images
+ private bool IsJpegEncodingAvailable( IBaseFilter baseFilter )
+ {
+ bool ret = false;
+ IEnumPins pinEnum = null;
+ IPin[] pins = new IPin[1];
+ int pinsFetched;
+
+ if ( ( baseFilter.EnumPins( out pinEnum ) == 0 ) && ( pinEnum != null ) )
+ {
+ try
+ {
+ while ( ( pinEnum.Next( 1, pins, out pinsFetched ) == 0 ) && ( !ret ) )
+ {
+ PinDirection pinDir;
+
+ if ( ( pins[0].QueryDirection( out pinDir ) == 0 ) && ( pinDir == PinDirection.Output ) )
+ {
+ // enum preferred media types of the pin
+ IEnumMediaTypes mediaEnum = null;
+ AMMediaType[] mediaTypes = new AMMediaType[1];
+ int typesFetched;
+
+ if ( pins[0].EnumMediaTypes( out mediaEnum ) == 0 )
+ {
+ try
+ {
+ while ( ( mediaEnum.Next( 1, mediaTypes, out typesFetched ) == 0 ) && ( !ret ) )
+ {
+ if ( ( mediaTypes[0].MajorType == MediaType.Video ) && ( mediaTypes[0].SubType == MediaSubType.MJpeg ))
+ {
+ ret = true;
+ }
+
+ mediaTypes[0].Dispose( );
+ }
+ }
+ finally
+ {
+ Marshal.ReleaseComObject( mediaEnum );
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ Marshal.ReleaseComObject( pinEnum );
+ }
+ }
+
+ return ret;
}
// Set resolution for the specified stream configuration
@@ -1396,6 +1510,8 @@ private void GetPinCapabilitiesAndConfigureSizeAndRate( ICaptureGraphBuilder2 gr
SetResolution( streamConfig, resolutionToSet );
}
}
+
+ Marshal.ReleaseComObject( streamConfigObject );
}
// if failed resolving capabilities, then just create empty capabilities array,
@@ -1648,47 +1764,62 @@ 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 );
+ System.Drawing.Bitmap image = null;
- // lock bitmap data
- BitmapData imageData = image.LockBits(
- new Rectangle( 0, 0, width, height ),
- ImageLockMode.ReadWrite,
- PixelFormat.Format24bppRgb );
+ if ( !parent.jpegEncodingEnabled )
+ {
+ // create new image
+ image = new Bitmap( width, height, PixelFormat.Format24bppRgb );
- // copy image data
- int srcStride = imageData.Stride;
- int dstStride = imageData.Stride;
+ // lock bitmap data
+ BitmapData imageData = image.LockBits(
+ new Rectangle( 0, 0, width, height ),
+ ImageLockMode.ReadWrite,
+ PixelFormat.Format24bppRgb );
- unsafe
- {
- byte* dst = (byte*) imageData.Scan0.ToPointer( ) + dstStride * ( height - 1 );
- byte* src = (byte*) buffer.ToPointer( );
+ // copy image data
+ int srcStride = imageData.Stride;
+ int dstStride = imageData.Stride;
- for ( int y = 0; y < height; y++ )
+ unsafe
{
- Win32.memcpy( dst, src, srcStride );
- dst -= dstStride;
- src += srcStride;
- }
- }
+ byte* dst = (byte*) imageData.Scan0.ToPointer( ) + dstStride * ( height - 1 );
+ byte* src = (byte*) buffer.ToPointer( );
- // unlock bitmap data
- image.UnlockBits( imageData );
+ for ( int y = 0; y < height; y++ )
+ {
+ Win32.memcpy( dst, src, srcStride );
+ dst -= dstStride;
+ src += srcStride;
+ }
+ }
- // notify parent
- if ( snapshotMode )
- {
- parent.OnSnapshotFrame( image );
+ // unlock bitmap data
+ image.UnlockBits( imageData );
}
else
{
- parent.OnNewFrame( image );
+ unsafe
+ {
+ image = (Bitmap)Bitmap.FromStream( new UnmanagedMemoryStream( (byte*)buffer.ToPointer( ), bufferLen ) );
+ }
}
- // release the image
- image.Dispose( );
+ if ( image != null )
+ {
+ // notify parent
+ if (snapshotMode)
+ {
+ parent.OnSnapshotFrame( image );
+ }
+ else
+ {
+ parent.OnNewFrame( image );
+ }
+
+ // release the image
+ image.Dispose( );
+ }
}
return 0;
diff --git a/Sources/Video.DirectShow/VideoCaptureDeviceForm.Designer.cs b/Sources/Video.DirectShow/VideoCaptureDeviceForm.Designer.cs
index c300a4f8..031aaa1c 100644
--- a/Sources/Video.DirectShow/VideoCaptureDeviceForm.Designer.cs
+++ b/Sources/Video.DirectShow/VideoCaptureDeviceForm.Designer.cs
@@ -118,7 +118,7 @@ private void InitializeComponent( )
this.snapshotsLabel.Name = "snapshotsLabel";
this.snapshotsLabel.Size = new System.Drawing.Size( 101, 13 );
this.snapshotsLabel.TabIndex = 15;
- this.snapshotsLabel.Text = "Snapshot resoluton:";
+ this.snapshotsLabel.Text = "Snapshot resolution:";
//
// snapshotResolutionsCombo
//
@@ -145,7 +145,7 @@ private void InitializeComponent( )
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size( 83, 13 );
this.label2.TabIndex = 12;
- this.label2.Text = "Video resoluton:";
+ this.label2.Text = "Video resolution:";
//
// label1
//
diff --git a/Sources/Video.FFMPEG/VideoFileWriter.cpp b/Sources/Video.FFMPEG/VideoFileWriter.cpp
index afcefada..d9ad7f47 100644
--- a/Sources/Video.FFMPEG/VideoFileWriter.cpp
+++ b/Sources/Video.FFMPEG/VideoFileWriter.cpp
@@ -208,18 +208,12 @@ void VideoFileWriter::Close( )
libffmpeg::av_free( data->VideoOutputBuffer );
}
- for ( unsigned int i = 0; i < data->FormatContext->nb_streams; i++ )
- {
- libffmpeg::av_freep( &data->FormatContext->streams[i]->codec );
- libffmpeg::av_freep( &data->FormatContext->streams[i] );
- }
-
if ( data->FormatContext->pb != NULL )
{
libffmpeg::avio_close( data->FormatContext->pb );
}
- libffmpeg::av_free( data->FormatContext );
+ libffmpeg::avformat_free_context( data->FormatContext );
}
if ( data->ConvertContext != NULL )