. 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;
}
}
}