diff --git a/Greenshot/Helpers/AviHelper.cs b/Greenshot/Helpers/AviHelper.cs index ba8b623cb..29b307ae8 100644 --- a/Greenshot/Helpers/AviHelper.cs +++ b/Greenshot/Helpers/AviHelper.cs @@ -12,314 +12,355 @@ using System.Drawing.Imaging; using System.Runtime.InteropServices; using GreenshotPlugin.UnmanagedHelpers; +using System.Collections.Generic; +using System.IO; namespace Greenshot.Helpers { - - /// - /// AVI files writing using Video for Windows interface. - /// - /// - /// The class allows to write AVI files using Video for Windows API. - /// - /// Sample usage: - /// /// // instantiate AVI writer, use WMV3 codec - /// AVIWriter writer = new AVIWriter( "wmv3" ); - /// // create new AVI file and open it - /// writer.Open( "test.avi", 320, 240 ); - /// // create frame image - /// Bitmap image = new Bitmap( 320, 240 ); - /// - /// for ( int i = 0; i < 240; i++ ) - /// { - /// // update image - /// image.SetPixel( i, i, Color.Red ); - /// // add the image as a new frame of video file - /// writer.AddFrame( image ); - /// } - /// writer.Close( ); - /// + + /// + /// AVI files writing using Video for Windows interface. + /// + /// + /// The class allows to write AVI files using Video for Windows API. + /// + /// Sample usage: + /// /// // instantiate AVI writer, use WMV3 codec + /// AVIWriter writer = new AVIWriter( "wmv3" ); + /// // create new AVI file and open it + /// writer.Open( "test.avi", 320, 240 ); + /// // create frame image + /// Bitmap image = new Bitmap( 320, 240 ); + /// + /// for ( int i = 0; i < 240; i++ ) + /// { + /// // update image + /// image.SetPixel( i, i, Color.Red ); + /// // add the image as a new frame of video file + /// writer.AddFrame( image ); + /// } + /// writer.Close( ); + /// /// - /// - public class AVIWriter : IDisposable { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AVIWriter)); - // AVI file - private IntPtr file; - // video stream - private IntPtr stream; - // compressed stream - private IntPtr streamCompressed; - // width of video frames - private int width; - // height of vide frames - private int height; - // length of one line - private int stride; - // quality - private int quality = -1; - // frame rate - private int rate = 25; - // current position - private int position; - // codec used for video compression - private string codec = null; //"DIB "; - - /// - /// Width of video frames. - /// - /// - /// The property specifies the width of video frames, which are acceptable - /// by method for saving, which is set in - /// method. - /// - public int Width { - get { return width; } - } - - /// - /// Height of video frames. - /// - /// - /// The property specifies the height of video frames, which are acceptable - /// by method for saving, which is set in - /// method. - /// - public int Height { - get { return height; } - } - - /// - /// Current position in video stream. - /// - /// - /// The property tell current position in video stream, which actually equals - /// to the amount of frames added using method. - /// - public int Position - { - get { return position; } - } - - /// - /// Desired playing frame rate. - /// - /// - /// The property sets the video frame rate, which should be use during playing - /// of the video to be saved. - /// - /// The property should be set befor opening new file to take effect. - /// - /// Default frame rate is set to 25. - /// - public int FrameRate - { - get { return rate; } - set { rate = value; } - } - - /// - /// Codec used for video compression. - /// - /// - /// The property sets the FOURCC code of video compression codec, which needs to - /// be used for video encoding. - /// - /// The property should be set befor opening new file to take effect. - /// - /// Default video codec is set "DIB ", which means no compression. - /// - public string Codec - { - get { return codec; } - set { codec = value; } - } - - /// - /// Compression video quality. - /// - /// - /// The property sets video quality used by codec in order to balance compression rate - /// and image quality. The quality is measured usually in the [0, 100] range. - /// - /// The property should be set befor opening new file to take effect. - /// - /// Default value is set to -1 - default compression quality of the codec. - /// - public int Quality - { - get { return quality; } - set { quality = value; } - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Initializes Video for Windows library. - /// - public AVIWriter() { - Avi32.AVIFileInit(); - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Codec to use for compression. eg [CVID],[IV50] - /// - /// Initializes Video for Windows library. - /// - public AVIWriter(string codec) : this() { - this.codec = codec; - } - - /// - /// Destroys the instance of the class. - /// - /// - ~AVIWriter() { - Dispose(false); - } - - /// - /// Dispose the object. - /// - /// - /// Frees unmanaged resources used by the object. The object becomes unusable - /// after that. - /// - public void Dispose() { - Dispose(true); - // remove me from the Finalization queue - GC.SuppressFinalize(this); - } - - /// - /// Dispose the object. - /// - /// - /// Indicates if disposing was initiated manually. - /// - protected virtual void Dispose(bool disposing) { - if (disposing) { - // dispose managed resources - } - // close current AVI file if any opened and uninitialize AVI library - Close(); - Avi32.AVIFileExit(); - } - - /// - /// Create new AVI file and open it for writing. - /// - /// - /// AVI file name to create. - /// Video width. - /// Video height. - /// - /// The method opens (creates) a video files, configure video codec and prepares - /// the stream for saving video frames with a help of method. - /// - /// Failure of opening video files (the exception message - /// specifies the issues). - /// - public bool Open(string fileName, int width, int height) { - lock (this) { - // calculate stride - stride = width * 4; - if ((stride % 4) != 0) - stride += (4 - stride % 4); - - // create new file - if (Avi32.AVIFileOpen(out file, fileName, Avi32.OpenFileMode.Create | Avi32.OpenFileMode.Write, IntPtr.Zero) != 0) { - throw new ApplicationException("Failed opening file"); - } - - this.width = width; - this.height = height; - - // describe new stream - Avi32.AVISTREAMINFO info = new Avi32.AVISTREAMINFO(); - - info.type = Avi32.mmioFOURCC("vids"); - if (codec != null) { - info.handler = Avi32.mmioFOURCC(codec); - } else { - info.handler = Avi32.mmioFOURCC("DIB "); - } - info.scale = 1; - info.rate = rate; - info.suggestedBufferSize = stride * height; - - // describe compression options - Avi32.AVICOMPRESSOPTIONS options = new Avi32.AVICOMPRESSOPTIONS(); + /// + public class AVIWriter : IDisposable { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AVIWriter)); + // AVI file + private IntPtr file; + // video stream + private IntPtr stream; + // compressed stream + private IntPtr streamCompressed; + // width of video frames + private int width; + // height of vide frames + private int height; + // length of one line + private int stride; + // quality + private int quality = -1; + // frame rate + private int rate = 25; + // current position + private int position; + // codec used for video compression + private string codec = null; //"DIB "; - // create stream - if (Avi32.AVIFileCreateStream(file, out stream, ref info) != 0) { - throw new ApplicationException("Failed creating stream"); + /// + /// Width of video frames. + /// + /// + /// The property specifies the width of video frames, which are acceptable + /// by method for saving, which is set in + /// method. + /// + public int Width { + get { + return width; + } + } + + /// + /// Height of video frames. + /// + /// + /// The property specifies the height of video frames, which are acceptable + /// by method for saving, which is set in + /// method. + /// + public int Height { + get { + return height; + } + } + + /// + /// Current position in video stream. + /// + /// + /// The property tell current position in video stream, which actually equals + /// to the amount of frames added using method. + /// + public int Position { + get { + return position; + } + } + + /// + /// Desired playing frame rate. + /// + /// + /// The property sets the video frame rate, which should be use during playing + /// of the video to be saved. + /// + /// The property should be set befor opening new file to take effect. + /// + /// Default frame rate is set to 25. + /// + public int FrameRate { + get { + return rate; + } + set { + rate = value; + } + } + + /// + /// Codec used for video compression. + /// + /// + /// The property sets the FOURCC code of video compression codec, which needs to + /// be used for video encoding. + /// + /// The property should be set befor opening new file to take effect. + /// + /// Default video codec is set "DIB ", which means no compression. + /// + public string Codec { + get { + return codec; + } + set { + codec = value; + } + } + + /// + /// Compression video quality. + /// + /// + /// The property sets video quality used by codec in order to balance compression rate + /// and image quality. The quality is measured usually in the [0, 100] range. + /// + /// The property should be set befor opening new file to take effect. + /// + /// Default value is set to -1 - default compression quality of the codec. + /// + public int Quality { + get { + return quality; + } + set { + quality = value; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Initializes Video for Windows library. + /// + public AVIWriter() { + Avi32.AVIFileInit(); + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Codec to use for compression. eg [CVID],[IV50] + /// + /// Initializes Video for Windows library. + /// + public AVIWriter(string codec) + : this() { + this.codec = codec; + } + + /// + /// Destroys the instance of the class. + /// + /// + ~AVIWriter() { + Dispose(false); + } + + /// + /// Dispose the object. + /// + /// + /// Frees unmanaged resources used by the object. The object becomes unusable + /// after that. + /// + public void Dispose() { + Dispose(true); + // remove me from the Finalization queue + GC.SuppressFinalize(this); + } + + /// + /// Dispose the object. + /// + /// + /// Indicates if disposing was initiated manually. + /// + protected virtual void Dispose(bool disposing) { + if (disposing) { + // dispose managed resources + } + // close current AVI file if any opened and uninitialize AVI library + Close(); + Avi32.AVIFileExit(); + } + + /// + /// Create new AVI file and open it for writing. + /// + /// + /// AVI file name to create. + /// Video width. + /// Video height. + /// + /// The method opens (creates) a video files, configure video codec and prepares + /// the stream for saving video frames with a help of method. + /// + /// Failure of opening video files (the exception message + /// specifies the issues). + /// + public bool Open(string fileName, int width, int height) { + lock (this) { + // calculate stride + stride = width * 4; + if ((stride % 4) != 0) { + stride += (4 - stride % 4); } - - // uncomment if video settings dialog is required to show - int retCode = 0; - if (codec == null) { - retCode = Avi32.AVISaveOptions( stream, ref options ); - if (retCode == 0) { - LOG.Debug("Cancel clicked!"); - return false; - } - } else { - options.handler = Avi32.mmioFOURCC(codec); - options.quality = quality; - } + + this.width = width; + this.height = height; + + // describe new stream + Avi32.AVISTREAMINFO info = new Avi32.AVISTREAMINFO(); + + LOG.InfoFormat("Available codecs: {0}", String.Join(", ", Avi32.AvailableCodecs.ToArray())); + + info.type = Avi32.mmioFOURCC("vids"); + if (codec != null) { + info.handler = Avi32.mmioFOURCC(codec); + } else { + info.handler = Avi32.mmioFOURCC("DIB "); + } + info.scale = 1; + info.rate = rate; + info.suggestedBufferSize = stride * height; + + try { + // create new file + if (Avi32.AVIFileOpen(out file, fileName, Avi32.OpenFileMode.Create | Avi32.OpenFileMode.Write, IntPtr.Zero) != 0) { + throw new ApplicationException("Failed opening file"); + } + + // create stream + if (Avi32.AVIFileCreateStream(file, out stream, ref info) != 0) { + throw new ApplicationException("Failed creating stream"); + } + + // describe compression options + Avi32.AVICOMPRESSOPTIONS options = new Avi32.AVICOMPRESSOPTIONS(); + // uncomment if video settings dialog is required to show + int retCode = 0; + if (codec == null) { + retCode = Avi32.AVISaveOptions(stream, ref options); + if (retCode == 0) { + LOG.Debug("Cancel clicked!"); + return false; + } + codec = Avi32.decode_mmioFOURCC(options.handler); + quality = options.quality; + } else { + options.handler = Avi32.mmioFOURCC(codec); + options.quality = quality; + } + LOG.DebugFormat("Codec {0} selected with quality {1}.", codec, quality); + + AviError retval; + // create compressed stream + try { + retval = Avi32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero); + } catch (Exception exCompress) { + LOG.Warn("Couldn't use compressed stream.", exCompress); + retval = AviError.AVIERR_OK; + } + if (retval != AviError.AVIERR_OK) { + throw new ApplicationException(string.Format("Failed creating compressed stream: {0}", retval)); + } - // create compressed stream - int retval = Avi32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero); - if (retval != 0) { - throw new ApplicationException("Failed creating compressed stream: " + retval); - } - - // describe frame format - BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(width, height, 32); - - // set frame format - retval = Avi32.AVIStreamSetFormat(streamCompressed, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType())); - if (retval != 0) { - throw new ApplicationException("Failed creating compressed stream: "+ retval); - } - position = 0; - return true; - } - } - - /// - /// Close video file. - /// - /// - public void Close() { - LOG.Debug("Close called"); - lock (this) { - // release compressed stream - if (streamCompressed != IntPtr.Zero) { - LOG.Debug("AVIStreamRelease streamCompressed"); - Avi32.AVIStreamRelease(streamCompressed); - streamCompressed = IntPtr.Zero; - } - - // release stream - if (stream != IntPtr.Zero) { - LOG.Debug("AVIStreamRelease stream"); - Avi32.AVIStreamRelease(stream); - stream = IntPtr.Zero; - } - - // release file - if (file != IntPtr.Zero) { - LOG.Debug("AVIFileRelease file"); - Avi32.AVIFileRelease(file); - file = IntPtr.Zero; - } - } - } + // describe frame format + BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(width, height, 32); + + // set frame format + if (streamCompressed != IntPtr.Zero) { + retval = Avi32.AVIStreamSetFormat(streamCompressed, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType())); + } else { + retval = Avi32.AVIStreamSetFormat(stream, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType())); + } + if (retval != 0) { + throw new ApplicationException(string.Format("Failed creating stream: {0}", retval)); + } + position = 0; + return true; + } catch (Exception ex) { + Close(); + Avi32.AVIFileExit(); + if (File.Exists(fileName)) { + File.Delete(fileName); + } + throw ex; + } + } + } + + /// + /// Close video file. + /// + /// + public void Close() { + LOG.Debug("Close called"); + lock (this) { + // release compressed stream + if (streamCompressed != IntPtr.Zero) { + LOG.Debug("AVIStreamRelease streamCompressed"); + Avi32.AVIStreamRelease(streamCompressed); + streamCompressed = IntPtr.Zero; + } + + // release stream + if (stream != IntPtr.Zero) { + LOG.Debug("AVIStreamRelease stream"); + Avi32.AVIStreamRelease(stream); + stream = IntPtr.Zero; + } + + // release file + if (file != IntPtr.Zero) { + LOG.Debug("AVIFileRelease file"); + Avi32.AVIFileRelease(file); + file = IntPtr.Zero; + } + } + } public void AddEmptyFrames(int frames) { lock (this) { @@ -328,581 +369,753 @@ namespace Greenshot.Helpers { } /// - /// Add new frame to the AVI file. - /// - /// New frame data. - public void AddLowLevelFrame(IntPtr frameData) { - lock (this) { - // write to stream - if (Avi32.AVIStreamWrite(streamCompressed, position, 1, frameData, stride * height, 0, IntPtr.Zero, IntPtr.Zero) != 0) { - throw new ApplicationException("Failed adding frame"); - } - - position++; - } - } - } - - /// - /// Windows API functions and structures. - /// - /// - /// The class provides Video for Windows and some other Avi32 functions and structurs. - /// - internal static class Avi32 { - /// - /// Copy a block of memory. - /// - /// - /// Destination pointer. - /// Source pointer. - /// Memory block's length to copy. - /// - /// Return's the value of dst - pointer to destination. - /// - [DllImport("ntdll.dll")] - public static extern int memcpy(int dst, int src, int count); - - - // --- Video for Windows Functions - - /// - /// Initialize the AVIFile library. - /// - /// - [DllImport("avifil32.dll")] - public static extern void AVIFileInit(); - - /// - /// Exit the AVIFile library. - /// - [DllImport("avifil32.dll")] - public static extern void AVIFileExit(); - - /// - /// Open an AVI file. - /// - /// - /// Opened AVI file interface. - /// AVI file name. - /// Opening mode (see ). - /// Handler to use (null to use default). - /// - /// Returns zero on success or error code otherwise. - /// - [DllImport("avifil32.dll", CharSet = CharSet.Unicode)] - public static extern int AVIFileOpen(out IntPtr aviHandler, String fileName, OpenFileMode mode, IntPtr handler); - - /// - /// Release an open AVI stream. - /// - /// - /// Open AVI file interface. - /// - /// Returns the reference count of the file. - /// - [DllImport("avifil32.dll")] - public static extern int AVIFileRelease(IntPtr aviHandler); - - /// - /// Get stream interface that is associated with a specified AVI file - /// - /// - /// Handler to an open AVI file. - /// Stream interface. - /// Stream type to open. - /// Count of the stream type. Identifies which occurrence of the specified stream type to access. - /// - /// - /// - [DllImport("avifil32.dll")] - public static extern int AVIFileGetStream(IntPtr aviHandler, out IntPtr streamHandler, int streamType, int streamNumner); - - /// - /// Create a new stream in an existing file and creates an interface to the new stream. - /// - /// - /// Handler to an open AVI file. - /// Stream interface. - /// Pointer to a structure containing information about the new stream. - /// - /// Returns zero if successful or an error otherwise. - /// - [DllImport("avifil32.dll")] - public static extern int AVIFileCreateStream(IntPtr aviHandler, out IntPtr streamHandler, ref AVISTREAMINFO streamInfo); - - /// - /// Release an open AVI stream. - /// - /// - /// Handle to an open stream. - /// - /// Returns the current reference count of the stream. - /// - [DllImport("avifil32.dll")] - public static extern int AVIStreamRelease(IntPtr streamHandler); - - /// - /// Set the format of a stream at the specified position. - /// - /// - /// Handle to an open stream. - /// Position in the stream to receive the format. - /// Pointer to a structure containing the new format. - /// Size, in bytes, of the block of memory referenced by format. - /// - /// Returns zero if successful or an error otherwise. - /// - [DllImport("avifil32.dll")] - public static extern int AVIStreamSetFormat(IntPtr streamHandler, int position, ref BitmapInfoHeader format, int formatSize); - - /// - /// Get the starting sample number for the stream. - /// - /// - /// Handle to an open stream. - /// - /// Returns the number if successful or – 1 otherwise. - /// - [DllImport("avifil32.dll")] - public static extern int AVIStreamStart(IntPtr streamHandler); - - /// - /// Get the length of the stream. - /// - /// Handle to an open stream. - /// Returns the stream's length, in samples, if successful or -1 otherwise. - [DllImport("avifil32.dll")] - public static extern int AVIStreamLength(IntPtr streamHandler); - - /// - /// Obtain stream header information. - /// - /// - /// Handle to an open stream. - /// Pointer to a structure to contain the stream information. - /// Size, in bytes, of the structure used for streamInfo. - /// - /// Returns zero if successful or an error otherwise. - /// - [DllImport("avifil32.dll", CharSet = CharSet.Unicode)] - public static extern int AVIStreamInfo(IntPtr streamHandler, ref AVISTREAMINFO streamInfo, int infoSize); - - /// - /// Prepare to decompress video frames from the specified video stream - /// - /// Pointer to the video stream used as the video source. - /// Pointer to a structure that defines the desired video format. Specify NULL to use a default format. - /// Returns an object that can be used with the function. - [DllImport("avifil32.dll")] - public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, ref BitmapInfoHeader wantedFormat); - - /// - /// Prepare to decompress video frames from the specified video stream. - /// - /// Pointer to the video stream used as the video source. - /// Pointer to a structure that defines the desired video format. Specify NULL to use a default format. - /// Returns a GetFrame object that can be used with the function. - [DllImport("avifil32.dll")] - public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, int wantedFormat); - - /// - /// Releases resources used to decompress video frames. - /// - /// Handle returned from the function. - /// Returns zero if successful or an error otherwise. - [DllImport("avifil32.dll")] - public static extern int AVIStreamGetFrameClose(IntPtr getFrameObject); - - /// - /// Return the address of a decompressed video frame. - /// - /// Pointer to a GetFrame object. - /// Position, in samples, within the stream of the desired frame. - /// Returns a pointer to the frame data if successful or NULL otherwise. - [DllImport("avifil32.dll")] - public static extern IntPtr AVIStreamGetFrame(IntPtr getFrameObject, int position); - - /// - /// Write data to a stream. - /// - /// Handle to an open stream. - /// First sample to write. - /// Number of samples to write. - /// Pointer to a buffer containing the data to write. - /// Size of the buffer referenced by buffer. - /// Flag associated with this data. - /// Pointer to a buffer that receives the number of samples written. This can be set to NULL. - /// Pointer to a buffer that receives the number of bytes written. This can be set to NULL. - /// - /// Returns zero if successful or an error otherwise. - /// - [DllImport("avifil32.dll")] - public static extern int AVIStreamWrite(IntPtr streamHandler, int start, int samples, IntPtr buffer, int bufferSize, int flags, IntPtr samplesWritten, IntPtr bytesWritten); - - /// - /// Retrieve the save options for a file and returns them in a buffer. - /// - /// Handle to the parent window for the Compression Options dialog box. - /// Flags for displaying the Compression Options dialog box. - /// Number of streams that have their options set by the dialog box. - /// Pointer to an array of stream interface pointers. - /// Pointer to an array of pointers to AVICOMPRESSOPTIONS structures. - /// Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise. - [DllImport("avifil32.dll")] - public static extern int AVISaveOptions(IntPtr window, int flags, int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] streamInterfaces, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options); - - /// - /// Free the resources allocated by the AVISaveOptions function. - /// - /// Count of the AVICOMPRESSOPTIONS structures referenced in options. - /// Pointer to an array of pointers to AVICOMPRESSOPTIONS structures. - /// Returns 0. - [DllImport("avifil32.dll")] - public static extern int AVISaveOptionsFree(int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options); - - /// - /// Create a compressed stream from an uncompressed stream and a - /// compression filter, and returns the address of a pointer to - /// the compressed stream. - /// - /// Pointer to a buffer that receives the compressed stream pointer. - /// Pointer to the stream to be compressed. - /// Pointer to a structure that identifies the type of compression to use and the options to apply. - /// Pointer to a class identifier used to create the stream. - /// Returns 0 if successful or an error otherwise. - [DllImport("avifil32.dll")] - public static extern int AVIMakeCompressedStream(out IntPtr compressedStream, IntPtr sourceStream, ref AVICOMPRESSOPTIONS options, IntPtr clsidHandler); - - // --- structures - - /// - /// Structure, which contains information for a single stream . - /// - /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] - public struct AVISTREAMINFO - { - /// - /// Four-character code indicating the stream type. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int type; - - /// - /// Four-character code of the compressor handler that will compress this video stream when it is saved. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int handler; - - /// - /// Applicable flags for the stream. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int flags; - - /// - /// Capability flags; currently unused. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int ñapabilities; - - /// - /// Priority of the stream. - /// - /// - [MarshalAs(UnmanagedType.I2)] - public short priority; - - /// - /// Language of the stream. - /// - /// - [MarshalAs(UnmanagedType.I2)] - public short language; - - /// - /// Time scale applicable for the stream. - /// - /// - /// Dividing rate by scale gives the playback rate in number of samples per second. - /// - [MarshalAs(UnmanagedType.I4)] - public int scale; - - /// - /// Rate in an integer format. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int rate; - - /// - /// Sample number of the first frame of the AVI file. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int start; - - /// - /// Length of this stream. - /// - /// - /// The units are defined by rate and scale. - /// - [MarshalAs(UnmanagedType.I4)] - public int length; - - /// - /// Audio skew. This member specifies how much to skew the audio data ahead of the video frames in interleaved files. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int initialFrames; - - /// - /// Recommended buffer size, in bytes, for the stream. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int suggestedBufferSize; - - /// - /// Quality indicator of the video data in the stream. - /// - /// - /// Quality is represented as a number between 0 and 10,000. - /// - [MarshalAs(UnmanagedType.I4)] - public int quality; - - /// - /// Size, in bytes, of a single data sample. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int sampleSize; - - /// - /// Dimensions of the video destination rectangle. - /// - /// - [MarshalAs(UnmanagedType.Struct, SizeConst = 16)] - public RECT rectFrame; - - /// - /// Number of times the stream has been edited. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int editCount; - - /// - /// Number of times the stream format has changed. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int formatChangeCount; - - /// - /// Description of the stream. - /// - /// - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] - public string name; - } - - /// - /// Structure, which contains information about a stream and how it is compressed and saved. - /// - /// - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct AVICOMPRESSOPTIONS - { - /// - /// Four-character code indicating the stream type. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int type; - - /// - /// Four-character code for the compressor handler that will compress this video stream when it is saved. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int handler; - - /// - /// Maximum period between video key frames. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int keyFrameEvery; - - /// - /// Quality value passed to a video compressor. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int quality; - - /// - /// Video compressor data rate. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int bytesPerSecond; - - /// - /// Flags used for compression. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int flags; - - /// - /// Pointer to a structure defining the data format. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int format; - - /// - /// Size, in bytes, of the data referenced by format. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int formatSize; - - /// - /// Video-compressor-specific data; used internally. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int parameters; - - /// - /// Size, in bytes, of the data referenced by parameters. - /// - [MarshalAs(UnmanagedType.I4)] - public int parametersSize; - - /// - /// Interleave factor for interspersing stream data with data from the first stream. - /// - /// - [MarshalAs(UnmanagedType.I4)] - public int interleaveEvery; - } - - // --- enumerations - - /// - /// File access modes. - /// - /// - [Flags] - public enum OpenFileMode { - Read = 0x00000000, - Write = 0x00000001, - ReadWrite = 0x00000002, - ShareCompat = 0x00000000, - ShareExclusive = 0x00000010, - ShareDenyWrite = 0x00000020, - ShareDenyRead = 0x00000030, - ShareDenyNone = 0x00000040, - Parse = 0x00000100, - Delete = 0x00000200, - Verify = 0x00000400, - Cancel = 0x00000800, - Create = 0x00001000, - Prompt = 0x00002000, - Exist = 0x00004000, - Reopen = 0x00008000 - } - - /// - /// .NET replacement of mmioFOURCC macros. Converts four characters to code. - /// - /// - /// Four characters string. - /// - /// Returns the code created from provided characters. - /// - public static int mmioFOURCC(string str) { - return ( ((int)(byte)(str[0])) | - ((int)(byte)(str[1]) << 8) | - ((int)(byte)(str[2]) << 16) | - ((int)(byte)(str[3]) << 24)); - } - - /// - /// Inverse to . Converts code to fout characters string. - /// - /// - /// Code to convert. - /// - /// Returns four characters string. - /// - public static string decode_mmioFOURCC(int code) { - char[] chs = new char[4]; - - for (int i = 0; i < 4; i++) { - chs[i] = (char)(byte)((code >> (i << 3)) & 0xFF); - if (!char.IsLetterOrDigit(chs[i])) { - chs[i] = ' '; - } - } - return new string(chs); - } - - - /// - /// Version of for one stream only. - /// - /// - /// Stream to configure. - /// Stream options. - /// - /// Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise. - /// - public static int AVISaveOptions(IntPtr stream, ref AVICOMPRESSOPTIONS options) { - IntPtr[] streams = new IntPtr[1]; - IntPtr[] infPtrs = new IntPtr[1]; - IntPtr mem; - int ret; - - // alloc unmanaged memory - mem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(AVICOMPRESSOPTIONS))); - - // copy from managed structure to unmanaged memory - Marshal.StructureToPtr(options, mem, false); - - streams[0] = stream; - infPtrs[0] = mem; - - // show dialog with a list of available compresors and configuration - ret = AVISaveOptions(IntPtr.Zero, 0, 1, streams, infPtrs); - - // copy from unmanaged memory to managed structure - options = (AVICOMPRESSOPTIONS)Marshal.PtrToStructure(mem, typeof(AVICOMPRESSOPTIONS)); - - // free AVI compression options - AVISaveOptionsFree(1, infPtrs); - - // clear it, because the information already freed by AVISaveOptionsFree - options.format = 0; - options.parameters = 0; - - // free unmanaged memory - Marshal.FreeHGlobal(mem); - - return ret; - } - } + /// Add new frame to the AVI file. + /// + /// New frame data. + public void AddLowLevelFrame(IntPtr frameData) { + lock (this) { + // write to stream + if (Avi32.AVIStreamWrite(streamCompressed, position, 1, frameData, stride * height, 0, IntPtr.Zero, IntPtr.Zero) != 0) { + throw new ApplicationException("Failed adding frame"); + } + + position++; + } + } + } + + /// + /// Windows API functions and structures. + /// + /// + /// The class provides Video for Windows and some other Avi32 functions and structurs. + /// + internal static class Avi32 { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Avi32)); + + [DllImport("MSVFW32", CharSet = CharSet.Ansi)] + static extern bool ICInfo(int fccType, int fccHandler, ref ICINFO lpicinfo); + + [DllImport("MSVFW32"), PreserveSig] + static extern IntPtr ICOpen(int fccType, int fccHandler, ICMODE wMode); + + [DllImport("MSVFW32")] + static extern int ICClose(IntPtr hic); + + [DllImport("MSVFW32", CharSet = CharSet.Ansi)] + static extern int ICGetInfo(IntPtr hic, ref ICINFO lpicinfo, int cb); + + // --- Video for Windows Functions + + /// + /// Initialize the AVIFile library. + /// + /// + [DllImport("avifil32")] + public static extern void AVIFileInit(); + + /// + /// Exit the AVIFile library. + /// + [DllImport("avifil32")] + public static extern void AVIFileExit(); + + /// + /// Open an AVI file. + /// + /// + /// Opened AVI file interface. + /// AVI file name. + /// Opening mode (see ). + /// Handler to use (null to use default). + /// + /// Returns zero on success or error code otherwise. + /// + [DllImport("avifil32", CharSet = CharSet.Unicode)] + public static extern AviError AVIFileOpen(out IntPtr aviHandler, String fileName, OpenFileMode mode, IntPtr handler); + + /// + /// Release an open AVI stream. + /// + /// + /// Open AVI file interface. + /// + /// Returns the reference count of the file. + /// + [DllImport("avifil32")] + public static extern int AVIFileRelease(IntPtr aviHandler); + + /// + /// Get stream interface that is associated with a specified AVI file + /// + /// + /// Handler to an open AVI file. + /// Stream interface. + /// Stream type to open. + /// Count of the stream type. Identifies which occurrence of the specified stream type to access. + /// + /// + /// + [DllImport("avifil32")] + public static extern int AVIFileGetStream(IntPtr aviHandler, out IntPtr streamHandler, int streamType, int streamNumner); + + /// + /// Create a new stream in an existing file and creates an interface to the new stream. + /// + /// + /// Handler to an open AVI file. + /// Stream interface. + /// Pointer to a structure containing information about the new stream. + /// + /// Returns zero if successful or an error otherwise. + /// + [DllImport("avifil32")] + public static extern int AVIFileCreateStream(IntPtr aviHandler, out IntPtr streamHandler, ref AVISTREAMINFO streamInfo); + + /// + /// Release an open AVI stream. + /// + /// + /// Handle to an open stream. + /// + /// Returns the current reference count of the stream. + /// + [DllImport("avifil32")] + public static extern int AVIStreamRelease(IntPtr streamHandler); + + /// + /// Set the format of a stream at the specified position. + /// + /// + /// Handle to an open stream. + /// Position in the stream to receive the format. + /// Pointer to a structure containing the new format. + /// Size, in bytes, of the block of memory referenced by format. + /// + /// Returns zero if successful or an error otherwise. + /// + [DllImport("avifil32")] + public static extern AviError AVIStreamSetFormat(IntPtr streamHandler, int position, ref BitmapInfoHeader format, int formatSize); + + /// + /// Get the starting sample number for the stream. + /// + /// + /// Handle to an open stream. + /// + /// Returns the number if successful or – 1 otherwise. + /// + [DllImport("avifil32")] + public static extern int AVIStreamStart(IntPtr streamHandler); + + /// + /// Get the length of the stream. + /// + /// Handle to an open stream. + /// Returns the stream's length, in samples, if successful or -1 otherwise. + [DllImport("avifil32")] + public static extern int AVIStreamLength(IntPtr streamHandler); + + /// + /// Obtain stream header information. + /// + /// + /// Handle to an open stream. + /// Pointer to a structure to contain the stream information. + /// Size, in bytes, of the structure used for streamInfo. + /// + /// Returns zero if successful or an error otherwise. + /// + [DllImport("avifil32", CharSet = CharSet.Unicode)] + public static extern int AVIStreamInfo(IntPtr streamHandler, ref AVISTREAMINFO streamInfo, int infoSize); + + /// + /// Prepare to decompress video frames from the specified video stream + /// + /// Pointer to the video stream used as the video source. + /// Pointer to a structure that defines the desired video format. Specify NULL to use a default format. + /// Returns an object that can be used with the function. + [DllImport("avifil32")] + public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, ref BitmapInfoHeader wantedFormat); + + /// + /// Prepare to decompress video frames from the specified video stream. + /// + /// Pointer to the video stream used as the video source. + /// Pointer to a structure that defines the desired video format. Specify NULL to use a default format. + /// Returns a GetFrame object that can be used with the function. + [DllImport("avifil32")] + public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, int wantedFormat); + + /// + /// Releases resources used to decompress video frames. + /// + /// Handle returned from the function. + /// Returns zero if successful or an error otherwise. + [DllImport("avifil32")] + public static extern int AVIStreamGetFrameClose(IntPtr getFrameObject); + + /// + /// Return the address of a decompressed video frame. + /// + /// Pointer to a GetFrame object. + /// Position, in samples, within the stream of the desired frame. + /// Returns a pointer to the frame data if successful or NULL otherwise. + [DllImport("avifil32")] + public static extern IntPtr AVIStreamGetFrame(IntPtr getFrameObject, int position); + + /// + /// Write data to a stream. + /// + /// Handle to an open stream. + /// First sample to write. + /// Number of samples to write. + /// Pointer to a buffer containing the data to write. + /// Size of the buffer referenced by buffer. + /// Flag associated with this data. + /// Pointer to a buffer that receives the number of samples written. This can be set to NULL. + /// Pointer to a buffer that receives the number of bytes written. This can be set to NULL. + /// + /// Returns zero if successful or an error otherwise. + /// + [DllImport("avifil32")] + public static extern AviError AVIStreamWrite(IntPtr streamHandler, int start, int samples, IntPtr buffer, int bufferSize, int flags, IntPtr samplesWritten, IntPtr bytesWritten); + + /// + /// Retrieve the save options for a file and returns them in a buffer. + /// + /// Handle to the parent window for the Compression Options dialog box. + /// Flags for displaying the Compression Options dialog box. + /// Number of streams that have their options set by the dialog box. + /// Pointer to an array of stream interface pointers. + /// Pointer to an array of pointers to AVICOMPRESSOPTIONS structures. + /// Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise. + [DllImport("avifil32")] + public static extern int AVISaveOptions(IntPtr window, int flags, int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] streamInterfaces, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options); + + /// + /// Free the resources allocated by the AVISaveOptions function. + /// + /// Count of the AVICOMPRESSOPTIONS structures referenced in options. + /// Pointer to an array of pointers to AVICOMPRESSOPTIONS structures. + /// Returns 0. + [DllImport("avifil32")] + public static extern AviError AVISaveOptionsFree(int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options); + + /// + /// Create a compressed stream from an uncompressed stream and a + /// compression filter, and returns the address of a pointer to + /// the compressed stream. + /// + /// Pointer to a buffer that receives the compressed stream pointer. + /// Pointer to the stream to be compressed. + /// Pointer to a structure that identifies the type of compression to use and the options to apply. + /// Pointer to a class identifier used to create the stream. + /// Returns 0 if successful or an error otherwise. + [DllImport("avifil32")] + public static extern AviError AVIMakeCompressedStream(out IntPtr compressedStream, IntPtr sourceStream, ref AVICOMPRESSOPTIONS options, IntPtr clsidHandler); + + /// + /// Code type + /// + public enum ICMODE { + ICMODE_COMPRESS = 1, + ICMODE_DECOMPRESS = 2, + ICMODE_FASTDECOMPRESS = 3, + ICMODE_QUERY = 4, + ICMODE_FASTCOMPRESS = 5, + ICMODE_DRAW = 8 + } + + // --- structures + + /// + /// Structor for the codec info + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd743162%28v=vs.85%29.aspx + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct ICINFO { + public int dwSize; + public int fccType; + public int fccHandler; + public int dwFlags; + public int dwVersion; + public int dwVersionICM; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] + public string szName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string szDescription; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string szDriver; + + public ICINFO(int type) { + dwSize = Marshal.SizeOf(typeof(ICINFO)); + fccType = type; + fccHandler = 0; + dwFlags = 0; + dwVersion = 0; + dwVersionICM = 0; + szName = null; + szDescription = null; + szDriver = null; + } + } + + /// + /// Structure, which contains information for a single stream . + /// + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + public struct AVISTREAMINFO { + /// + /// Four-character code indicating the stream type. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int type; + + /// + /// Four-character code of the compressor handler that will compress this video stream when it is saved. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int handler; + + /// + /// Applicable flags for the stream. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int flags; + + /// + /// Capability flags; currently unused. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int ñapabilities; + + /// + /// Priority of the stream. + /// + /// + [MarshalAs(UnmanagedType.I2)] + public short priority; + + /// + /// Language of the stream. + /// + /// + [MarshalAs(UnmanagedType.I2)] + public short language; + + /// + /// Time scale applicable for the stream. + /// + /// + /// Dividing rate by scale gives the playback rate in number of samples per second. + /// + [MarshalAs(UnmanagedType.I4)] + public int scale; + + /// + /// Rate in an integer format. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int rate; + + /// + /// Sample number of the first frame of the AVI file. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int start; + + /// + /// Length of this stream. + /// + /// + /// The units are defined by rate and scale. + /// + [MarshalAs(UnmanagedType.I4)] + public int length; + + /// + /// Audio skew. This member specifies how much to skew the audio data ahead of the video frames in interleaved files. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int initialFrames; + + /// + /// Recommended buffer size, in bytes, for the stream. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int suggestedBufferSize; + + /// + /// Quality indicator of the video data in the stream. + /// + /// + /// Quality is represented as a number between 0 and 10,000. + /// + [MarshalAs(UnmanagedType.I4)] + public int quality; + + /// + /// Size, in bytes, of a single data sample. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int sampleSize; + + /// + /// Dimensions of the video destination rectangle. + /// + /// + [MarshalAs(UnmanagedType.Struct, SizeConst = 16)] + public RECT rectFrame; + + /// + /// Number of times the stream has been edited. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int editCount; + + /// + /// Number of times the stream format has changed. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int formatChangeCount; + + /// + /// Description of the stream. + /// + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string name; + } + + /// + /// Structure, which contains information about a stream and how it is compressed and saved. + /// + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AVICOMPRESSOPTIONS { + /// + /// Four-character code indicating the stream type. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int type; + + /// + /// Four-character code for the compressor handler that will compress this video stream when it is saved. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int handler; + + /// + /// Maximum period between video key frames. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int keyFrameEvery; + + /// + /// Quality value passed to a video compressor. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int quality; + + /// + /// Video compressor data rate. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int bytesPerSecond; + + /// + /// Flags used for compression. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int flags; + + /// + /// Pointer to a structure defining the data format. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int format; + + /// + /// Size, in bytes, of the data referenced by format. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int formatSize; + + /// + /// Video-compressor-specific data; used internally. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int parameters; + + /// + /// Size, in bytes, of the data referenced by parameters. + /// + [MarshalAs(UnmanagedType.I4)] + public int parametersSize; + + /// + /// Interleave factor for interspersing stream data with data from the first stream. + /// + /// + [MarshalAs(UnmanagedType.I4)] + public int interleaveEvery; + } + + // --- enumerations + + /// + /// File access modes. + /// + /// + [Flags] + public enum OpenFileMode { + Read = 0x00000000, + Write = 0x00000001, + ReadWrite = 0x00000002, + ShareCompat = 0x00000000, + ShareExclusive = 0x00000010, + ShareDenyWrite = 0x00000020, + ShareDenyRead = 0x00000030, + ShareDenyNone = 0x00000040, + Parse = 0x00000100, + Delete = 0x00000200, + Verify = 0x00000400, + Cancel = 0x00000800, + Create = 0x00001000, + Prompt = 0x00002000, + Exist = 0x00004000, + Reopen = 0x00008000 + } + + /// + /// .NET replacement of mmioFOURCC macros. Converts four characters to code. + /// + /// + /// Four characters string. + /// + /// Returns the code created from provided characters. + /// + public static int mmioFOURCC(string str) { + return (((int)(byte)(str[0])) | + ((int)(byte)(str[1]) << 8) | + ((int)(byte)(str[2]) << 16) | + ((int)(byte)(str[3]) << 24)); + } + + /// + /// Inverse to . Converts code to fout characters string. + /// + /// + /// Code to convert. + /// + /// Returns four characters string. + /// + public static string decode_mmioFOURCC(int code) { + char[] chs = new char[4]; + + for (int i = 0; i < 4; i++) { + chs[i] = (char)(byte)((code >> (i << 3)) & 0xFF); + if (!char.IsLetterOrDigit(chs[i])) { + chs[i] = ' '; + } + } + return new string(chs); + } + + /// + /// Get a list of available codecs. + /// + /// List + public static List AvailableCodecs { + get { + List returnValues = new List(); + int codecNr = 0; + + ICINFO codecInfo = new ICINFO(mmioFOURCC("VIDC")); + + bool success = true; + do { + success = ICInfo(codecInfo.fccType, codecNr++, ref codecInfo); + if (success) { + IntPtr hic = ICOpen(codecInfo.fccType, codecInfo.fccHandler, ICMODE.ICMODE_QUERY); + if (hic != IntPtr.Zero) { + ICGetInfo(hic, ref codecInfo, Marshal.SizeOf(codecInfo)); + string codecName = decode_mmioFOURCC(codecInfo.fccHandler); + returnValues.Add(codecName); + LOG.DebugFormat("Found codec {0} {4}, with name {1} and description {2}, driver {3}", codecName, codecInfo.szName, codecInfo.szDescription, codecInfo.szDriver, codecInfo.dwVersion); + ICClose(hic); + } + } + } while (success); + return returnValues; + } + } + + /// + /// Version of for one stream only. + /// + /// + /// Stream to configure. + /// Stream options. + /// + /// Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise. + /// + public static int AVISaveOptions(IntPtr stream, ref AVICOMPRESSOPTIONS options) { + IntPtr[] streams = new IntPtr[1]; + IntPtr[] infPtrs = new IntPtr[1]; + IntPtr mem; + int ret; + + // alloc unmanaged memory + mem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(AVICOMPRESSOPTIONS))); + + // copy from managed structure to unmanaged memory + Marshal.StructureToPtr(options, mem, false); + + streams[0] = stream; + infPtrs[0] = mem; + + // show dialog with a list of available compresors and configuration + ret = AVISaveOptions(IntPtr.Zero, 0, 1, streams, infPtrs); + + // copy from unmanaged memory to managed structure + options = (AVICOMPRESSOPTIONS)Marshal.PtrToStructure(mem, typeof(AVICOMPRESSOPTIONS)); + + // free AVI compression options + AVISaveOptionsFree(1, infPtrs); + + // clear it, because the information already freed by AVISaveOptionsFree + options.format = 0; + options.parameters = 0; + + // free unmanaged memory + Marshal.FreeHGlobal(mem); + + return ret; + } + } + + /// + /// AVI Error Codes + /// + [Flags] + public enum AviError : uint { + /// + /// Compression is not supported for this type of data. + /// This error might be returned if you try to compress + /// data that is not audio or video. + /// + AVIERR_UNSUPPORTED = 0x80044065, + /// + /// The file couldn't be read, indicating a corrupt file or an unrecognized format + /// + AVIERR_BADFORMAT = 0x80044066, + /// + /// There is not enough memory to complete the operation. + /// + AVIERR_MEMORY = 0x80044067, + /// + /// + /// + // TODO : Put documentation + AVIERR_INTERNAL = 0x80044068, + /// + /// + /// + // TODO : Put documentation + AVIERR_BADFLAGS = 0x80044069, + /// + /// + /// + // TODO : Put documentation + AVIERR_BADPARAM = 0x8004406A, + /// + /// + /// + // TODO : Put documentation + AVIERR_BADSIZE = 0x8004406B, + /// + /// + /// + // TODO : Put documentation + AVIERR_BADHANDLE = 0x8004406C, + /// + /// A disk error occurred while reading the file + /// + AVIERR_FILEREAD = 0x8004406D, + /// + /// + /// + // TODO : Put documentation + AVIERR_FILEWRITE = 0x8004406E, + /// + /// A disk error occurred while opening the file + /// + AVIERR_FILEOPEN = 0x8004406F, + /// + /// + /// + // TODO : Put documentation + AVIERR_COMPRESSOR = 0x80044070, + /// + /// A suitable compressor cannot be found. + /// + AVIERR_NOCOMPRESSOR = 0x80044071, + /// + /// + /// + // TODO : Put documentation + AVIERR_READONLY = 0x80044072, + /// + /// + /// + // TODO : Put documentation + AVIERR_NODATA = 0x80044073, + /// + /// + /// + // TODO : Put documentation + AVIERR_BUFFERTOOSMALL = 0x80044074, + /// + /// + /// + // TODO : Put documentation + AVIERR_CANTCOMPRESS = 0x80044075, + /// + /// + /// + // TODO : Put documentation + AVIERR_USERABORT = 0x800440C6, + /// + /// + /// + // TODO : Put documentation + AVIERR_ERROR = 0x800440C7, + /// + /// Operation successful + /// + AVIERR_OK = 0x0 + } } diff --git a/Greenshot/Helpers/ScreenCaptureHelper.cs b/Greenshot/Helpers/ScreenCaptureHelper.cs index defa01a44..c43ab0097 100644 --- a/Greenshot/Helpers/ScreenCaptureHelper.cs +++ b/Greenshot/Helpers/ScreenCaptureHelper.cs @@ -93,6 +93,11 @@ namespace Greenshot.Helpers { return exceptionToThrow; } + /// + /// Start the recording + /// + /// + /// public bool Start(int framesPerSecond) { if (recordingWindow != null) { string windowTitle = Regex.Replace(recordingWindow.Text, @"[^\x20\d\w]", ""); @@ -176,8 +181,8 @@ namespace Greenshot.Helpers { aviWriter = new AVIWriter(); // Comment the following 2 lines to make the user select it's own codec - //aviWriter.Codec = "msvc"; - //aviWriter.Quality = 99; + aviWriter.Codec = "msvc"; + aviWriter.Quality = 10000; aviWriter.FrameRate = framesPerSecond; if (aviWriter.Open(filename, recordingSize.Width, recordingSize.Height)) { @@ -195,6 +200,9 @@ namespace Greenshot.Helpers { return false; } + /// + /// Do the actual frame capture + /// private void CaptureFrame() { int MSBETWEENCAPTURES = 1000/framesPerSecond; int msToNextCapture = MSBETWEENCAPTURES; @@ -262,6 +270,9 @@ namespace Greenshot.Helpers { Cleanup(); } + /// + /// Stop the recording, after the next frame + /// public void Stop() { stop = true; if (backgroundTask != null) { @@ -269,6 +280,7 @@ namespace Greenshot.Helpers { } Cleanup(); } + /// /// Free resources /// @@ -297,7 +309,9 @@ namespace Greenshot.Helpers { if (ffmpegexe != null) { try { string webMFile = filename.Replace(".avi", ".webm"); - ProcessStartInfo processStartInfo = new ProcessStartInfo(ffmpegexe, "-i \"" + filename + "\" -vcodec libvpx \"" + webMFile + "\""); + string arguments = "-i \"" + filename + "\" -codec:v libvpx -quality good -cpu-used 0 -b:v 1000k -qmin 10 -qmax 42 -maxrate 1000k -bufsize 4000k -threads 4 \"" + webMFile + "\""; + LOG.DebugFormat("Starting {0} with arguments {1}", ffmpegexe, arguments); + ProcessStartInfo processStartInfo = new ProcessStartInfo(ffmpegexe, arguments); processStartInfo.CreateNoWindow = false; processStartInfo.RedirectStandardOutput = false; processStartInfo.UseShellExecute = false;