-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for NGINX VOD Module #1116
Add support for NGINX VOD Module #1116
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope these comments/notes are helpful as you look through this.
|
||
try: | ||
server.serve_forever() | ||
except KeyboardInterrupt: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't necessarily belong as a part of this PR, but in testing I noticed some exceptions being raised on ctrl+C
so this handles it.
@@ -35,7 +35,7 @@ def log_process(log_queue): | |||
while True: | |||
try: | |||
record = log_queue.get(timeout=5) | |||
except queue.Empty: | |||
except (queue.Empty, KeyboardInterrupt): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above, an exception was being raised here on shutdown, so handling it here.
@@ -446,10 +449,37 @@ def latest_frame(camera_name): | |||
return "Camera named {} not found".format(camera_name), 404 | |||
|
|||
|
|||
@bp.route("/vod/<path:path>") | |||
def vod(path): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This builds a JSON object to be consumed by nginx-vod-module
. Currently we are just using the existing recording path, but can expand this to add additional filters or functionality later.
@@ -0,0 +1,46 @@ | |||
FROM ubuntu:20.04 AS base |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to build NGINX from source to include support for aio files and multiple architectures. nginx-vod-module
has a repo we could add, but it is only built for amd64
.
@@ -18,16 +20,13 @@ ENV DEBIAN_FRONTEND=noninteractive | |||
# Install packages for apt repo | |||
RUN apt-get -qq update \ | |||
&& apt-get upgrade -y \ | |||
&& apt-get -qq install --no-install-recommends -y \ | |||
gnupg wget unzip tzdata nginx libnginx-mod-rtmp \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removing nginx
and libnginx-mod-rtmp
as they are built-in to our compiled version of NGINX along with nginx-vod-module
.
Will update docs before you merge if this looks like a good path forward to you. |
clips.append({"type": "source", "path": filename}) | ||
video = cv2.VideoCapture(filename) | ||
duration = int( | ||
video.get(cv2.CAP_PROP_FRAME_COUNT) / video.get(cv2.CAP_PROP_FPS) * 1000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How long does it take to do this dynamically? It could take a while if using a network drive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s two seconds on my dev machine, but it’s also pretty beefy and the files were local. I almost just hardcoded the 60 seconds here, but know that the command (and thus the time) can be changed in configuration.
I saw the use of ffprobe elsewhere for clips, but since OpenCV was already imported and this stackoverflow answer said it was faster, I just used it. Granted I did not do any verification myself. It’s probably worth a shot testing this on a Pi with video on a network drive to see.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verified timing in comment below.
Just out of curiosity, what benefits would this have for the 'clips' feature? |
This doesn't really have any benefit for clips as they are non-continuous and already are the length you expect them to be. This is just a way to combine the 60 second recording files together in an hour long video to make viewing the 24/7 recording easier. What we could do, eventually, is in the front-end automatically add markers to the timeline for the continuous recording at the timestamps that events occurred to be able to seek to them with relative ease. |
I literally just built a small script to generate a downloadable mp4 file to facilitate large chunks of time. I'm wondering if instead of Then you just glob the files and do a greater than/less than check. You could default to the last 60 minutes. This is my relevant bash code: file_list=$(ls **/**/**/$CAMERA/*.mp4)
real_list=()
for file in $file_list; do
if [ "$file" \> "$START_FILE" ] && [ "$file" \< "$END_FILE" ]; then
real_list+=("file '$PWD/$file'")
fi
done |
I honestly think that's the next step, but wanted to keep the initial implementation simple (easier to review just the relevant VOD module code) and expand the functionality of filters/etc in a follow-up PR. |
If you take a look at the PR I opened against your branch, I illustrated what I meant (I haven't tested it fully yet), but, tbh, I don't think it's too much more complicated. |
After some initial testing, query string parameters do not get passed on from the VOD module. We can do some path based filtering like |
I was afraid of that. Everyone knows you shouldn’t use the directory tree as a database. Might be best to table it like you said and work on optimizing how we look up available recordings and clips |
Did some testing on the Glob: 0.000562 versus FFProbe that is used to verify clips and recordings: Glob: 0.000504 Granted it is a Ryzen 3900x so it may take longer on a Raspberry Pi, but it's encouraging that the OpenCV method is not only faster than a ffprobe sub process, but is less lines of code as well. Trying to load something like 24 hours worth of video would take 53 seconds however, which is too inefficient for the initial release. I also have NGINX aggressively caching these manifests for 100 days, so this lookup is only seen the first time you load the VOD. The only other option would be to default duration to 60, as that is what it will be the vast majority of time. I figured if it didn't take too long to be certain though, it's better for cases where recordings ended early or a user modified the recording segment time in their configuration. I'm happy with this PR now - the next commit updating docs should be the last. |
@blakeblackshear - could you run the nginx make command to push the images to docker hub? That would make it so others can successfully build frigate. |
My buildx command is failing to build the armv7 image. Did you do some set up to get it to work? |
No, it built just fine for me. What step does it fail at? |
Built and pushed for all 3 architectures here: https://hub.docker.com/r/hunterjm/frigate-nginx/tags?page=1&ordering=last_updated |
Got it working with these steps. Mine are pushed. |
This adds support for viewing recordings as a "video on demand". It can be tested by loading the stream URL into this demo site or VLC.
The VOD stream format currently follows the recording directory format - i.e.: http:https://localhost:5000/vod/2021-05/17/20/{camera}/master.m3u8
This first version is obviously limited to an hour's worth of recordings based on the current recording file structure. We can expand it later by modifying the
vod
function inhttp.py
. Regardless, The Home Assistant integration can be updated to use this new URL to allow Media Browser recordings of entire hour long segments without having to use FFMPEG to combine the videos. The Web UI can also use this along with something likevideojs
to build a recording playback page. I left the/recordings
directive in tact for backwards compatibility until things switch over.