/// <summary>Add an existing wave audio stream to the file</summary> /// <param name="waveData">The new stream's data</param> /// <param name="streamInfo">Header info for the new stream</param> /// <param name="streamFormat">The new stream' format info</param> /// <param name="streamLength">Length of the new stream</param> public void AddAudioStream(IntPtr waveData, Avi.AVISTREAMINFO streamInfo, Avi.PCMWAVEFORMAT streamFormat, int streamLength) { IntPtr aviStream; int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref streamInfo); if (result != 0) { throw new Exception("Exception in AVIFileCreateStream: " + result.ToString()); } result = Avi.AVIStreamSetFormat(aviStream, 0, ref streamFormat, Marshal.SizeOf(streamFormat)); if (result != 0) { throw new Exception("Exception in AVIStreamSetFormat: " + result.ToString()); } result = Avi.AVIStreamWrite(aviStream, 0, streamLength, waveData, streamLength, Avi.AVIIF_KEYFRAME, 0, 0); if (result != 0) { throw new Exception("Exception in AVIStreamWrite: " + result.ToString()); } result = Avi.AVIStreamRelease(aviStream); if (result != 0) { throw new Exception("Exception in AVIStreamRelease: " + result.ToString()); } }
/// <summary>Create a new stream</summary> private void CreateStreamWithoutFormat() { int scale = 1; double rate = FrameRate; GetRateAndScale(ref rate, ref scale); Avi.AVISTREAMINFO strhdr = new Avi.AVISTREAMINFO { fccType = Avi.mmioStringToFOURCC("vids", 0), fccHandler = Avi.mmioStringToFOURCC("CVID", 0), dwFlags = 0, dwCaps = 0, wPriority = 0, wLanguage = 0, dwScale = scale, dwRate = (int)rate, dwStart = 0, dwLength = 0, dwInitialFrames = 0, dwSuggestedBufferSize = FrameSize, dwQuality = -1, dwSampleSize = 0, rcFrame = { top = 0, left = 0, bottom = (uint)Height, right = (uint)Width }, dwEditCount = 0, dwFormatChangeCount = 0, szName = new UInt16[64] }; int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref strhdr); if (result != 0) { throw new Exception("Exception in AVIFileCreateStream: " + result); } }
/// <summary>Free ressources that have been used by GetFrameOpen</summary> public void GetFrameClose() { if (getFrameObject != 0) { Avi.AVIStreamGetFrameClose(getFrameObject); getFrameObject = 0; } }
/// <summary>Close the stream</summary> public virtual void Close() { if (writeCompressed) { Avi.AVIStreamRelease(compressedStream); } Avi.AVIStreamRelease(StreamPointer); }
/// <summary>Read the stream's format information</summary> /// <returns>PCMWAVEFORMAT</returns> public Avi.PCMWAVEFORMAT GetFormat() { Avi.PCMWAVEFORMAT format = new Avi.PCMWAVEFORMAT(); int size = Marshal.SizeOf(format); Avi.AVIStreamReadFormat(aviStream, 0, ref format, ref size); return(format); }
/// <summary>Release all ressources</summary> public void Close() { foreach (AviStream stream in streams) { stream.Close(); } Avi.AVIFileRelease(aviFile); Avi.AVIFileExit(); }
/// <summary>Change the AviStreamInfo values and update the frame rate</summary> /// <param name="info"></param> public void SetInfo(Avi.AVISTREAMINFO info) { int result = Avi.EditStreamSetInfo(editableStream, ref info, Marshal.SizeOf(info)); if (result != 0) { throw new Exception("Exception in SetInfo: " + result); } FrameRate = info.dwRate / info.dwScale; }
/// <summary>Initialize an AudioStream for an existing stream</summary> /// <param name="aviFile">The file that contains the stream</param> /// <param name="aviStream">An IAVISTREAM from [aviFile]</param> public AudioStream(int aviFile, IntPtr aviStream) { this.aviFile = aviFile; this.aviStream = aviStream; int size = Marshal.SizeOf(waveFormat); Avi.AVIStreamReadFormat(aviStream, 0, ref waveFormat, ref size); GetStreamInfo(aviStream); }
/// <summary>Read the stream's header information</summary> /// <param name="aviStream">The IAVISTREAM to read from</param> /// <returns>AVISTREAMINFO</returns> private Avi.AVISTREAMINFO GetStreamInfo(IntPtr aviStream) { Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO(); int result = Avi.AVIStreamInfo(aviStream, ref streamInfo, Marshal.SizeOf(streamInfo)); if (result != 0) { throw new Exception("Exception in AVIStreamInfo: " + result); } return(streamInfo); }
/// <summary>Prepare for decompressing frames</summary> /// <remarks> /// This method has to be called before GetBitmap and ExportBitmap. /// Release ressources with GetFrameClose. /// </remarks> public void GetFrameOpen() { GetStreamInfo(StreamPointer); //Open frames Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); bih.biBitCount = CountBitsPerPixel; bih.biClrImportant = 0; bih.biClrUsed = 0; bih.biCompression = 0; bih.biPlanes = 1; bih.biSize = Marshal.SizeOf(bih); bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; // Corrections by M. Covington: // If these are pre-set, interlaced video is not handled correctly. // Better to give zeroes and let Windows fill them in. bih.biHeight = 0; // was (Int32)streamInfo.rcFrame.bottom; bih.biWidth = 0; // was (Int32)streamInfo.rcFrame.right; // Corrections by M. Covington: // Validate the bit count, because some AVI files give a bit count // that is not one of the allowed values in a BitmapInfoHeader. // Here 0 means for Windows to figure it out from other information. if (bih.biBitCount > 24) { bih.biBitCount = 32; } else if (bih.biBitCount > 16) { bih.biBitCount = 24; } else if (bih.biBitCount > 8) { bih.biBitCount = 16; } else if (bih.biBitCount > 4) { bih.biBitCount = 8; } else if (bih.biBitCount > 0) { bih.biBitCount = 4; } getFrameObject = Avi.AVIStreamGetFrameOpen(StreamPointer, ref bih); if (getFrameObject == 0) { throw new Exception("Exception in VideoStreamGetFrameOpen!"); } }
/// <summary>Copy a number of frames into a temporary stream</summary> /// <param name="start">First frame to copy</param> /// <param name="length">Count of frames to copy</param> /// <returns>Pointer to the unmanaged temporary stream</returns> public IntPtr Copy(int start, int length) { IntPtr copyPointer = IntPtr.Zero; int result = Avi.EditStreamCopy(editableStream, ref start, ref length, ref copyPointer); if (result != 0) { throw new Exception("Exception in Copy: " + result); } return(copyPointer); }
/// <summary>Paste a number of frames from another video stream into this stream</summary> /// <param name="sourceStream">Pointer to the unmanaged stream to copy from</param> /// <param name="copyPosition">Index of the first frame to copy</param> /// <param name="pastePosition">Where to paste the copied frames</param> /// <param name="length">Count of frames to paste</param> public void Paste(IntPtr sourceStream, int copyPosition, int pastePosition, int length) { int pastedLength = 0; int result = Avi.EditStreamPaste(editableStream, ref pastePosition, ref pastedLength, sourceStream, copyPosition, length); if (result != 0) { throw new Exception("Exception in Paste: " + result); } CountFrames += pastedLength; }
/// <summary>Move a number of frames into a temporary stream</summary> /// <param name="start">First frame to cut</param> /// <param name="length">Count of frames to cut</param> /// <returns>Pointer to the unmanaged temporary stream</returns> public IntPtr Cut(int start, int length) { IntPtr copyPointer = IntPtr.Zero; int result = Avi.EditStreamCut(editableStream, ref start, ref length, ref copyPointer); if (result != 0) { throw new Exception("Exception in Cut: " + result); } CountFrames -= length; return(copyPointer); }
/// <summary>Create a compressed stream from an uncompressed stream</summary> private void CreateCompressedStream(Avi.AVICOMPRESSOPTIONS options) { int result = Avi.AVIMakeCompressedStream(out compressedStream, aviStream, ref options, 0); if (result != 0) { throw new Exception("Exception in AVIMakeCompressedStream: " + result); } compressOptions = options; SetFormat(compressedStream); }
/// <summary>Create an editable stream from an uneditable stream</summary> /// <param name="stream">uneditable stream</param> public EditableVideoStream(VideoStream stream) : base(stream.FrameSize, stream.FrameRate, stream.Width, stream.Height, stream.CountBitsPerPixel, stream.CountFrames, stream.CompressOptions, stream.WriteCompressed) { Avi.AVIFileInit(); int result = Avi.CreateEditableStream(ref editableStream, stream.StreamPointer); if (result != 0) { throw new Exception("Exception in CreateEditableStream: " + result); } SetInfo(stream.StreamInfo); }
/// <summary>Copy the stream into a new file</summary> /// <param name="fileName">Name of the new file</param> public override void ExportStream(String fileName) { Avi.AVICOMPRESSOPTIONS_CLASS opts = new Avi.AVICOMPRESSOPTIONS_CLASS { fccType = (uint)Avi.streamtypeVIDEO, lpParms = IntPtr.Zero, lpFormat = IntPtr.Zero }; IntPtr streamPointer = StreamPointer; Avi.AVISaveOptions(IntPtr.Zero, Avi.ICMF_CHOOSE_KEYFRAME | Avi.ICMF_CHOOSE_DATARATE, 1, ref streamPointer, ref opts); Avi.AVISaveOptionsFree(1, ref opts); Avi.AVISaveV(fileName, 0, 0, 1, ref aviStream, ref opts); }
public static void MakeFileFromStream(String fileName, AviStream stream) { IntPtr newFile = IntPtr.Zero; IntPtr streamPointer = stream.StreamPointer; Avi.AVICOMPRESSOPTIONS_CLASS opts = new Avi.AVICOMPRESSOPTIONS_CLASS(); opts.fccType = (uint)Avi.streamtypeVIDEO; opts.lpParms = IntPtr.Zero; opts.lpFormat = IntPtr.Zero; Avi.AVISaveOptions(IntPtr.Zero, Avi.ICMF_CHOOSE_KEYFRAME | Avi.ICMF_CHOOSE_DATARATE, 1, ref streamPointer, ref opts); Avi.AVISaveOptionsFree(1, ref opts); Avi.AVISaveV(fileName, 0, 0, 1, ref streamPointer, ref opts); }
/// <summary>Add an existing wave audio stream to the file</summary> /// <param name="newStream">The stream to add</param> /// <param name="startAtFrameIndex"> /// The index of the video frame at which the sound is going to start. /// '0' inserts the sound at the beginning of the video. /// </param> public void AddAudioStream(AudioStream newStream, int startAtFrameIndex) { Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO(); Avi.PCMWAVEFORMAT streamFormat = new Avi.PCMWAVEFORMAT(); int streamLength = 0; IntPtr rawData = newStream.GetStreamData(ref streamInfo, ref streamFormat, ref streamLength); IntPtr waveData = rawData; if (startAtFrameIndex > 0) { //not supported //streamInfo.dwStart = startAtFrameIndex; double framesPerSecond = GetVideoStream().FrameRate; double samplesPerSecond = newStream.CountSamplesPerSecond; double startAtSecond = startAtFrameIndex / framesPerSecond; int startAtSample = (int)(samplesPerSecond * startAtSecond); waveData = InsertSilence(startAtSample - 1, waveData, streamLength, ref streamInfo); } IntPtr aviStream; int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref streamInfo); if (result != 0) { throw new Exception("Exception in AVIFileCreateStream: " + result.ToString()); } result = Avi.AVIStreamSetFormat(aviStream, 0, ref streamFormat, Marshal.SizeOf(streamFormat)); if (result != 0) { throw new Exception("Exception in AVIStreamSetFormat: " + result.ToString()); } result = Avi.AVIStreamWrite(aviStream, 0, streamLength, waveData, streamLength, Avi.AVIIF_KEYFRAME, 0, 0); if (result != 0) { throw new Exception("Exception in AVIStreamWrite: " + result.ToString()); } result = Avi.AVIStreamRelease(aviStream); if (result != 0) { throw new Exception("Exception in AVIStreamRelease: " + result.ToString()); } Marshal.FreeHGlobal(waveData); }
/// <summary>Apply a format to a new stream</summary> /// <param name="aviStream">The IAVISTREAM</param> /// <remarks> /// The format must be set before the first frame can be written, /// and it cannot be changed later. /// </remarks> private void SetFormat(IntPtr aviStream) { Avi.BITMAPINFOHEADER bi = new Avi.BITMAPINFOHEADER(); bi.biSize = Marshal.SizeOf(bi); bi.biWidth = Width; bi.biHeight = Height; bi.biPlanes = 1; bi.biBitCount = CountBitsPerPixel; bi.biSizeImage = FrameSize; int result = Avi.AVIStreamSetFormat(aviStream, 0, ref bi, bi.biSize); if (result != 0) { throw new Exception("Error in VideoStreamSetFormat: " + result); } }
/// <summary>Copy the stream into a new file</summary> /// <param name="fileName">Name of the new file</param> public override void ExportStream(String fileName) { Avi.AVICOMPRESSOPTIONS_CLASS opts = new Avi.AVICOMPRESSOPTIONS_CLASS { fccType = (UInt32)Avi.mmioStringToFOURCC("auds", 0), fccHandler = (UInt32)Avi.mmioStringToFOURCC("CAUD", 0), dwKeyFrameEvery = 0, dwQuality = 0, dwFlags = 0, dwBytesPerSecond = 0, lpFormat = new IntPtr(0), cbFormat = 0, lpParms = new IntPtr(0), cbParms = 0, dwInterleaveEvery = 0 }; Avi.AVISaveV(fileName, 0, 0, 1, ref aviStream, ref opts); }
/// <summary>Returns all data needed to copy the stream</summary> /// <remarks>Do not forget to call Marshal.FreeHGlobal and release the raw data pointer</remarks> /// <param name="streamInfo">Receives the header information</param> /// <param name="format">Receives the format</param> /// <param name="streamLength">Receives the length of the stream</param> /// <returns>Pointer to the wave data</returns> public IntPtr GetStreamData(ref Avi.AVISTREAMINFO streamInfo, ref Avi.PCMWAVEFORMAT format, ref int streamLength) { streamInfo = GetStreamInfo(); format = GetFormat(); //length in bytes = length in samples * length of a sample streamLength = Avi.AVIStreamLength(aviStream.ToInt32()) * streamInfo.dwSampleSize; IntPtr waveData = Marshal.AllocHGlobal(streamLength); int result = Avi.AVIStreamRead(aviStream, 0, streamLength, waveData, streamLength, 0, 0); if (result != 0) { throw new Exception("Exception in AVIStreamRead: " + result); } return(waveData); }
/// <summary>Getthe first wave audio stream</summary> /// <returns>AudioStream object for the stream</returns> public AudioStream GetWaveStream() { IntPtr aviStream; int result = Avi.AVIFileGetStream( aviFile, out aviStream, Avi.streamtypeAUDIO, 0); if (result != 0) { throw new Exception("Exception in AVIFileGetStream: " + result.ToString()); } AudioStream stream = new AudioStream(aviFile, aviStream); streams.Add(stream); return(stream); }
/// <summary>Get the first video stream - usually there is only one video stream</summary> /// <returns>VideoStream object for the stream</returns> public VideoStream GetVideoStream() { IntPtr aviStream; int result = Avi.AVIFileGetStream( aviFile, out aviStream, Avi.streamtypeVIDEO, 0); if (result != 0) { throw new Exception("Exception in AVIFileGetStream: " + result.ToString()); } VideoStream stream = new VideoStream(aviFile, aviStream); streams.Add(stream); return(stream); }
/// <summary>Initialize a VideoStream for an existing stream</summary> /// <param name="aviFile">The file that contains the stream</param> /// <param name="aviStream">An IAVISTREAM from [aviFile]</param> public VideoStream(int aviFile, IntPtr aviStream) { this.aviFile = aviFile; this.aviStream = aviStream; Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); int size = Marshal.SizeOf(bih); Avi.AVIStreamReadFormat(aviStream, 0, ref bih, ref size); Avi.AVISTREAMINFO streamInfo = GetStreamInfo(aviStream); FrameRate = (float)streamInfo.dwRate / (float)streamInfo.dwScale; Width = (int)streamInfo.rcFrame.right; Height = (int)streamInfo.rcFrame.bottom; FrameSize = bih.biSizeImage; CountBitsPerPixel = bih.biBitCount; FirstFrame = Avi.AVIStreamStart(aviStream.ToInt32()); CountFrames = Avi.AVIStreamLength(aviStream.ToInt32()); }
/// <summary>Open or create an AVI file</summary> /// <param name="fileName">Name of the AVI file</param> /// <param name="open">true: Open the file; false: Create or overwrite the file</param> public AviManager(String fileName, bool open) { Avi.AVIFileInit(); int result; if (open) //open existing file { result = Avi.AVIFileOpen(ref aviFile, fileName, Avi.OF_READWRITE, 0); } else //create empty file { result = Avi.AVIFileOpen(ref aviFile, fileName, Avi.OF_WRITE | Avi.OF_CREATE, 0); } if (result != 0) { throw new Exception("Exception in AVIFileOpen: " + result.ToString()); } }
/// <summary>Create a compressed stream from an uncompressed stream</summary> private void CreateCompressedStream() { //display the compression options dialog... Avi.AVICOMPRESSOPTIONS_CLASS options = new Avi.AVICOMPRESSOPTIONS_CLASS { fccType = (uint)Avi.streamtypeVIDEO, lpParms = IntPtr.Zero, lpFormat = IntPtr.Zero }; Avi.AVISaveOptions(IntPtr.Zero, Avi.ICMF_CHOOSE_KEYFRAME | Avi.ICMF_CHOOSE_DATARATE, 1, ref aviStream, ref options); Avi.AVISaveOptionsFree(1, ref options); //..or set static options /*Avi.AVICOMPRESSOPTIONS opts = new Avi.AVICOMPRESSOPTIONS(); * opts.fccType = (UInt32)Avi.mmioStringToFOURCC("vids", 0); * opts.fccHandler = (UInt32)Avi.mmioStringToFOURCC("CVID", 0); * opts.dwKeyFrameEvery = 0; * opts.dwQuality = 0; // 0 .. 10000 * opts.dwFlags = 0; // AVICOMRPESSF_KEYFRAMES = 4 * opts.dwBytesPerSecond= 0; * opts.lpFormat = new IntPtr(0); * opts.cbFormat = 0; * opts.lpParms = new IntPtr(0); * opts.cbParms = 0; * opts.dwInterleaveEvery = 0;*/ //get the compressed stream compressOptions = options.ToStruct(); int result = Avi.AVIMakeCompressedStream(out compressedStream, aviStream, ref compressOptions, 0); if (result != 0) { throw new Exception("Exception in AVIMakeCompressedStream: " + result); } SetFormat(compressedStream); }
/// <summary>Add one frame to a new stream</summary> /// <param name="bmp"></param> /// <remarks> /// This works only with uncompressed streams, /// and compressed streams that have not been saved yet. /// Use DecompressToNewFile to edit saved compressed streams. /// </remarks> public void AddFrame(Bitmap bmp) { bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); BitmapData bmpDat = bmp.LockBits( new Rectangle( 0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); int result = Avi.AVIStreamWrite(writeCompressed ? compressedStream : StreamPointer, CountFrames, 1, bmpDat.Scan0, bmpDat.Stride * bmpDat.Height, 0, 0, 0); if (result != 0) { throw new Exception("Exception in VideoStreamWrite: " + result); } bmp.UnlockBits(bmpDat); CountFrames++; }
/// <summary>Close the stream</summary> public override void Close() { base.Close(); Avi.AVIFileExit(); }
/// <summary>Export a frame into a bitmap</summary> /// <param name="position">Position of the frame</param> public Bitmap GetBitmap(int position) { if (position > CountFrames) { throw new Exception("Invalid frame position: " + position); } GetStreamInfo(StreamPointer); //Decompress the frame and return a pointer to the DIB int dib = Avi.AVIStreamGetFrame(getFrameObject, FirstFrame + position); //Copy the bitmap header into a managed struct Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); bih = (Avi.BITMAPINFOHEADER)Marshal.PtrToStructure(new IntPtr(dib), bih.GetType()); if (bih.biSizeImage < 1) { throw new Exception("Exception in VideoStreamGetFrame"); } //copy the image byte[] bitmapData; int address = dib + Marshal.SizeOf(bih); if (bih.biBitCount < 16) { //copy palette and pixels bitmapData = new byte[bih.biSizeImage + Avi.PALETTE_SIZE]; } else { //copy only pixels bitmapData = new byte[bih.biSizeImage]; } Marshal.Copy(new IntPtr(address), bitmapData, 0, bitmapData.Length); //copy bitmap info byte[] bitmapInfo = new byte[Marshal.SizeOf(bih)]; IntPtr ptr; ptr = Marshal.AllocHGlobal(bitmapInfo.Length); Marshal.StructureToPtr(bih, ptr, false); address = ptr.ToInt32(); Marshal.Copy(new IntPtr(address), bitmapInfo, 0, bitmapInfo.Length); Marshal.FreeHGlobal(ptr); //create file header Avi.BITMAPFILEHEADER bfh = new Avi.BITMAPFILEHEADER(); bfh.bfType = Avi.BMP_MAGIC_COOKIE; bfh.bfSize = 55 + bih.biSizeImage; //size of file as written to disk bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = Marshal.SizeOf(bih) + Marshal.SizeOf(bfh); if (bih.biBitCount < 16) { //There is a palette between header and pixel data bfh.bfOffBits += Avi.PALETTE_SIZE; } //write a bitmap stream BinaryWriter bw = new BinaryWriter(new MemoryStream()); //write header bw.Write(bfh.bfType); bw.Write(bfh.bfSize); bw.Write(bfh.bfReserved1); bw.Write(bfh.bfReserved2); bw.Write(bfh.bfOffBits); //write bitmap info bw.Write(bitmapInfo); //write bitmap data bw.Write(bitmapData); Bitmap bmp = (Bitmap)Image.FromStream(bw.BaseStream); Bitmap saveableBitmap = new Bitmap(bmp.Width, bmp.Height); Graphics g = Graphics.FromImage(saveableBitmap); g.DrawImage(bmp, 0, 0); g.Dispose(); bmp.Dispose(); bw.Close(); return(saveableBitmap); }