'C# Camera Capture with AviCap32.dll

I'm trying to capture images from my webcam by using avicap32.dll. An event should be called when a new image is available. The problem is that it only shows a black image with a few rows of colored pixels at the bottom (Sample image).

I DON'T want to use any other libraries like Aforge, DirectShow, OpenCV or something similar.

Here is my code:

public class CameraCapture2
{
    [DllImport("user32", EntryPoint = "SendMessage")]
    static extern bool SendMessage(int hWnd, uint wMsg, int wParam, int lParam);

    [DllImport("user32", EntryPoint = "SendMessage")]
    static extern int SendBitmapMessage(int hWnd, uint wMsg, int wParam, ref BITMAPINFO lParam);

    [DllImport("user32", EntryPoint = "SendMessage")]
    static extern int SendHeaderMessage(int hWnd, uint wMsg, int wParam, CallBackDelegate lParam);

    [DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindow")]
    static extern int capCreateCaptureWindow(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);

    delegate void CallBackDelegate(IntPtr hwnd, ref VIDEOHEADER hdr);
    CallBackDelegate delegateFrameCallBack;

    AutoResetEvent autoEvent = new AutoResetEvent(false);
    Thread frameThread;


    public event EventHandler<NewFrameEventArgs> NewFrame;
    public int FPS = 0;

    public const int BitsPerPixel = 24; //RGB  (by changing this value, change the other PixelFormats)
    public int frameWidth = 0;
    public int frameHeight = 0;
    public int camID = 0;
    int camHwnd, parentHwnd;
    bool bStart = false;
    object threadLock = new object();

    int preferredFPSms;

    public CameraCapture2(int frameWidth, int frameHeight, int preferredFPS, int camID, int parentHwnd)
    {
        this.frameWidth = frameWidth;
        this.frameHeight = frameHeight;
        this.parentHwnd = parentHwnd;
        this.camID = camID;
        PreferredFPS = preferredFPS;

        delegateFrameCallBack = FrameCallBack;
    }

    public void Start()
    {
        try
        {
            camHwnd = capCreateCaptureWindow("WebCam", 0, 0, 0, frameWidth, frameHeight, parentHwnd, camID);

            // connect to the device
            if (SendMessage(camHwnd, WM_CAP.WM_CAP_DRIVER_CONNECT, 0, 0))
            {
                BITMAPINFO bInfo = new BITMAPINFO();
                bInfo.bmiHeader = new BITMAPINFOHEADER();
                bInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(bInfo.bmiHeader);
                bInfo.bmiHeader.biWidth = frameWidth;
                bInfo.bmiHeader.biHeight = frameHeight;
                bInfo.bmiHeader.biPlanes = 1;
                bInfo.bmiHeader.biBitCount = BitsPerPixel; // bits per pixel, 24 - RGB

                //Enable preview mode. In preview mode, frames are transferred from the 
                //capture hardware to system memory and then displayed in the capture 
                //window using GDI functions.
                SendMessage(camHwnd, WM_CAP.WM_CAP_SET_PREVIEW, 1, 0);
                SendMessage(camHwnd, WM_CAP.WM_CAP_SET_PREVIEWRATE, 34, 0); // sets the frame display rate in preview mode
                SendBitmapMessage(camHwnd, WM_CAP.WM_CAP_SET_VIDEOFORMAT, Marshal.SizeOf(bInfo), ref bInfo);

                frameThread = new Thread(new ThreadStart(this.FrameGrabber));
                bStart = true;       // First, set variable
                frameThread.Priority = ThreadPriority.Lowest;
                frameThread.Start(); // Only then put thread to the queue
            }
            else
                throw new Exception("Cannot connect to device");
        }
        catch (Exception e)
        {
            Stop();
            throw new Exception("Error: " + e.Message);
        }
    }

    public void Stop()
    {
        try
        {
            bStart = false;
            Set();
            SendMessage(camHwnd, WM_CAP.WM_CAP_DRIVER_DISCONNECT, 0, 0);
        }
        catch { }
    }

    private void FrameGrabber()
    {
        while (bStart) // if worker active thread is still required
        {
            try
            {
                // get the next frame. This is the SLOWEST part of the program
                SendMessage(camHwnd, WM_CAP.WM_CAP_GRAB_FRAME_NOSTOP, 0, 0);
                SendHeaderMessage(camHwnd, WM_CAP.WM_CAP_SET_CALLBACK_FRAME, 0, delegateFrameCallBack);
            }
            catch (Exception excep)
            {
                this.Stop(); // stop the process
                throw new Exception("Capturing error:\r\n" + excep.Message);
            }
        }
    }

    /// <summary>
    /// Allow waiting worker (FrameGrabber) thread to proceed
    /// </summary>
    public void Set()
    {
        autoEvent.Set();
    }

    private void FrameCallBack(IntPtr hwnd, ref VIDEOHEADER hdr)
    {
        if (NewFrame != null)
        {
            //Bitmap bmp = new Bitmap(frameWidth, frameHeight, frameWidth * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, hdr.lpData);
            byte[] _imageTemp = new byte[hdr.dwBufferLength];
            Marshal.Copy(hdr.lpData, _imageTemp, 0, (int)hdr.dwBufferLength);
            Bitmap bmp = new Bitmap(new System.IO.MemoryStream(WriteBitmapFile(frameWidth, frameHeight, _imageTemp)));
            NewFrame(this, new NewFrameEventArgs(bmp));
        }

        // block thread for preferred milleseconds
        if (preferredFPSms == 0)
            autoEvent.WaitOne();
        else
            autoEvent.WaitOne(preferredFPSms, false);
    }

    private static byte[] WriteBitmapFile(int width, int height, byte[] imageData)
    {
        using (var stream = new System.IO.MemoryStream(imageData))
        using (var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
        {
            System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height)
                                                , System.Drawing.Imaging.ImageLockMode.WriteOnly
                                                , bmp.PixelFormat
            );

            Marshal.Copy(imageData, 0, bmpData.Scan0, imageData.Length);

            bmp.UnlockBits(bmpData);


            if (bmp == null)
                return null;

            bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);

            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);    // get bitmap bytes
                return ms.ToArray();
            } // End Using stream

        }

    }


    public void ShowVideoDialog()
    {
        SendMessage(camHwnd, WM_CAP.WM_CAP_DLG_VIDEODISPLAY, 0, 0);
    }

    public int PreferredFPS
    {
        get { return 1000 / preferredFPSms; }
        set
        {
            if (value == 0)
                preferredFPSms = 0;
            else if (value > 0 && value <= 30)
            {
                preferredFPSms = 1000 / value;
            }
        }
    }
}

public class NewFrameEventArgs
{
    public Bitmap Frame;

    public NewFrameEventArgs(Bitmap frame)
    {
        Frame = frame;
    }
}

Most of this code is from Codeproject



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source