mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-12-05 07:12:34 -05:00
UI: improve aspect ratio handling
As written in the changelog: Live streams formerly worked around a Firefox pixel aspect ratio bug by forcing all videos to 16:9, which dramatically distorted 9:16 camera views. Playback didn't, so anamorphic videos looked correct on Chrome but slightly stretched on Firefox. Now both live streams and playback are fully correct on all browsers.
This commit is contained in:
@@ -17,7 +17,9 @@ interface Props {
|
||||
range90k: [number, number] | null;
|
||||
split90k?: number;
|
||||
trimStartAndEnd: boolean;
|
||||
setActiveRecording: (recording: [Stream, api.Recording] | null) => void;
|
||||
setActiveRecording: (
|
||||
recording: [Stream, api.Recording, api.VideoSampleEntry] | null
|
||||
) => void;
|
||||
formatTime: (time90k: number) => string;
|
||||
}
|
||||
|
||||
@@ -169,7 +171,7 @@ const VideoList = ({
|
||||
<Row
|
||||
key={r.startId}
|
||||
className="recording"
|
||||
onClick={() => setActiveRecording([stream, r])}
|
||||
onClick={() => setActiveRecording([stream, r, vse])}
|
||||
start={formatTime(start)}
|
||||
end={formatTime(end)}
|
||||
resolution={`${vse.width}x${vse.height}`}
|
||||
|
||||
@@ -18,6 +18,9 @@ import DisplaySelector, { DEFAULT_DURATION } from "./DisplaySelector";
|
||||
import StreamMultiSelector from "./StreamMultiSelector";
|
||||
import TimerangeSelector from "./TimerangeSelector";
|
||||
import VideoList from "./VideoList";
|
||||
import { useLayoutEffect } from "react";
|
||||
import { fillAspect } from "../aspect";
|
||||
import useResizeObserver from "@react-hook/resize-observer";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
root: {
|
||||
@@ -64,13 +67,33 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
"& video": {
|
||||
objectFit: "contain",
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
objectFit: "fill",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
interface FullScreenVideoProps {
|
||||
src: string;
|
||||
aspect: [number, number];
|
||||
}
|
||||
|
||||
/**
|
||||
* A video sized for the entire document window constrained to aspect ratio.
|
||||
* This is particularly helpful for Firefox (89), which doesn't honor the
|
||||
* pixel aspect ratio specified in .mp4 files. Thus we need to specify it
|
||||
* out-of-band.
|
||||
*/
|
||||
const FullScreenVideo = ({ src, aspect }: FullScreenVideoProps) => {
|
||||
const ref = React.useRef<HTMLVideoElement>(null);
|
||||
useLayoutEffect(() => {
|
||||
fillAspect(document.body.getBoundingClientRect(), ref, aspect);
|
||||
});
|
||||
useResizeObserver(document.body, (entry: ResizeObserverEntry) => {
|
||||
fillAspect(entry.contentRect, ref, aspect);
|
||||
});
|
||||
return <video ref={ref} controls preload="auto" autoPlay src={src} />;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
timeZoneName: string;
|
||||
cameras: Camera[];
|
||||
@@ -98,7 +121,7 @@ const Main = ({ cameras, timeZoneName, showSelectors }: Props) => {
|
||||
const [timestampTrack, setTimestampTrack] = useState(false);
|
||||
|
||||
const [activeRecording, setActiveRecording] = useState<
|
||||
[Stream, api.Recording] | null
|
||||
[Stream, api.Recording, api.VideoSampleEntry] | null
|
||||
>(null);
|
||||
const formatTime = useMemo(() => {
|
||||
return (time90k: number) => {
|
||||
@@ -160,10 +183,7 @@ const Main = ({ cameras, timeZoneName, showSelectors }: Props) => {
|
||||
{videoLists.length > 0 && recordingsTable}
|
||||
{activeRecording != null && (
|
||||
<Modal open onClose={closeModal} className={classes.videoModal}>
|
||||
<video
|
||||
controls
|
||||
preload="auto"
|
||||
autoPlay
|
||||
<FullScreenVideo
|
||||
src={api.recordingUrl(
|
||||
activeRecording[0].camera.uuid,
|
||||
activeRecording[0].streamType,
|
||||
@@ -171,6 +191,10 @@ const Main = ({ cameras, timeZoneName, showSelectors }: Props) => {
|
||||
timestampTrack,
|
||||
trimStartAndEnd ? range90k! : undefined
|
||||
)}
|
||||
aspect={[
|
||||
activeRecording[2].aspectWidth,
|
||||
activeRecording[2].aspectHeight,
|
||||
]}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user