Предисловие
Не так давно, возникла необходимость захвата видео с web камеры и передавать его по сети используя .Net.
Так как с подобной задачей я столкнулся впервые, то первым делом начал искать информацию по этому вопросу.
Как выяснилось, что в чистом .Net нет поддержки работы с web камерами. Перебрав несколько различных библиотек, свой выбор остановил на Aforge.net.
Aforge.net — это фреймворк для решения целого ряда задач, из которого нам понадобится библиотеки AForge.Video.
Захват изображения
Для захвата видео с устройства видео ввода существует класс
AForge.Video.DirectShow.VideoCaptureDevice
. Ему необходимо задать моникер устройства с которого будет происходить захват. Так же необходимо задать обработчик события NewFrame
. Это событие возникает каждый раз, когда с устройства будет получен новый кадр, который и передается в обработчик в виде объекта Bitmap
, где его уже можно обработать:private void VideoSourceNewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
{
var img = (Image) eventArgs.Frame;
using (var ms=new MemoryStream())
{
img.Save(ms,ImageFormat.Jpeg);
//Сохраняем изображение в массив байт, для последующего формирования mjpeg
_bufImage = ms.ToArray();
}
}
Запуск видеозахвата осуществляется вызовом метода
Start()
.Список доступных видеокамер, установленных в системе, можно получить с помощью класса
FilterInfoCollection
, передав ему, в качестве параметра, необходимую категорию устройств:var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
Это класс представляет из себя коллекцию элементов FilterInfo, которые содержат в себе два поля:
- Name — название устройства
- MonikerString — моникер устройства.
Таким образом, получив моникер устройства мы можем передать его в класс
VideoCaptureDevice
.Формирование видео-потока MJPEG
MJPEG (Motion JPEG) является простейшим алгоритмом видеосжатия, поэтому свой выбор я остановил именно на нем.
Поток видео MJPEG представляет из себя последовательно идущие кадры в JPEG формате дополненные http заголовком:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: multipart/x-mixed-replace; boundary=--myboundary
Expires: -1
--myboundary
Content-Type: image/jpeg
Content-Length:96719
.....image.......
--myboundary
Content-Type: image/jpeg
Content-Length:96720
.....next image.......
Пример реализации:
public ActionResult Video()
{
Response.Clear();
//Устанавливает тип передаваемых данных и разделитель кадров
Response.ContentType = "multipart/x-mixed-replace; boundary=--myboundary";
//Отключаем кеширование
Response.Expires = 0;
Response.Cache.SetCacheability(HttpCacheability.NoCache);
var ae = new ASCIIEncoding();
//Передаем поток пока клиент не отключится
while (Response.IsClientConnected)
{
try
{
//_bufImage - переменная, в которой хранится новый кадр в формате jpeg
var buf = _bufImage;
//Формируем заголовок разделителя
var boundary = ae.GetBytes("\r\n--myboundary\r\nContent-Type: image/jpeg\r\nContent-Length:"
+ buf.Length + "\r\n\r\n");
Response.OutputStream.Write(boundary, 0, boundary.Length);
Response.OutputStream.Write(buf, 0, buf.Length);
Response.Flush();
//Усыпляем поток, для поддержки частоты кадров 20 кадров/с
Thread.Sleep(50);
}
catch (Exception)
{
}
}
Response.End();
return null;
}
Aforge.net
MJPEG
Ссылка на исходник в Google Docs