Add jsmpeg support to new webUI and make birdseye default for live page (#8995)

* Add jsmpeg and make birdseye default for live view

* Fix jsmpeg

* Fix
This commit is contained in:
Nicolas Mowen
2023-12-20 07:34:27 -07:00
committed by Blake Blackshear
parent 1a27c7db29
commit 2236ae5d3b
5 changed files with 164 additions and 19 deletions

View File

@@ -0,0 +1,36 @@
import WebRtcPlayer from "./WebRTCPlayer";
import { BirdseyeConfig } from "@/types/frigateConfig";
import ActivityIndicator from "../ui/activity-indicator";
import JSMpegPlayer from "./JSMpegPlayer";
type LivePlayerProps = {
birdseyeConfig: BirdseyeConfig;
liveMode: string;
};
export default function BirdseyeLivePlayer({
birdseyeConfig,
liveMode,
}: LivePlayerProps) {
if (liveMode == "webrtc") {
return (
<div className="max-w-5xl">
<WebRtcPlayer camera="birdseye" />
</div>
);
} else if (liveMode == "mse") {
return <div className="max-w-5xl">Not yet implemented</div>;
} else if (liveMode == "jsmpeg") {
return (
<div className={`max-w-[${birdseyeConfig.width}px]`}>
<JSMpegPlayer
camera="birdseye"
width={birdseyeConfig.width}
height={birdseyeConfig.height}
/>
</div>
);
} else {
<ActivityIndicator />;
}
}

View File

@@ -0,0 +1,94 @@
import { baseUrl } from "@/api/baseUrl";
import { useResizeObserver } from "@/hooks/resize-observer";
// @ts-ignore we know this doesn't have types
import JSMpeg from "@cycjimmy/jsmpeg-player";
import { useEffect, useMemo, useRef } from "react";
type JSMpegPlayerProps = {
camera: string;
width: number;
height: number;
};
export default function JSMpegPlayer({
camera,
width,
height,
}: JSMpegPlayerProps) {
const url = `${baseUrl.replace(/^http/, "ws")}live/jsmpeg/${camera}`;
const playerRef = useRef<HTMLDivElement | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const [{ width: containerWidth }] = useResizeObserver(containerRef);
// Add scrollbar width (when visible) to the available observer width to eliminate screen juddering.
// https://github.com/blakeblackshear/frigate/issues/1657
let scrollBarWidth = 0;
if (window.innerWidth && document.body.offsetWidth) {
scrollBarWidth = window.innerWidth - document.body.offsetWidth;
}
const availableWidth = scrollBarWidth
? containerWidth + scrollBarWidth
: containerWidth;
const aspectRatio = width / height;
const scaledHeight = useMemo(() => {
const scaledHeight = Math.floor(availableWidth / aspectRatio);
const finalHeight = Math.min(scaledHeight, height);
if (finalHeight > 0) {
return finalHeight;
}
return 100;
}, [availableWidth, aspectRatio, height]);
const scaledWidth = useMemo(
() => Math.ceil(scaledHeight * aspectRatio - scrollBarWidth),
[scaledHeight, aspectRatio, scrollBarWidth]
);
useEffect(() => {
if (!playerRef.current) {
return;
}
console.log("player ref exists and creating video");
const video = new JSMpeg.VideoElement(
playerRef.current,
url,
{},
{ protocols: [], audio: false, videoBufferSize: 1024 * 1024 * 4 }
);
const fullscreen = () => {
if (video.els.canvas.webkitRequestFullScreen) {
video.els.canvas.webkitRequestFullScreen();
} else {
video.els.canvas.mozRequestFullScreen();
}
};
video.els.canvas.addEventListener("click", fullscreen);
return () => {
if (playerRef.current) {
try {
video.destroy();
} catch (e) {}
playerRef.current = null;
}
};
}, [url]);
return (
<div ref={containerRef}>
<div
ref={playerRef}
className={`jsmpeg`}
style={{
height: `${scaledHeight}px`,
width: `${scaledWidth}px`,
}}
/>
</div>
);
}

View File

@@ -9,6 +9,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
import { Switch } from "../ui/switch";
import { Label } from "../ui/label";
import { usePersistence } from "@/hooks/use-persistence";
import JSMpegPlayer from "./JSMpegPlayer";
const emptyObject = Object.freeze({});
@@ -66,7 +67,11 @@ export default function LivePlayer({
} else if (liveMode == "jsmpeg") {
return (
<div className={`max-w-[${cameraConfig.detect.width}px]`}>
Not Yet Implemented
<JSMpegPlayer
camera={cameraConfig.name}
width={cameraConfig.detect.width}
height={cameraConfig.detect.height}
/>
</div>
);
} else if (liveMode == "debug") {