Results 1 to 4 of 4

Thread: Direct show doesn't change webcam resolution

  1. #1
    Chris93 is offline VB.NET Forum Newbie
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2011
    Posts
    2
    Reputation
    0

    Direct show doesn't change webcam resolution

    Hi,

    I have two Microsoft LifeCam Studio webcams that need to have a still image taken when required. I have managed to put this code together that works for all except changing the resolution. The weird thing that I don't understand is that the equivalent code for the form works in C# but not in vb.

    The code is built up of 3 parts, a form with a picturebox and a button, the class written in C# that uses directshow and another class that acts between them (the form is just temporary until it works).

    My form written in vb (it does need the dispose event to close the camera adding but I've left this out)
    Code:
    Imports SnapShot
    
    Public Class Form1
    
    
        Private cam As Class1
    
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            cam.takeImage("C:\Users\Programming\Desktop\me.jpg")
        End Sub
    
    
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            cam = New Class1(0, PictureBox1)
        End Sub
    End Class
    The "middle" class, based upon the directshow example.
    Code:
    using System;using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Drawing;
    using System.Drawing.Imaging;
    
    
    namespace SnapShot
    {
        public class Class1
        {
            private Capture cam;
            IntPtr m_ip = IntPtr.Zero;
    
    
            public Class1(int VIDEODEVICE, Control pictureBox2)
            {
                cam = new Capture(VIDEODEVICE, 1024, 768, 24, pictureBox2);
            }
    
    
            public void dispose()
            {
                if (m_ip != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(m_ip);
                    m_ip = IntPtr.Zero;
                }
            }
    
    
            public void takeImage(String name)
            {
                // Release any previous buffer
                if (m_ip != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(m_ip);
                    m_ip = IntPtr.Zero;
                }
    
    
                // capture image
                m_ip = cam.Click();
                Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
    
    
                // If the image is upsidedown
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                b.Save(name, ImageFormat.Jpeg);
            }
        }
    }
    The class that uses direct show, from the samples:
    Code:
    /****************************************************************************While the underlying libraries are covered by LGPL, this sample is released 
    as public domain.  It is distributed in the hope that it will be useful, but 
    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
    or FITNESS FOR A PARTICULAR PURPOSE.  
    *****************************************************************************/
    
    
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Collections;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Diagnostics;
    using System.Windows.Forms;
    
    
    using DirectShowLib;
    
    
    
    
    namespace SnapShot
    {
        /// <summary> Summary description for MainForm. </summary>
        internal class Capture : ISampleGrabberCB, IDisposable
        {
            #region Member variables
    
    
            /// <summary> graph builder interface. </summary>
            private IFilterGraph2 m_FilterGraph = null;
    
    
            // Used to snap picture on Still pin
            private IAMVideoControl m_VidControl = null;
            private IPin m_pinStill = null;
    
    
            /// <summary> so we can wait for the async job to finish </summary>
            private ManualResetEvent m_PictureReady = null;
    
    
            private bool m_WantOne = false;
    
    
            /// <summary> Dimensions of the image, calculated once in constructor for perf. </summary>
            private int m_videoWidth;
            private int m_videoHeight;
            private int m_stride;
    
    
            /// <summary> buffer for bitmap data.  Always release by caller</summary>
            private IntPtr m_ipBuffer = IntPtr.Zero;
    
    
    #if DEBUG
            // Allow you to "Connect to remote graph" from GraphEdit
            DsROTEntry m_rot = null;
    #endif
            #endregion
    
    
            #region APIs
            [DllImport("Kernel32.dll", EntryPoint="RtlMoveMemory")]
            private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);
            #endregion
    
    
            // Zero based device index and device params and output window
            public Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP, Control hControl)
            {
                DsDevice [] capDevices;
    
    
                // Get the collection of video devices
                capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
    
    
                if (iDeviceNum + 1 > capDevices.Length)
                {
                    throw new Exception("No video capture devices found at that index!");
                }
    
    
                try
                {
                    // Set up the capture graph
                    SetupGraph( capDevices[iDeviceNum], iWidth, iHeight, iBPP, hControl);
    
    
                    // tell the callback to ignore new images
                    m_PictureReady = new ManualResetEvent(false);
                }
                catch
                {
                    Dispose();
                    throw;
                }
            }
    
    
            /// <summary> release everything. </summary>
            public void Dispose()
            {
    #if DEBUG
                if (m_rot != null)
                {
                    m_rot.Dispose();
                }
    #endif
                CloseInterfaces();
                if (m_PictureReady != null)
                {
                    m_PictureReady.Close();
                }
            }
            // Destructor
            ~Capture()
            {
                Dispose();
            }
    
    
            /// <summary>
            /// Get the image from the Still pin.  The returned image can turned into a bitmap with
            /// Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
            /// If the image is upside down, you can fix it with
            /// b.RotateFlip(RotateFlipType.RotateNoneFlipY);
            /// </summary>
            /// <returns>Returned pointer to be freed by caller with Marshal.FreeCoTaskMem</returns>
            public IntPtr Click()
            {
                int hr;
    
    
                // get ready to wait for new image
                m_PictureReady.Reset();
                m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);
    
    
                try
                {
                    m_WantOne = true;
    
    
                    // If we are using a still pin, ask for a picture
                    if (m_VidControl != null)
                    {
                        // Tell the camera to send an image
                        hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
                        DsError.ThrowExceptionForHR( hr );
                    }
    
    
                    // Start waiting
                    if ( ! m_PictureReady.WaitOne(9000, false) )
                    {
                        throw new Exception("Timeout waiting to get picture");
                    }
                }
                catch
                {
                    Marshal.FreeCoTaskMem(m_ipBuffer);
                    m_ipBuffer = IntPtr.Zero;
                    throw;
                }
    	
                // Got one
                return m_ipBuffer;
            }
    
    
            public int Width
            {
                get
                {
                    return m_videoWidth;
                }
            }
            public int Height
            {
                get
                {
                    return m_videoHeight;
                }
            }
            public int Stride
            {
                get
                {
                    return m_stride;
                }
            }
    
    
    
    
            /// <summary> build the capture graph for grabber. </summary>
            private void SetupGraph(DsDevice dev, int iWidth, int iHeight, short iBPP, Control hControl)
            {
                int hr;
    
    
                ISampleGrabber sampGrabber = null;
                IBaseFilter capFilter = null;
                IPin pCaptureOut = null;
                IPin pSampleIn = null;
                IPin pRenderIn = null;
    
    
                // Get the graphbuilder object
                m_FilterGraph = new FilterGraph() as IFilterGraph2;
    
    
                try
                {
    #if DEBUG
                    m_rot = new DsROTEntry(m_FilterGraph);
    #endif
                    // add the video input device
                    hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
                    DsError.ThrowExceptionForHR( hr );
    
    
                    // Find the still pin
                    m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0);
    
    
                    // Didn't find one.  Is there a preview pin?
                    if (m_pinStill == null)
                    {
                        m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Preview, 0);
                    }
    
    
                    // Still haven't found one.  Need to put a splitter in so we have
                    // one stream to capture the bitmap from, and one to display.  Ok, we
                    // don't *have* to do it that way, but we are going to anyway.
                    if (m_pinStill == null)
                    {
                        IPin pRaw = null;
                        IPin pSmart = null;
    
    
                        // There is no still pin
                        m_VidControl = null;
    
    
                        // Add a splitter
                        IBaseFilter iSmartTee = (IBaseFilter)new SmartTee();
    
    
                        try
                        {
                            hr = m_FilterGraph.AddFilter(iSmartTee, "SmartTee");
                            DsError.ThrowExceptionForHR( hr );
    
    
                            // Find the find the capture pin from the video device and the
                            // input pin for the splitter, and connnect them
                            pRaw = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);
                            pSmart = DsFindPin.ByDirection(iSmartTee, PinDirection.Input, 0);
    
    
                            hr = m_FilterGraph.Connect(pRaw, pSmart);
                            DsError.ThrowExceptionForHR( hr );
    
    
                            // Now set the capture and still pins (from the splitter)
                            m_pinStill = DsFindPin.ByName(iSmartTee, "Preview");
                            pCaptureOut = DsFindPin.ByName(iSmartTee, "Capture");
    
    
                            // If any of the default config items are set, perform the config
                            // on the actual video device (rather than the splitter)
                            if (iHeight + iWidth + iBPP > 0)
                            {
                                SetConfigParms(pRaw, iWidth, iHeight, iBPP);
                            }
                        }
                        finally
                        {
                            if (pRaw != null)
                            {
                                Marshal.ReleaseComObject(pRaw);
                            }
                            if (pRaw != pSmart)
                            {
                                Marshal.ReleaseComObject(pSmart);
                            }
                            if (pRaw != iSmartTee)
                            {
                                Marshal.ReleaseComObject(iSmartTee);
                            }
                        }
                    }
                    else
                    {
                        // Get a control pointer (used in Click())
                        m_VidControl = capFilter as IAMVideoControl;
    
    
                        pCaptureOut = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);
    
    
                        // If any of the default config items are set
                        if (iHeight + iWidth + iBPP > 0)
                        {
                            SetConfigParms(m_pinStill, iWidth, iHeight, iBPP);
                        }
                    }
    
    
                    // Get the SampleGrabber interface
                    sampGrabber = new SampleGrabber() as ISampleGrabber;
    
    
                    // Configure the sample grabber
                    IBaseFilter baseGrabFlt = sampGrabber as IBaseFilter;
                    ConfigureSampleGrabber(sampGrabber);
                    pSampleIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
    
    
                    // Get the default video renderer
                    IBaseFilter pRenderer = new VideoRendererDefault() as IBaseFilter;
                    hr = m_FilterGraph.AddFilter(pRenderer, "Renderer");
                    DsError.ThrowExceptionForHR( hr );
    
    
                    pRenderIn = DsFindPin.ByDirection(pRenderer, PinDirection.Input, 0);
    
    
                    // Add the sample grabber to the graph
                    hr = m_FilterGraph.AddFilter( baseGrabFlt, "Ds.NET Grabber" );
                    DsError.ThrowExceptionForHR( hr );
    
    
                    if (m_VidControl == null)
                    {
                        // Connect the Still pin to the sample grabber
                        hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);
                        DsError.ThrowExceptionForHR( hr );
    
    
                        // Connect the capture pin to the renderer
                        hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn);
                        DsError.ThrowExceptionForHR( hr );
                    }
                    else
                    {
                        // Connect the capture pin to the renderer
                        hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn);
                        DsError.ThrowExceptionForHR( hr );
    
    
                        // Connect the Still pin to the sample grabber
                        hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);
                        DsError.ThrowExceptionForHR( hr );
                    }
    
    
                    // Learn the video properties
                    SaveSizeInfo(sampGrabber);
                    ConfigVideoWindow(hControl);
    
    
                    // Start the graph
                    IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;
                    hr = mediaCtrl.Run();
                    DsError.ThrowExceptionForHR( hr );
                }
                finally
                {
                    if (sampGrabber != null)
                    {
                        Marshal.ReleaseComObject(sampGrabber);
                        sampGrabber = null;
                    }
                    if (pCaptureOut != null)
                    {
                        Marshal.ReleaseComObject(pCaptureOut);
                        pCaptureOut = null;
                    }
                    if (pRenderIn != null)
                    {
                        Marshal.ReleaseComObject(pRenderIn);
                        pRenderIn = null;
                    }
                    if (pSampleIn != null)
                    {
                        Marshal.ReleaseComObject(pSampleIn);
                        pSampleIn = null;
                    }
                }
            }
    
    
            private void SaveSizeInfo(ISampleGrabber sampGrabber)
            {
                int hr;
    
    
                // Get the media type from the SampleGrabber
                AMMediaType media = new AMMediaType();
    
    
                hr = sampGrabber.GetConnectedMediaType( media );
                DsError.ThrowExceptionForHR( hr );
    
    
                if( (media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero) )
                {
                    throw new NotSupportedException( "Unknown Grabber Media Format" );
                }
    
    
                // Grab the size info
                VideoInfoHeader videoInfoHeader = (VideoInfoHeader) Marshal.PtrToStructure( media.formatPtr, typeof(VideoInfoHeader) );
                m_videoWidth = videoInfoHeader.BmiHeader.Width;
                m_videoHeight = videoInfoHeader.BmiHeader.Height;
                m_stride = m_videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);
    
    
                DsUtils.FreeAMMediaType(media);
                media = null;
            }
    
    
            // Set the video window within the control specified by hControl
            private void ConfigVideoWindow(Control hControl)
            {
                int hr;
    
    
                IVideoWindow ivw = m_FilterGraph as IVideoWindow;
    
    
                // Set the parent
                hr = ivw.put_Owner(hControl.Handle);
                DsError.ThrowExceptionForHR( hr );
    
    
                // Turn off captions, etc
                hr = ivw.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
                DsError.ThrowExceptionForHR( hr );
    
    
                // Yes, make it visible
                hr = ivw.put_Visible( OABool.True );
                DsError.ThrowExceptionForHR( hr );
    
    
                // Move to upper left corner
                Rectangle rc = hControl.ClientRectangle;
                hr = ivw.SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
                DsError.ThrowExceptionForHR( hr );
            }
    
    
            private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
            {
                int hr;
                AMMediaType media = new AMMediaType();
    
    
                // Set the media type to Video/RBG24
                media.majorType = MediaType.Video;
                media.subType = MediaSubType.RGB24;
                media.formatType = FormatType.VideoInfo;
                hr = sampGrabber.SetMediaType( media );
                DsError.ThrowExceptionForHR( hr );
    
    
                DsUtils.FreeAMMediaType(media);
                media = null;
    
    
                // Configure the samplegrabber
                hr = sampGrabber.SetCallback( this, 1 );
                DsError.ThrowExceptionForHR( hr );
            }
    
    
            // Set the Framerate, and video size
            private void SetConfigParms(IPin pStill, int iWidth, int iHeight, short iBPP)
            {
                int hr;
                AMMediaType media;
                VideoInfoHeader v;
    
    
                IAMStreamConfig videoStreamConfig = pStill as IAMStreamConfig;
    
    
                // Get the existing format block
                hr = videoStreamConfig.GetFormat(out media);
                DsError.ThrowExceptionForHR(hr);
    
    
                try
                {
                    // copy out the videoinfoheader
                    v = new VideoInfoHeader();
                    Marshal.PtrToStructure( media.formatPtr, v );
    
    
                    // if overriding the width, set the width
                    if (iWidth > 0)
                    {
                        v.BmiHeader.Width = iWidth;
                    }
    
    
                    // if overriding the Height, set the Height
                    if (iHeight > 0)
                    {
                        v.BmiHeader.Height = iHeight;
                    }
    
    
                    // if overriding the bits per pixel
                    if (iBPP > 0)
                    {
                        v.BmiHeader.BitCount = iBPP;
                    }
    
    
                    // Copy the media structure back
                    Marshal.StructureToPtr( v, media.formatPtr, false );
    
    
                    // Set the new format
                    hr = videoStreamConfig.SetFormat( media );
                    DsError.ThrowExceptionForHR( hr );
                }
                finally
                {
                    DsUtils.FreeAMMediaType(media);
                    media = null;
                }
            }
    
    
            /// <summary> Shut down capture </summary>
            private void CloseInterfaces()
            {
                int hr;
    
    
                try
                {
                    if( m_FilterGraph != null )
                    {
                        IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;
    
    
                        // Stop the graph
                        hr = mediaCtrl.Stop();
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                }
    
    
                if (m_FilterGraph != null)
                {
                    Marshal.ReleaseComObject(m_FilterGraph);
                    m_FilterGraph = null;
                }
    
    
                if (m_VidControl != null)
                {
                    Marshal.ReleaseComObject(m_VidControl);
                    m_VidControl = null;
                }
    
    
                if (m_pinStill != null)
                {
                    Marshal.ReleaseComObject(m_pinStill);
                    m_pinStill = null;
                }
            }
    
    
            /// <summary> sample callback, NOT USED. </summary>
            int ISampleGrabberCB.SampleCB( double SampleTime, IMediaSample pSample )
            {
                Marshal.ReleaseComObject(pSample);
                return 0;
            }
    
    
            /// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>
            int ISampleGrabberCB.BufferCB( double SampleTime, IntPtr pBuffer, int BufferLen )
            {
                // Note that we depend on only being called once per call to Click.  Otherwise
                // a second call can overwrite the previous image.
                Debug.Assert(BufferLen == Math.Abs(m_stride) * m_videoHeight, "Incorrect buffer length");
    
    
                if (m_WantOne)
                {
                    m_WantOne = false;
                    Debug.Assert(m_ipBuffer != IntPtr.Zero, "Unitialized buffer");
    
    
                    // Save the buffer
                    CopyMemory(m_ipBuffer, pBuffer, BufferLen);
    
    
                    // Picture is ready.
                    m_PictureReady.Set();
                }
    
    
                return 0;
            }
        }
    }
    Many thanks,

    Chris

  2. #2
    liviana is offline VB.NET Forum Newbie
    .NET Framework
    .NET 4.0
    Join Date
    Jun 2012
    Posts
    4
    Reputation
    0
    Hi Chris,
    you said: "The weird thing that I don't understand is that the equivalent code for the form works in C# but not in vb."

    one question: can you change resolution using c#?

    I am trying to get 5MP pictures from my VX6000 using different options from VIDCAP to Microsoft.LifeCam.*.dll using VB and C# and I only can get 640x480 pictures. Could you explain me how do you change the resolution with c#?


    Thanks in advance
    Livi

  3. #3
    Chris93 is offline VB.NET Forum Newbie
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2011
    Posts
    2
    Reputation
    0
    In the end I used DirectShow (DirectShow) and made a simple command line program in C# that took arguments for the resolution then launched that using vb, pretty much all the necessary code to is above to implement the solution I used. You'll never be able to take true 5MP photos though as that sensor is only 1.3MP (you've probably taken interpolated photos at 5MP).

  4. #4
    liviana is offline VB.NET Forum Newbie
    .NET Framework
    .NET 4.0
    Join Date
    Jun 2012
    Posts
    4
    Reputation
    0
    Chris, thank for your quick answer. I'll try again.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •