AForge.NET

  :: AForge.NET Framework :: Articles :: Forums ::

Reducing "WebCam" Framrate

The forum is to discuss topics related to different areas of image processing and computer vision.

Reducing "WebCam" Framrate

Postby rmk60 » Thu Aug 18, 2016 6:16 pm

I'm using DirectShow to access Usb web cams.
Unfortunately the cams are streaming MJPEG images with always maximum framerate of approx. 30fps.
For my application I need a much lower framerate of 5fps. The overhead of frames are thrown away but the cpu load will rise by 40% because of decoding jpeg stream of all images. I tried to skip samples in the "Grabber" of "Class VideoCaptureDevice" but without cpu load reduction.
Is there any solution to avoid decoding of unneeded frames?
Can anyone help?
rmk60
 
Posts: 6
Joined: Sat Apr 02, 2016 3:02 pm

Re: Reducing "WebCam" Framrate

Postby andrew.kirillov » Fri Aug 19, 2016 8:44 am

Try using version 2.2.4 of the AForge.NET Framework and set DesiredFrameRate property to what you need. It may help (not guaranteed).
With best regards,
Andrew


Interested in supporting AForge.NET Framework?
User avatar
andrew.kirillov
Site Admin, AForge.NET Developer
 
Posts: 3453
Joined: Fri Jan 23, 2009 9:12 am
Location: UK

Re: Reducing "WebCam" Framrate

Postby rmk60 » Fri Aug 19, 2016 11:36 pm

I just tried 2.2.4 Rev. but still the same problem.
No adjust of framerate possible... :evil:
rmk60
 
Posts: 6
Joined: Sat Apr 02, 2016 3:02 pm

Re: Reducing "WebCam" Framrate

Postby rmk60 » Mon Aug 22, 2016 9:32 am

I solved the problem!
As I studied the basics of filter graph, I found out if the base video filter (the filter that implement the decoding) avoids flooding the cpu by unprocessed frames, then one can PAUSE the Grabber callback by a calculated time so that the result will be the desired frame rate.
So what did I do:
1. New introduction of desired frame rate what is in Rev. 2.2.5 "obsolete".
2. Adding some new Properties to "VideoCaptureDevice" class.
3. Changing the Grabber Class by adding an auto adjustment source code.

This is the final result in VideoCaptureDevice class:
    Disable (comment out)
    Code: Select all
    /*
            /// <summary>
            /// Obsolete - no longer in use.
            /// </summary>
            ///
            /// <remarks><para>The property is obsolete. Setting this property does not have any effect.</para></remarks>
            ///
            [Obsolete]
            public int DesiredFrameRate
            {
                get { return 0; }
                set { }
            }
            */

    Append the following Properties:
    Code: Select all
            //------------------------------------------------------------------//
            // Author: RMK                                                      //
            // This implementation is necessary to pause the decoding if the    //
            // video device does not support variable frame rates.              //
            // It reduces the cpu computation time if the base video filter     //
            // suports decreasing (slow down) of max. device frame rate!        //
            // Set the Field Member "PauseDecoding_ms" [in ms] > 0 to pause the //
            // incoming callback (thread).                                      //
            //------------------------------------------------------------------//
            private int FDesiredFrameRate = 5;
            /// <summary>
            /// New Introduced "DesiredFrameRate". Only enabled if "AutoAdjustFrameRate" is set to true!
            /// </summary>
            public int DesiredFrameRate
            {
                get { return FDesiredFrameRate; }
                set
                {
                    FDesiredFrameRate = value;
                    FPauseDecoding_ms = (int)(1000.0 / value);
                }
            }
            private int FPauseDecoding_ms = 200;
            /// <summary>
            /// RMK: Pause decoding in milli seconds if frame rate adjust not available!
            /// It's a start value only. It will be adjusted by Grabber callback method.
            /// </summary>
            public int PauseDecoding_ms
            {
                get { return FPauseDecoding_ms; }
                set
                {
                    FPauseDecoding_ms = value;
                }
            }
            /// <summary>
            /// if PauseDecoding_ms ist set > 0, the Grabber adjust to
            /// </summary>
            public bool AutoAdjustFrameRate
            {
                get;
                set;
            }

    Add following code in private class Grabber:
    Code: Select all
                // add lock object:
                private object _lockBufferCB = new object();

                // add the ticktime of last call time of routine "BufferCB":
                int lastCallTime = 0;

    Change the Method "BufferCB" by inserting further code:
    Code: Select all
                // Callback method that receives a pointer to the sample buffer
                public int BufferCB( double sampleTime, IntPtr buffer, int bufferLen )
                {
                    lock (_lockBufferCB)    // add a locking!
                    {
                        if (parent.NewFrame != null)
                        {
                            // Add this if statement //
                            // Pause the Callback :
                            if (parent.AutoAdjustFrameRate)
                            {
                                int callTime = Environment.TickCount;
                                int dTime = callTime - lastCallTime;
                                lastCallTime = callTime;
                                if (dTime > 0)
                                {
                                    // adjust the pause time:
                                    double currentFrameRate = 1000.0 / dTime;
                                    if (currentFrameRate > parent.DesiredFrameRate)
                                        parent.PauseDecoding_ms++;
                                    else
                                        parent.PauseDecoding_ms--;
                                    parent.PauseDecoding_ms = Math.Max(0, parent.PauseDecoding_ms);
                                }
                                Thread.Sleep(parent.PauseDecoding_ms);
                            }

                            // create new image
                            System.Drawing.Bitmap image = new Bitmap(width, height, PixelFormat.Format24bppRgb);

                            // lock bitmap data
                            BitmapData imageData = image.LockBits(
                                new Rectangle(0, 0, width, height),
                                ImageLockMode.ReadWrite,
                                PixelFormat.Format24bppRgb);

                            // copy image data
                            int srcStride = imageData.Stride;
                            int dstStride = imageData.Stride;

                            unsafe
                            {
                                byte* dst = (byte*)imageData.Scan0.ToPointer() + dstStride * (height - 1);
                                byte* src = (byte*)buffer.ToPointer();

                                for (int y = 0; y < height; y++)
                                {
                                    Win32.memcpy(dst, src, srcStride);
                                    dst -= dstStride;
                                    src += srcStride;
                                }
                            }

                            // unlock bitmap data
                            image.UnlockBits(imageData);

                            // notify parent
                            if (snapshotMode)
                            {
                                parent.OnSnapshotFrame(image);
                            }
                            else
                            {
                                parent.OnNewFrame(image);
                            }

                            // release the image
                            image.Dispose();
                        }

                        return 0;
                    }
                }


How to set the parameters in your application:
Code: Select all
            FilterInfoCollection f = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            // e.g. select Filterinfo at index 0 or whatever you choose:
            device = new VideoCaptureDevice(f[0].MonikerString);
            // set the desired frame rate e.g. 5fps:
            device.DesiredFrameRate = 5;
            // let the Grabber auto adjust to the desired frame rate:
            device.AutoAdjustFrameRate = true;


I hope you understood what the implementation does. It will insert a Thread.Sleep() of variable (adjusted) time as long as the desired frame rate is reached. I tested it and it works very well. Andrew, may be you will implement this adjustments in a future release because I know it's fast and dirty code... but it works well!
rmk60
 
Posts: 6
Joined: Sat Apr 02, 2016 3:02 pm




Return to Image Processing and Computer Vision