GuilhermeC18/node-onvif

SetVideoEncoderConfigurations

vinnitu opened this issue · 4 comments

How to change encoder Quality (or any) options?

It is also very necessary

I wrote a function to set the configuration according to the documentation, but my camera swears at startup that the configuration is missing, can someone tell me what I did wrong?
I added my setVideoEncoderConfiguration function to /lib/service-media.js
According to documentation: https://www.onvif.org/ver10/media/wsdl/media.wsdl

my function:

OnvifServiceMedia.prototype.setVideoEncoderConfiguration = function(params, callback) {
	let promise = new Promise((resolve, reject) => {
		let err_msg = '';
		if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
			reject(new Error('The value of "params" was invalid: ' + err_msg));
			return;
		}

		if(err_msg = mOnvifSoap.isInvalidValue(params['Configuration'], 'object')) {
			reject(new Error('The "Configuration" property was invalid: ' + err_msg));
			return;
		}

		if(err_msg = mOnvifSoap.isInvalidValue(params['ForcePersistence'], 'boolean')) {
			reject(new Error('The "ConfigurationToken" property was invalid: ' + err_msg));
			return;
		}

		let soap_body = '';
		soap_body += '<trt:setVideoEncoderConfiguration>';
		soap_body +=	'<Configuration>';
		soap_body +=	'<tt:token>' + params['Configuration']['$']['token'] + '</tt:token>';
		soap_body +=	'<tt:Name>' + params['Configuration']['Name'] + '</tt:Name>';
		soap_body +=	'<tt:UseCount>' + params['Configuration']['UseCount'] + '</tt:UseCount>';
		soap_body +=	'<tt:GuaranteedFrameRate>' + params['Configuration']['GuaranteedFrameRate'] + '</tt:GuaranteedFrameRate>';
		soap_body +=	'<tt:Encoding>' + params['Configuration']['Encoding'] + '</tt:Encoding>';
		soap_body +=	'<tt:Resolution>';
		soap_body +=		'<Width>' + params['Configuration']['Resolution']['Width'] + '</Width>';
		soap_body +=		'<Height>' + params['Configuration']['Resolution']['Height'] + '</Height>';
		soap_body += 	'</tt:Resolution>';
		soap_body +=	'<tt:Quality>' + params['Configuration']['Quality'] + '</tt:Quality>';
		soap_body +=	'<tt:Multicast>';
		soap_body +=		'<Address>';
		soap_body +=			'<Type>' + params['Configuration']['Multicast']['Address']['Type'] + '</Type>';
		soap_body +=			'<IPv4Address>' + params['Configuration']['Multicast']['Address']['IPv4Address'] + '</IPv4Address>';
		soap_body += 		'</Address>';
		soap_body +=		'<Port>' + params['Configuration']['Multicast']['Port'] + '</Port>';
		soap_body +=		'<TTL>' + params['Configuration']['Multicast']['TTL'] + '</TTL>';
		soap_body +=		'<AutoStart>' + params['Configuration']['Multicast']['AutoStart'] + '</AutoStart>';
		soap_body += 	'</tt:Multicast>';
		soap_body +=	'<tt:SessionTimeout>' + params['Configuration']['SessionTimeout'] + '</tt:SessionTimeout>';
		/*
			https://www.onvif.org/ver10/media/wsdl/media.wsdl - page 75 SetVideoEncoderConfiguration
			RateControl - optional; [VideoRateControl]
			MPEG4 - optional; [Mpeg4Configuration]
			H264 - optional; [H264Configuration]
		 */
		soap_body += 	'</Configuration>';
		soap_body +=   '<ForcePersistence>' + params['ForcePersistence'] + '</ForcePersistence>';
		soap_body += '</trt:setVideoEncoderConfiguration>';

		let soap = this._createRequestSoap(soap_body);
		//console.log(soap);
		//return;

		mOnvifSoap.requestCommand(this.oxaddr, 'setVideoEncoderConfiguration', soap).then((result) => {
			resolve(result);
		}).catch((error) => {
			reject(error);
		});
	});
	if(callback) {
		promise.then((result) => {
			callback(null, result);
		}).catch((error) => {
			callback(error);
		});
	} else {
		return promise;
	}
};

and wrote my own script to set the configuration on the camera:

const onvif = require('node-onvif');

let device = new onvif.OnvifDevice({
    'xaddr': 'http://192.168.1.151:8899/onvif/device_service',
    'user': 'admin',
    'pass': 'xxxxxxxxx'
});

device.init().then((cam) => {

    try {

        // Get a list of ENCODER encoding configurations
        device.services.media.getVideoEncoderConfigurations().then((result) => {
            result.data.GetVideoEncoderConfigurationsResponse.Configurations.forEach((data) => {
                //console.log(data);
                if (data.Encoding == 'JPEG') {
                    //console.log(data['$'].token + ' ' + data.Encoding);

                    // get encoder options
                    var params = {'ConfigurationToken': data['$'].token};
                    device.services.media.getVideoEncoderConfigurationOptions(params).then((result) => {
                        //console.log(JSON.stringify(result.data.GetVideoEncoderConfigurationOptionsResponse.Options.JPEG.ResolutionsAvailable, null, '  '));

                        // update the encoder configuration
                        data.UseCount = 100;
                        data.GuaranteedFrameRate = false;
                        data.Resolution = {Width: '1920', Height: '1080'};
                        data.Quality = 3;

                        // RateControl didn't make optional
                        data.RateControl = {
                            FrameRateLimit: '-3600',
                            EncodingInterval: '0',
                            BitrateLimit: '512'
                        };

                        var params = {'Configuration': data, 'ForcePersistence': true};
                        device.services.media.setVideoEncoderConfiguration(params).then((result) => {
                            console.log(JSON.stringify(result.data, null, '  '));


                        }).catch((error) => {
                            console.error('Error setVideoEncoderConfiguration');
                            console.error(error);
                        });

                    }).catch((error) => {
                        console.error('Error getVideoEncoderConfigurationOptions');
                        console.error(error);
                    });

                }
            });

        }).catch((error) => {
            console.error('error getVideoEncoderConfigurations');
            console.error(error);
        });


    } catch (e) {

        console.log('Error ' + e.name + ":" + e.message + "\n" + e.stack); // (3) <--

    }


}).catch((error) => {
    console.error('device.init error');
    console.error(error);
});

The result of the execution upset me ... :(


smarthome@smarthome:~/mytest$ node onvif_test.js
Error setVideoEncoderConfiguration
Error: 400 Bad Request - Config Not Exist
    at /home/smarthome/mytest/node_modules/node-onvif/lib/modules/soap.js:143:16
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
smarthome@smarthome:~/mytest$


Sended soap xml:



<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope
	xmlns:s="http://www.w3.org/2003/05/soap-envelope"
	xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
	xmlns:tt="http://www.onvif.org/ver10/schema">
	<s:Header>
		<Security s:mustUnderstand="1"
			xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
			<UsernameToken>
				<Username>admin</Username>
				<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">aaaaaaaaaaaaaaaaaaaaaaa</Password>
				<Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bbbbbbbbbbbbbbbbbbbbbb</Nonce>
				<Created
					xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2022-11-20T13:40:38.471Z
				</Created>
			</UsernameToken>
		</Security>
	</s:Header>
	<s:Body>
		<trt:setVideoEncoderConfiguration>
			<Configuration>
				<tt:token>V_ENC_002</tt:token>
				<tt:Name>V_ENC_002</tt:Name>
				<tt:UseCount>100</tt:UseCount>
				<tt:GuaranteedFrameRate>false</tt:GuaranteedFrameRate>
				<tt:Encoding>JPEG</tt:Encoding>
				<tt:Resolution>
					<Width>1920</Width>
					<Height>1080</Height>
				</tt:Resolution>
				<tt:Quality>3</tt:Quality>
				<tt:Multicast>
					<Address>
						<Type>IPv4</Type>
						<IPv4Address>239.0.1.0</IPv4Address>
					</Address>
					<Port>32002</Port>
					<TTL>2</TTL>
					<AutoStart>false</AutoStart>
				</tt:Multicast>
				<tt:SessionTimeout>PT10S</tt:SessionTimeout>
			</Configuration>
			<ForcePersistence>true</ForcePersistence>
		</trt:setVideoEncoderConfiguration>
	</s:Body>
</s:Envelope>


Something is starting to clear up, I added a token to the Configuration and the error has changed!

soap_body +=	'<Configuration token="' + params['Configuration']['$']['token'] + '">';

result:
Error: 400 Bad Request - The configuration parameters are not possible to set

Either I am not setting the configuration parameters correctly, or my camera does not support setting these parameters.

If I unset my values, and try to just set the same configuration options as I thought I would get

/*
       // update the encoder configuration
                        data.GuaranteedFrameRate = false;
                        data.Resolution = {Width: '1920', Height: '1080'};
                        data.Quality = 3;

                        // RateControl didn't make optional
                        data.RateControl = {
                            FrameRateLimit: '-3600',
                            EncodingInterval: '0',
                            BitrateLimit: '512'
                        };
*/

I get an interesting error...

Error: The device seems to not support the setVideoEncoderConfiguration() method.

Perhaps because I send the same configuration that I thought. And the camera, realizing that nothing has changed, gives me such an error.

The final version of my function looks like this.

OnvifServiceMedia.prototype.setVideoEncoderConfiguration = function(params, callback) {
	let promise = new Promise((resolve, reject) => {
		let err_msg = '';
		if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
			reject(new Error('The value of "params" was invalid: ' + err_msg));
			return;
		}

		if(err_msg = mOnvifSoap.isInvalidValue(params['Configuration'], 'object')) {
			reject(new Error('The "Configuration" property was invalid: ' + err_msg));
			return;
		}

		if(err_msg = mOnvifSoap.isInvalidValue(params['ForcePersistence'], 'boolean')) {
			reject(new Error('The "ConfigurationToken" property was invalid: ' + err_msg));
			return;
		}

		let soap_body = '';
		soap_body += '<trt:setVideoEncoderConfiguration>';
		soap_body +=	'<Configuration token="' + params['Configuration']['$']['token'] + '">';

		soap_body +=	'<tt:token>' + params['Configuration']['$']['token'] + '</tt:token>';
		soap_body +=	'<tt:Name>' + params['Configuration']['Name'] + '</tt:Name>';
		soap_body +=	'<tt:UseCount>' + params['Configuration']['UseCount'] + '</tt:UseCount>';
		soap_body +=	'<tt:GuaranteedFrameRate>' + params['Configuration']['GuaranteedFrameRate'] + '</tt:GuaranteedFrameRate>';
		soap_body +=	'<tt:Encoding>' + params['Configuration']['Encoding'] + '</tt:Encoding>';
		soap_body +=	'<tt:Resolution>';
		soap_body +=		'<Width>' + params['Configuration']['Resolution']['Width'] + '</Width>';
		soap_body +=		'<Height>' + params['Configuration']['Resolution']['Height'] + '</Height>';
		soap_body += 	'</tt:Resolution>';
		soap_body +=	'<tt:Quality>' + params['Configuration']['Quality'] + '</tt:Quality>';
		soap_body +=	'<tt:Multicast>';
		soap_body +=		'<Address>';
		soap_body +=			'<Type>' + params['Configuration']['Multicast']['Address']['Type'] + '</Type>';
		soap_body +=			'<IPv4Address>' + params['Configuration']['Multicast']['Address']['IPv4Address'] + '</IPv4Address>';
		soap_body += 		'</Address>';
		soap_body +=		'<Port>' + params['Configuration']['Multicast']['Port'] + '</Port>';
		soap_body +=		'<TTL>' + params['Configuration']['Multicast']['TTL'] + '</TTL>';
		soap_body +=		'<AutoStart>' + params['Configuration']['Multicast']['AutoStart'] + '</AutoStart>';
		soap_body += 	'</tt:Multicast>';
		soap_body +=	'<tt:SessionTimeout>' + params['Configuration']['SessionTimeout'] + '</tt:SessionTimeout>';
		/*
			https://www.onvif.org/ver10/media/wsdl/media.wsdl - page 75 SetVideoEncoderConfiguration
			RateControl - optional; [VideoRateControl]
			MPEG4 - optional; [Mpeg4Configuration]
			H264 - optional; [H264Configuration]
		 */
		soap_body += 	'</Configuration>';
		soap_body +=   '<ForcePersistence>' + params['ForcePersistence'] + '</ForcePersistence>';
		soap_body += '</trt:setVideoEncoderConfiguration>';
		let soap = this._createRequestSoap(soap_body);

		mOnvifSoap.requestCommand(this.oxaddr, 'setVideoEncoderConfiguration', soap).then((result) => {
			resolve(result);
		}).catch((error) => {
			reject(error);
		});
	});
	if(callback) {
		promise.then((result) => {
			callback(null, result);
		}).catch((error) => {
			callback(error);
		});
	} else {
		return promise;
	}
};

I hope my work is useful to you.

right now not have camera, can't test ((
but tell me please in your case does it work?