From 71c0c87bfb301820b9d7357cd7879df8cd5103cc Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Sat, 4 Sep 2021 20:57:37 -0700 Subject: [PATCH] ffmpeg ordering fixups --- common/src/ffmpeg-rebroadcast.ts | 114 ++++++++++++++++++ plugins/amcrest/package-lock.json | 4 +- plugins/amcrest/package.json | 2 +- plugins/amcrest/src/main.ts | 4 +- plugins/core/package-lock.json | 4 +- plugins/core/package.json | 2 +- plugins/core/src/aggregate.ts | 11 +- .../google-device-access/package-lock.json | 4 +- plugins/google-device-access/package.json | 2 +- plugins/google-device-access/src/main.ts | 4 +- plugins/google-home/src/types/light.ts | 12 +- plugins/rtsp/package-lock.json | 4 +- plugins/rtsp/package.json | 2 +- plugins/rtsp/src/main.ts | 4 +- plugins/unifi-protect/package-lock.json | 4 +- plugins/unifi-protect/package.json | 2 +- 16 files changed, 147 insertions(+), 32 deletions(-) create mode 100644 common/src/ffmpeg-rebroadcast.ts diff --git a/common/src/ffmpeg-rebroadcast.ts b/common/src/ffmpeg-rebroadcast.ts new file mode 100644 index 000000000..d160ce241 --- /dev/null +++ b/common/src/ffmpeg-rebroadcast.ts @@ -0,0 +1,114 @@ +import { createServer, Socket, Server } from 'net'; +import child_process from 'child_process'; +import { ChildProcess } from 'child_process'; +import { FFMpegInput } from '@scrypted/sdk/types'; +import { listenZeroCluster } from './listen-cluster'; +import { readLength } from './read-length'; +import { EventEmitter } from 'events'; + +export interface MP4Atom { + header: Buffer; + length: number; + type: string; + data: Buffer; +} + +export interface FFMpegRebroadcastSession { + server: Server; + cp: ChildProcess; + ffmpegInput: FFMpegInput; +} + +export interface FFMpegRebroadcastOptions { + vcodec: string; + acodec: string; +} + +export async function startRebroadcastSession(ffmpegInput: FFMpegInput, options: FFMpegRebroadcastOptions): Promise { + return new Promise(async (resolve) => { + let clients = 0; + let timeout: any; + const startTimeout = () => { + clearTimeout(timeout); + timeout = setTimeout(() => { + cp?.kill(); + server?.close(); + rebroadcast?.close(); + }, 30000); + } + startTimeout(); + + const events = new EventEmitter(); + + const rebroadcast = createServer(socket => { + console.log('rebroadcast client'); + clients++; + + clearTimeout(timeout) + + const data = (data: Buffer) => { + socket.write(data); + }; + const cleanup = () => { + socket.removeAllListeners(); + events.removeListener('data', data); + clients--; + if (clients === 0) { + startTimeout(); + } + } + + events.on('data', data); + + socket.on('end', cleanup); + socket.on('close', cleanup); + socket.on('error', cleanup); + }); + + const rebroadcastPort = await listenZeroCluster(rebroadcast); + + const server = createServer(socket => { + server.close(); + + (async() => { + while (true) { + const data = await readLength(socket, 188); + events.emit('data', data); + } + })(); + + resolve({ + server: rebroadcast, + cp, + ffmpegInput: { + inputArguments: [ + '-f', + 'mpegts', + '-i', + `tcp://127.0.0.1:${rebroadcastPort}` + ] + }, + }); + }); + + const serverPort = await listenZeroCluster(server); + + const args = ffmpegInput.inputArguments.slice(); + + args.push( + '-f', 'mpegts', + '-vcodec', options.vcodec, + ...(options.acodec ? ['-acodec', options.acodec] : ['-an']), + `tcp://127.0.0.1:${serverPort}` + ); + + console.log(args); + + const cp = child_process.spawn('ffmpeg', args, { + // stdio: 'ignore', + }); + cp.stdout.on('data', data => console.log(data.toString())); + cp.stderr.on('data', data => console.error(data.toString())); + + }); +} diff --git a/plugins/amcrest/package-lock.json b/plugins/amcrest/package-lock.json index 1db88295a..b505cb0f5 100644 --- a/plugins/amcrest/package-lock.json +++ b/plugins/amcrest/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/amcrest", - "version": "0.0.18", + "version": "0.0.19", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/amcrest", - "version": "0.0.18", + "version": "0.0.19", "license": "Apache", "dependencies": { "@mhoc/axios-digest-auth": "^0.7.0", diff --git a/plugins/amcrest/package.json b/plugins/amcrest/package.json index 9c656f657..d9d5bc2e8 100644 --- a/plugins/amcrest/package.json +++ b/plugins/amcrest/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/amcrest", - "version": "0.0.18", + "version": "0.0.19", "description": "Amcrest Plugin for Scrypted", "author": "Scrypted", "license": "Apache", diff --git a/plugins/amcrest/src/main.ts b/plugins/amcrest/src/main.ts index 1068862dc..de295fb34 100644 --- a/plugins/amcrest/src/main.ts +++ b/plugins/amcrest/src/main.ts @@ -59,14 +59,14 @@ class AmcrestCamera extends ScryptedDeviceBase implements VideoCamera, Camera, S return mediaManager.createFFmpegMediaObject({ inputArguments: [ - "-i", - url, '-analyzeduration', '15000000', '-probesize', '100000000', "-reorder_queue_size", "1024", "-max_delay", "20000000", + "-i", + url, ] }); } diff --git a/plugins/core/package-lock.json b/plugins/core/package-lock.json index 9cc8e7b1c..f6976d6f6 100644 --- a/plugins/core/package-lock.json +++ b/plugins/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/core", - "version": "0.0.61", + "version": "0.0.62", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/core", - "version": "0.0.61", + "version": "0.0.62", "license": "Apache-2.0", "dependencies": { "@scrypted/sdk": "file:../../sdk", diff --git a/plugins/core/package.json b/plugins/core/package.json index 20eb7f8ae..1ea779984 100644 --- a/plugins/core/package.json +++ b/plugins/core/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/core", - "version": "0.0.61", + "version": "0.0.62", "description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.", "author": "Scrypted", "license": "Apache-2.0", diff --git a/plugins/core/src/aggregate.ts b/plugins/core/src/aggregate.ts index 81c3e17a2..562e5d105 100644 --- a/plugins/core/src/aggregate.ts +++ b/plugins/core/src/aggregate.ts @@ -85,10 +85,6 @@ function createVideoCamera(devices: VideoCamera[]): VideoCamera { filter.push(`[${i}:v] setpts=PTS-STARTPTS, scale=${w}x${h} [pos${i}];`) } - filteredInput.inputArguments.push( - '-f', 'lavfi', '-i', 'anullsrc', - ) - let prev = 'base'; let curx = 0; let cury = 0; @@ -109,9 +105,10 @@ function createVideoCamera(devices: VideoCamera[]): VideoCamera { filter.join(' '), ); - // return mediaManager.createFFmpegMediaObject(ret); - - const ret = await startRebroadcastSession(filteredInput); + const ret = await startRebroadcastSession(filteredInput, { + vcodec: 'libx264', + acodec: undefined, + }); return mediaManager.createFFmpegMediaObject(ret.ffmpegInput); } } diff --git a/plugins/google-device-access/package-lock.json b/plugins/google-device-access/package-lock.json index 729cdd261..e9a2d4791 100644 --- a/plugins/google-device-access/package-lock.json +++ b/plugins/google-device-access/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/google-device-access", - "version": "0.0.10", + "version": "0.0.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/google-device-access", - "version": "0.0.10", + "version": "0.0.11", "dependencies": { "@googleapis/smartdevicemanagement": "^0.2.0", "axios": "^0.21.1", diff --git a/plugins/google-device-access/package.json b/plugins/google-device-access/package.json index f3c9b1a7c..f7c117edb 100644 --- a/plugins/google-device-access/package.json +++ b/plugins/google-device-access/package.json @@ -36,5 +36,5 @@ "@types/node": "^14.17.11", "@types/url-parse": "^1.4.3" }, - "version": "0.0.10" + "version": "0.0.11" } diff --git a/plugins/google-device-access/src/main.ts b/plugins/google-device-access/src/main.ts index 929c1e65f..31ccd3472 100644 --- a/plugins/google-device-access/src/main.ts +++ b/plugins/google-device-access/src/main.ts @@ -76,14 +76,14 @@ class NestCamera extends ScryptedDeviceBase implements VideoCamera, MotionSensor inputArguments: [ "-rtsp_transport", "tcp", - "-i", - u.toString(), '-analyzeduration', '15000000', '-probesize', '100000000', "-reorder_queue_size", "1024", "-max_delay", "20000000", + "-i", + u.toString(), ] }) } diff --git a/plugins/google-home/src/types/light.ts b/plugins/google-home/src/types/light.ts index fb96eafef..f8c4e6b17 100644 --- a/plugins/google-home/src/types/light.ts +++ b/plugins/google-home/src/types/light.ts @@ -24,10 +24,14 @@ addSupportedType({ ret.attributes['colorModel'] = 'rgb'; if (device.interfaces.includes(ScryptedInterface.ColorSettingTemperature)) { - ret.attributes.colorTemperatureRange = { - temperatureMinK: await device.getTemperatureMinK(), - temperatureMaxK: await device.getTemperatureMaxK(), - }; + try { + ret.attributes.colorTemperatureRange = { + temperatureMinK: await device.getTemperatureMinK(), + temperatureMaxK: await device.getTemperatureMaxK(), + }; + } + catch (e) { + } } } return ret; diff --git a/plugins/rtsp/package-lock.json b/plugins/rtsp/package-lock.json index 7ae180113..21c0726e2 100644 --- a/plugins/rtsp/package-lock.json +++ b/plugins/rtsp/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/rtsp", - "version": "0.0.16", + "version": "0.0.17", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/rtsp", - "version": "0.0.16", + "version": "0.0.17", "license": "Apache", "dependencies": { "axios": "^0.18.1", diff --git a/plugins/rtsp/package.json b/plugins/rtsp/package.json index 38e2adb8f..25310eddd 100644 --- a/plugins/rtsp/package.json +++ b/plugins/rtsp/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/rtsp", - "version": "0.0.16", + "version": "0.0.17", "description": "RTSP Cameras and Streams Plugin for Scrypted", "author": "Scrypted", "license": "Apache", diff --git a/plugins/rtsp/src/main.ts b/plugins/rtsp/src/main.ts index 77cb10411..edcb2712b 100644 --- a/plugins/rtsp/src/main.ts +++ b/plugins/rtsp/src/main.ts @@ -19,14 +19,14 @@ class RtspCamera extends ScryptedDeviceBase implements VideoCamera, Settings { return mediaManager.createFFmpegMediaObject({ inputArguments: [ - "-i", - url.toString(), '-analyzeduration', '15000000', '-probesize', '100000000', "-reorder_queue_size", "1024", "-max_delay", "20000000", + "-i", + url.toString(), ] }); } diff --git a/plugins/unifi-protect/package-lock.json b/plugins/unifi-protect/package-lock.json index a6559f1fe..27bb0e094 100644 --- a/plugins/unifi-protect/package-lock.json +++ b/plugins/unifi-protect/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/unifi-protect", - "version": "0.0.23", + "version": "0.0.24", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/unifi-protect", - "version": "0.0.23", + "version": "0.0.24", "license": "Apache", "dependencies": { "@types/ws": "^7.4.7", diff --git a/plugins/unifi-protect/package.json b/plugins/unifi-protect/package.json index 4066dfeb9..f57042d48 100644 --- a/plugins/unifi-protect/package.json +++ b/plugins/unifi-protect/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/unifi-protect", - "version": "0.0.23", + "version": "0.0.24", "description": "Unifi Protect Plugin for Scrypted", "author": "Scrypted", "license": "Apache",