Проблема с Bitmap изображениями полученными с веб камера их обработкой в списке и создание из них видео с помощью Accord.Video.FFMPEG

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;

using Accord.Video.FFMPEG;
using AForge.Video.DirectShow;

namespace Camera
{
    class Class1
    {
        static List<Bitmap> array_image_bitmap = new List<Bitmap>();
        static int width;
        static int height;
        static int frameRate;

        private static void Main()
        {
            FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
            width = videoSource.VideoCapabilities[videoSource.VideoCapabilities.Length - 1].FrameSize.Width;
            height = videoSource.VideoCapabilities[videoSource.VideoCapabilities.Length - 1].FrameSize.Height;
            frameRate = videoSource.VideoCapabilities[videoSource.VideoCapabilities.Length - 1].AverageFrameRate;
            if (width > 1920) width = 1920;
            if (height > 1080) height = 1080;
            if (frameRate > 30) frameRate = 30;

            videoSource.NewFrame += VideoSource_NewFrame;
            videoSource.Start();
            Thread.Sleep(10000);
            videoSource.SignalToStop();
            videoSource.WaitForStop();
            videoCreate("путь до папки\\video.avi", array_image_bitmap.ToArray());
        }

        private static void VideoSource_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            Bitmap bmp = new Bitmap(eventArgs.Frame, width, height);

            array_image_bitmap.Add(bmp);
        }

        private static void videoCreate(string outputFileName, Bitmap[] inputImages)
        {
            using (VideoFileWriter videoWriter = new VideoFileWriter())
            {
                videoWriter.Open(outputFileName, width, height, frameRate, VideoCodec.H264, bitRate: 5000000);

                foreach (Bitmap image in inputImages)
                {
                    videoWriter.WriteVideoFrame(image);
                }
                videoWriter.Close();
            }
        }
    }
}

Я хочу получать видео с веб камеры и записывать это в видео файл, но в у меня проблема в том, что этот код "съедает" слишком много памяти, за 10 секунд спокойно на это уходит ~2гб оперативки. Как я понял, виноваты Bitmap в списке, которых там может становится пару сотен за те же 10 секунд. Я решил эту проблему путем сохранения каждого Bitmap'а в файл и вызовом у него .Dispose(), но мне совсем не подходит такой вариант, особенно из-за сильного снижения скорости получения изображения с камеры. Если есть люди использующие другие методы получения видео с камеры, был бы рад их изучить, но это единственный способ который я нашел. У остальных библиотек нет хороших документаций, а видео по ним ничего не объясняют.


Ответы (1 шт):

Автор решения: Alexander Petrov

Начну с мелочей.

array_image_bitmap.ToArray() - конвертировать List<T> в массив - это тоже затраты времени и памяти. Не нужно этого делать!
Метод videoCreate должен принимать параметр List<Bitmap> inputImages, тогда конвертация в массив становится не нужна.
А если учесть, что нужна всего лишь итерация по этой коллекции в цикле foreach, то ещё лучше сделать параметр типа IEnumerable<Bitmap>.


Имя array_image_bitmap я бы заменил на bitmaps.


Свойство Frame класса AForge.Video.NewFrameEventArgs имеет тип Bitmap. Поэтому не нужно копировать его, создавая ещё один экземпляр изображения new Bitmap(eventArgs.Frame, width, height).
Впрочем, если нужно менять размер кадра, то это может быть необходимо.

Я не знаю, что происходит внутри этой библиотеки. Если Frame диспозится автоматически, то добавлять его в List<Bitmap> нельзя. В этом случае можно писать его в файл прямо в событии VideoSource_NewFrame.


А вообще, как мне кажется, следует создать и открыть VideoFileWriter заранее и просто использовать его в событии:

private static void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    videoWriter.WriteVideoFrame(eventArgs.Frame);
}

В этом случае становится не нужен ни промежуточный список, ни сохранение в файлы изображений.
Возможно, от создания битмапа с нужными размерами не избавиться, если только этот VideoWriter сам на лету не умеет изменять размер кадра.

→ Ссылка