Autor Beitrag
Sven Bauermann
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 29.11.11 10:01 
Hallo liebe Gemeinde. Ich habe ein Memory Leak Problem mit einer WebCam Klasse und finde es nicht.
Es gibt auch auf Codeproject.com ein Beispiel DirectShow.Net www.codeproject.com/...=1023862#xx1023862xx
Hier speziell das Example "Capturing". Aber auch hier ist ein Memory Leak enthalten. Wenn man die Funktion "CloseInterface" aufruft sollte der Speicher, auch der unmanaged Speicher,
wieder freigegeben werden. Dem ist nicht so. Mit jeden neuen Aufruf der Webcam werden ca. 11MB Speicher belegt und bei "CloseInterface" nicht wieder freigeben.

Es wäre wirklich klasse, wenn hier jemand helfen kann. Ich poste hier die vollständige Klasse WebCamControl:
--------------------------------------

Aufruf des Objektes:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379:
380:
381:
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
430:
431:
432:
433:
434:
435:
436:
437:
438:
439:
440:
441:
442:
443:
444:
445:
446:
447:
448:
449:
450:
451:
452:
453:
454:
455:
456:
457:
458:
459:
460:
461:
462:
463:
464:
465:
466:
467:
468:
469:
470:
471:
472:
473:
474:
475:
476:
477:
478:
479:
480:
481:
482:
483:
484:
485:
486:
487:
488:
489:
490:
491:
492:
493:
494:
495:
496:
497:
498:
499:
500:
501:
502:
503:
504:
505:
506:
507:
508:
509:
510:
511:
512:
513:
514:
515:
516:
517:
518:
519:
520:
521:
522:
523:
524:
525:
526:
527:
528:
529:
530:
531:
532:
533:
534:
535:
536:
537:
538:
539:
540:
541:
542:
543:
544:
545:
546:
547:
548:
549:
550:
551:
552:
553:
554:
555:
556:
557:
558:
559:
560:
561:
562:
563:
564:
565:
566:
567:
568:
569:
570:
571:
572:
573:
574:
575:
576:
577:
578:
579:
580:
581:
582:
583:
584:
585:
586:
587:
588:
589:
590:
591:
592:
593:
594:
595:
596:
597:
598:
599:
600:
601:
602:
603:
604:
605:
606:
607:
608:
609:
610:
611:
612:
613:
614:
615:
616:
617:
618:
619:
620:
621:
622:
623:
624:
625:
626:
627:
628:
629:
630:
631:
632:
633:
634:
635:
636:
637:
638:
639:
640:
641:
642:
643:
644:
645:
646:
647:
648:
649:
650:
651:
652:
653:
654:
655:
656:
657:
658:
659:
660:
661:
662:
663:
664:
665:
666:
667:
668:
669:
670:
671:
672:
673:
674:
675:
676:
677:
678:
679:
680:
681:
682:
683:
684:
685:
686:
687:
688:
689:
690:
691:
692:
693:
694:
695:
696:
697:
698:
699:
700:
701:
702:
703:
704:
705:
706:
707:
708:
709:
710:
711:
712:
713:
714:
715:
716:
717:
718:
719:
720:
721:
722:
723:
724:
725:
726:
727:
728:
729:
730:
731:
732:
733:
734:
735:
736:
737:
738:
739:
740:
741:
742:
743:
744:
745:
746:
747:
748:
749:
750:
751:
752:
753:
754:
755:
756:
757:
758:
759:
760:
761:
762:
763:
764:
765:
766:
767:
768:
769:
770:
771:
772:
773:
774:
775:
776:
777:
778:
779:
780:
781:
782:
783:
784:
785:
786:
787:
788:
789:
790:
791:
792:
793:
794:
795:
796:
797:
798:
799:
800:
801:
802:
803:
804:
805:
806:
807:
808:
809:
810:
811:
812:
813:
814:
815:
816:
817:
818:
819:
820:
821:
822:
823:
824:
825:
826:
827:
828:
829:
830:
831:
832:
833:
834:
835:
836:
837:
838:
839:
840:
841:
842:
843:
844:
845:
846:
847:
848:
849:
850:
851:
852:
853:
854:
855:
856:
857:
858:
859:
860:
861:
862:
863:
864:
865:
866:
867:
868:
869:
870:
871:
872:
873:
874:
875:
876:
877:
878:
879:
880:
881:
882:
883:
884:
885:
886:
887:
888:
889:
890:
891:
892:
893:
894:
895:
896:
897:
898:
899:
900:
901:
902:
903:
904:
905:
906:
907:
908:
909:
910:
911:
912:
913:
914:
915:
916:
private WebCamControler _cam1;
private WebCamControler _cam2;

_cam1 = new WebCamControler(panelWebCam1, this);
_cam2 = new WebCamControler(panelWebCam2, this);

 /// <summary>Startet die Webcam</summary>
        /// <param name="i">1 = WebCam1 / 2 = WebCam2</param>
        public void StartWebCam(int i)
        {
            if (i == 1)
                _cam1.StartWebCam(VideoQuality1);
            if (i == 2)
                if (_webCam2IsVisible)
                    _cam2.StartWebCam(VideoQuality2);
        }

        /// <summary>Stopt die WebCam</summary>
        /// <param name="i">1 = WebCam1 / 2 = WebCam2</param>
        public void CloseWebCam(int i)
        {
            if (i == 1)
                _cam1.CloseInterfaces();
                
            if (i == 2)
                if(_webCam2IsVisible)
                    _cam2.CloseInterfaces();
        }




 protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {               
                components.Dispose();
            }
            if (_cam1 != null) _cam1.CloseInterfaces();
            if (_cam2 != null) _cam2.CloseInterfaces();
            base.Dispose(disposing);           
            _cam1.bitmapDone -= _cam1_bitmapDone;
            _cam2.bitmapDone -= _cam2_bitmapDone;
            _cam1.startCamera -= _cam1_startCamera;
            _cam2.startCamera -= _cam2_startCamera;
            _cam1.stopCamera -= _cam1_stopCamera;
            _cam2.stopCamera -= _cam2_stopCamera;
            _cam1.Dispose();
            _cam2.Dispose();
            _cam1 = null;
            _cam2 = null;
        }


Klasse
------------------------------------------------------------------

using System;
using System.Collections;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using DShowNET;
using DShowNET.Device;
using SampleGrabberNET;

namespace WebCam
{
    class WebCamControler : ISampleGrabberCB, IDisposable
    {
        #region constructor
        /// <summary>constructor</summary>
        public WebCamControler(Panel panel, UserControl userControl)
        {
            _panel = panel;
            _userControl = userControl;
        }
        #endregion

        #region DllImport
        //A (modified) definition of OleCreatePropertyFrame
        [DllImport("oleaut32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
        public static extern int OleCreatePropertyFrame(
            IntPtr hwndOwner,
            int x,
            int y,
            [MarshalAs(UnmanagedType.LPWStr)] string lpszCaption,
            int cObjects,
            [MarshalAs(UnmanagedType.Interface, ArraySubType = UnmanagedType.IUnknown)] 
            ref object ppUnk,
            int cPages,
            IntPtr lpPageClsID,
            int lcid,
            int dwReserved,
            IntPtr lpvReserved);
        #endregion

        #region private members

        /// <summary>transfer parameter for constructor</summary>
        private Panel _panel = new Panel();

        /// <summary>second transfer parameter for constructor</summary>
        private UserControl _userControl = new UserControl();

        /// <summary> base filter of the actually used video devices. </summary>
        private IBaseFilter capFilter;

        /// <summary> graph builder interface. </summary>
        private IGraphBuilder graphBuilder;

        /// <summary> capture graph builder interface. </summary>
        private ICaptureGraphBuilder2 capGraph;

        /// <summary>Sample Capture interface/// </summary>
        private ISampleGrabber sampGrabber;

        /// <summary> control interface. </summary>
        private IMediaControl mediaCtrl;

        /// <summary> event interface. </summary>
        private IMediaEventEx mediaEvt;

        /// <summary> video window interface. </summary>
        private IVideoWindow videoWin;

        /// <summary> grabber filter interface. </summary>
        private IBaseFilter baseGrabFlt;

        /// <summary> structure describing the bitmap to grab. </summary>
        private VideoInfoHeader videoInfoHeader;

        /// <summary>Bitmap from Capture Grab</summary>
        private Bitmap _bitmap;

        /// <summary>Devices</summary>
        private DsDevice dev = null;
        
        /// <summary>bool</summary>
        private bool _disposed;
        
        private bool captured = true;

        private bool _start = false;

        private int bufferedSize;

        /// <summary> event when callback has finished (ISampleGrabberCB.BufferCB). </summary>
        private delegate void CaptureDone();

        /// <summary> buffer for bitmap data. </summary>
        private byte[] savedArray;

        private const int WM_GRAPHNOTIFY = 0x00008001;  // message from graph
        private const int WS_CHILD = 0x40000000;  // attributes for video window
        private const int WS_CLIPCHILDREN = 0x02000000;
        private const int WS_CLIPSIBLINGS = 0x04000000;

        public int pWM_GRAPHNOTIFY
        {
            get
            {
                return WM_GRAPHNOTIFY;
            }
        }

        public IMediaEventEx pmediaEvt
        {
            get
            {
                return mediaEvt;
            }
        }



        private ArrayList capDevices;
        #endregion

        #region internal member
        internal enum PlayState
        {
            Init,
            Stopped,
            Paused,
            Running
        }
        #endregion

        #region internal functions
        /// <summary> sample callback, NOT USED. </summary>
        int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)
        {
            return 0;
        }

        /// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>
        int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
        {
            if (captured || (savedArray == null))
            {

                return 0;
            }
            captured = true;
            bufferedSize = BufferLen;

            if ((pBuffer != IntPtr.Zero) && (BufferLen > 1000) && (BufferLen <= savedArray.Length))
                Marshal.Copy(pBuffer, savedArray, 0, BufferLen);
            else
                MessageBox.Show("Grab Fehler");

            _userControl.BeginInvoke(new CaptureDone(this.OnCaptureDone));

            return 0;
        }
        #endregion

        #region public functions
        /// <summary>This Sample Callback will not used at the moment</summary>
        public int SampleCB(double SampleTime, IMediaSample pSample)
        {
            return 0;
        }

        /// <summary>This Buffer Callback will not used at the moment</summary>
        public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
        {
            return 0;
        }

        /// <summary>start function for start webcam1 und webcam2</summary>
        public void StartWebCam(Size _size)
        {          
            if (!_start)
            {
                try
                {
                    _start = true;
                    startCamera(false);
                    DsDev.GetDevicesOfCat(FilterCategory.VideoInputDevice, out capDevices);

                    if (capDevices == null)
                    {
                        MessageBox.Show("Es wurde keine WebCam gefunden!");
                        return;
                    }

                    if (_panel != null && _panel.Name == "panelWebCam1")
                    {
                        foreach (DsDevice webCam in capDevices)
                        {
                            if (webCam.Name == WebCam.WebCam1)
                            {

                                dev = webCam;
                                if (!StartupVideo(dev.Mon, _size))
                                    break;
                            }

                        }
                    }

                    if (_panel != null && _panel.Name == "panelWebCam2")
                    {
                        foreach (DsDevice webCam in capDevices)
                        {
                            if (webCam.Name == WebCam.WebCam2)
                            {

                                dev = webCam;
                                if (!StartupVideo(dev.Mon, _size))
                                    break;
                            }
                        }
                    }
                    startCamera(true);
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("{0} {1}", ex, ex.GetBaseException()));
                }
            }
            else
            {
                return;
            }                                      
        }

        /// <summary>Check if WebCams are available </summary>
        public void ShowCams()
        {
            try
            {
                if (DsDev.GetDevicesOfCat(FilterCategory.VideoInputDevice, out capDevices))
                {
                    DeviceSelector selector = new DeviceSelector(capDevices);
                    selector.ShowDialog();
                    dev = selector.SelectedDevice;
                }
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }            
        }

        /// <summary>Check is DirectXVersion is ok</summary>
        public string CheckFalseDirectXVersion()
        {
            string message = string.Empty;
            try
            {
                message = !DsUtils.IsCorrectDirectXVersion() ?
                string.Empty : "DirectX 8.1 oder höher ist installiert!";                
            }
            catch (Exception ex)
            {
               throw new Exception(string.Format("{0}{1}", ex, ex.GetBaseException()));
            }
            return message;
        }

        /// <summary> do cleanup and release DirectShow. </summary>
        public void CloseInterfaces()
        {
            int hr;
            try
            {
                stopCamera(false);
#if DEBUG
                if (rotCookie != 0)
                    DsROT.RemoveGraphFromRot(ref rotCookie);
#endif

                if (mediaCtrl != null)
                {
                    hr = mediaCtrl.Stop();
                    mediaCtrl = null;
                }

                if (mediaEvt != null)
                {
                    hr = mediaEvt.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero);
                    mediaEvt = null;
                }

                if (videoWin != null)
                {
                    hr = videoWin.put_Visible(DsHlp.OAFALSE);
                    hr = videoWin.put_Owner(IntPtr.Zero);
                    videoWin = null;
                }

                baseGrabFlt = null;
                if (sampGrabber != null)
                    Marshal.ReleaseComObject(sampGrabber);
                sampGrabber = null;

                if (capGraph != null)
                    Marshal.ReleaseComObject(capGraph);
                capGraph = null;


                if (graphBuilder != null)
                    Marshal.ReleaseComObject(graphBuilder);
                graphBuilder = null;


                if (capFilter != null)
                    Marshal.ReleaseComObject(capFilter);
                capFilter = null;

                if (capDevices != null)
                {
                    foreach (DsDevice d in capDevices)
                        d.Dispose();
                    capDevices = null;
                }
                stopCamera(true);
                _start = false;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
        }

        /// <summary>Take a Picture from Camera</summary>
        /// <returns>Picture from Camera</returns>
        public void SnapShot()
        {
            if (_start)
            {
                int hr;
                try
                {
                    if (sampGrabber == null)
                    {
                        MessageBox.Show("sampGrabber = null");
                        return;
                    }

                    if (savedArray == null)
                    {
                        int size = videoInfoHeader.BmiHeader.ImageSize;
                        savedArray = new byte[size + 64000];
                    }

                    captured = false;
                    hr = sampGrabber.SetCallback(this1);
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.ToString());
                }
            }
        }

        /// <summary> graph event (WM_GRAPHNOTIFY) handler. </summary>
        public void OnGraphNotify()
        {
            try
            {
                DsEvCode code;
                int p1, p2, hr1 = 0;
                do
                {
                    hr1 = mediaEvt.GetEvent(out code, out p1, out p2, 0);
                    if (hr1 < 0)
                        break;
                    hr1 = mediaEvt.FreeEventParams(code, p1, p2);
                }
                while (hr1 == 0);
            }
            catch (Exception ex)
            {                
               throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
            
        }

        /// <summary>Call Propertie Page</summary>
        public void DisplayCameraPropeties()
        {
            try
            {
                if (capFilter != null)
                    DisplayPropertyPage(capFilter);
            }
            catch (Exception ex)
            {                
                throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
            
        }

        protected virtual void Dispose(bool disposing)
        {
            // If you need thread safety, use a lock around these 
            // operations, as well as in your methods that use the resource.
        
                if (disposing)
                {                   
                    if (_panel != null) _panel.Dispose();
                    if (_bitmap != null) _bitmap.Dispose();
                    if (_panel != null) _panel.Dispose();
                }
                _disposed = true;            
        }


        public void Dispose()
        {
            _disposed = true;
            Dispose(_disposed);
            GC.SuppressFinalize(this);
            
        }

        #endregion

        #region public events
        /// <summary>
        /// Will be fired, if Bitmap is available
        /// </summary>
        /// <param name="_bitmap">Bitmap</param>
        public delegate void BitmapDone(Bitmap _bitmap);

        /// <summary>
        /// Will be fired, if Bitmap is available
        /// </summary>
        public event BitmapDone bitmapDone;

        /// <summary>
        /// Will be fired if camera start
        /// </summary>
        /// <param name="start">bool for start begin and end</param>
        public delegate void StartCamera(bool start);

        /// <summary>
        /// Will be fired if camera start
        /// </summary>
        public event StartCamera startCamera;

        /// <summary>
        /// Will be fired if Camera stoped
        /// </summary>
        /// <param name="stop">bool stop  begin and start</param>
        public delegate void StopCamera(bool stop);

        public event StopCamera stopCamera;

        #endregion

        #region private functions
        /// <summary> start all the interfaces, graphs and preview window. </summary>
        private bool StartupVideo(UCOMIMoniker mon, Size _size)
        {
            int hr;
            try
            {
                if (!CreateCaptureDevice(mon))
                    return false;

                if (!GetInterfaces())
                    return false;

                if (!SetupGraph(_size))
                    return false;

                if (!SetupVideoWindow())
                    return false;


//#if DEBUG
//                DsROT.AddGraphToRot(graphBuilder, out rotCookie);    // graphBuilder capGraph
//#endif

                hr = mediaCtrl.Run();
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
               

                //bool hasTuner = DsUtils.ShowTunerPinDialog( capGraph, capFilter, this.Handle );
                //toolBarBtnTune.Enabled = hasTuner;


                return true;
            }
            catch (Exception ex)
            {
               throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
        }

        /// <summary> make the video preview window to show in videoPanel. </summary>
        private bool SetupVideoWindow()
        {
            int hr;
            try
            {
                // Set the video window to be a child of the main window
                hr = videoWin.put_Owner(_panel.Handle);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                // Set video window style
                hr = videoWin.put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                // Use helper function to position video window in client rect of owner window
                ResizeVideoWindow();

                // Make the video window visible, now that it is properly positioned
                hr = videoWin.put_Visible(DsHlp.OATRUE);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                hr = mediaEvt.SetNotifyWindow(_userControl.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                return true;
            }
            catch (Exception ex)
            {
               throw new Exception(string.Format("{0}{1}",ex, ex.GetBaseException()));
            }
        }

        /// <summary> create the user selected capture device. </summary>
        private bool CreateCaptureDevice(UCOMIMoniker mon)
        {
            object capObj = null;
            try
            {
                Guid gbf = typeof(IBaseFilter).GUID;
                mon.BindToObject(nullnullref gbf, out capObj);
                capFilter = (IBaseFilter)capObj;
                capObj = null;
                return true;
            }
            catch (Exception ee)
            {
                MessageBox.Show("Could not create capture device\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return false;
            }
            finally
            {
                if (capObj != null)
                    Marshal.ReleaseComObject(capObj);
                capObj = null;
            }
        }

        /// <summary> create the used COM components and get the interfaces. </summary>
        private bool GetInterfaces()
        {
            Type comType = null;
            object comObj = null;
            try
            {
                comType = Type.GetTypeFromCLSID(Clsid.FilterGraph);
                if (comType == null)
                    throw new NotImplementedException(@"DirectShow FilterGraph not installed/registered!");
                comObj = Activator.CreateInstance(comType);
                graphBuilder = (IGraphBuilder)comObj;
                comObj = null;

                Guid clsid = Clsid.CaptureGraphBuilder2;
                Guid riid = typeof(ICaptureGraphBuilder2).GUID;
                comObj = DsBugWO.CreateDsInstance(ref clsid, ref riid);
                capGraph = (ICaptureGraphBuilder2)comObj;
                comObj = null;

                comType = Type.GetTypeFromCLSID(Clsid.SampleGrabber);
                if (comType == null)
                    throw new NotImplementedException(@"DirectShow SampleGrabber not installed/registered!");
                comObj = Activator.CreateInstance(comType);
                sampGrabber = (ISampleGrabber)comObj;
                comObj = null;

                mediaCtrl = (IMediaControl)graphBuilder;
                videoWin = (IVideoWindow)graphBuilder;
                mediaEvt = (IMediaEventEx)graphBuilder;
                baseGrabFlt = (IBaseFilter)sampGrabber;

                return true;
            }
            catch (Exception ex)
            {
               throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
            finally
            {
                if (comObj != null)
                    Marshal.ReleaseComObject(comObj);
                comObj = null;
            }
        }

        /// <summary> build the capture graph for grabber. </summary>
        private bool SetupGraph(Size _size)
        {
            int hr;

            try
            {
                hr = capGraph.SetFiltergraph(graphBuilder);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);


                hr = graphBuilder.AddFilter(capFilter, "Ds.NET Video Capture Device");

                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                //Quality Setup
                if (((WebCam)_userControl).VideoSettingsDialog)
                    DsUtils.ShowCapPinDialog(capGraph, capFilter, _panel.Handle);


                AMMediaType media = new AMMediaType();
                media.majorType = MediaType.Video;
                media.subType = MediaSubType.RGB24;
                media.formatType = FormatType.VideoInfo;
                hr = sampGrabber.SetMediaType(media);

                if (!((WebCam)_userControl).VideoSettingsDialog)
                {
                    //Size size = ((WebCam)_userControl).VideoQuality;   
                    SetCaptureResolution(_size);
                }

                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                hr = graphBuilder.AddFilter(baseGrabFlt, "Ds.NET Grabber");
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);



                Guid cat = PinCategory.Preview;
                Guid med = MediaType.Video;
                hr = capGraph.RenderStream(ref cat, ref med, capFilter, nullnull); // baseGrabFlt 
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                cat = PinCategory.Capture;
                med = MediaType.Video;
                hr = capGraph.RenderStream(ref cat, ref med, capFilter, null, baseGrabFlt); // baseGrabFlt 
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                media = new AMMediaType();
                hr = sampGrabber.GetConnectedMediaType(media);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
                if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
                    throw new NotSupportedException("Unknown Grabber Media Format");

                videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
                Marshal.FreeCoTaskMem(media.formatPtr);
                media.formatPtr = IntPtr.Zero;

                hr = sampGrabber.SetBufferSamples(false);
                if (hr == 0)
                    hr = sampGrabber.SetOneShot(false);
                if (hr == 0)
                    hr = sampGrabber.SetCallback(null0);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);

                return true;
            }
            catch (Exception ex)
            {
               throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
        }

        private void SetCaptureResolution(Size size)
        {
            Guid streamConfigId = typeof(IAMStreamConfig).GUID;
            Guid ycat = PinCategory.Capture;
            Guid ymed = MediaType.Video;
            object videoConfigObj;
            int hr = capGraph.FindInterface(ref ycat, ref ymed, capFilter, ref streamConfigId, out videoConfigObj);

            Marshal.ThrowExceptionForHR(hr);

            IAMStreamConfig videoConfig = videoConfigObj as IAMStreamConfig;

            if (null == videoConfig)

                throw new COMException("Cannot obtain IAMStreamConfig");

            // enumerate the capabilities of the video capture device
            // This code looks for a specific video format:
            // colorspace I420, frame dimensions 640x480, frame rate of 25 fps

            int capsCount, capSize;

            hr = videoConfig.GetNumberOfCapabilities(out capsCount, out capSize);
            Marshal.ThrowExceptionForHR(hr);

            VideoInfoHeader vih = new VideoInfoHeader();
            IntPtr pSC = Marshal.AllocHGlobal(capSize);

            AMMediaType mt = null;

            int videoFormatIndex = -1;
            long frameInterval = 10000000 / 25// 25 fps

            for (int i = 0; i < capsCount; ++i)
            {

                // the video format is described in AMMediaType and VideoStreamConfigCaps
                hr = videoConfig.GetStreamCaps(i, out mt, pSC);
                Marshal.ThrowExceptionForHR(hr);

                // copy the unmanaged structures to managed in order to check the format
                Marshal.PtrToStructure(mt.formatPtr, vih);

                // log the video format
                string capline = String.Format("width:{0}, height:{1}, colorDepth: {2}", vih.BmiHeader.Width, vih.BmiHeader.Height, vih.BmiHeader.BitCount);
                Debug.WriteLine(capline);

                // check colorspace
                //             if( mt.subType == DirectShowLib.MediaSubType.I420 ) {
                // the video format has a range of supported frame rates (min-max)
                // check the required frame rate and frame size

                if (vih.BmiHeader.Width == size.Width &&
                    vih.BmiHeader.Height == size.Height && vih.BmiHeader.BitCount == 24)
                {
                    vih.BmiHeader.Width = size.Width;
                    vih.BmiHeader.Height = size.Height;
                    // remember the index of the video format that we'll use
                    videoFormatIndex = i;
                }
            }

            // set the desired format to the video capture device
            if (videoFormatIndex != -1)
            {
                hr = videoConfig.GetStreamCaps(videoFormatIndex, out mt, pSC);
                Marshal.ThrowExceptionForHR(hr);
                // explicitly set the framerate since the default may not what we want
                Marshal.PtrToStructure(mt.formatPtr, vih);
                vih.AvgTimePerFrame = frameInterval;
                Marshal.StructureToPtr(vih, mt.formatPtr, false);

                hr = videoConfig.SetFormat(mt);
                Marshal.ThrowExceptionForHR(hr);
            }

            Marshal.FreeHGlobal(pSC);
        }

        /// <summary> resize preview video window to fill client area. </summary>
        private void ResizeVideoWindow()
        {
            if (videoWin != null)
            {
                Rectangle rc = _panel.ClientRectangle;
                videoWin.SetWindowPosition(00, rc.Right, rc.Bottom);
            }
        }

        /// <summary> capture event, triggered by buffer callback. </summary>
        private void OnCaptureDone()
        {
            Bitmap b = null;
            try
            {
                int hr;
                hr = sampGrabber.SetCallback(null0);

                int w = videoInfoHeader.BmiHeader.Width;
                int h = videoInfoHeader.BmiHeader.Height;
                if (((w & 0x03) != 0) || (w < 32) || (w > 4096) || (h < 32) || (h > 4096))
                    MessageBox.Show("Fehler bei der Bildverarbeitung");
                int stride = w * 3;

                GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);
                int scan0 = (int)handle.AddrOfPinnedObject();
                scan0 += (h - 1) * stride;
                b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, (IntPtr)scan0);
                _bitmap = new Bitmap(b);
                bitmapDone(b);
                //b.Save(@"c:\test.bmp", ImageFormat.Bmp);
                handle.Free();
                savedArray = null;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
        }

        /// <summary>
        /// Call the Propertie Page
        /// </summary>
        /// <param name="dev">BaseFilter</param>
        private void DisplayPropertyPage(IBaseFilter dev)
        {
            //Get the ISpecifyPropertyPages for the filter
            ISpecifyPropertyPages pProp = dev as ISpecifyPropertyPages;
            int hr = 0;

            // Get the propertypages from the property bag
            DsCAUUID caGUID;
            hr = pProp.GetPages(out caGUID);
            //DsError.ThrowExceptionForHR(hr);

            //Create and display the OlePropertyFrame
            object oDevice = (object)dev;
            hr = OleCreatePropertyFrame(_userControl.Handle, 00""1ref oDevice, caGUID.cElems, caGUID.pElems, 00, IntPtr.Zero);

            Marshal.ReleaseComObject(oDevice);

            // Release COM objects
            Marshal.FreeCoTaskMem(caGUID.pElems);
        }
        #endregion

        #region public properties
        /// <summary>transfer bitmap</summary>
        public Bitmap Bitmap
        {
            get
            {
                return _bitmap;
            }
            set
            {
                _bitmap = value;
            }
        }
        #endregion

        #region debug
#if DEBUG
        private int rotCookie = 0;
#endif
        #endregion
        
    }
}


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
ujr
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 102
Erhaltene Danke: 12



BeitragVerfasst: Di 29.11.11 10:16 
user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe ein Memory Leak Problem mit einer WebCam Klasse und finde es nicht.


Dafür gibt's Memory Profiler.

user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:
Ich poste hier die vollständige Klasse WebCamControl:


Und gleich zwei Mal. Unleserlich. "Da - sucht mir den Fehler" - oder wie stellst Du Dir das vor?
Sven Bauermann Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 29.11.11 10:40 
Das Doppelposting ist bedauerlich, der Server hat ein Timeout gemeldet und den Misserfolg der Einstellung verkündet. Ich neige dazu solche Meldungen ernst zu nehmen.
Wie gesagt, keinerlei Absicht und eine Löschfunktion gibt es nicht für den Author.

Ich poste für die Übersicht nochmal isoliert die Funktion:

bei mediaCtrl.Run(),

Wird der Speicher belegt. In CloseInterface() sollte er wieder freigegben werden.
Ich habe damit schon einige Stunden zugebracht und erbitte lediglich Ratschläge, Ideen u.ä.,
es ist sehr selten das ich Hilfe dieser Art erbitten muss und mache dies auch nur wenn ich auf den üblichen Wegen nicht mehr weiterkomme.

Es gibt auch durchaus noch mehr Probleme dieser Art von anderen Entwicklern. Leider kaum Lösungen.
Es gab einen Poster auf Codeproject der eine Lösung hatte und das auch temporär ins Netz stellte.

Ist leider nicht mehr zu bekommen. Ich denk aber das es durchaus noch mehr Interessierte gibt und es lohnenswert wäre, für die Allgemeinheit den korrekten Weg zu veröffentlichen

Vielen Dank
Sven


Es passiert hier:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
/// <summary> start all the interfaces, graphs and preview window. </summary>
        private bool StartupVideo(UCOMIMoniker mon, Size _size)
        {
            int hr;
            try
            {
                if (!CreateCaptureDevice(mon))
                    return false;

                if (!GetInterfaces())
                    return false;

                if (!SetupGraph(_size))
                    return false;

                if (!SetupVideoWindow())
                    return false;


//#if DEBUG
//                DsROT.AddGraphToRot(graphBuilder, out rotCookie);    // graphBuilder capGraph
//#endif

                hr = mediaCtrl.Run();
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
               

                //bool hasTuner = DsUtils.ShowTunerPinDialog( capGraph, capFilter, this.Handle );
                //toolBarBtnTune.Enabled = hasTuner;


                return true;
            }
            catch (Exception ex)
            {
               throw new Exception(string.Format("{0}{1}",ex,ex.GetBaseException()));
            }
        }


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
ujr
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 102
Erhaltene Danke: 12



BeitragVerfasst: Di 29.11.11 11:13 
Hallo,

user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:
Ich poste für die Übersicht nochmal isoliert die Funktion:


Mit "Unleserlich" meinte ich in erster Linie die fehlenden C#-Tags. Aber auch sonst - es ist einfach zu viel Code, vor allem auch viel unerhebliches. Wie z. B. die Funktion DisplayPropertyPage. Entweder deren Aufruf verursacht das Memory Leak, oder sie ist entbehrlich für die Fehlersuche. Diese Reduktion des Quelltexts ist Deine Aufgabe.

user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:

bei mediaCtrl.Run(),

Wird der Speicher belegt.


Wie kommst Du darauf?

user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:

erbitte lediglich Ratschläge, Ideen u.ä.,


Hast Du bekommen - was ist mit dem Memory Profiler?

user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:

Es passiert hier:


Da gibt's nur Funktionsaufrufe - es wird kein Speicher belegt.

Generell sind doch offensichtlich z. B. die Get-Funktionen verdächtig, Speicher zu belegen. Also schaut man sich deren Dokumentation an. Nimm bspw. IAMStreamConfig::GetStreamCaps. Da steht doch eindeutig, dass der Speicher hinter dem 2. Parameter frei gegeben werden muss, was bei Dir aber fehlt.
Sven Bauermann Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 29.11.11 11:59 
Danke Dir für die Hinweise.

Ich komme deshalb darauf, weil genau beim Aufruf dieser Zeile, der Speicher um die 11MB hochzählt.
Den Memory Profiler habe ich vorhin installiert. Ich versuche mich mit dem Programm einzuarbeiten.

Mit der IAMStreamConfig::GetStreamCaps hast Du sicher recht aber die wird nur mit der Funktion SetCaptureResolution(Size size) verwendet.

Das Programm ist auch ohne deren Aufruf verwendbar und das Problem ist das gleiche, leider.

Sven
Sven Bauermann Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 29.11.11 12:18 
Ich habe mir das mit Memory Profiler angesehen.

Eigentlich hatte ich erwartet, das im GDI+ Bereich irgendwas hängen bleibt.
Es passiert aber laut Übersicht in der ntdll.dll. Minimal im Heap, hauptsächlich im virtuellen Speicher.

:-(
Sven Bauermann Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 29.11.11 17:50 
Hallo ujr,

Du hattes recht. Ich habe an einer anderen Stelle 3 MB Memory Leak gefunden und freigeben und weitere 8 MB kommen wirklich von
hr = videoConfig.GetStreamCaps(i, out mt, pSC);

Allerdings bekomme ich die einfach mit C# Mitteln nicht freigegenen.
Was mache ich falsch?
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
pSC = IntPtr.Zero;
Marshal.FreeHGlobal(pSC);
mt = null;                       
Marshal.ReleaseComObject(videoConfigObj);
videoConfigObj = null;
Marshal.ReleaseComObject(videoConfig);
videoConfig = null;
ujr
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 102
Erhaltene Danke: 12



BeitragVerfasst: Di 29.11.11 21:31 
user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:
Was mache ich falsch?


Zum einen hast Du die Reihenfolge von Null-Setzen und Freigabe vertauscht. Zum anderen steht doch in der oben verlinkten Dokumentation was wie freizugeben ist. Zudem war GetStreamCaps nur ein Beispiel - eben das erste, das mir auffiel.

user profile iconSven Bauermann hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe an einer anderen Stelle 3 MB Memory Leak gefunden und freigeben und weitere 8 MB kommen wirklich von
hr = videoConfig.GetStreamCaps(i, out mt, pSC);


Nun ja, prinzipiell ist die Speicherverwaltung der CLR aufgrund der GC nicht sooo deterministisch. Insofern sind die Angaben des Memory Profilers tatsächlich wichtiger als Werte des Task Managers.