PTZ Control on ONVIF Standard in C#

Looking at highly price Camera SDK to handle ONVIF Standard, I decided to build some code to control PTZ camera movement using C#.

It it a nice tutorial video by Onvif Channel. That video describes basic step to make a C# project on visual studio. Unfortunately, I can’t get it work for my camera. I’m having YooSee camera GW-1113 which is already support PTZ Control.

There is another tutorial in CodeProject to use PTZ Control. My code is always get a closed connection message from the camera. Both using password or nor, it alway failed. Next, I got nice tool to cek my Onvif Camera. It can detect camera’s IP, port, display video stream and controlling camera using PTZ. You can get it here Afterward, I got IP, Port, and service.

With correct IP, Password, port and service address, it still error on getProfiles() command. I inisiate to find tool to debug Onvif request. I grab this tool in this forum Nice step by step tutorial with pictures. I made my dummy service and dump post header request and then save it into textfile. Here is PHP code i got from // to dump request. I save it on http://localhost:5000/onvif/device_service/index.php


class DumpHTTPRequestToFile {

	public function execute($targetFile) {

		$data = sprintf(
			"%s %s %s\n\nHTTP headers:\n",

		foreach ($this->getHeaderList() as $name => $value) {
			$data .= $name . ': ' . $value . "\n";

		$data .= "\nRequest body:\n";

			$data . file_get_contents('php://input') . "\n"


	private function getHeaderList() {

		$headerList = [];
		foreach ($_SERVER as $name => $value) {
			if (preg_match('/^HTTP_/',$name)) {
				// convert HTTP_HEADER_NAME to Header-Name
				$name = strtr(substr($name,5),'_',' ');
				$name = ucwords(strtolower($name));
				$name = strtr($name,' ','-');

				// add to list
				$headerList[$name] = $value;

		return $headerList;

(new DumpHTTPRequestToFile)->execute('./dumprequest.txt');

And here are resutl I got from C# and Device Test Tool

POST /onvif/device_service/index.php HTTP/1.1

HTTP headers:
Host: localhost
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

Request body:
<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s=""><s:Body xmlns:xsi="" xmlns:xsd=""><GetCapabilities xmlns="" /></s:Body></s:Envelope>

POST /onvif/device_service/index.php HTTP/1.1

HTTP headers:
Host: localhost
Accept: */*

Request body:
<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s=""><s:Body xmlns:xsi="" xmlns:xsd=""><GetCapabilities xmlns="" /></s:Body></s:Envelope>

Above was C# request, while next into it was Tool request You can see that the difference is only at HTTP headers section. Thus, I have to remove Expect:100-continue , gzip compression and Keep-Alive Connection (oprional). As well as add an Accept type.

                var messageElement = new TextMessageEncodingBindingElement()
                    MessageVersion = MessageVersion.CreateVersion(
                      EnvelopeVersion.Soap12, AddressingVersion.None)

                HttpTransportBindingElement httpBinding = new HttpTransportBindingElement()
                    AuthenticationScheme = AuthenticationSchemes.Digest

                //remove compression
                httpBinding.DecompressionEnabled = false;
                // remove keep alive
                httpBinding.KeepAliveEnabled = false;

                CustomBinding bind = new CustomBinding(messageElement, httpBinding);
                // Remove Expect
                ServicePoint servicePoint =
                servicePoint.Expect100Continue = false;

                if (searchServiceUri)
                    // now execute some service operation 
                    Device.DeviceClient device = new Device.DeviceClient(bind,
                      new EndpointAddress(service_uri));
                    device.ClientCredentials.HttpDigest.AllowedImpersonationLevel =
                    device.ClientCredentials.HttpDigest.ClientCredential.UserName = userName;
                    device.ClientCredentials.HttpDigest.ClientCredential.Password = password;

                    Device.Capabilities cap = device.GetCapabilities(null);


Later I got nice php script to controlling PTZ at