legohead
legohead

Reputation: 540

How do I scan every frame from ISampleGrabber using directshow.net

I have a program which currently displays a preview of a usb webcam and then displays a frame within a picturebox when a button is pressed. This is done by using the directshow DxSnap sample thus using the ISampleGrabberCB interface.

Would it be possible for each frame to be scanned automatically without the use of a button?

I tried to do this with a timer however the result ended with bad image quality from both preview and the captured image.

Would this be achieved by using the IsampleGrabberCB.BufferCB function?

The way I am currently getting frames using is a button consists of:

int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr buffer, int bufferLength)
    {
        Debug.Assert(bufferLength == Math.Abs(pitch) * videoHeight, "Wrong Buffer Length");

        if (gotFrame)
        {
            gotFrame = false;
            Debug.Assert(imageBuffer != IntPtr.Zero, "Remove Buffer");

            CopyMemory(imageBuffer, buffer, bufferLength);

            pictureReady.Set();
        }
        return 0;
    }
public void getFrameFromWebcam()
{
   if (iPtr != IntPtr.Zero)
   {
       Marshal.FreeCoTaskMem(iPtr);
       iPtr = IntPtr.Zero;
   }

        //Get Image
        iPtr = sampleGrabberCallBack.getFrame();
        Bitmap bitmapOfFrame = new Bitmap(sampleGrabberCallBack.width, sampleGrabberCallBack.height, sampleGrabberCallBack.capturePitch, PixelFormat.Format32bppRgb, iPtr);
        bitmapOfFrame.RotateFlip(RotateFlipType.RotateNoneFlipY);
        pictureBox3.Image = bitmapOfFrame;
        barcodeReader(bitmapOfFrame);
}

public IntPtr getFrame()
    {
        int hr;
        pictureReady.Reset();
        imageBuffer = Marshal.AllocCoTaskMem(Math.Abs(pitch) * videoHeight);

        try
        {
            gotFrame = true;

            if (videoControl != null)
            {
                hr = videoControl.SetMode(stillPin, VideoControlFlags.Trigger);
                DsError.ThrowExceptionForHR(hr);
            }

            if (!pictureReady.WaitOne(9000, false))
            {
                throw new Exception("Timeout waiting to get picture");
            }

        }
        catch
        {
            Marshal.FreeCoTaskMem(imageBuffer);
            imageBuffer = IntPtr.Zero;
        }

        return imageBuffer;

    }

Upvotes: 0

Views: 1594

Answers (1)

Roman Ryltsov
Roman Ryltsov

Reputation: 69687

DirectShow sets you up video streaming, hence you have a stream of frames, not individual images such as obtained when pressing a button (in fact, response to button is untypical for DirectShow and is likely to require some camera-specific integration). ISampleGrabberCB::SampleCB is thus getting you every captured video frame sequentially. You don't poll it with timer, instead you have a callback called for every frame.

Since it sounds like you are not getting this, I suppose you are missing one of the two things, or both:

  1. You can/need set capture resolution and pixel format of your interest - for image processing you might prefer uncompressed video formats rather than compressed
  2. Callback calls are blocking, the slower is the frame processing the lower is effective frame rate since you are delaying video streaming with the video processing time.

Also note that some consumer grade cameras have higher resolution for snapshots and lower resolution for video streaming, so when it comes to video processing you are unable to reach highest declared resolution on the camera specification.

Upvotes: 2

Related Questions