Dynamically extract dimensions from loaded media.

This commit is contained in:
Dermot Duffy
2021-09-23 20:38:39 -07:00
parent c75e99e09c
commit e3ccbb0787
13 changed files with 312 additions and 44 deletions
+33 -9
View File
@@ -7,7 +7,7 @@ import { signedPathSchema } from '../types';
import type { ExtendedHomeAssistant, FrigateCardConfig } from '../types';
import { localize } from '../localize/localize';
import { homeAssistantWSRequest } from '../common';
import { dispatchMediaLoadEvent, homeAssistantWSRequest } from '../common';
import {
renderMessage,
renderErrorMessage,
@@ -68,13 +68,13 @@ export class FrigateCardViewerFrigate extends LitElement {
if (!(this.cameraEntity in this.hass.states)) {
return renderMessage(localize('error.no_live_camera'), 'mdi:camera-off');
}
return html` <ha-camera-stream
return html` <frigate-card-ha-camera-stream
.hass=${this.hass}
.stateObj=${this.hass.states[this.cameraEntity]}
.controls=${true}
.muted=${true}
>
</ha-camera-stream>`;
</frigate-card-ha-camera-stream>`;
}
static get styles(): CSSResultGroup {
@@ -119,6 +119,19 @@ export class FrigateCardViewerWebRTC extends LitElement {
return html`${this._webRTCElement}`;
}
public updated(): void {
// Extract the video component after it has been rendered and generate the
// media load event.
this.updateComplete.then(() => {
const video = this.renderRoot.querySelector('#video') as HTMLVideoElement;
if (video) {
video.onloadedmetadata = () => {
dispatchMediaLoadEvent(this, video);
}
}
})
}
static get styles(): CSSResultGroup {
return unsafeCSS(liveStyle);
}
@@ -135,7 +148,7 @@ export class FrigateCardViewerJSMPEG extends LitElement {
@property({ attribute: false })
protected clientId!: string;
protected _jsmpegCanvasElement: HTMLElement | null = null;
protected _jsmpegCanvasElement: HTMLCanvasElement | null = null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected _jsmpegVideoPlayer: any | null = null;
@@ -187,10 +200,7 @@ export class FrigateCardViewerJSMPEG extends LitElement {
return renderErrorMessage('Could not retrieve or sign JSMPEG websocket path');
}
// Return the html canvas node only after the JSMPEG video has loaded and
// is playing, to reduce the amount of time the user is staring at a blank
// white canvas (instead they get the progress spinner until this promise
// resolves).
let videoDecoded = false;
return new Promise<TemplateResult>((resolve) => {
this._jsmpegVideoPlayer = new JSMpeg.VideoElement(
this,
@@ -198,12 +208,26 @@ export class FrigateCardViewerJSMPEG extends LitElement {
{
canvas: this._jsmpegCanvasElement,
hooks: {
// Don't resolve the promise until it's playing to minimize the
// amount of time the canvas is empty (and show the spinner
// instead).
play: () => {
resolve(html`${this._jsmpegCanvasElement}`);
},
},
},
{ protocols: [], videoBufferSize: 1024 * 1024 * 4 },
{ protocols: [],
videoBufferSize: 1024 * 1024 * 4,
onVideoDecode: () => {
// This is the only callback that is called after the dimensions
// are available. It's called on every frame decode, so just
// ignore any subsequent calls.
if (!videoDecoded && this._jsmpegCanvasElement) {
videoDecoded = true;
dispatchMediaLoadEvent(this, this._jsmpegCanvasElement);
}
}
},
);
});
}