2016-09-22 14 views
0

私は現在のスクリーンショットを表示し、それをaviファイルに連続的に書き込むサンプルアプリケーションを作成しています。私はSharpAviをaviの書き込みに使用しています。私の問題は、私は、この例外がスロー取得しています:C#メモリ不足の例外を修正するにはどうすればよいですか?

「型 『System.OutOfMemoryExceptionに』の未処理の例外がSystem.Drawing.dll

で発生しました追加情報:メモリ不足。」

私が呼び出すLockBits()メソッドと関係があり、アプリケーションを実行してから約30秒後に例外が発生すると思います。ここで

スクリーンショットを取る私のコードです:ここでは

public class Recording 
{ 
//... 
private void TakeScreenshot(byte[] buffer) 
{ 
     using (var bitmap = new System.Drawing.Bitmap(m_screenWidth, m_screenHeight)) 
     { 
      using (var g = System.Drawing.Graphics.FromImage(bitmap)) 
      { 
       g.CopyFromScreen(m_screenLeft, m_screenTop, 0, 0, new System.Drawing.Size(m_screenWidth, m_screenHeight), System.Drawing.CopyPixelOperation.SourceCopy); 

       // Draw cursor. 
       User32.CURSORINFO pci; 
       pci.cbSize = Marshal.SizeOf(typeof(User32.CURSORINFO)); 

       if (User32.GetCursorInfo(out pci)) 
       { 
        if (pci.flags == User32.CURSOR_SHOWING) 
        { 
         User32.DrawIcon(g.GetHdc(), pci.ptScrenPos.x - m_screenLeft, pci.ptScrenPos.y - m_screenTop, pci.hCursor); 
         g.ReleaseHdc(); 
        } 
       } 


       if (OnScreenCapture != null) 

       { 
        CaptureEventArgs args = new CaptureEventArgs(bitmap); 
        OnScreenCapture(this, args); 
       } 

       var bits = bitmap.LockBits(new Rectangle(// code breaks here 
        0, 
        0, 
        m_screenWidth, 
        m_screenHeight), 
        ImageLockMode.ReadOnly, 
        System.Drawing.Imaging.PixelFormat.Format32bppRgb); 
       Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length); 
       bitmap.UnlockBits(bits);     
      } 
     } 
    } 
} 
public class CaptureEventArgs : EventArgs 
{ 
    public System.Windows.Media.Imaging.BitmapSource BitmapSource 
    { 
     get; 
     private set; 
    } 

    public CaptureEventArgs(Bitmap bitmap) 
    { 
     BitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
      bitmap.GetHbitmap(), 
      IntPtr.Zero, 
      Int32Rect.Empty, 
      System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 
     BitmapSource.Freeze(); 
    } 
} 
} 

は私MainWindow.xaml.csです:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     m_recordTimer = new DispatcherTimer(); 
     m_recordTimer.Interval = TimeSpan.FromSeconds(1); 
     m_recordTimer.Tick += recordTimer_Tick; 

     m_stopwatch = new Stopwatch(); 
     DataContext = this; 

    } 

    private void recordTimer_Tick(object sender, EventArgs e) 
    { 
     var elapsed = m_stopwatch.Elapsed; 
     Elapsed = string.Format("{00:00}:{1:00}", Math.Floor(elapsed.TotalMinutes), elapsed.Seconds); 
    } 

    private void btnStart_Click(object sender, RoutedEventArgs e) 
    { 
     StartRecording(); 
    } 

    private void btnStop_Click(object sender, RoutedEventArgs e) 
    { 
     StopRecording(); 
    } 

    private void StartRecording() 
    { 
     if(IsRecording) 
     { 
      return; 
     } 

     IsRecording = true; 
     Elapsed = "00:00"; 
     IsLastScreenshot = false; 

     m_stopwatch.Reset(); 
     m_recordTimer.Start(); 

     m_lastFileName = System.IO.Path.Combine("", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".avi"); 

     m_recorder = new Recording(m_lastFileName, KnownFourCCs.Codecs.MotionJpeg, 70, this); 

     m_stopwatch.Start(); 

     m_recorder.OnScreenCapture += m_recorder_OnScreenCapture; 
    } 

    void m_recorder_OnScreenCapture(object sender, CaptureEventArgs e) 
    { 
     imgLive.Dispatcher.BeginInvoke((Action)delegate 
     { 
      imgLive.Source = e.BitmapSource; 
     }); 
    } 

    private void StopRecording() 
    { 
     if (!IsRecording) 
     { 
      return; 
     } 

     m_recorder.Dispose(); 
     m_recorder = null; 
     m_recordTimer.Stop(); 
     m_stopwatch.Stop(); 
     IsRecording = false; 
     IsLastScreenshot = true; 
    } 

    public bool IsRecording { get; private set; } 

    public string Elapsed { get; private set; } 

    public bool IsLastScreenshot { get; private set; } 

    #region fields 


    private DispatcherTimer m_recordTimer; 
    private readonly Stopwatch m_stopwatch; 
    private Recording m_recorder; 
    private string m_lastFileName; 
    #endregion 

    internal void SetImage(System.Drawing.Bitmap bitmap) 
    { 
     imgLive.Dispatcher.BeginInvoke((Action)delegate 
     { 
      imgLive.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
      bitmap.GetHbitmap(), 
      IntPtr.Zero, 
      Int32Rect.Empty, 
      System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 
     }); 
    } 
} 

は、私はより多くのコードを投稿する必要がある場合は、私を知ってみましょう。私は必要なものだけを見せようとしています。また、私は経験豊富ではないと言及する必要があります。私はスレッドとメモリ管理についてちょっと知っています。そして改善のための提案をします。

+0

スタックトレースを取得しましたか? – n8wrl

+0

私の最初の考えは、あなたが以前のスクリーンショットをaviに書き込んだ後で解放していないということです。それを見てください。 – ChrisF

+0

一見したところでは、「使用する」ことでビットマップを破棄していることを示しています。ロックされたビットを解放すると、ロックされたビットが解放されます。私はデバッガに入り、さまざまなパラメータの数値を調べることをお勧めします。場合によっては何かがうまくいかず、0(ゼロ)をグラフィックスシステムに渡して高さや幅を渡すとOOM例外が発生します。 –

答えて

0

私の問題は解決したようです。私は本当に詳細に説明することはできませんが。私はすべてがこれに私のCaptureEventArgsクラスを変更した:

public class CaptureEventArgs : EventArgs 
{ 
    public BitmapImage BitmapImage 
    { 
     get; 
     private set; 
    } 

    public CaptureEventArgs(Bitmap bitmap) 
    { 
     using (var memory = new MemoryStream()) 
     { 
      bitmap.Save(memory, ImageFormat.Bmp); 
      memory.Position = 0; 
      BitmapImage = new BitmapImage(); 
      BitmapImage.BeginInit(); 
      BitmapImage.StreamSource = memory; 
      BitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
      BitmapImage.EndInit(); 
      BitmapImage.Freeze(); 
     } 
    } 
} 

私はここでのメモリリークを持っていた、とのBitmapImageに切り替えると使用は私の問題を修正した後に処分されますのMemoryStreamタイプを使用する必要がありますよ。

関連する問題