onvif: add text overlays

This commit is contained in:
Koushik Dutta
2025-02-08 09:41:48 -08:00
parent 6024b4ceaf
commit adbc2aaed9
4 changed files with 71 additions and 16 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/onvif",
"version": "0.1.28",
"version": "0.1.29",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/onvif",
"version": "0.1.28",
"version": "0.1.29",
"license": "Apache",
"dependencies": {
"@scrypted/common": "file:../../common",
@@ -39,21 +39,28 @@
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.62",
"version": "0.3.116",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.24.7",
"adm-zip": "^0.5.14",
"axios": "^1.7.3",
"babel-loader": "^9.1.3",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"typescript": "^5.5.4",
"webpack": "^5.93.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
@@ -66,11 +73,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^22.1.0",
"@types/stringify-object": "^4.0.5",
"stringify-object": "^3.3.0",
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.5"
"typedoc": "^0.26.11"
}
},
"node_modules/@scrypted/common": {

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/onvif",
"version": "0.1.28",
"version": "0.1.29",
"description": "ONVIF Camera Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -1,4 +1,4 @@
import sdk, { AdoptDevice, Device, DeviceCreatorSettings, DeviceDiscovery, DeviceInformation, DiscoveredDevice, Intercom, MediaObject, MediaStreamOptions, ObjectDetectionTypes, ObjectDetector, PictureOptions, Reboot, RequestPictureOptions, ScryptedDeviceType, ScryptedInterface, ScryptedNativeId, Setting, SettingValue, VideoCamera, VideoCameraConfiguration } from "@scrypted/sdk";
import sdk, { AdoptDevice, Device, DeviceCreatorSettings, DeviceDiscovery, DeviceInformation, DiscoveredDevice, Intercom, MediaObject, MediaStreamOptions, ObjectDetectionTypes, ObjectDetector, PictureOptions, Reboot, RequestPictureOptions, ScryptedDeviceType, ScryptedInterface, ScryptedNativeId, Setting, SettingValue, VideoCamera, VideoCameraConfiguration, VideoTextOverlay, VideoTextOverlays } from "@scrypted/sdk";
import { AddressInfo } from "net";
import onvif from 'onvif';
import { Stream } from "stream";
@@ -13,7 +13,7 @@ import { automaticallyConfigureSettings, checkPluginNeedsAutoConfigure, onvifAut
const { mediaManager, systemManager, deviceManager } = sdk;
class OnvifCamera extends RtspSmartCamera implements ObjectDetector, Intercom, VideoCameraConfiguration, Reboot {
class OnvifCamera extends RtspSmartCamera implements ObjectDetector, Intercom, VideoCameraConfiguration, Reboot, VideoTextOverlays {
eventStream: Stream;
client: OnvifCameraAPI;
rtspMediaStreamOptions: Promise<UrlMediaStreamOptions[]>;
@@ -64,6 +64,42 @@ class OnvifCamera extends RtspSmartCamera implements ObjectDetector, Intercom, V
this.info = info;
}
async getVideoTextOverlays(): Promise<Record<string, VideoTextOverlay>> {
const client = await this.getClient();
const osds = await client.getOSDs();
const ret: Record<string, VideoTextOverlay> = {};
for (const osd of osds.getOSDsResponse.OSDs) {
const id = osd.$.token;
const readonly = osd.textString.type !== 'Plain' ? true : undefined;
// readonly toggling not supported
if (readonly)
continue;
ret[id] = {
text: !readonly ? osd.textString.plainText : osd.textString.type,
readonly,
}
}
return ret;
}
async setVideoTextOverlay(id: string, value: VideoTextOverlay): Promise<void> {
const client = await this.getClient();
const osds = await client.getOSDs();
const osd = osds.getOSDsResponse.OSDs.find(osd => osd.$.token === id);
if (!osd)
throw new Error('osd not found');
osd.textString.plainText = value.text;
await client.setOSD({
OSDToken: osd.$.token,
plaintext: value.text,
position: osd.position.type === 'Custom'
? {
...osd.position.pos.$,
}
: osd.position,
});
}
getDetectionInput(detectionId: any, eventId?: any): Promise<MediaObject> {
throw new Error("Method not implemented.");
}
@@ -418,6 +454,7 @@ class OnvifProvider extends RtspProvider implements DeviceDiscovery {
ScryptedInterface.AudioSensor,
ScryptedInterface.MotionSensor,
ScryptedInterface.VideoCameraConfiguration,
ScryptedInterface.VideoTextOverlays,
];
}

View File

@@ -368,6 +368,19 @@ export class OnvifCameraAPI {
this.cam.getDeviceInformation(cb);
})
}
async getOSDs(): Promise<any> {
// this function accept video token but why?
return promisify(cb => {
this.cam.getOSDs(cb);
});
}
async setOSD(osd: any) {
return promisify(cb => {
this.cam.setOSD(osd, cb);
});
}
}
export async function connectCameraAPI(ipAndPort: string, username: string, password: string, console: Console, binaryStateEvent: string) {