feat: max webcam height to fit on the screen (#1246)
This commit is contained in:
parent
92438bf8a7
commit
43dc843eca
@ -6,7 +6,8 @@
|
||||
:icon="mdiWebcam"
|
||||
:title="$t('Panels.WebcamPanel.Headline')"
|
||||
:collapsible="$route.fullPath !== '/cam'"
|
||||
card-class="webcam-panel">
|
||||
card-class="webcam-panel"
|
||||
:margin-bottom="currentPage !== 'page'">
|
||||
<template v-if="webcams.length > 1" #buttons>
|
||||
<v-menu :offset-y="true" title="Webcam">
|
||||
<template #activator="{ on, attrs }">
|
||||
|
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<video
|
||||
ref="video"
|
||||
v-observe-visibility="visibilityChanged"
|
||||
autoplay
|
||||
muted
|
||||
:style="webcamStyle"
|
||||
class="webcamImage" />
|
||||
<div class="d-flex justify-center">
|
||||
<video
|
||||
ref="video"
|
||||
v-observe-visibility="visibilityChanged"
|
||||
autoplay
|
||||
muted
|
||||
:style="webcamStyle"
|
||||
class="webcamImage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -15,6 +17,7 @@ import Hls from 'hls.js'
|
||||
|
||||
@Component
|
||||
export default class Hlsstreamer extends Mixins(BaseMixin) {
|
||||
private aspectRatio: null | number = null
|
||||
private isVisible = true
|
||||
private hls: Hls | null = null
|
||||
|
||||
@ -35,12 +38,24 @@ export default class Hlsstreamer extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
get webcamStyle() {
|
||||
const output = {
|
||||
transform: 'none',
|
||||
aspectRatio: 16 / 9,
|
||||
maxHeight: window.innerHeight - 155 + 'px',
|
||||
maxWidth: 'auto',
|
||||
}
|
||||
|
||||
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 ''
|
||||
if (this.aspectRatio) {
|
||||
output.aspectRatio = this.aspectRatio
|
||||
output.maxWidth = (window.innerHeight - 155) * this.aspectRatio + 'px'
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
visibilityChanged(isVisible: boolean) {
|
||||
@ -49,6 +64,11 @@ export default class Hlsstreamer extends Mixins(BaseMixin) {
|
||||
|
||||
mounted() {
|
||||
this.play()
|
||||
|
||||
const video = this.$refs.video
|
||||
video.onplaying = () => {
|
||||
this.aspectRatio = video.videoWidth / video.videoHeight
|
||||
}
|
||||
}
|
||||
|
||||
updated() {
|
||||
|
@ -1,22 +1,5 @@
|
||||
<style scoped>
|
||||
.webcamImage {
|
||||
width: 100%;
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
.webcamFpsOutput {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
padding: 3px 10px;
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div style="position: relative">
|
||||
<div style="position: relative" class="d-flex justify-center">
|
||||
<img
|
||||
ref="image"
|
||||
v-observe-visibility="viewportVisibilityChanged"
|
||||
@ -40,8 +23,10 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
|
||||
private currentFPS = 0
|
||||
private streamState = false
|
||||
private aspectRatio: null | number = null
|
||||
private timerFPS: number | null = null
|
||||
private timerRestart: number | null = null
|
||||
// eslint-disable-next-line no-undef
|
||||
private timerFPS: NodeJS.Timeout | null = null
|
||||
// eslint-disable-next-line no-undef
|
||||
private timerRestart: NodeJS.Timeout | null = null
|
||||
private stream: ReadableStream | null = null
|
||||
private controller: AbortController | null = null
|
||||
private isVisibleViewport = false
|
||||
@ -72,6 +57,8 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
|
||||
const output = {
|
||||
transform: 'none',
|
||||
aspectRatio: 16 / 9,
|
||||
maxHeight: window.innerHeight - 155 + 'px',
|
||||
maxWidth: 'auto',
|
||||
}
|
||||
|
||||
let transforms = ''
|
||||
@ -79,7 +66,10 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
|
||||
if ('flipX' in this.camSettings && this.camSettings.flipY) transforms += ' scaleY(-1)'
|
||||
if (transforms.trimStart().length) output.transform = transforms.trimStart()
|
||||
|
||||
if (this.aspectRatio) output.aspectRatio = this.aspectRatio
|
||||
if (this.aspectRatio) {
|
||||
output.aspectRatio = this.aspectRatio
|
||||
output.maxWidth = (window.innerHeight - 155) * this.aspectRatio + 'px'
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
@ -252,3 +242,20 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.webcamImage {
|
||||
width: 100%;
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
.webcamFpsOutput {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
padding: 3px 10px;
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,21 +1,5 @@
|
||||
<style scoped>
|
||||
.webcamImage {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.webcamFpsOutput {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
padding: 3px 10px;
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div style="position: relative">
|
||||
<div style="position: relative" class="d-flex justify-center">
|
||||
<div v-if="!isLoaded" class="text-center py-5">
|
||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
||||
</div>
|
||||
@ -44,7 +28,8 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
private isVisibleDocument = true
|
||||
private isVisibleViewport = false
|
||||
private isLoaded = true
|
||||
private timer: number | undefined = undefined
|
||||
// eslint-disable-next-line no-undef
|
||||
private timer: NodeJS.Timeout | undefined = undefined
|
||||
|
||||
private request_start_time = performance.now()
|
||||
private start_time = performance.now()
|
||||
@ -67,6 +52,8 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
const output = {
|
||||
transform: 'none',
|
||||
aspectRatio: 16 / 9,
|
||||
maxHeight: window.innerHeight - 155 + 'px',
|
||||
maxWidth: 'auto',
|
||||
}
|
||||
|
||||
let transforms = ''
|
||||
@ -75,7 +62,10 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
if ((this.camSettings.rotate ?? 0) === 180) transforms += ' rotate(180deg)'
|
||||
if (transforms.trimStart().length) output.transform = transforms.trimStart()
|
||||
|
||||
if (this.aspectRatio) output.aspectRatio = this.aspectRatio
|
||||
if (this.aspectRatio) {
|
||||
output.aspectRatio = this.aspectRatio
|
||||
output.maxWidth = (window.innerHeight - 155) * this.aspectRatio + 'px'
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
@ -114,10 +104,10 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
canvas.width = canvas.clientWidth
|
||||
if (this.rotate) {
|
||||
if (this.aspectRatio === null) this.aspectRatio = frame.height / frame.width
|
||||
canvas.height = canvas.clientWidth / (frame.height / frame.width)
|
||||
canvas.height = canvas.clientWidth / this.aspectRatio
|
||||
} else {
|
||||
if (this.aspectRatio === null) this.aspectRatio = frame.width / frame.height
|
||||
canvas.height = canvas.clientWidth * (frame.width / frame.height)
|
||||
canvas.height = canvas.clientWidth * this.aspectRatio
|
||||
}
|
||||
|
||||
if (this.rotate) {
|
||||
@ -223,3 +213,19 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.webcamImage {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.webcamFpsOutput {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
padding: 3px 10px;
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,17 +1,12 @@
|
||||
<style scoped>
|
||||
.webcamImage {
|
||||
width: 100%;
|
||||
background: lightgray;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<img
|
||||
ref="webcamUv4lMjpegImage"
|
||||
v-observe-visibility="viewportVisibilityChanged"
|
||||
:style="webcamStyle"
|
||||
class="webcamImage"
|
||||
@load="onload" />
|
||||
<div class="d-flex justify-center">
|
||||
<img
|
||||
ref="webcamUv4lMjpegImage"
|
||||
v-observe-visibility="viewportVisibilityChanged"
|
||||
:style="webcamStyle"
|
||||
class="webcamImage"
|
||||
@load="onload" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -45,6 +40,8 @@ export default class Uv4lMjpeg extends Mixins(BaseMixin) {
|
||||
const output = {
|
||||
transform: 'none',
|
||||
aspectRatio: 16 / 9,
|
||||
maxHeight: window.innerHeight - 155 + 'px',
|
||||
maxWidth: 'auto',
|
||||
}
|
||||
|
||||
let transforms = ''
|
||||
@ -52,7 +49,10 @@ export default class Uv4lMjpeg extends Mixins(BaseMixin) {
|
||||
if ('flipX' in this.camSettings && this.camSettings.flipY) transforms += ' scaleY(-1)'
|
||||
if (transforms.trimStart().length) output.transform = transforms.trimStart()
|
||||
|
||||
if (this.aspectRatio) output.aspectRatio = this.aspectRatio
|
||||
if (this.aspectRatio) {
|
||||
output.aspectRatio = this.aspectRatio
|
||||
output.maxWidth = (window.innerHeight - 155) * this.aspectRatio + 'px'
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
@ -116,3 +116,10 @@ export default class Uv4lMjpeg extends Mixins(BaseMixin) {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.webcamImage {
|
||||
width: 100%;
|
||||
background: lightgray;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user