functioning birdseye view

This commit is contained in:
Blake Blackshear 2021-06-12 09:55:40 -05:00
parent 0df35379ef
commit 89c2ae2208
8 changed files with 122 additions and 96 deletions

View File

@ -162,7 +162,7 @@ npm run test
#### 1. Installation #### 1. Installation
```console ```console
npm run install npm install
``` ```
#### 2. Local Development #### 2. Local Development

163
web/package-lock.json generated
View File

@ -2942,6 +2942,25 @@
"minimist": "^1.2.0" "minimist": "^1.2.0"
} }
}, },
"@cycjimmy/awesome-js-funcs": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@cycjimmy/awesome-js-funcs/-/awesome-js-funcs-2.5.0.tgz",
"integrity": "sha512-xy4MkuL8FcmRfWm0FwdHUCWB+EQ/ljCuTAf6d3SdaXPDgD4celrq0/vJT9ekLF0E6Au4fLbvRh1G8sXnGwDUkg=="
},
"@cycjimmy/jsmpeg-player": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-5.0.1.tgz",
"integrity": "sha512-x2kCCEfmXinebXC3d8XBJmOeFP+Jw0f4peT2rAmNvhggP1hYPvACP2ioobxeZvp255rPQTt/RPNi9y2SJ5ATMQ==",
"requires": {
"@cycjimmy/awesome-js-funcs": "^2.3.0",
"@cycjimmy/sass-lib": "^1.0.3"
}
},
"@cycjimmy/sass-lib": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@cycjimmy/sass-lib/-/sass-lib-1.0.3.tgz",
"integrity": "sha512-OTr8uMjeRapr0bWTKs782Jj84/xQt1XvVl5ZyYW1yi4sEbqY1FfW1FYLeflBp4gSU99o4c/nPi2Fx5aRxna5dw=="
},
"@dsherret/to-absolute-glob": { "@dsherret/to-absolute-glob": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", "resolved": "https://registry.npmjs.org/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
@ -4118,17 +4137,17 @@
"dev": true "dev": true
}, },
"@videojs/http-streaming": { "@videojs/http-streaming": {
"version": "2.6.4", "version": "2.9.0",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.6.4.tgz", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.9.0.tgz",
"integrity": "sha512-sFVE0MVXhawAkET8EgiUSMvDDv6u3uGidtO0BvNXG0/qKWlze/zEzhvLsyPU4HmLFRnffKeHK5RE2XpO5vHY8Q==", "integrity": "sha512-fRooepCcSYUKcplrn4h/teqL08Nr5bo4KDs8uGI6RAYOuDhGfWjaxFpmdUhr6Yme9G+ci+2Hh/hk9hHXxYGWaw==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.2",
"aes-decrypter": "3.1.2", "aes-decrypter": "3.1.2",
"global": "^4.4.0", "global": "^4.4.0",
"m3u8-parser": "4.5.2", "m3u8-parser": "4.7.0",
"mpd-parser": "0.15.4", "mpd-parser": "0.17.0",
"mux.js": "5.10.0", "mux.js": "5.11.0",
"video.js": "^6 || ^7" "video.js": "^6 || ^7"
}, },
"dependencies": { "dependencies": {
@ -4878,14 +4897,6 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true "dev": true
}, },
"chainsaw": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.0.9.tgz",
"integrity": "sha1-EaBRAtHEx4W20EFdM21aOhYSkT4=",
"requires": {
"traverse": ">=0.3.0 <0.4"
}
},
"chalk": { "chalk": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@ -6091,11 +6102,6 @@
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true "dev": true
}, },
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="
},
"esutils": { "esutils": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -6559,9 +6565,9 @@
} }
}, },
"glob-parent": { "glob-parent": {
"version": "5.1.1", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true, "dev": true,
"requires": { "requires": {
"is-glob": "^4.0.1" "is-glob": "^4.0.1"
@ -6685,14 +6691,6 @@
} }
} }
}, },
"hashish": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz",
"integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=",
"requires": {
"traverse": ">=0.2.4"
}
},
"himalaya": { "himalaya": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.0.tgz", "resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.0.tgz",
@ -8929,9 +8927,9 @@
"dev": true "dev": true
}, },
"m3u8-parser": { "m3u8-parser": {
"version": "4.5.2", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.5.2.tgz", "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.0.tgz",
"integrity": "sha512-sN/lu3TiRxmG2RFjZxo5c0/7Dr4RrEztl43jXrWwj5gFZ7vfa2iIxGfiPx485dm5QCazaIcKk+vNkUso8Aq0Ag==", "integrity": "sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.0",
@ -8953,6 +8951,7 @@
"version": "0.25.7", "version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
"dev": true,
"requires": { "requires": {
"sourcemap-codec": "^1.4.4" "sourcemap-codec": "^1.4.4"
} }
@ -9116,14 +9115,14 @@
"dev": true "dev": true
}, },
"mpd-parser": { "mpd-parser": {
"version": "0.15.4", "version": "0.17.0",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.15.4.tgz", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.17.0.tgz",
"integrity": "sha512-YcOclxKc5gnT87UQYwRoPJpWOFvQORwN+bXYmTWCJ4U2pCSS7jjtPrIhoOLHFAyekj48CHTX4hjGBV/VSNsUsg==", "integrity": "sha512-oKS5G0jCcHHJ3sHYlcLeM9Xcbuixl08eAx7QW0Th7ChlZiI0YvLtGaHE/L0aKUBJFNvtkeksIr8XgJgSBBsS4g==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.2",
"global": "^4.4.0", "global": "^4.4.0",
"xmldom": "^0.4.0" "xmldom": "^0.5.0"
}, },
"dependencies": { "dependencies": {
"global": { "global": {
@ -9157,9 +9156,9 @@
} }
}, },
"mux.js": { "mux.js": {
"version": "5.10.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.10.0.tgz", "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.11.0.tgz",
"integrity": "sha512-kLzvYsHYBwNa+ckkmpxWV3eImwntJbrwd1KbN4WR0hLe+dK/KB82aCuC0fQzAI2hkjYszdlSGsAWFgYdiFBUuA==", "integrity": "sha512-Q/iLfohHh5Pp6lW7EFtcxNuaCNJ3Ruywfy46pWLsY+yIxR1kXXImYY1wOhg8jLdBMs1kRaZqsiB4Zncsiw0a2Q==",
"requires": { "requires": {
"@babel/runtime": "^7.11.2" "@babel/runtime": "^7.11.2"
} }
@ -10281,14 +10280,6 @@
} }
} }
}, },
"remove": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/remove/-/remove-0.1.5.tgz",
"integrity": "sha1-CV/9gn1lyfQa2X0z5BanWBEHmVU=",
"requires": {
"seq": ">= 0.3.5"
}
},
"remove-trailing-separator": { "remove-trailing-separator": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@ -10473,23 +10464,6 @@
} }
} }
}, },
"rollup-plugin-replace": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz",
"integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==",
"requires": {
"magic-string": "^0.25.2",
"rollup-pluginutils": "^2.6.0"
}
},
"rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"requires": {
"estree-walker": "^0.6.1"
}
},
"rsvp": { "rsvp": {
"version": "4.8.5", "version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@ -10766,15 +10740,6 @@
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
} }
}, },
"seq": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/seq/-/seq-0.3.5.tgz",
"integrity": "sha1-rgKvOkJHk9jMvyEtaRdODFTf/jg=",
"requires": {
"chainsaw": ">=0.0.7 <0.1",
"hashish": ">=0.0.2 <0.1"
}
},
"set-blocking": { "set-blocking": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@ -11094,7 +11059,8 @@
"sourcemap-codec": { "sourcemap-codec": {
"version": "1.4.8", "version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true
}, },
"spdx-correct": { "spdx-correct": {
"version": "3.1.1", "version": "3.1.1",
@ -11575,11 +11541,6 @@
"punycode": "^2.1.1" "punycode": "^2.1.1"
} }
}, },
"traverse": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
"integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
},
"ts-morph": { "ts-morph": {
"version": "9.1.0", "version": "9.1.0",
"resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-9.1.0.tgz", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-9.1.0.tgz",
@ -11926,20 +11887,34 @@
} }
}, },
"video.js": { "video.js": {
"version": "7.11.8", "version": "7.13.0",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.11.8.tgz", "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.13.0.tgz",
"integrity": "sha512-iQmNYB+pdgu8b45Za1AKSa5J7uDyHIqfJy+picw4voKfjErXK/BEvs+A3f99Ck7SCZU4cmMmX/s17AwaaNs+1w==", "integrity": "sha512-wJcB2R5q3/6Ez5XUfpZBZTdgF321rX/M1HkDKxXQIdfsVi/pfP4l+equ2xL9O3X0XAPHRxLEegraIEuX28mRkA==",
"requires": { "requires": {
"@babel/runtime": "^7.9.2", "@babel/runtime": "^7.12.5",
"@videojs/http-streaming": "2.6.4", "@videojs/http-streaming": "2.9.0",
"@videojs/vhs-utils": "^3.0.2",
"@videojs/xhr": "2.5.1", "@videojs/xhr": "2.5.1",
"global": "4.3.2", "aes-decrypter": "3.1.2",
"global": "^4.4.0",
"keycode": "^2.2.0", "keycode": "^2.2.0",
"remove": "^0.1.5", "m3u8-parser": "4.7.0",
"rollup-plugin-replace": "^2.2.0", "mpd-parser": "0.17.0",
"mux.js": "5.11.0",
"safe-json-parse": "4.0.0", "safe-json-parse": "4.0.0",
"videojs-font": "3.2.0", "videojs-font": "3.2.0",
"videojs-vtt.js": "^0.15.2" "videojs-vtt.js": "^0.15.3"
},
"dependencies": {
"global": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
"requires": {
"min-document": "^2.19.0",
"process": "^0.11.10"
}
}
} }
}, },
"videojs-font": { "videojs-font": {
@ -12138,9 +12113,9 @@
"dev": true "dev": true
}, },
"xmldom": { "xmldom": {
"version": "0.4.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.4.0.tgz", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz",
"integrity": "sha512-2E93k08T30Ugs+34HBSTQLVtpi6mCddaY8uO+pMNk1pqSjV5vElzn4mmh6KLxN3hki8rNcHSYzILoh3TEWORvA==" "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA=="
}, },
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",

View File

@ -11,13 +11,14 @@
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"@cycjimmy/jsmpeg-player": "^5.0.1",
"date-fns": "^2.21.3", "date-fns": "^2.21.3",
"idb-keyval": "^5.0.2", "idb-keyval": "^5.0.2",
"immer": "^8.0.1", "immer": "^8.0.1",
"preact": "^10.5.9", "preact": "^10.5.9",
"preact-async-route": "^2.2.1", "preact-async-route": "^2.2.1",
"preact-router": "^3.2.1", "preact-router": "^3.2.1",
"video.js": "^7.11.8", "video.js": "^7.13.0",
"videojs-playlist": "^4.3.1", "videojs-playlist": "^4.3.1",
"videojs-seek-buttons": "^2.0.1" "videojs-seek-buttons": "^2.0.1"
}, },

View File

@ -27,6 +27,7 @@ export default function App() {
<Router> <Router>
<AsyncRoute path="/cameras/:camera/editor" getComponent={Routes.getCameraMap} /> <AsyncRoute path="/cameras/:camera/editor" getComponent={Routes.getCameraMap} />
<AsyncRoute path="/cameras/:camera" getComponent={Routes.getCamera} /> <AsyncRoute path="/cameras/:camera" getComponent={Routes.getCamera} />
<AsyncRoute path="/birdseye" getComponent={Routes.getBirdseye} />
<AsyncRoute path="/events/:eventId" getComponent={Routes.getEvent} /> <AsyncRoute path="/events/:eventId" getComponent={Routes.getEvent} />
<AsyncRoute path="/events" getComponent={Routes.getEvents} /> <AsyncRoute path="/events" getComponent={Routes.getEvents} />
<AsyncRoute path="/recording/:camera/:date?/:hour?/:seconds?" getComponent={Routes.getRecording} /> <AsyncRoute path="/recording/:camera/:date?/:hour?/:seconds?" getComponent={Routes.getRecording} />

View File

@ -49,6 +49,7 @@ export default function Sidebar() {
) : null ) : null
} }
</Match> </Match>
<Destination href="/birdseye" text="Birdseye" />
<Destination href="/events" text="Events" /> <Destination href="/events" text="Events" />
<Destination href="/debug" text="Debug" /> <Destination href="/debug" text="Debug" />
<Separator /> <Separator />

View File

@ -0,0 +1,29 @@
import { h } from 'preact';
import { baseUrl } from '../api/baseUrl';
import { useRef, useEffect } from 'preact/hooks';
import JSMpeg from '@cycjimmy/jsmpeg-player';
export default function JSMpegPlayer({ camera }) {
const playerRef = useRef();
const canvasRef = useRef();
const url = `${baseUrl.replace(/^http/, 'ws')}/live/${camera}`
useEffect(() => {
const video = new JSMpeg.VideoElement(
playerRef.current,
url,
{canvas: canvasRef.current},
{protocols: []}
);
return () => {
video.destroy();
};
}, [url]);
return (
<div ref={playerRef} className="jsmpeg">
<canvas ref={canvasRef} className="relative w-full" />
</div>
);
}

View File

@ -0,0 +1,14 @@
import { h } from 'preact';
import JSMpegPlayer from '../components/JSMpegPlayer';
import Heading from '../components/Heading';
export default function Birdseye() {
return (
<div className="space-y-4">
<Heading size="2xl">Birdseye</Heading>
<div>
<JSMpegPlayer camera="birdseye" />
</div>
</div>
);
}

View File

@ -13,6 +13,11 @@ export async function getEvent(url, cb, props) {
return module.default; return module.default;
} }
export async function getBirdseye(url, cb, props) {
const module = await import('./Birdseye.jsx');
return module.default;
}
export async function getEvents(url, cb, props) { export async function getEvents(url, cb, props) {
const module = await import('./Events.jsx'); const module = await import('./Events.jsx');
return module.default; return module.default;