feat: add jmuxer-stream webcam type, supporting raw h264 (#1342)
Co-authored-by: Stefan Dej <meteyou@gmail.com>
This commit is contained in:
parent
4d7ffbe090
commit
40e8f9cd63
30
package-lock.json
generated
30
package-lock.json
generated
@ -27,6 +27,7 @@
|
|||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"echarts-gl": "^2.0.8",
|
"echarts-gl": "^2.0.8",
|
||||||
"hls.js": "^1.3.3",
|
"hls.js": "^1.3.3",
|
||||||
|
"jmuxer": "^2.0.5",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
"lodash.kebabcase": "^4.1.1",
|
"lodash.kebabcase": "^4.1.1",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
@ -54,6 +55,7 @@
|
|||||||
"@intlify/vite-plugin-vue-i18n": "^2.5.0",
|
"@intlify/vite-plugin-vue-i18n": "^2.5.0",
|
||||||
"@mdi/js": "^7.0.0",
|
"@mdi/js": "^7.0.0",
|
||||||
"@types/file-saver": "^2.0.5",
|
"@types/file-saver": "^2.0.5",
|
||||||
|
"@types/jmuxer": "^2.0.3",
|
||||||
"@types/lodash.kebabcase": "^4.1.6",
|
"@types/lodash.kebabcase": "^4.1.6",
|
||||||
"@types/lodash.throttle": "^4.1.6",
|
"@types/lodash.throttle": "^4.1.6",
|
||||||
"@types/semver": "^7.3.8",
|
"@types/semver": "^7.3.8",
|
||||||
@ -2800,6 +2802,15 @@
|
|||||||
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jmuxer": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jmuxer/-/jmuxer-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-jRwZXuPbNRG8wTfJT7gjpZm72EaMzvN3oG7zbFWdW8+OHJmxAhLyqycTd/0GtZ/P8OjKXa1cbyKxQg6coXlERg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.11",
|
"version": "7.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||||
@ -6778,6 +6789,11 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jmuxer": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/jmuxer/-/jmuxer-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-4qjXl8JS138WyCZZoOYwXq/qVrHcE0UIpt2lMtGyq2wuBSPMNSzP1K2CEWSrwAMgjZ9jD7Btc0SxMkiLIhoHsg=="
|
||||||
|
},
|
||||||
"node_modules/joi": {
|
"node_modules/joi": {
|
||||||
"version": "17.6.2",
|
"version": "17.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/joi/-/joi-17.6.2.tgz",
|
||||||
@ -12032,6 +12048,15 @@
|
|||||||
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/jmuxer": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jmuxer/-/jmuxer-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-jRwZXuPbNRG8wTfJT7gjpZm72EaMzvN3oG7zbFWdW8+OHJmxAhLyqycTd/0GtZ/P8OjKXa1cbyKxQg6coXlERg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/json-schema": {
|
"@types/json-schema": {
|
||||||
"version": "7.0.11",
|
"version": "7.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||||
@ -14837,6 +14862,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jmuxer": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/jmuxer/-/jmuxer-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-4qjXl8JS138WyCZZoOYwXq/qVrHcE0UIpt2lMtGyq2wuBSPMNSzP1K2CEWSrwAMgjZ9jD7Btc0SxMkiLIhoHsg=="
|
||||||
|
},
|
||||||
"joi": {
|
"joi": {
|
||||||
"version": "17.6.2",
|
"version": "17.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/joi/-/joi-17.6.2.tgz",
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"echarts-gl": "^2.0.8",
|
"echarts-gl": "^2.0.8",
|
||||||
"hls.js": "^1.3.3",
|
"hls.js": "^1.3.3",
|
||||||
|
"jmuxer": "^2.0.5",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
"lodash.kebabcase": "^4.1.1",
|
"lodash.kebabcase": "^4.1.1",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
@ -69,6 +70,7 @@
|
|||||||
"@intlify/vite-plugin-vue-i18n": "^2.5.0",
|
"@intlify/vite-plugin-vue-i18n": "^2.5.0",
|
||||||
"@mdi/js": "^7.0.0",
|
"@mdi/js": "^7.0.0",
|
||||||
"@types/file-saver": "^2.0.5",
|
"@types/file-saver": "^2.0.5",
|
||||||
|
"@types/jmuxer": "^2.0.3",
|
||||||
"@types/lodash.kebabcase": "^4.1.6",
|
"@types/lodash.kebabcase": "^4.1.6",
|
||||||
"@types/lodash.throttle": "^4.1.6",
|
"@types/lodash.throttle": "^4.1.6",
|
||||||
"@types/semver": "^7.3.8",
|
"@types/semver": "^7.3.8",
|
||||||
|
@ -60,6 +60,9 @@
|
|||||||
<template v-else-if="currentCam.service === 'hlsstream'">
|
<template v-else-if="currentCam.service === 'hlsstream'">
|
||||||
<webcam-hlsstreamer :cam-settings="currentCam" />
|
<webcam-hlsstreamer :cam-settings="currentCam" />
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="currentCam.service === 'jmuxer-stream'">
|
||||||
|
<webcam-jmuxer-stream :cam-settings="currentCam" />
|
||||||
|
</template>
|
||||||
<template v-else-if="currentCam.service === 'webrtc-camerastreamer'">
|
<template v-else-if="currentCam.service === 'webrtc-camerastreamer'">
|
||||||
<webcam-webrtc-camerastreamer :cam-settings="currentCam" />
|
<webcam-webrtc-camerastreamer :cam-settings="currentCam" />
|
||||||
</template>
|
</template>
|
||||||
@ -81,6 +84,7 @@ import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vu
|
|||||||
import Hlsstreamer from '@/components/webcams/Hlsstreamer.vue'
|
import Hlsstreamer from '@/components/webcams/Hlsstreamer.vue'
|
||||||
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
||||||
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
||||||
|
import JMuxerStream from '@/components/webcams/JMuxerStream.vue'
|
||||||
import WebrtcCameraStreamer from '@/components/webcams/WebrtcCameraStreamer.vue'
|
import WebrtcCameraStreamer from '@/components/webcams/WebrtcCameraStreamer.vue'
|
||||||
import WebcamGrid from '@/components/webcams/WebcamGrid.vue'
|
import WebcamGrid from '@/components/webcams/WebcamGrid.vue'
|
||||||
import Component from 'vue-class-component'
|
import Component from 'vue-class-component'
|
||||||
@ -99,6 +103,7 @@ import WebcamMixin from '@/components/mixins/webcam'
|
|||||||
'webcam-ipstreamer': Ipstreamer,
|
'webcam-ipstreamer': Ipstreamer,
|
||||||
'webcam-hlsstreamer': Hlsstreamer,
|
'webcam-hlsstreamer': Hlsstreamer,
|
||||||
'webcam-uv4l-mjpeg': Uv4lMjpeg,
|
'webcam-uv4l-mjpeg': Uv4lMjpeg,
|
||||||
|
'webcam-jmuxer-stream': JMuxerStream,
|
||||||
'webcam-webrtc-camerastreamer': WebrtcCameraStreamer,
|
'webcam-webrtc-camerastreamer': WebrtcCameraStreamer,
|
||||||
'webcam-grid': WebcamGrid,
|
'webcam-grid': WebcamGrid,
|
||||||
},
|
},
|
||||||
|
@ -131,7 +131,7 @@
|
|||||||
attach></v-select>
|
attach></v-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row v-if="form.service === 'mjpegstreamer-adaptive'">
|
<v-row v-if="form.service === 'mjpegstreamer-adaptive' || form.service === 'jmuxer-stream'">
|
||||||
<v-col class="py-2 col-6">
|
<v-col class="py-2 col-6">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="form.targetFps"
|
v-model="form.targetFps"
|
||||||
@ -190,6 +190,9 @@
|
|||||||
<template v-else-if="form.service === 'hlsstream'">
|
<template v-else-if="form.service === 'hlsstream'">
|
||||||
<webcam-hlsstreamer :cam-settings="form" />
|
<webcam-hlsstreamer :cam-settings="form" />
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="form.service === 'jmuxer-stream'">
|
||||||
|
<webcam-jmuxer-stream :cam-settings="form" />
|
||||||
|
</template>
|
||||||
<template v-else-if="form.service === 'webrtc-camerastreamer'">
|
<template v-else-if="form.service === 'webrtc-camerastreamer'">
|
||||||
<webcam-webrtc-camerastreamer :cam-settings="form" />
|
<webcam-webrtc-camerastreamer :cam-settings="form" />
|
||||||
</template>
|
</template>
|
||||||
@ -228,6 +231,7 @@ import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vu
|
|||||||
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
||||||
import WebrtcCameraStreamer from '@/components/webcams/WebrtcCameraStreamer.vue'
|
import WebrtcCameraStreamer from '@/components/webcams/WebrtcCameraStreamer.vue'
|
||||||
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
||||||
|
import JMuxerStream from '@/components/webcams/JMuxerStream.vue'
|
||||||
import { mdiMenuDown, mdiDelete, mdiPencil, mdiWebcam } from '@mdi/js'
|
import { mdiMenuDown, mdiDelete, mdiPencil, mdiWebcam } from '@mdi/js'
|
||||||
import WebcamMixin from '@/components/mixins/webcam'
|
import WebcamMixin from '@/components/mixins/webcam'
|
||||||
import { FileStateFile } from '@/store/files/types'
|
import { FileStateFile } from '@/store/files/types'
|
||||||
@ -257,6 +261,7 @@ interface webcamForm {
|
|||||||
'webcam-ipstreamer': Ipstreamer,
|
'webcam-ipstreamer': Ipstreamer,
|
||||||
'webcam-webrtc-camerastreamer': WebrtcCameraStreamer,
|
'webcam-webrtc-camerastreamer': WebrtcCameraStreamer,
|
||||||
'webcam-hlsstreamer': Hlsstreamer,
|
'webcam-hlsstreamer': Hlsstreamer,
|
||||||
|
'webcam-jmuxer-stream': JMuxerStream,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class SettingsWebcamsTab extends Mixins(BaseMixin, WebcamMixin) {
|
export default class SettingsWebcamsTab extends Mixins(BaseMixin, WebcamMixin) {
|
||||||
@ -322,6 +327,7 @@ export default class SettingsWebcamsTab extends Mixins(BaseMixin, WebcamMixin) {
|
|||||||
{ value: 'ipstream', text: this.$t('Settings.WebcamsTab.Ipstream') },
|
{ value: 'ipstream', text: this.$t('Settings.WebcamsTab.Ipstream') },
|
||||||
{ value: 'webrtc-camerastreamer', text: this.$t('Settings.WebcamsTab.WebrtcCameraStreamer') },
|
{ value: 'webrtc-camerastreamer', text: this.$t('Settings.WebcamsTab.WebrtcCameraStreamer') },
|
||||||
{ value: 'hlsstream', text: this.$t('Settings.WebcamsTab.Hlsstream') },
|
{ value: 'hlsstream', text: this.$t('Settings.WebcamsTab.Hlsstream') },
|
||||||
|
{ value: 'jmuxer-stream', text: this.$t('Settings.WebcamsTab.JMuxerStream') },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
src/components/webcams/JMuxerStream.vue
Normal file
114
src/components/webcams/JMuxerStream.vue
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<video ref="video" autoplay :style="webcamStyle" class="webcamImage" />
|
||||||
|
<v-row v-if="status !== 'connected'">
|
||||||
|
<v-col class="_webcam_jmuxer_output text-center d-flex flex-column justify-center align-center">
|
||||||
|
<v-progress-circular v-if="status === 'connecting'" indeterminate color="primary" class="mb-3" />
|
||||||
|
<span class="mt-3">{{ status }}</span>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import JMuxer from 'jmuxer'
|
||||||
|
import { Component, Mixins, Prop, Watch } from 'vue-property-decorator'
|
||||||
|
import BaseMixin from '@/components/mixins/base'
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class JMuxerStreamer extends Mixins(BaseMixin) {
|
||||||
|
private jmuxer: JMuxer | null = null
|
||||||
|
private status: string = 'connecting'
|
||||||
|
|
||||||
|
@Prop({ required: true })
|
||||||
|
camSettings: any
|
||||||
|
|
||||||
|
@Prop()
|
||||||
|
printerUrl: string | undefined
|
||||||
|
|
||||||
|
declare $refs: {
|
||||||
|
video: HTMLVideoElement
|
||||||
|
}
|
||||||
|
|
||||||
|
get url() {
|
||||||
|
return this.camSettings.urlStream || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
get webcamStyle() {
|
||||||
|
let transforms = ''
|
||||||
|
if ('flipX' in this.camSettings && this.camSettings.flipX) transforms += ' scaleX(-1)'
|
||||||
|
if ('flipX' in this.camSettings && this.camSettings.flipY) transforms += ' scaleY(-1)'
|
||||||
|
if (transforms.trimStart().length) return { transform: transforms.trimStart() }
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.play()
|
||||||
|
}
|
||||||
|
|
||||||
|
play() {
|
||||||
|
this.status = 'connecting'
|
||||||
|
this.jmuxer?.destroy()
|
||||||
|
|
||||||
|
// Only websocket streams supported
|
||||||
|
if (!this.url.startsWith('ws://') && !this.url.startsWith('wss://')) {
|
||||||
|
console.error('jmuxer error: only websocket streams supported (ws://.. or wss://..)')
|
||||||
|
this.status = 'error'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const video = this.$refs.video
|
||||||
|
const targetFps = this.camSettings.targetFps || 10
|
||||||
|
|
||||||
|
this.jmuxer = new JMuxer({
|
||||||
|
node: video,
|
||||||
|
mode: 'video',
|
||||||
|
flushingTime: 0,
|
||||||
|
fps: targetFps,
|
||||||
|
// debug: true,
|
||||||
|
onReady: (data: any) => {
|
||||||
|
this.status = 'connected'
|
||||||
|
console.log('jmuxer ready:', data)
|
||||||
|
},
|
||||||
|
onError: (data: any) => {
|
||||||
|
this.status = 'error'
|
||||||
|
console.log('jmuxer error:', data)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const ws = new WebSocket(this.url)
|
||||||
|
ws.binaryType = 'arraybuffer'
|
||||||
|
ws.addEventListener('message', (event) => {
|
||||||
|
this.jmuxer?.feed({
|
||||||
|
video: new Uint8Array(event.data),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ws.addEventListener('error', (event) => {
|
||||||
|
this.status = 'error'
|
||||||
|
console.log('jmuxer ws error:', event)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeUnmount() {
|
||||||
|
this.jmuxer?.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Watch('camSettings', { deep: true })
|
||||||
|
onCamSettingsChanged() {
|
||||||
|
// restart stream, when camSettings change
|
||||||
|
this.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.webcamImage {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._webcam_jmuxer_output {
|
||||||
|
aspect-ratio: calc(3 / 2);
|
||||||
|
}
|
||||||
|
</style>
|
@ -22,6 +22,9 @@
|
|||||||
<template v-else-if="webcam.service === 'webrtc-camerastreamer'">
|
<template v-else-if="webcam.service === 'webrtc-camerastreamer'">
|
||||||
<webcam-webrtc-camerastreamer :cam-settings="webcam" />
|
<webcam-webrtc-camerastreamer :cam-settings="webcam" />
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="webcam.service === 'jmuxer-stream'">
|
||||||
|
<webcam-jmuxer-stream :cam-settings="webcam" />
|
||||||
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p class="text-center py-3 font-italic">{{ $t('Panels.WebcamPanel.UnknownWebcamService') }}</p>
|
<p class="text-center py-3 font-italic">{{ $t('Panels.WebcamPanel.UnknownWebcamService') }}</p>
|
||||||
</template>
|
</template>
|
||||||
@ -38,6 +41,7 @@ import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vu
|
|||||||
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
||||||
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
||||||
import Hlsstreamer from '@/components/webcams/Hlsstreamer.vue'
|
import Hlsstreamer from '@/components/webcams/Hlsstreamer.vue'
|
||||||
|
import JMuxerStream from '@/components/webcams/JMuxerStream.vue'
|
||||||
import WebrtcCameraStreamer from '@/components/webcams/WebrtcCameraStreamer.vue'
|
import WebrtcCameraStreamer from '@/components/webcams/WebrtcCameraStreamer.vue'
|
||||||
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
|
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
|
||||||
|
|
||||||
@ -48,6 +52,7 @@ import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
|
|||||||
'webcam-uv4l-mjpeg': Uv4lMjpeg,
|
'webcam-uv4l-mjpeg': Uv4lMjpeg,
|
||||||
'webcam-ipstreamer': Ipstreamer,
|
'webcam-ipstreamer': Ipstreamer,
|
||||||
'webcam-hlsstreamer': Hlsstreamer,
|
'webcam-hlsstreamer': Hlsstreamer,
|
||||||
|
'webcam-jmuxer-stream': JMuxerStream,
|
||||||
'webcam-webrtc-camerastreamer': WebrtcCameraStreamer,
|
'webcam-webrtc-camerastreamer': WebrtcCameraStreamer,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1055,6 +1055,7 @@
|
|||||||
"Hlsstream": "HLS Stream",
|
"Hlsstream": "HLS Stream",
|
||||||
"Mjpegstreamer": "MJPEG-Streamer",
|
"Mjpegstreamer": "MJPEG-Streamer",
|
||||||
"MjpegstreamerAdaptive": "Adaptiv MJPEG-Streamer (eksperimental)",
|
"MjpegstreamerAdaptive": "Adaptiv MJPEG-Streamer (eksperimental)",
|
||||||
|
"JMuxerStream": "Rå h264 stream (jmuxer)",
|
||||||
"Name": "Navn",
|
"Name": "Navn",
|
||||||
"NameAlreadyExists": "Navnet bruges allerede",
|
"NameAlreadyExists": "Navnet bruges allerede",
|
||||||
"Required": "Krævet",
|
"Required": "Krævet",
|
||||||
|
@ -1058,6 +1058,7 @@
|
|||||||
"Ipstream": "IP Kamera",
|
"Ipstream": "IP Kamera",
|
||||||
"Mjpegstreamer": "MJPEG-Streamer",
|
"Mjpegstreamer": "MJPEG-Streamer",
|
||||||
"MjpegstreamerAdaptive": "Adaptive MJPEG-Streamer (experimental)",
|
"MjpegstreamerAdaptive": "Adaptive MJPEG-Streamer (experimental)",
|
||||||
|
"JMuxerStream": "Roher h264 stream (jmuxer)",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"NameAlreadyExists": "Name existiert bereits",
|
"NameAlreadyExists": "Name existiert bereits",
|
||||||
"Required": "benötigt",
|
"Required": "benötigt",
|
||||||
|
@ -1065,6 +1065,7 @@
|
|||||||
"Hlsstream": "HLS Stream",
|
"Hlsstream": "HLS Stream",
|
||||||
"Mjpegstreamer": "MJPEG-Streamer",
|
"Mjpegstreamer": "MJPEG-Streamer",
|
||||||
"MjpegstreamerAdaptive": "Adaptive MJPEG-Streamer (experimental)",
|
"MjpegstreamerAdaptive": "Adaptive MJPEG-Streamer (experimental)",
|
||||||
|
"JMuxerStream": "Raw h264 stream (jmuxer)",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"NameAlreadyExists": "Name already exists",
|
"NameAlreadyExists": "Name already exists",
|
||||||
"Required": "required",
|
"Required": "required",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user