From 1171a7c4ce94be2ff4fcff33f8d76b200f40186b Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Wed, 20 Apr 2022 20:18:05 -0700 Subject: [PATCH] rebroadcast: fix streams crossing --- common/src/ffmpeg-rebroadcast.ts | 16 ++++--- plugins/prebuffer-mixin/package-lock.json | 4 +- plugins/prebuffer-mixin/package.json | 2 +- plugins/prebuffer-mixin/src/main.ts | 54 ++++++++++++++--------- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/common/src/ffmpeg-rebroadcast.ts b/common/src/ffmpeg-rebroadcast.ts index 1296c3455..86c27f6f5 100644 --- a/common/src/ffmpeg-rebroadcast.ts +++ b/common/src/ffmpeg-rebroadcast.ts @@ -298,11 +298,17 @@ export async function startParserSession(ffmpegInput: FFmpegIn return { sdp, - inputAudioCodec, - inputVideoCodec, - inputVideoResolution: { - width: parseInt(inputVideoResolution?.[1]), - height: parseInt(inputVideoResolution?.[2]), + get inputAudioCodec() { + return inputAudioCodec; + }, + get inputVideoCodec() { + return inputVideoCodec; + }, + get inputVideoResolution() { + return { + width: parseInt(inputVideoResolution?.[1]), + height: parseInt(inputVideoResolution?.[2]), + } }, get isActive() { return isActive }, kill, diff --git a/plugins/prebuffer-mixin/package-lock.json b/plugins/prebuffer-mixin/package-lock.json index 9444b238d..803ebc67f 100644 --- a/plugins/prebuffer-mixin/package-lock.json +++ b/plugins/prebuffer-mixin/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/prebuffer-mixin", - "version": "0.1.238", + "version": "0.1.239", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/prebuffer-mixin", - "version": "0.1.238", + "version": "0.1.239", "license": "Apache-2.0", "dependencies": { "@scrypted/common": "file:../../common", diff --git a/plugins/prebuffer-mixin/package.json b/plugins/prebuffer-mixin/package.json index 49b323658..20fb07cca 100644 --- a/plugins/prebuffer-mixin/package.json +++ b/plugins/prebuffer-mixin/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/prebuffer-mixin", - "version": "0.1.238", + "version": "0.1.239", "description": "Rebroadcast and Prebuffer for VideoCameras.", "author": "Scrypted", "license": "Apache-2.0", diff --git a/plugins/prebuffer-mixin/src/main.ts b/plugins/prebuffer-mixin/src/main.ts index 65ba708e2..5abec7e0e 100644 --- a/plugins/prebuffer-mixin/src/main.ts +++ b/plugins/prebuffer-mixin/src/main.ts @@ -331,7 +331,7 @@ class PrebufferSession { key: this.rtspParserKey, group, title: 'RTSP Parser', - description: `Experimental: The RTSP Parser used to read the stream. FFmpeg is stable. The Scrypted parser is lower latency. The Scrypted Parser is only available when the Audo Codec is not Transcoding and the Rebroadcast Container is RTSP. The default is "${defaultValue}" for this camera.`, + description: `The RTSP Parser used to read the stream. The default is "${defaultValue}" for this camera.`, value: this.storage.getItem(this.rtspParserKey) || STRING_DEFAULT, choices: [ STRING_DEFAULT, @@ -689,6 +689,22 @@ class PrebufferSession { channel += 2; } + let setupVideoSection: any; + for (const section of parsedSdp.msections) { + if (section.type === 'video') { + if (setupVideoSection) { + this.console.warn('additional video section found. skipping.'); + continue; + } + setupVideoSection = section; + } + else if (section.type !== 'audio') { + this.console.warn('unknown section', section.type); + continue; + } + await doSetup(section.control, section.codec) + } + // grab all available audio sections if (!audioSoftMuted) { for (const audioSection of parsedSdp.msections.filter(msection => msection.type === 'audio')) { @@ -699,14 +715,11 @@ class PrebufferSession { this.console.warn('sdp did not contain audio track and audio was not reported as missing.'); } - const videoSection = parsedSdp.msections.find(msection => msection.type === 'video'); - // sdp may contain multiple audio/video sections. take only the first video section. - parsedSdp.msections = parsedSdp.msections.filter(msection => msection === videoSection || msection.type === 'audio'); + parsedSdp.msections = parsedSdp.msections.filter(msection => msection === setupVideoSection || msection.type === 'audio'); sdp = [...parsedSdp.header.lines, ...parsedSdp.msections.map(msection => msection.lines).flat()].join('\r\n'); this.sdp = Promise.resolve(sdp); - await doSetup(videoSection.control, videoSection.codec); await rtspClient.play(); const earlyData = rtspClient.rfc4571.read(); if (earlyData) @@ -1044,24 +1057,25 @@ class PrebufferSession { const codecMap = new Map(); if (container === 'rtsp') { + let channelsMatch = true; const parsedSdp = parseSdp(sdp); - if (parsedSdp.msections.length > 2) { - parsedSdp.msections = parsedSdp.msections.filter(msection => msection.codec === mediaStreamOptions.video?.codec || msection.codec === mediaStreamOptions.audio?.codec); - sdp = parsedSdp.toSdp(); - filter = chunk => { - const channel = codecMap.get(chunk.type); - if (channel == undefined) - return; - const chunks = chunk.chunks.slice(); - const header = Buffer.from(chunks[0]); - header.writeUInt8(channel, 1); - chunks[0] = header; - return { - startStream: chunk.startStream, - chunks, - } + // if (parsedSdp.msections.length > 2) { + parsedSdp.msections = parsedSdp.msections.filter(msection => msection.codec === mediaStreamOptions.video?.codec || msection.codec === mediaStreamOptions.audio?.codec); + sdp = parsedSdp.toSdp(); + filter = chunk => { + const channel = codecMap.get(chunk.type); + if (channel == undefined) + return; + const chunks = chunk.chunks.slice(); + const header = Buffer.from(chunks[0]); + header.writeUInt8(channel, 1); + chunks[0] = header; + return { + startStream: chunk.startStream, + chunks, } } + // } const client = await listenZeroSingleClient(); socketPromise = client.clientPromise.then(async (socket) => {