/// <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.AVISTREAMINFO streamInfo = GetStreamInfo(aviStream); //Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); //int size = Marshal.SizeOf(bih); Avi.BITMAPINFO bih = new Avi.BITMAPINFO(); int size = Marshal.SizeOf(bih.bmiHeader); Avi.AVIStreamReadFormat(aviStream, 0, ref bih, ref size); if (bih.bmiHeader.biBitCount < 24) { size = Marshal.SizeOf(bih.bmiHeader) + Avi.PALETTE_SIZE; Avi.AVIStreamReadFormat(aviStream, 0, ref bih, ref size); CopyPalette(bih.bmiColors); } this.frameRate = (float)streamInfo.dwRate / (float)streamInfo.dwScale; this.width = (int)streamInfo.rcFrame.right; this.height = (int)streamInfo.rcFrame.bottom; this.frameSize = bih.bmiHeader.biSizeImage; this.countBitsPerPixel = bih.bmiHeader.biBitCount; this.firstFrame = Avi.AVIStreamStart(aviStream.ToInt32()); this.countFrames = Avi.AVIStreamLength(aviStream.ToInt32()); }
/// <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>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.ToString()); } return streamInfo; }
/// <summary>Copy a piece of video and wave sound int a new file</summary> /// <param name="newFileName">File name</param> /// <param name="startAtSecond">Start copying at second x</param> /// <param name="stopAtSecond">Stop copying at second y</param> /// <returns>AviManager for the new video</returns> public AviManager CopyTo(String newFileName, float startAtSecond, float stopAtSecond) { AviManager newFile = new AviManager(newFileName, false); try { //copy video stream VideoStream videoStream = GetVideoStream(); int startFrameIndex = (int)(videoStream.FrameRate * startAtSecond); int stopFrameIndex = (int)(videoStream.FrameRate * stopAtSecond); videoStream.GetFrameOpen(); Bitmap bmp = videoStream.GetBitmap(startFrameIndex); VideoStream newStream = newFile.AddVideoStream(false, videoStream.FrameRate, bmp); for (int n = startFrameIndex + 1; n <= stopFrameIndex; n++) { bmp = videoStream.GetBitmap(n); newStream.AddFrame(bmp); } videoStream.GetFrameClose(); //copy audio stream AudioStream waveStream = GetWaveStream(); Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO(); Avi.PCMWAVEFORMAT streamFormat = new Avi.PCMWAVEFORMAT(); int streamLength = 0; IntPtr ptrRawData = waveStream.GetStreamData( ref streamInfo, ref streamFormat, ref streamLength); int startByteIndex = (int)(startAtSecond * (float)(waveStream.CountSamplesPerSecond * streamFormat.nChannels * waveStream.CountBitsPerSample) / 8); int stopByteIndex = (int)(stopAtSecond * (float)(waveStream.CountSamplesPerSecond * streamFormat.nChannels * waveStream.CountBitsPerSample) / 8); IntPtr ptrWavePart = new IntPtr(ptrRawData.ToInt32() + startByteIndex); byte[] rawData = new byte[stopByteIndex - startByteIndex]; Marshal.Copy(ptrWavePart, rawData, 0, rawData.Length); Marshal.FreeHGlobal(ptrRawData); streamInfo.dwLength = rawData.Length; streamInfo.dwStart = 0; IntPtr unmanagedRawData = Marshal.AllocHGlobal(rawData.Length); Marshal.Copy(rawData, 0, unmanagedRawData, rawData.Length); newFile.AddAudioStream(unmanagedRawData, streamInfo, streamFormat, rawData.Length); Marshal.FreeHGlobal(unmanagedRawData); } catch (Exception ex) { newFile.Close(); throw ex; } return(newFile); }
/// <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); Avi.AVISTREAMINFO streamInfo = GetStreamInfo(aviStream); }
/// <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.ToString()); } frameRate = info.dwRate / info.dwScale; }
/// <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.ToString()); } 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() { Avi.AVISTREAMINFO streamInfo = 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>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>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.ToString()); } return(waveData); }
/// <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(); strhdr.fccType = Avi.mmioStringToFOURCC("vids", 0); strhdr.fccHandler = Avi.mmioStringToFOURCC("CVID", 0); strhdr.dwFlags = 0; strhdr.dwCaps = 0; strhdr.wPriority = 0; strhdr.wLanguage = 0; strhdr.dwScale = (int)scale; strhdr.dwRate = (int)rate; // Frames per Second strhdr.dwStart = 0; strhdr.dwLength = 0; strhdr.dwInitialFrames = 0; strhdr.dwSuggestedBufferSize = frameSize; //height_ * stride_; strhdr.dwQuality = -1; //default strhdr.dwSampleSize = 0; strhdr.rcFrame.top = 0; strhdr.rcFrame.left = 0; strhdr.rcFrame.bottom = (uint)height; strhdr.rcFrame.right = (uint)width; strhdr.dwEditCount = 0; strhdr.dwFormatChangeCount = 0; strhdr.szName = new UInt16[64]; int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref strhdr); if (result != 0) { throw new Exception("Exception in AVIFileCreateStream: " + result.ToString()); } }
/// <summary>Copy a piece of video and wave sound int a new file</summary> /// <param name="newFileName">File name</param> /// <param name="startAtSecond">Start copying at second x</param> /// <param name="stopAtSecond">Stop copying at second y</param> /// <returns>AviManager for the new video</returns> public AviManager CopyTo(String newFileName, float startAtSecond, float stopAtSecond) { AviManager newFile = new AviManager(newFileName, false); try { //copy video stream VideoStream videoStream = GetVideoStream(); int startFrameIndex = (int)(videoStream.FrameRate * startAtSecond); int stopFrameIndex = (int)(videoStream.FrameRate * stopAtSecond); videoStream.GetFrameOpen(); Bitmap bmp = videoStream.GetBitmap(startFrameIndex); VideoStream newStream = newFile.AddVideoStream(false, videoStream.FrameRate, bmp); for (int n = startFrameIndex + 1; n <= stopFrameIndex; n++) { bmp = videoStream.GetBitmap(n); newStream.AddFrame(bmp); } videoStream.GetFrameClose(); //copy audio stream AudioStream waveStream = GetWaveStream(); Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO(); Avi.PCMWAVEFORMAT streamFormat = new Avi.PCMWAVEFORMAT(); int streamLength = 0; IntPtr ptrRawData = waveStream.GetStreamData( ref streamInfo, ref streamFormat, ref streamLength); int startByteIndex = (int)( startAtSecond * (float)(waveStream.CountSamplesPerSecond * streamFormat.nChannels * waveStream.CountBitsPerSample) / 8); int stopByteIndex = (int)( stopAtSecond * (float)(waveStream.CountSamplesPerSecond * streamFormat.nChannels * waveStream.CountBitsPerSample) / 8); IntPtr ptrWavePart = new IntPtr(ptrRawData.ToInt32() + startByteIndex); byte[] rawData = new byte[stopByteIndex - startByteIndex]; Marshal.Copy(ptrWavePart, rawData, 0, rawData.Length); Marshal.FreeHGlobal(ptrRawData); streamInfo.dwLength = rawData.Length; streamInfo.dwStart = 0; IntPtr unmanagedRawData = Marshal.AllocHGlobal(rawData.Length); Marshal.Copy(rawData, 0, unmanagedRawData, rawData.Length); newFile.AddAudioStream(unmanagedRawData, streamInfo, streamFormat, rawData.Length); Marshal.FreeHGlobal(unmanagedRawData); } catch (Exception ex) { newFile.Close(); throw ex; } return newFile; }
/// <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); }
private IntPtr InsertSilence(int countSilentSamples, IntPtr waveData, int lengthWave, ref Avi.AVISTREAMINFO streamInfo) { //initialize silence int lengthSilence = countSilentSamples * streamInfo.dwSampleSize; byte[] silence = new byte[lengthSilence]; //initialize new sound int lengthNewStream = lengthSilence + lengthWave; IntPtr newWaveData = Marshal.AllocHGlobal(lengthNewStream); //copy silence Marshal.Copy(silence, 0, newWaveData, lengthSilence); //copy sound byte[] sound = new byte[lengthWave]; Marshal.Copy(waveData, sound, 0, lengthWave); IntPtr startOfSound = new IntPtr(newWaveData.ToInt32() + lengthSilence); Marshal.Copy(sound, 0, startOfSound, lengthWave); Marshal.FreeHGlobal(newWaveData); streamInfo.dwLength = lengthNewStream; return(newWaveData); }
/// <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); } Avi.AVISTREAMINFO streamInfo = GetStreamInfo(StreamPointer); Avi.BITMAPINFO bih = new Avi.BITMAPINFO(); int headerSize = Marshal.SizeOf(bih.bmiHeader); //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 bih.bmiColors = this.palette; bih.bmiHeader = (Avi.BITMAPINFOHEADER)Marshal.PtrToStructure(new IntPtr(dib), bih.bmiHeader.GetType()); if (bih.bmiHeader.biSizeImage < 1) { throw new Exception("Exception in VideoStreamGetFrame"); } //copy the image int framePaletteSize = bih.bmiHeader.biClrUsed * Avi.RGBQUAD_SIZE; byte[] bitmapData = new byte[bih.bmiHeader.biSizeImage]; IntPtr dibPointer = new IntPtr(dib + Marshal.SizeOf(bih.bmiHeader) + framePaletteSize); Marshal.Copy(dibPointer, bitmapData, 0, bih.bmiHeader.biSizeImage); //copy bitmap info byte[] bitmapInfo = new byte[Marshal.SizeOf(bih)]; IntPtr ptr = Marshal.AllocHGlobal(bitmapInfo.Length); Marshal.StructureToPtr(bih, ptr, false); Marshal.Copy(ptr, bitmapInfo, 0, bitmapInfo.Length); Marshal.FreeHGlobal(ptr); //create file header Avi.BITMAPFILEHEADER bfh = new Avi.BITMAPFILEHEADER(); bfh.bfType = Avi.BMP_MAGIC_COOKIE; bfh.bfSize = (Int32)(55 + bih.bmiHeader.biSizeImage); //size of file as written to disk bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = Marshal.SizeOf(bih) + Marshal.SizeOf(bfh); if (bih.bmiHeader.biBitCount < 8) { //There is a palette between header and pixel data bfh.bfOffBits += bih.bmiHeader.biClrUsed * Avi.RGBQUAD_SIZE; //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); }