Oppure

Loading
03/09/11 17:14
Roby94
Salve, oggi mi sono trovato a dover sviluppare in c# un applicazione che sfrutta le librerie aforce.video per acquisire immagini da una webcam. Il programma, molto semplice non ha dato particolari problemi finche non mi sono accorto che riempie eccessivamente la ram senza svuotarla, mi spiego meglio, all'avio dell'applicazione essa consuma circa 5mb di ram ma da quando inizia ad acquisire immagini e a visualizzarle in un picurebox il consumo di ram va aumentando di circa 30mb ogni secondo. Ho cercato in rete e dopo aver testato applicazioni simili alla mia mi sono accorto che anche queste presentano lo stesso problema.
Suppongo che quei 30 mb siano dati dalle immagini che vengono inserite nel picturebox e che al cambiare di esso non vengono eliminate dalla memoria, rimanendo come un peso morto in quanto non verranno più utilizzate.
Mi potreste spiegare come eliminare questi dati obsoleti.
Vi incollo le parti principali del codice che ho usato
public partial class FormWebcamFtp : Form
    {
        private FilterInfoCollection VideoCaptureDevices;
        private VideoCaptureDevice FinalVideo = null;

        public FormWebcamFtp()
        {
            InitializeComponent();
            
            VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            if (VideoCaptureDevices.Count != 0)
            {
                foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
                {
                    DevicesList.Items.Add(VideoCaptureDevice.Name);
                }
                DevicesList.SelectedIndex = 0;
                try
                {
                    FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[DevicesList.SelectedIndex].MonikerString);
                    FinalVideo.NewFrame += new NewFrameEventHandler(NewFrame);
                    FinalVideo.Start();
                    TimerFps.Enabled = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Errore: " + ex);
                }
            }
            else
            {
                DevicesList.Items.Add("(Nessun dispositivo video trovato)");
                DevicesList.Enabled = false;
            }
        }
(...)
        
        void NewFrame(object sender, NewFrameEventArgs eventArgs) 
        {
            WebcamFrame.Dispose();
            WebcamFrame.Image = (Bitmap)eventArgs.Frame.Clone();
        }
        private void FormWebcamFtp_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (FinalVideo != null)
            {
                if (FinalVideo.IsRunning)
                {
                    TimerFps.Enabled = false;
                    FinalVideo.SignalToStop();
                    FinalVideo = null;
                }
            }
        }
(...)

Grazie in anticipo ^^
aaa
03/09/11 18:07
pierotofy
        void NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            WebcamFrame.Dispose();
            WebcamFrame.Image = (Bitmap)eventArgs.Frame.Clone();
        }


Perchè chiami Clone()?
Il mio blog: piero.dev
03/09/11 19:08
Roby94
è la prima volta che uso le librerie aforge per questo scopo, l'ho messo perchè le guide che ho trovato in rete usavano clone, non sapevo che fosse quello la causa del problema. con cosa lo posso sostituire?

Edit:
Dispose nel codice he ho adesso non c'è più, era solo una prova per risolvere il problema
Ultima modifica effettuata da Roby94 03/09/11 19:10
aaa
03/09/11 19:17
pierotofy
void NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            WebcamFrame.Image = (Bitmap)eventArgs.Frame;
        }


Penso dovrebbe andare. Clone() crea una copia dell'oggetto su cui viene chiamato. Ovviamente devi leggere la documentazione di AForge e assicurarti che ci pensi la libreria a chiamare dispose alla ricezione del frame successivo. Altrimenti dovrai scrivere tu il codice che si occupa di eliminare il frame precedente. Qualcosa del genere:

if (WebCamFrame.Image != null) WebCamFrame.Image.Dispose();
WebCamFrame.Image = (Bitmap)eventArgs.Frame;


Gli oggetti Bitmap devono essere sempre eliminati esplicitamente; è uno di quei casi in cui il garbage collection del .NET non ti è d'aiuto.
Il mio blog: piero.dev
03/09/11 19:25
Roby94
Ok credo di aver capito, però lasciando perdere un attimo la questione della ram, se tolgo Clone() viene visualizzata un immagine bianca con una X rossa e mi restituisce anche un eccezione non gestita nell'applicazione:
Le informazioni su come richiamare il debug JIT (Just-In-Time) anziché questa finestra
sono riportate in fondo al messaggio.

************** Testo dell'eccezione **************
System.ArgumentException: Parametro non valido.
   in System.Drawing.Image.get_Width()
   in System.Drawing.Image.get_Size()
   in System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
   in System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
   in System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
   in System.Windows.Forms.Control.WmPaint(Message& m)
   in System.Windows.Forms.Control.WndProc(Message& m)
   in System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   in System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   in System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
aaa
03/09/11 19:30
pierotofy
Devi leggere la documentazione di AForge. E' probabile che la libreria faccia il dispose di ogni frame dopo aver scatenato l'evento NewFrame. In quel caso devi usare Clone() per farti una copia locale, ma devi ricordarti di chiamare Dispose() non appena hai terminato di usarla.
Il mio blog: piero.dev
03/09/11 19:36
Roby94
Grazie mille Piero, ho rimesso clone e fatto il dispose come mi hai fatto vedere tu e adesso il consumo non supera i 14mb, la tua teoria si è rivelata esatta, aforce effetua il dispose gia per conto suo.
Grazie ancora ^^
aaa