Pelco Developer Network (PDN)

Problems with video streaming/playback on VideoXpert

Hi, I'm trying to integrate with a VideoXpert system and I'm really struggling to get video display working. I'm not too familiar with C# (actually a Delphi developer) so I've just tried to reverse engineer the demo application, which does work. I'm testing against the Partner Integration Lab VideoXpert unit on 192.168.5.178. Here's the main part of my code which is called on a short timer after the form appears:

private void PlayVideo()
        {
            // initialise SDK
            tmrPlay.Enabled = false;
            Text = "Please wait...";
            cctvSystem = new VXSystem(IPAddr); // 192.168.5.178
 
            try
            {
                var result = cctvSystem.InitializeSdk(sdkKey);
                if (result != Results.Value.OK)
                {
                    cctvSystem.Dispose();
                    MessageBox.Show(String.Format("Failed to initialise SDK: {0}", result), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(-1);
                }
 
                result = cctvSystem.Login(username, password);
                if (result != Results.Value.OK)
                {
                    cctvSystem.Dispose();
                    MessageBox.Show(String.Format("Failed to log in: {0}", result), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(-1);
                }
                //CurrentDevices = cctvSystem.GetDevices(); // doesn't seem to be needed
            }
            catch (Exception Ex)
            {
                MessageBox.Show(String.Format("Error loading SDK: {0}", Ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(-1);
            }
 
            // find camera/interface and get ready to play
            CurrentDataSources = cctvSystem.GetDataSources();
            DataSource dataSource = null;
            bool dsOK = false;
            foreach (DataSource ds in CurrentDataSources)
            {
                // searching for Id "uuid:f2d246df-42f9-1951-6edf-247422ffe204:video"
                if (!dsOK && ds.Id == uuid && ds.Type == DataSource.Types.Video)
                {
                    dataSource = ds;
                    dsOK = true;
                }
            }
            if (!dsOK)
            {
                MessageBox.Show(String.Format("Failed to find device for camera ID {0}", uuid), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(-1);
            }
            VxStreamProtocol selProtocol = VxStreamProtocol.RtspRtp;
            // SelectDataInterface() is almost the same as in the demo program, except that it always selects interface 0
            var dataInterface = SelectDataInterface(selProtocol, dataSource);
            cctvMediaControl = new MediaControl(dataSource, dataInterface);
            cctvMediaControl.TimestampEvent += OnTimestampEvent;
            cctvMediaControl.SetVideoWindow(pnlVideo.Handle);
 
            // play video - default(DateTime) means play live, otherwise play recorded
            if (seekTime == default(DateTime))
            {
                if (!cctvMediaControl.Play(1))
                {
                    MessageBox.Show("Unable to start stream", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    if (cctvMediaControl.IsPipelineActive)
                        Environment.Exit(-1);
 
                    cctvMediaControl.Dispose();
                    cctvMediaControl = null;
                    Environment.Exit(-1);
                }
            }
            else
            {
                if (!cctvMediaControl.Seek(seekTime, 1))
                {
                    MessageBox.Show("Error: Unable to start recorded stream", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    if (cctvMediaControl.IsPipelineActive)
                        Environment.Exit(-1);
 
                    cctvMediaControl.Dispose();
                    cctvMediaControl = null;
                    Environment.Exit(-1);
                }
            }
            tmrAutoClose.Enabled = true;
        }

Everything returns OK but the panel never updates with CCTV video, and the label linked to cctvMediaControl.TimestampEvent never updates. Any ideas as to where I'm going wrong? Also, is there an easier way to identify a camera than UUID (such as camera/channel number)?

Many thanks,

Tim

Hi Tim -

I've sent your questions over to one of our engineers and this was the feedback that we can provide to you:

RE: your first question where Everything returns OK but the panel never updates...
Our best guess is that the GStreamer bin directory needs to be added to the PATH environment variable. It can be manually added to the PATH or at runtime using the same method that Program.cs users in the C# sample:

// Build the path to GStreamer based on the current system settings.
var processType = Environment.Is64BitProcess ? "x64" : "x86";
var currentPath = new System.IO.DirectoryInfo(Application.ExecutablePath);
var rootSamplePath = currentPath.Parent.Parent.Parent.Parent.Parent.Parent.FullName;
const string PathFormat = "{0}\\MediaController\\ThirdParty\\GStreamer\\1.8.1\\{1}\\gstreamer_runtime\\bin";
var gstreamerPath = new System.IO.DirectoryInfo(string.Format(PathFormat, rootSamplePath, processType));
 
// Add the GStreamer location to the path.  It will use it to automatically find the needed files.
Environment.SetEnvironmentVariable("PATH", gstreamerPath.FullName);

RE: second question about having an easier way to identify a camera than UUID:

Data sources have a number property which can also be used. These number values are the same ones displayed in the data source list in the Ops Center Client and under the Live tab when using VideoXpert Admin Portal web application.

Hi Chris, thanks for the response.

I don't think the issue is the GStreamer libraries as I already found that the program wouldn't run if I didn't set them up properly. I had copied the GStreamer bin folder to the directory that my program runs from (renaming it "gstreamer"), and added the following lines to the program.cs file:

var currentPath = new FileInfo(Application.ExecutablePath).Directory.FullName;
var gstreamerPath = new DirectoryInfo(string.Format("{0}\\gstreamer", currentPath));
Environment.SetEnvironmentVariable("PATH", gstreamerPath.FullName);

As to the second part, I did look at using the number property of the cameras on the demo unit but I found they were all set to zero.

Kind regards,

Tim

Hi Tim,

You've done pretty much the same as I have, there is one thing I wanted to ask you about though.

There are 2 if statements in your code if (!cctvMediaControl.Play(1)) and if (!cctvMediaControl.Seek(seekTime, 1)) that call functions that return void. As far as I can tell this should not work as the if condition should be a bool. What happens if you call .Seek or .Play without them being in the if condition?

Thanks,
Mark

Hi Mark,

I adapted that code mostly as it was from the demo app:

if (seekTime == default(DateTime))
{
    if (!Control.Current.Play((int) nudSpeed.Value))
    {
        WriteToLog(string.Format("Error: Unable to {0} stream.\n",
            Control.Current.Mode == MediaControl.Modes.Playback ? "resume" : "start"));
        if (Control.Current.IsPipelineActive)
        {
            StopStream();
            return;
        }
 
        Control.Current.Dispose();
        Control.Current = null;
        Control.SelectedPanel.Refresh();
        return;
    }
}
else
{
    if (!Control.Current.Seek(seekTime, (int)nudSpeed.Value))
    {
        WriteToLog("Error: Unable to start recorded stream.\n");
        if (Control.Current.IsPipelineActive)
        {
            StopStream();
            return;
        }
 
        Control.Current.Dispose();
        Control.Current = null;
        Control.SelectedPanel.Refresh();
        return;
    }
}

and in the metadata for the MediaControl class it lists the Play and Seek methods with public bool signatures. However, I did try it without the if clauses anyway but it didn't change the result.

Many thanks,

Tim

Tim -

Something else to consider is bandwidth streaming from our Partner Lab. Streaming over VPN can sometimes be a challenge. It sounds like you aren't getting the video over that connection.

Can you stream MJPEG? That might work where the other video stream doesn't.

Hi Chris,

the demo application works with both MJPEG and RTSP, so I don't think it's that. I gave my program another go with MJPEG anyway, but I still get the same result.

Kind regards,

Tim

Hi guys,

I still haven't managed to get this working. Any further suggestions before I scrap it and try something else?

I'm afraid not. If the sample code successfully connects to obtain both MJPEG and RTSP, then we know that the lab is functioning properly and that code is functioning properly.

Our best suggestion at this point is to continue to compare the differences between the working sample code and the implementation to try and narrow down where the problem may be. A problem with the GStreamer is still the most likely suggestion that we can offer right now.

Hi guys,

I managed to get something working by 'recycling' the sample application. Is there any way for me to test recorded playback? None of the cameras hooked into the VideoXpert system seem to be recording (pressing the seek button just returns "Unable to start recorded stream."), and I can't see a way to start recording in the sample application.

Kind regards,

Tim

I reboot several of the devices in the lab for the VideoXpert VMS this morning, and I've added/removed a few cameras to see about getting recording. I'm still having some difficulty getting consistent playback from several of the cameras, however some of them are working and some others may start working later on in the day as I have time to work on it more (I hope).

I have been able to fairly consistently obtain playback from the P1220-T42304659 Spectra pro camera in the VX VMS in the lab. A few others work off and on as I have gaps from rebooting. Some are also attached to other recorders (like DigitalSentry) and that causes problems with stream availability from the camera too.

Aha! Finally (re-)discovered the culprit. Another partner was testing creating and modifying a recording schedule using our lab recently. In VX Admin Portal website, under the Recording tab, the Schedule option was only set to record that one camera. I've enabled all of the cameras for recording and as of a little earlier this morning recording is working for many of the cameras in the VideoXpert system.

SDK Stability?

Environment: 1 OPS-WKS and 1 SERVER / MG v10 with 2 Pelco IME cams installed on a single switch. Also a high end Workstation running Windows 8.1.

I have adapted the C# sample app to simply cycle between 2 cameras every 2 seconds. Start a stream, stop the stream, and so forth. After some random time (10-30 minutes, sometimes more, sometimes less) the app throws an unknown external exception in the MediControl.CPP around the lines to either _control->GotoLive(); or _control->Stop();
OR the video simply freezes for some time and then quickly flip-flops between the cameras quickly. This occurs on ANY machine I try it on. Increasing the frequency of the timer to add more time between changes slows this process down. Around 5 seconds the issue goes away. I am not doing any bells and whistles, just a couple of lines of code to display a camera. I have also tried several variations in case of some resource issue by reusing the variable I set the mediacontrol to and / or just creating a new instance every time I start to display a camera and then dispose it. Doesn't make any difference. The program is not showing any unusual memory usage while running or when it errors out. Muticast / Unicast settings on Core make no difference
Any ideas? Five seconds is to long.

Hi kyndall.taylor -

I've moved your question to a new post since it's not the same topic as the original poster.

You can find the question here: SDK Streaming and Stabiilty

Edit: fixed the link for your new topic, kyndall.taylor.

Hi guys,

I think the issue I had was with the gstreamer stuff. Because I'm going to be running this program with my application, I copied the
MediaController\ThirdParty\GStreamer\1.8.1\x86\gstreamer_runtime\bin

directory to

gstreamer

and changed the environment path assignment from

var currentPath = new System.IO.DirectoryInfo(Application.ExecutablePath);
var rootSamplePath = currentPath.Parent.Parent.Parent.Parent.Parent.Parent.FullName;
const string PathFormat = "{0}\\MediaController\\ThirdParty\\GStreamer\\1.8.1\\{1}\\gstreamer_runtime\\bin";
var gstreamerPath = new System.IO.DirectoryInfo(string.Format(PathFormat, rootSamplePath, processType));

to the following:

var currentPath = new System.IO.FileInfo(Application.ExecutablePath).Directory.FullName;
var gstreamerPath = new System.IO.DirectoryInfo(string.Format("{0}\\gstreamer", currentPath));

and now the program isn't working again, it just shows a blank screen exactly like the previous one did. Any idea as to what I'm doing wrong here? I copied all of the DLLs that were compiled with the CCTV application into my application directory, and moved the gstreamer code to the gstreamer directory in the same place.

Kind regards,

Tim

I sent your question over to one of our engineers and he was able to shoot me a quick reply today.

Please try this:

MediaController\ThirdParty\GStreamer\1.8.1\x86\gstreamer_runtime
to
gstreamer

and change your 2nd part to this:

var currentPath = new System.IO.FileInfo(Application.ExecutablePath).Directory.FullName;
var gstreamerPath = new System.IO.DirectoryInfo(string.Format("{0}\\gstreamer\\bin", currentPath));

It's still an issue with the way GStreamer is being copied. This information is taken from Installing on Windows GStreamer documentation here:

It is the application's responsibility to ensure that, at runtime, GStreamer can access its libraries and plugins. It can be done by adding %GSTREAMER_SDK_ROOT_X86%\bin to the %PATH% environment variable, or by running the application from this same folder.

At runtime, GStreamer will look for its plugins in the following folders:

• %HOMEDRIVE%%HOMEFOLDER%/.gstreamer-0.10/plugins
• C:\gstreamer-sdk\0.10\x86\lib\gstreamer-0.10
• \..\lib\gstreamer-0.10
• %GST_PLUGIN_PATH%

So, typically, if your application can find libgstreamer-0.10-0.dll, it will find the GStreamer plugins, as long as the installation folder structure is unmodified. If you do change this structure in your application, then you can use the %GST_PLUGIN_PATH% environment variable to point GStreamer to its plugins. The plugins are initially found at %GSTREAMER_SDK_ROOT_X86%\lib\gstreamer-0.10.

Additionally, if you want to prevent GStreamer from looking in all the default folders listed above, you can set the %GST_PLUGIN_SYSTEM_PATH% environment variable to point where the plugins are located.

In your sample code that you'd included above it is above, it points to the bin directory. These are the Core GStreamer files and the libs directory holds the plugins that are dynamically loaded based on the media being requested. The sample uses the 3rd search location from the GStreamer info pasted above: "\...\lib\gstreamer-1.0". Unless you use one of the other methods then you must have the GStreamer directory set up in the same way.

Edit: I wanted to add this part as well:

Doing things this way does work ok for sample code, but we wouldn't recommend it for deployed integrations. It would rely too much on the relative path between the executable and Gstreamer. Instead a better way would be to add the Gstreamer bin directory to the system PATH or add it to a new GST_PLUGIN_PATH environment variable. If you do it that way, you could have the application anywhere and move it anywhere as long as the correct Gstreamer location is in the path.

Hi Chris,

thanks for that - I think I have it working now. After installing Gstreamer and some playing about I found that this line works:

Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("GSTREAMER_1_0_ROOT_X86", 
EnvironmentVariableTarget.User) + "\\bin");

I've been asked by my colleagues to find a better way to identify the cameras than UUID and earlier you said that I could use the number property. Unfortunately when I check it in code it is all set to zero for all data interfaces, I don't have access to the Ops Center Client and in the VideoXpert Admin Portal the ID column is blank for all cameras. I'm probably just being blind here but could you point me to where I can set this number?

Many thanks,

Tim

Great! I'm glad to hear that you have it working now.

Regarding the camera numbers in VideoXpert, I believe they can me modified via the Admin portal page. On the Live tab, if you right click on a video source and modify the "ID" value and Save that, I believe that will set the number properly.

I've gone through many of the cameras in the Partner lab on the Admin portal page and assigned them camera numbers based on the last digits of their IP address (so no two are the same and they aren't 1, 2, 3, 4, ... etc). Hopefully this will work for your testing now.

Hi Chris,

thanks for doing that for me, hopefully this shouldn't take very long.

I do have another question: are there any known issues with this code on Windows 10? I passed the code from last week to a colleague for initial testing, and it keeps complaining about dependency issues for CSharpWrapper.dll. I've made sure that the Gstreamer framework is installed on his machine and I added it to the Path variable. I've run it through Dependency Walker on my machine and on his (I'm on Windows 7, he's on Windows 10) and on his machine it complains about a lot of Windows API modules that mine has no problem with. I do have the Dependency Walker output from his machine in case it helps, if there is somewhere to upload/email it to.

Many thanks,

Tim

Hi Chris,

one other thing I've been asked to prepare as a backup solution is direct streaming from the cameras through an embedded web browser (we already have this as an option in our software).

I have tried navigating to various cameras on the system but I can't seem to get any video to work. Some cameras request I install a Pelco video plugin (I don't have any install media and I haven't been able to locate any plugin on your website) or choose to use quicktime (IE) or VLC player (Firefox), the others just try to use quicktime/VLC by default. When the player does load, I get no video and the play button has no effect. Chrome just says "This plug-in is not supported".

Do I just need the Pelco video plugin to get this working?

Many thanks,

Tim

I'm not aware of any specific or known issues with Windows 10, I'll check with our test lead to find out if he's heard of any specific problems.

For your 2nd question, are you specifically talking about streaming from a camera's Web GUI? In the past it's used Quicktime but I believe we may be dropping support for that. Unfortunately if this is the question you're searching for answers on, you'll want to check with our Product Support teams. I'm sorry to say I don't know that information with enough detail to answer.

I did receive word back from our testing lead and he's commented that he has not seen issues specific to Windows 10. In fact he uses that on both of his main development machines and has not seen any problems.

Could it be debug or release build related - requiring either redistributables or Visual studio (if debug is what you're using)?

Perhaps it's related to a .NET version that isn't installed between the two machines that you're targeting on one but not the other?

These are simply suggestions, since issues related to these specific points are typically the kinds of things that we would rely on our partner developers to troubleshoot and resolve.