How to concat multiple video source in C#

This example represents a simple way to concat pictures of two or more video sources. To implement this example, you need to have Ozeki Camera SDK installed, and a reference to OzekiSDK.dll should be added to your Visual Studio project.

Getting started

To get started it is recomended to Download and Install the latest version of Ozeki Camera SDK. After installation you can find the example code discussed in this page with full source code in the following location on your harddisk:

To compile this example you will need Microsoft Visual Studio installed on your computer.


Using a videoconcat object you can integrate video sources from an IP camera, Web Camera or video file. Therefore you can create one source instead of numerous sources. You are also be able to specify how you would like to concat the sources: all in one row or one column or in a table. If you have two or more sources with different resolutions, the program finds the biggest resolution and provides it for every sources. If one of the resolution of the sources is less than the provided, the program set its picture in the centre.

Properties:

  • FrameRate:this property provides the framerate of the main sender.
  • Senders:It gives back a list of the sources.
  • Viewmatrix:It returns the viewmatrix.
  • Resolution:this property return the resolution of the combined pictures.

Methods:

  • VideoConcat(ViewMatrix desiredMatrix):by using this contructor, you can set the matrix which represent layout of the video pictures and initializes the other properties.
  • VideoConcat(List<IVideoSender> desiredSenderList):by using this contructor, you can set the senders and initializes the other properties.
  • Start():to start the concat function.
  • Stop():to stop the concat function.
  • Dispose():close the resources.
  • SwapSources(IVideoSender from, IVideoSender to):change the "from" sender to the other sender called "to".
  • SwapSources(IVideoSender source, int to):put the "from" sender to the the list of senders.It's index will be the "to" parameter's value.
  • SwapSources(int from, int to):permute the "from" sender and the "to" sender in the sender list.
  • AddSource(IVideoSender sender):to add a video source to the list.
  • RemoveSource(IVideoSender sender):to remove a video source to the list.
  • ClearSources():to remove the entire list of video sources.

How to concat video streams into one source?

MainForm.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using Ozeki.Camera;
using Ozeki.Media;

namespace AVideoConcatWF
{
    public partial class VideoConcatWF : Form
    {
        private DrawingImageProvider _provider;
        private MediaConnector _connector;
        private VideoConcat _concat;
        private ViewMatrix _gridSize;

        private List<WebCamera> _webCams;
        
        public VideoConcatWF()
        {
            InitializeComponent();

            this.Text = "VideoConcatWF";
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            this.MaximizeBox = false;

            _provider = new DrawingImageProvider();
            _connector = new MediaConnector();
            _concat = new VideoConcat();
            _webCams = new List<WebCamera>();

            _gridSize = new ViewMatrix();
            GridSizeM.Text = _gridSize.Row.ToString();
            GridSizeN.Text = _gridSize.Column.ToString();

            GridSizeM.TextChanged += GridSizeChanged;
            GridSizeN.TextChanged += GridSizeChanged;

            startButton.Focus();
            addButton.Enabled = false;
            swapButton.Enabled = false;
        }

        private void GridSizeChanged(object sender, EventArgs e)
        {
            int n;
            int m;
            if(Int32.TryParse(GridSizeM.Text, out m) && Int32.TryParse(GridSizeN.Text, out n) && m > 0 && n > 0)
            {
                _gridSize = new ViewMatrix(n, m);
                _concat.ViewMatrix = _gridSize;
            } else
            {
                MessageBox.Show("nem");
            }
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            var cameras = WebCameraFactory.GetDevices();
            if (cameras.Count > 0)
            {
                foreach (var camInfo in cameras)
                {
                    _webCams.Add(new WebCamera(camInfo));
                }
            }
            else
            {
                MessageBox.Show("No cam");
                return;
            }

            _connector.Connect(_concat, _provider);

            foreach (var wcam in _webCams)
            {
                _concat.AddSource(wcam.VideoChannel);
                wcam.Resolution = new Resolution(320, 240);
                wcam.Start();
            }

            _webCams[1].Resolution = new Resolution(160, 120);

            _concat.Start();

            VideoViewer.SetImageProvider(_provider);
            VideoViewer.Start();

            startButton.Enabled = false;
            addButton.Enabled = true;
            swapButton.Enabled = true;

        }

        void streamer_ClientConnected(object sender, VoIPEventArgs<IMJPEGStreamClient> e)
        {
            e.Item.StartStreaming();
        }

        void streamer_ClientDisconnected(object sender, VoIPEventArgs<IMJPEGStreamClient> e)
        {
            e.Item.StopStreaming();
        }

        private void addButton_Click(object sender, EventArgs e)
        {
            ScreenCapture cap = new ScreenCapture();
            cap.DesiredResolution = new Resolution(640, 480);
            _concat.AddSource(cap);
            cap.Start();
            addButton.Enabled = false;
        }

        private void swapButton_Click(object sender, EventArgs e)
        {
            int n;
            int m;
            if (Int32.TryParse(SwapFrom.Text, out m) && Int32.TryParse(SwapTo.Text, out n) && m > 0 && n > 0 && m != n)
            {
                bool status =_concat.SwapSources(n, m);
                if (!status)
                {
                    MessageBox.Show("no");
                }
            }
            else
            {
                MessageBox.Show("no");
            }
        }
    }
}

Code 1 - integrate the pictures of different video sources

Application window

the application window
Figure 1 - The application window

MainForm.Designer.cs

namespace AVideoConcatWF
{
    partial class VideoConcatWF
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.startButton = new System.Windows.Forms.Button();
            this.VideoViewer = new Ozeki.Media.VideoViewerWF();
            this.addButton = new System.Windows.Forms.Button();
            this.printDocument1 = new System.Drawing.Printing.PrintDocument();
            this.GridSizeN = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.GridSizeM = new System.Windows.Forms.TextBox();
            this.SwapTo = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.SwapFrom = new System.Windows.Forms.TextBox();
            this.swapButton = new System.Windows.Forms.Button();
            this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
            this.SuspendLayout();
            // 
            // startButton
            // 
            this.startButton.Location = new System.Drawing.Point(12, 12);
            this.startButton.Name = "startButton";
            this.startButton.Size = new System.Drawing.Size(75, 23);
            this.startButton.TabIndex = 0;
            this.startButton.Text = "START";
            this.startButton.UseVisualStyleBackColor = true;
            this.startButton.Click += new System.EventHandler(this.startButton_Click);
            // 
            // VideoViewer
            // 
            this.VideoViewer.BackColor = System.Drawing.Color.Black;
            this.VideoViewer.FlipMode = Ozeki.Media.FlipMode.None;
            this.VideoViewer.FrameStretch = Ozeki.Media.FrameStretch.Uniform;
            this.VideoViewer.FullScreenEnabled = true;
            this.VideoViewer.Location = new System.Drawing.Point(12, 41);
            this.VideoViewer.Name = "VideoViewer";
            this.VideoViewer.RotateAngle = 0;
            this.VideoViewer.Size = new System.Drawing.Size(672, 519);
            this.VideoViewer.TabIndex = 1;
            this.VideoViewer.Text = "videoViewerWF1";
            // 
            // addButton
            // 
            this.addButton.Location = new System.Drawing.Point(93, 12);
            this.addButton.Name = "addButton";
            this.addButton.Size = new System.Drawing.Size(75, 23);
            this.addButton.TabIndex = 2;
            this.addButton.Text = "ADD";
            this.addButton.UseVisualStyleBackColor = true;
            this.addButton.Click += new System.EventHandler(this.addButton_Click);
            // 
            // GridSizeN
            // 
            this.GridSizeN.Location = new System.Drawing.Point(306, 15);
            this.GridSizeN.Name = "GridSizeN";
            this.GridSizeN.Size = new System.Drawing.Size(51, 20);
            this.GridSizeN.TabIndex = 3;
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(204, 18);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(100, 13);
            this.label1.TabIndex = 5;
            this.label1.Text = "GridSize(Col x Row)";
            // 
            // GridSizeM
            // 
            this.GridSizeM.Location = new System.Drawing.Point(363, 15);
            this.GridSizeM.Name = "GridSizeM";
            this.GridSizeM.Size = new System.Drawing.Size(51, 20);
            this.GridSizeM.TabIndex = 6;
            // 
            // SwapTo
            // 
            this.SwapTo.Location = new System.Drawing.Point(551, 15);
            this.SwapTo.Name = "SwapTo";
            this.SwapTo.Size = new System.Drawing.Size(51, 20);
            this.SwapTo.TabIndex = 9;
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(422, 18);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(70, 13);
            this.label2.TabIndex = 8;
            this.label2.Text = "SwapFromTo";
            // 
            // SwapFrom
            // 
            this.SwapFrom.Location = new System.Drawing.Point(494, 15);
            this.SwapFrom.Name = "SwapFrom";
            this.SwapFrom.Size = new System.Drawing.Size(51, 20);
            this.SwapFrom.TabIndex = 7;
            // 
            // swapButton
            // 
            this.swapButton.Location = new System.Drawing.Point(609, 13);
            this.swapButton.Name = "swapButton";
            this.swapButton.Size = new System.Drawing.Size(75, 23);
            this.swapButton.TabIndex = 10;
            this.swapButton.Text = "SWAP";
            this.swapButton.UseVisualStyleBackColor = true;
            this.swapButton.Click += new System.EventHandler(this.swapButton_Click);
            // 
            // VideoConcatWF
            // 
            this.ClientSize = new System.Drawing.Size(696, 572);
            this.Controls.Add(this.swapButton);
            this.Controls.Add(this.SwapTo);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.SwapFrom);
            this.Controls.Add(this.GridSizeM);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.GridSizeN);
            this.Controls.Add(this.addButton);
            this.Controls.Add(this.VideoViewer);
            this.Controls.Add(this.startButton);
            this.Name = "VideoConcatWF";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button startButton;
        private Ozeki.Media.VideoViewerWF VideoViewer;
        private System.Windows.Forms.Button addButton;
        private System.Drawing.Printing.PrintDocument printDocument1;
        private System.Windows.Forms.TextBox GridSizeN;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.TextBox GridSizeM;
        private System.Windows.Forms.TextBox SwapTo;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.TextBox SwapFrom;
        private System.Windows.Forms.Button swapButton;
        private System.Windows.Forms.ToolTip toolTip1;
    }
}

Related Pages

FAQ

Below you can find the answers for the most frequently asked questions related to this topic:

  1. How can I get the URL of the camera?

    You can get the URL from the producer of the camera. (In the 10th tutorial you can find information on how to create an own IP camera discoverer program.)

  2. I have not managed to build the solution. How to solve it?

    • Please set the Target framework property of the project to .NET 4.0.
    • You should add the OzekiSDK.dll to the references of the solution.
    • Please import the missing classes.
  3. Which OS are supported? Does it work with Windows 10?

    Yes,the SDK works with Windows 10. The following Operating Systems are supported:.

    • Microsoft Windows Vista
    • Microsoft Windows 7
    • Microsoft Windows 8
    • Microsoft Windows 10
    • Microsoft Windows Server 2003
    • Microsoft Windows Server 2008

More information