Capturing video from a camera and transferring it over the network

Foreword


Not so long ago, there was a need to capture video from a web camera and transmit it over the network using .Net.
Since I faced this problem for the first time, the first thing I started to look for information on this issue.
As it turned out, in a clean .Net there is no support for working with web cameras. After going through several different libraries, I chose Aforge.net.

Aforge.net is a framework for solving a number of problems, from which we will need the AForge.Video library.

Image capture


There is a class for capturing video from a video input device AForge.Video.DirectShow.VideoCaptureDevice. He needs to set the moniker of the device from which the capture will occur. It is also necessary to set an event handler NewFrame. This event occurs every time a new frame is received from the device, which is transmitted to the handler as an object Bitmap, where it can already be processed:
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();
    }
}


Video capture is launched by calling the method Start().

The list of available cameras installed in the system can be obtained using the class FilterInfoCollection, passing it, as a parameter, the necessary category of devices:
var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

This class is a collection of FilterInfo elements that contain two fields:
  • Name - device name
  • MonikerString - device moniker.

Thus, having received the device moniker, we can pass it to the class VideoCaptureDevice.

MJPEG video stream generation


MJPEG (Motion JPEG) is the simplest video compression algorithm, so I chose it on it.
The MJPEG video stream consists of sequential frames in JPEG format supplemented by an http header:
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.......

Implementation Example:
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
Link to the source in Google Docs

Also popular now: