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