View Single Post
Old 14th June 2005, 07:00   #14  |  Link
stax76
Registered User
 
stax76's Avatar
 
Join Date: Jun 2002
Location: On thin ice
Posts: 6,837
you don't have to manipulate images unless you are having fun with it . My code is fast and can crop and scale. See it in the latest DVX version in action. For my crop dialog I want to borrow a idea of Recode but for now I'm working on Stax DVB but I'll try to give you some competion with my DVX successor later

Code:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Reflection;
using System.Diagnostics;

namespace VFW
{
	public class AVIFile
	{
		public int Left, Top, Right, Bottom;
		
		IntPtr AviFile;
		IntPtr FrameObject;
		IntPtr AviStream;
		AVISTREAMINFO StreamInfo;
		Control Control;
		
		int FrameCountValue;
		
		public int FrameCount
		{
			get { return FrameCountValue; }
		}
		
		public float FrameRate
		{
			get { return StreamInfo.dwRate / (float)StreamInfo.dwScale; }
		}
		
		public Size FrameSize
		{
			get { return new Size((int)StreamInfo.rcFrame.right, (int)StreamInfo.rcFrame.bottom); }
		}
		
		public void Open(string fileName, Control c)
		{
			Open(fileName);
			
			Control = c;
		}
		
		string GetFourCC(int value)
		{
			byte[] bytes = BitConverter.GetBytes(value);
			char[] chars = new char[4];
			
			for (int i = 0; i < bytes.Length; i++)
				chars[i] = Convert.ToChar(bytes[i]);
			
			return new String(chars);
		}
		
		public void Open(string fileName)
		{
			try
			{
				AVIFileInit();
				
				int OF_SHARE_DENY_WRITE = 32;
				
				int result = AVIFileOpen(ref AviFile, fileName,
					OF_SHARE_DENY_WRITE, 0);
				
				if (result != 0)
					throw new Exception("AVIFileOpen failed");
				
				result = AVIFileGetStream(AviFile, out AviStream,
					1935960438 /*FourCC for vids*/, 0);
				
				if (result != 0)
					throw new Exception("AVIFileGetStream failed");
				
				FrameCountValue = AVIStreamLength(AviStream.ToInt32());
				
				StreamInfo = new AVISTREAMINFO();
				
				result = AVIStreamInfo(AviStream.ToInt32(), ref StreamInfo,
					Marshal.SizeOf(StreamInfo));
				
				if (result != 0)
					throw new Exception("AVIStreamInfo failed");
				
				if (GetFourCC(Convert.ToInt32(StreamInfo.fccHandler)) == "YV12")
					FrameObject = AVIStreamGetFrameOpen(AviStream, 1);
				else
					FrameObject = AVIStreamGetFrameOpen(AviStream, 0);
				
				if (FrameObject == IntPtr.Zero) 
					throw new Exception("AVIStreamGetFrameOpen failed");
			}
			catch (Exception ex)
			{
				MessageBox.Show("An error occurred. Maybe no YV12 decoder available, installing XviD, DivX or ffdshow might help.\r\n\r\n" +
					ex.ToString(), Application.ProductName,
					MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
		
		int PositionValue;
		
		public int Position 
		{
			get { return PositionValue; }
			set 
			{
				if (value < 0)
					PositionValue = 0;
				else if (value > FrameCount - 1)
					PositionValue = FrameCount - 1;
				else
					PositionValue = value;
			}
		}
		
		public void Close()
		{
			if (FrameObject != IntPtr.Zero)
			{
				AVIStreamGetFrameClose(FrameObject);
				FrameObject = IntPtr.Zero;
			}

			if (AviStream != IntPtr.Zero)
			{
				AVIStreamRelease(AviStream);
				AviStream = IntPtr.Zero;
			}

			if (AviFile != IntPtr.Zero)
			{
				AVIFileRelease(AviFile);
				AviFile = IntPtr.Zero;
			}

			AVIFileExit();
		}

		public void Draw()
		{
			if (Control != null && Control.Visible)
			{
				Graphics g = Control.CreateGraphics();
				Draw(g);
				g.Dispose();			
			}
		}

		int DrawCount = 0;
		
		public void Draw(Graphics g)
		{
			try
			{
				if (Control != null && Control.Visible && FrameObject != IntPtr.Zero)
				{
					Debug.WriteLine(++DrawCount);
					
					Image img = GetBMPFromDib(new IntPtr(
						AVIStreamGetFrame(FrameObject, Position)));
					
					if (Left == 0 && Top == 0 && Right == 0 && Bottom == 0)
					{
						g.DrawImage(img, Control.ClientRectangle);
					}
					else
					{
						float factorX = (float)Control.Width / img.Width;
						float factorY = (float)Control.Height / img.Height;
						
						float left = Left * factorX;
						float right = Right * factorX;
						float top = Top * factorY;
						float bottom = Bottom * factorY;
						
						RectangleF rectDest = new RectangleF();
						
						rectDest.X = left;
						rectDest.Y = top;
						rectDest.Width = Control.Width - left - right;
						rectDest.Height = Control.Height - top - bottom;
						
						Rectangle rectSrc = new Rectangle();
						
						rectSrc.X = Left;
						rectSrc.Y = Top;
						rectSrc.Width = img.Width - Left - Right;
						rectSrc.Height = img.Height - Top - Bottom;
						
						g.DrawImage(img, rectDest, rectSrc,	GraphicsUnit.Pixel);
						
						SolidBrush sb = new SolidBrush(Color.White);
						
						g.FillRectangle(sb, 0, 0, left, Control.Height);
						g.FillRectangle(sb, 0, 0, Control.Width, top);
						g.FillRectangle(sb, Control.Width - right, 0, right, Control.Height);
						g.FillRectangle(sb, 0, Control.Height - bottom, Control.Width, bottom);
						
						sb.Dispose();
					}
				}			
			}
			catch (Exception ex)
			{
				MessageBox.Show("An error occurred. Maybe no YV12 decoder available, installing XviD, DivX or ffdshow might help.\r\n\r\n" +
					ex.ToString(), Application.ProductName,
					MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		public Bitmap GetBitmap()
		{
			return GetBMPFromDib(new IntPtr(
				AVIStreamGetFrame(FrameObject, Position)));
		}
		
		public Bitmap GetBMPFromDib(IntPtr pDIB) {
			IntPtr pPix = new IntPtr(pDIB.ToInt32() + Marshal.SizeOf(typeof(BITMAPINFOHEADER)));
			
			MethodInfo mi = typeof(Bitmap).GetMethod("FromGDIplus", 
				BindingFlags.Static | BindingFlags.NonPublic);
			
			IntPtr pBmp = IntPtr.Zero;
			int status = GdipCreateBitmapFromGdiDib(pDIB, pPix, ref pBmp);
			
			return (Bitmap)mi.Invoke(null, new object[] {pBmp});
		}
		
		[DllImport("gdi32.dll", ExactSpelling=true)]
		static extern bool DeleteObject( IntPtr obj );
		
		[DllImport("gdiplus.dll", ExactSpelling=true)]
		static extern int GdipCreateBitmapFromGdiDib( IntPtr bminfo, IntPtr pixdat, ref IntPtr image );
		
		[DllImport("gdiplus.dll", ExactSpelling=true)]
		static extern int GdipCreateHBITMAPFromBitmap( IntPtr image, out IntPtr hbitmap, int bkg );
		
		[DllImport("gdiplus.dll", ExactSpelling=true)]
		static extern int GdipDisposeImage( IntPtr image );
		
		[DllImport("avifil32.dll")]
		static extern void AVIFileInit();

		[DllImport("avifil32.dll", PreserveSig=true)]
		static extern int AVIFileOpen(
			ref IntPtr ppfile,
			String szFile,
			int uMode,
			int pclsidHandler);

		[DllImport("avifil32.dll")]
		static extern int AVIFileGetStream(
			IntPtr pfile,
			out IntPtr ppavi,
			int fccType,
			int lParam);

		[DllImport("avifil32.dll", PreserveSig=true)]
		static extern int AVIStreamStart(int pavi);

		[DllImport("avifil32.dll", PreserveSig=true)]
		static extern int AVIStreamLength(int pavi);

		[DllImport("avifil32.dll")]
		static extern int AVIStreamInfo(
			int pAVIStream,
			ref AVISTREAMINFO psi,
			int lSize);
		
		[DllImport("avifil32.dll")]
		static extern IntPtr AVIStreamGetFrameOpen(
			IntPtr pAVIStream,
			int lpbiWanted);
		
		[DllImport("avifil32.dll")]
		static extern int AVIStreamGetFrame(IntPtr pGetFrameObj, int lPos);

		[DllImport("avifil32.dll")]
		static extern int AVIFileCreateStream(
			int pfile,
			out IntPtr ppavi, 
			ref AVISTREAMINFO ptr_streaminfo);

		[DllImport("avifil32.dll")]
		static extern int AVIStreamGetFrameClose(
			IntPtr pGetFrameObj);

		[DllImport("avifil32.dll")]
		static extern int AVIStreamRelease(IntPtr aviStream);

		[DllImport("avifil32.dll")]
		static extern int AVIFileRelease(IntPtr pfile);

		[DllImport("avifil32.dll")]
		static extern void AVIFileExit();
		
		[StructLayout(LayoutKind.Sequential, Pack=1)]
			struct RECT { 
			public UInt32 left; 
			public UInt32 top; 
			public UInt32 right; 
			public UInt32 bottom; 
		} 		
		
		[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
			struct BITMAPFILEHEADER {
			[MarshalAs( UnmanagedType.ByValArray, SizeConst=2)] 
			public Char[]	Type;
			public Int32	Size;
			public Int16	reserved1;
			public Int16	reserved2;
			public Int32	OffBits;
		}
		
		[StructLayout(LayoutKind.Sequential, Pack=1)]
			struct BITMAPINFOHEADER {
			public UInt32 biSize;
			public Int32  biWidth;
			public Int32  biHeight;
			public Int16  biPlanes;
			public Int16  biBitCount;
			public UInt32 biCompression;
			public UInt32 biSizeImage;
			public Int32  biXPelsPerMeter;
			public Int32  biYPelsPerMeter;
			public UInt32 biClrUsed;
			public UInt32 biClrImportant;
		}
		
		[StructLayout(LayoutKind.Sequential, Pack=1)]
			struct AVISTREAMINFO {
			public UInt32    fccType;
			public UInt32    fccHandler;
			public UInt32    dwFlags;
			public UInt32    dwCaps;
			public UInt16    wPriority;
			public UInt16    wLanguage;
			public UInt32    dwScale;
			public UInt32    dwRate;
			public UInt32    dwStart;
			public UInt32    dwLength;
			public UInt32    dwInitialFrames;
			public UInt32    dwSuggestedBufferSize;
			public UInt32    dwQuality;
			public UInt32    dwSampleSize;
			public RECT		 rcFrame;
			public UInt32    dwEditCount;
			public UInt32    dwFormatChangeCount;
			[MarshalAs(UnmanagedType.ByValArray, SizeConst=64)]
			public UInt16[]    szName;
		}
	}
}
stax76 is offline   Reply With Quote