Code Monkey home page Code Monkey logo

moonfire-nvr's People

Contributors

clydebarrow avatar dependabot[bot] avatar dolfs avatar dsupru avatar ironoxidizer avatar jlpoolen avatar katyo avatar krystadev avatar ldfsilva avatar michioxd avatar scottlamb avatar sky1e avatar tim-seoss avatar valpackett avatar zetafunc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

moonfire-nvr's Issues

cross-compile to ARM

Compiling Rust code on ARM is really really slow. I've seen cases where my Pi2 simply can't do it due to lack of RAM. Figure out how to cross-compile Moonfire NVR from x86-64 to ARM and write up instructions.

I've done some work / wrote down some notes in a Google doc but haven't gotten a fully working setup.

on-camera motion detection with ONVIF

Realistically speaking any decent NVR must have motion detection. On-camera motion detection is one of the two paths forward. Marking milestone-1.0? accordingly.

Needs the signals schema (#28). Additionally, needs to speak SOAP in some way:

  • pure Rust SOAP library? raventid/soap-rs is the only one I've found; it's not usable yet.
  • C/C++ SOAP library? xris-hu/gsoap-onvif or xsmart/onvifcpplib?
  • just do the little bit of SOAP we need by hand? I noticed there's some node onvif library that does this, so maybe it's not so bad.

I'd also considered using Hikvision's simple non-SOAP/ONVIF proprietary protocol, but then Dahua came out with the Starlight camera series, and I bought one...I've even got some code to watch Hikvision camera motion events but it's much less appealing to me now.

user authentication

Current status: functional but some features missing:

  • schema for users and sessions
  • moonfire-nvr config for users
  • API endpoints to log in and out
  • check authentication status on API requests
  • moonfire-nvr login command to make a new session from the CLI (mostly for tools to use)
  • add the Varies: cookie or whatever headers to ensure authenticated and unauthenticated requests don't get mixed up in caches.
  • document how to set up a nginx proxy properly. (I have it working on my setup, though.)
  • consider tighter security (__Host + SameSite=strict) when using tls. currently it uses Secure; SameSite=Lax. (Update: I'm happy with the status quo.)
  • add an endpoint that shows what the auth request looks like, to ensure the nginx configuration + --trust-forward-hdrs are working together properly.
  • add ability to invalidate existing sessions.
  • add endpoint to see existing sessions associated with an account + use in JS
  • add a password change endpoint + use in JS
  • add some restriction on when insecure cookies can be served. They're useful for development with a WebPack proxy server (yarn start) but shouldn't ever be served in production. Maybe restrict via the Host header.

Original issue text:

I want proper user authentication; this (along with some manner of https) is a precondition of exposing Moonfire NVR to the Internet.

As @dolfs said, a temporary measure could be to do basic HTTP with a apache/nginx frontend. But I think it shouldn't be too bad to do a proper built-in thing.

Here's my proposal.

https is a prerequisite. (either built-in or through a proxy.)

You can create/delete/modify users through moonfire-nvr config.

Creating a session could be simply password-based. Some things that I consider out of scope:

  • two-factor authentication (maybe later)
  • email-based password recovery (maybe later)
  • web-based password changes (later)
  • OAuth2 (probably never; I want it to work without an Internet connection)
  • protection against online brute force attacks: rate limiting and/or auto password disable after too many failed guesses (maybe later; you've gotta pick a good password for now)
  • even logging of auth failures (likewise; pick a really good password for now)
  • roles / permissions (for now, the web interface is read-only, and everyone can read everything)
  • user/device settings, such as UI preferences stored on the server side (maybe later)

Sessions could simply be a long random number, stored as a hash for the same reason people hash passwords: so a database leak doesn't trivially compromise the credentials. (They should need to edit the database for to gain access, which may be harder to do than getting an old backup, and which leaves more evidence behind.)

Straw man schema:

create table users (
  id integer primary key,
  username unique not null,

  -- If set, a hash for password authentication, as generated by `libpasta::hash_password`.
  password_hash text,
  password_id integer not null default 0,  -- increasing with password sets/clears.
  password_failure_count integer not null,  -- updated lazily; reset when password_id incremented.

  -- If set, a Unix UID that is accepted for authentication when using HTTP over
  -- a Unix domain socket. (Additionally, the UID running Moonfire NVR can authenticate
  -- as anyone; there's no point in trying to do otherwise.) This might be an easy
  -- bootstrap method once configuration happens through a web UI rather than text UI.
  unix_uid integer
);

create table user_sessions (
  user_id integer references user (id),
  hashed_session_id blob unique not null,  -- hash function TBD
  creation_password_id integer not null, -- the id it was created from
  creation_peer_addr blob not null,  -- IPv4 or IPv6 address
  creation_time integer not null,  -- sec since epoch
  creation_user_agent text,
  revocation_time integer, -- likewise
  description text, -- probably a device name
  last_use_time integer,  -- updated lazily on flush
  use_count not null -- likewise
);

Typical sessions should probably be represented as cookies with the HttpOnly flag set (meaning not accessible to Javascript). If a hit on /api/... lacks the cookie, it should return a HTTP 401 which the Javascript knows means to redirect the browser to /login, a simple HTML login form which on success sets the cookie and redirects back.

The cookies should also be secure (meaning only sent over https, not http).

There should also be a way of getting a session id for use by some automated thing. Example: a program that dumps events into the database based on my Elk security system's zone status. Something you can paste into its config file. Better to have separate, high-entropy credentials where possible so you can see what was compromised and disable it independently of the others.

mobile-friendly UI

The current (table-based) UI is meant to be temporary (see #32) but will probably last a while longer.

It's quite unpleasant to use on a phone. Some ideas to improve this:

  • the page is too wide. Maybe the div#nav on the left could be a pull-out menu, or just stacked on top rather than on the left. Maybe the column list could be trimmed to the essentials (just start and end time really).
  • time entry is awkward. there's probably some input attribute to create a keyboard with just number keys and colons, not all the alpha keys.
  • it should be easier to switch from main streams to more bandwidth-friendly sub streams, rather than tapping literally all the checkboxes. Maybe default to sub streams. Maybe make the "main" and "sub" table labels themselves clickable and toggle everything.
  • when you tap on a video, it opens a window that's meant to be draggable and resizable, but I'm not sure that's even possible on mobile. And when it's a sub stream, it's too small to manipulate at all (I think the go full-screen button is missing on Chrome/Android). It might make more sense to just always open full-screen instead.
  • the error handling is poor, which is particularly noticeable on a flaky connection like a freshly-connected captive portal. It sometimes shows the (cached) main page and no streams (because the api requests have a dynamic url parameter that makes them non-cacheable). Anything would be better, like a butter-bar at the top.

Seg fault

Hello,

I am getting a Segfault all the time.

It seems to happen right here:

I0508 232630.200 stream-Auffahrt moonfire_nvr::streamer] Auffahrt: Opening input: rtsp://*:[email protected]:554/unicast
rt_sigaction(SIGTERM, {0x54bde2f4, [], SA_RESTORER|SA_RESTART|SA_SIGINFO|SA_NOCLDSTOP, 0x75d031a0}, {SIG_DFL, [], 0}, 8) = 0
clock_gettime(CLOCK_REALTIME, {1494278790, 201676377}) = 0
clock_gettime(CLOCK_MONOTONIC, {634483, 68003909}) = 0
futex(0x749ff81c, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x749ff818, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x749ff7fc, FUTEX_WAKE_PRIVATE, 1) = 1
I0508 232630.201 main moonfire_nvr::cmds::run] Ready to serve HTTP requests
clock_gettime(CLOCK_MONOTONIC, {634483, 68300106}) = 0
epoll_wait(9, {{EPOLLOUT, {u32=4, u64=4}}}, 1024, 0) = 1
clock_gettime(CLOCK_MONOTONIC, {634483, 68471043}) = 0
clock_gettime(CLOCK_MONOTONIC, {634483, 68547137}) = 0
epoll_wait(9, {}, 1024, 0) = 0
clock_gettime(CLOCK_MONOTONIC, {634483, 68773334}) = 0
clock_gettime(CLOCK_MONOTONIC, {634483, 68842761}) = 0
epoll_wait(9, [rtsp @ 0x73e16000] Estimating duration from bitrate, this may be inaccurate
I0508 232634.707 stream-Auffahrt moonfire_nvr::stream] Discarding the first packet to work around https://trac.ffmpeg.org/ticket/5018
<unfinished ...>
+++ killed by SIGSEGV +++
Segmentation fault

The camera is running the fang hacks on a Xiaomi Wifi Cam.

Any ideas what could be missing?

ffmpeg
ffmpeg version 2.8.11 Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 4.9.2 (Raspbian 4.9.2-10)
configuration: --arch=armel --target-os=linux --enable-gpl --enable-libx264 --enable-nonfree
libavutil 54. 31.100 / 54. 31.100
libavcodec 56. 60.100 / 56. 60.100
libavformat 56. 40.101 / 56. 40.101
libavdevice 56. 4.100 / 56. 4.100
libavfilter 5. 40.101 / 5. 40.101
libswscale 3. 1.101 / 3. 1.101
libswresample 1. 2.101 / 1. 2.101
libpostproc 53. 3.100 / 53. 3.100

Kind Regards,
Christoph

Moonfire crash

Found a crash tonight. This is probably an FYI and sort of duplicate of another issue regarding lack of robustness of the server against malformed API urls. At the time of this crash I was experiment with code and may have requested /api/cameras//view.mp4 without any query parameters.

Mar  9 23:23:33 moonfire moonfire-nvr[19022]: syncer moonfire_nvr::db] reserved 76201128-68f3-4ae4-a38d-265aec54a825
Mar  9 23:23:46 moonfire moonfire-nvr[19022]: syncer moonfire_nvr::dir] Back: deleting 10382181 bytes in 1 recordings (8773611 bytes needed)
Mar  9 23:23:46 moonfire moonfire-nvr[19022]: syncer moonfire_nvr::db] reserved 78bc3dda-2f20-4d27-b56f-fb1ced4cf4b8
Mar  9 23:24:01 moonfire moonfire-nvr[19022]: syncer moonfire_nvr::db] reserved 7f276a69-5eab-41a0-b39b-3e6511502f4f
Mar  9 23:24:11 moonfire moonfire-nvr[19022]: thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /checkout/src/libcore/option.rs:335:20
Mar  9 23:24:12 moonfire moonfire-nvr[19022]: stack backtrace:
Mar  9 23:24:12 moonfire moonfire-nvr[19022]: 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 1: std::sys_common::backtrace::_print
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/sys_common/backtrace.rs:71
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 2: std::panicking::default_hook::{{closure}}
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/sys_common/backtrace.rs:60
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:381
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 3: std::panicking::default_hook
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:397
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 4: std::panicking::rust_panic_with_hook
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:611
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 5: std::panicking::begin_panic
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:572
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 6: std::panicking::begin_panic_fmt
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:522
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 7: rust_begin_unwind
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:498
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 8: core::panicking::panic_fmt
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libcore/panicking.rs:71
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 9: core::panicking::panic
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: at ./checkout/src/libcore/panicking.rs:51
Mar  9 23:24:13 moonfire moonfire-nvr[19022]: 10: moonfire_nvr::mp4::FileBuilder::append_moov
Mar  9 23:24:17 moonfire moonfire-nvr[19022]: syncer moonfire_nvr::dir] Front Right: deleting 22786394 bytes in 1 recordings (15704467 bytes needed)
Mar  9 23:24:17 moonfire moonfire-nvr[19022]: syncer moonfire_nvr::db] reserved 58228b76-59c7-4781-a7d6-2dbe6b6d2f76
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./checkout/src/libcore/macros.rs:32
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at src/mp4.rs:1050
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at src/mp4.rs:1024
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at src/mp4.rs:923
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: 11: moonfire_nvr::mp4::FileBuilder::build
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at src/mp4.rs:856
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: 12: moonfire_nvr::web::ServiceInner::camera_view_mp4
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at src/web.rs:378
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: 13: <tokio_proto::streaming::pipeline::server::Dispatch<S, T, P> as tokio_proto::streaming::pipeline::advanced::Dispatch>::dispatch
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at src/web.rs:467
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/git/checkouts/hyper-d300147022600c0c/c038b24/src/server/mod.rs:480
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/git/checkouts/hyper-d300147022600c0c/c038b24/src/server/mod.rs:335
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-proto-0.1.1/src/streaming/pipeline/server.rs:124
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: 14: <tokio_proto::streaming::pipeline::advanced::Pipeline<T> as futures::future::Future>::poll
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-proto-0.1.1/src/streaming/pipeline/advanced.rs:171
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-proto-0.1.1/src/streaming/pipeline/advanced.rs:121
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-proto-0.1.1/src/streaming/pipeline/advanced.rs:376
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: 15: <futures::future::map_err::MapErr<A, F> as futures::future::Future>::poll
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/future/chain.rs:42
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/future/and_then.rs:32
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/future/map_err.rs:30
Mar  9 23:24:26 moonfire moonfire-nvr[19022]: 16: tokio_core::reactor::Core::poll
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/future/mod.rs:113
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/task_impl/mod.rs:289
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/task_impl/mod.rs:350
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/task_impl/std/mod.rs:79
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/task_impl/mod.rs:350
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.16/src/task_impl/mod.rs:289
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.9/src/reactor/mod.rs:356
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/scoped-tls-0.1.0/src/lib.rs:135
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.9/src/reactor/mod.rs:355
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.9/src/reactor/mod.rs:316
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.9/src/reactor/mod.rs:304
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.9/src/reactor/mod.rs:241
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./home/pi/.cargo/git/checkouts/hyper-d300147022600c0c/c038b24/src/server/mod.rs:425
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at src/cmds/run.rs:142
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: 18: moonfire_nvr::main
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at src/main.rs:144
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: 19: __rust_maybe_catch_panic
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./checkout/src/libpanic_unwind/lib.rs:99
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: 20: std::rt::lang_start
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panicking.rs:459
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/panic.rs:361
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: at ./checkout/src/libstd/rt.rs:61
Mar  9 23:24:28 moonfire moonfire-nvr[19022]: 21: __libc_start_main
Mar  9 23:24:28 moonfire systemd[1]: moonfire-nvr.service: main process exited, code=exited, status=101/n/a
Mar  9 23:24:28 moonfire systemd[1]: Unit moonfire-nvr.service entered failed state.

Not compatible with Node.js 11.2.0

yarn install v1.12.3                                                                                           
[1/4] Resolving packages...                                                                                    
[2/4] Fetching packages...                                                                                     
error [email protected]: The engine "node" is incompatible with this module. Expected version ">=4 <=9". Got "11.2.0"
error Found incompatible module                                                                                
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.                       

strip unnecessary non-VCL NALs from sample data

I briefly examined the actual H.264 bytestream via aizvorski/h264bitstream and found some suspect things. I believe the video samples I store and the .mp4s I serve include sps/pps information, for example, even though this is redundant with the video_sample_entry.

brokenness when switching video options of active stream

If you change a stream's video options (for example, its resolution) while Moonfire NVR is running, it doesn't ever recognize the change. It continues recording the video with an incorrect video_sample_entry. It will show the wrong resolution in the UI and playback will likely not work. (@dolfs reported a pure white recording.)

This should watch for the ffmpeg extra_data changing or the new SPS/PPS NALs in the H.264 stream (server/src/h264.rs / transform_sample_data) or some such.

web configuration UI

The TUI moonfire-nvr config is a decent way of configuring the system for now, but long-term I'd like all configuration to be done through the web UI:

  • lots of Javascript work to do for this
  • new JSON interfaces to define (split to #153)
  • server refactoring: the Streamer and Syncer interfaces in the server don't have any teardown logic, aren't exposed to the web UI in any way, etc. (split to #153 also)
  • needs to be authenticated, [edit: this is done as part of #26] and have a notion of a config permission (easy)
  • need a way to bootstrap the authentication if not moonfire-nvr config. I'm thinking a simple CLI for user manipulation which authenticates to the server over a Unix domain socket protected via file permissions or SO_PEERCRED.

Ncurses ui for config garbled

~T~@ ~ ~Main menu  ~T~\@ ~ ~T~PT~@ ~T~@
 ~T~@ ~T~@  ~T~B~T~@ ~T~@ ~T~@ ~T~@ ~T~ ~T~B@ ~T~@ ~
T~@ ~T~@ ~T ~T~B~@ ~T~@ ~T~@ ~T~@ ~T~@  ~T~B
            ~T~Brs                      ~T~B
            ~T~B                        ~T~B
            ~T~B                <Quit>  ~T~B
             ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@
 ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~
T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@ ~T~@
locale
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8

favicon

It's a small thing, but I keep lots of Chrome tabs open and have trouble finding the Moonfire one because there's no favicon. Make one. Probably red (to match the name moonfire) and some fitting imagery, such as:

  • camera: profile view of a bullet style is probably most identifiable in few pixels. Maybe a head-on view of a bullet style with glowing red LEDs.
  • moon: probably a crescent to be identifiable as something other than just a circle.
  • tree: a moonfire japanese maple. might be hard to represent well in such a limited number of pixels. the leaf unfortunately is easily confused with marijuana.

It'd be nice to have a larger logo as well for display on the UI, the main page, maybe in the future an icon for phone apps. But better to have a just a favicon for now than nothing.

fancy scrub bar UI

I've written the server-side code to support segmented .mp4 files for HTML5 Media Source Extensions. (design/api.md talks about this.) It may have some bugs but is essentially complete.

The goal was that to use this to create the classic NVR UI where there's a scrub bar at the bottom showing an entire day, it grows over time as new stuff is recorded, and none of this has to wait for huge moov segments to transfer.

I think this needs some significant work to be viable, though:

  • debug the current segmented .mp4 files. I noticed some of them were working, some weren't. I'm not sure what was different. Maybe related to #43. I think as part of getting the live view working I got this stuff all figured out. See 478323e.
    • a bunch of Javascript UI work. probably an automated test setup for UI changes with headless Chrome/Firefox or something.
    • event stream (#40)
    • some way of sending HTTP requests for video data, streaming the response back, and being able to cancel it when you seek to another part of the video.
      • XMLHTTPRequest: but apparently only Firefox supports streaming arraybuffers with this. The other browsers don't return any response data until the response is complete, so there'd have to essentially be an HTTP request per frame, which is annoying.
      • Fetch + Streams APIs: but this is Chrome-only last I checked and doesn't support cancelling requests, so if you seek around a lot your connection will get quite congested while the system catches up with you. fetch is well-supported by browsers now, including streams and cancellation.
      • WebSockets: this supports both streaming and cancellation, so I think it's the best way to go. But it requires some additional server-side work. hyper annoyingly doesn't support sharing the HTTP port with a WebSockets implementation. Could use a separate port for now. The live view uses WebSockets now. But given that fetch works well now, I don't think we need to add a WebSockets API for existing segments.

systemd socket activation for http/https port

This is probably the most user-friendly way to bind to privileged ports 80 and 443 on a modern Linux system. (One alternative would be setting up a firewall rule to redirect to 8080/8443 or some such.)

@dolfs found a nice article about it: https://www.darkcoding.net/software/systemd-socket-activation-in-go/. One of the drafts of #15 also sets up the systemd stuff for it. Not mentioned in that article: I think we'd want to use port names so we can distinguish http vs https vs maybe some other future port (rtsp for clients to use? websocket? rpc interface? who knows).

This will be more important after completing #27. Until then, ports 80 and 443 should belong to the proxy server anyway.

extraneous flushes with multiple sample file dirs

Moonfire NVR is supposed to minimize the number of flushes of the (on-SSD) SQLite3 database. The stream table has the flush_if_sec field to support deferring flushes after completing a recording, in the hopes that some other stream flushes in the meantime and the two flushes can be coalesced.

  -- Flush the database when the first instant of completed recording is this
  -- many seconds old. A value of 0 means that every completed recording will
  -- cause an immediate flush. Higher values may allow flushes to be combined,
  -- reducing SSD write cycles. For example, if all streams have a flush_if_sec
  -- >= x sec, there will be:
  --
  -- * at most one flush per x sec in total
  -- * at most x sec of completed but unflushed recordings per stream.
  -- * at most x completed but unflushed recordings per stream, in the worst
  --   case where a recording instantly fails, waits the 1-second retry delay,
  --   then fails again, forever.
  flush_if_sec integer not null,

For the most part, this works. But see this log snippet:

Jan 04 05:45:21 odroid.home.slamb.org moonfire-nvr[2005]: sync-/var/lib/moonfire-nvr/sample-8tb moonfire_db::db] Flush (why: 10 sec after start of 1 minute driveway-main recording): added 2 recordings, deleted 1, marked 3 files GCed.
Jan 04 05:45:26 odroid.home.slamb.org moonfire-nvr[2005]: sync-/var/lib/moonfire-nvr/sample-6tb moonfire_db::db] Flush (why: 180 sec after start of 59 seconds garage-main recording): added 1 recordings, deleted 0, marked 1 files GCed.

The second line's why doesn't make sense. The recording it's referring to should have already been added in the previous flush (if not before). The problem is that I have two sample file dirs, therefore two syncers. Each syncer independently computes next_flush and doesn't update it when something else causes a flush. This was fine when there was only syncer but not anymore.

switch database to a simple key/value store for speed

SQLite3 is a super-reliable database, was easy to get started with, and is easy to diagnose problems with, but it's not particularly fast. I've noticed in CPU profiles: its locking around column operations, its VM operations, and its prepare steps. The latency for some operations on the Pi2 isn't quite what I'd like it to be. Consider switching to a simpler key/value store, such as:

  • RocksDB
  • spacejam/sled (warning: currently very experimental)
  • lmdb

Calling API with invalid arg causes connection reset

I happened to be doing UI development using a proxy to a normally running moonfire instance. Due to coding error the API for recordings was called with start and end time set to null. Rather then producing an appropriate HTTP response (may be 500, or even 404) would have been expected.

Needless to say that the connection reset causes error messages that are unwanted, but it also means API calling code does not get its error path executed.

Sample output:

[HPM] Error occurred while trying to proxy request /api/cameras/1c844181-b807-4b80-83eb-579c8e194451/recordings?startTime90k=null&endTime90k=null&split90k=324000000&_=1520229643233 from localhost:3000 to http://192.168.10.232:8080 (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)

Moonfire cannot serve all static files present

NOTE: This is sideways related to #25

I was doing some UI development and an attempt at producing an optimized bundle produces source maps in files separate from the bundle itself:

nvr.bundle.js
nvr.bundle.js.gz
nvr.bundle.js.map

#25 mentions the inability to serve the .gz version of the bundle when gzip is offered as acceptable. This would be a little special code in lieu of on-the-fly gzipping.

The issue addressed here is that therein bundle (nvr.bundle.js) attempts to load the source map in a separate request. The request fails with a 404 status. It seems Moonfire filters available static files, possibly by extension? May be not a good idea.

If a request in a url matches an existing file, it should probably be served up, but I can see how a complication would be to have a mapping of extensions to mime types. Perhaps it is as simple, at least for this case, to add something for .map.

"no garbage row for <id>" flush failure loops

When I set up multiple sample file dirs, I started getting errors like the one below in which:

  • two flushes happen around the same time
  • there's an error about a recording having already been deleted
  • then the flush fails with "no garbage row" for the same recording, and it goes into a retry loop that can never end. The in-memory state starts diverging from the database; when it's eventually killed, nothing has been committed to the database since then, although more has been written to disk and has to be thrown away on next startup.

This happens when there's no flush between Writer::collect_garbage completing and starting again. Its call to delete_garbage doesn't immediately remove it from garbage (not until the next flush). So the next call tries to unlink it again (which fails) and then calls delete_garbage on it again (which will eventually result in the transaction failing because the second delete reports the row doesn't exist).

collect_garbage happens in the post-flush notification, so there usually is a flush between each call. But the notification is asynchronous via a channel so this isn't actually guaranteed when other syncers can also fire flushes at a time it's not expecting.

The solution is pretty simple: make delete_garbage immediately remove it from garbage. Currently there's a garbage (everything in the garbage row) and a to_gc (things that should be removed from it on the next transaction). Instead, do a garbage_needs_unlink and a garbage_unlinked which are mutually exclusive.

Nov 28 14:57:26 ...: sync-/var/lib/moonfire-nvr/sample-6tb moonfire_db::writer] 6: deleting 30070712 bytes in 1 recordings (18927767 bytes needed)
Nov 28 14:57:50 ...: sync-/var/lib/moonfire-nvr/sample-6tb moonfire_db::db] Flush (why: 90 sec after start of 1 minute 5 seconds garage-main recording): added 5 recordings, deleted 1, marked 0 files GCed.
Nov 28 14:57:50 ...: sync-/var/lib/moonfire-nvr/sample-8tb moonfire_db::db] Flush (why: 90 sec after start of 1 minute 20 seconds courtyard-sub recording): added 0 recordings, deleted 0, marked 0 files GCed.
Nov 28 14:57:50 ...: sync-/var/lib/moonfire-nvr/sample-6tb moonfire_db::writer] dir: recording 6/622053 already deleted!
Nov 28 14:57:52 ...: sync-/var/lib/moonfire-nvr/sample-8tb moonfire_db::writer] 11: deleting 5348864 bytes in 1 recordings (4447102 bytes needed)
Nov 28 14:57:53 ...: sync-/var/lib/moonfire-nvr/sample-8tb moonfire_db::writer] flush failure on save for reason 90 sec after start of 1 minute 32 seconds driveway-sub recording; will retry after PT60S: ErrorMessage { msg: "no garbage row for 6/622053" }
Nov 28 14:57:53 ...: stack backtrace:
Nov 28 14:57:53 ...:    0:   0x81398f - backtrace::backtrace::libunwind::trace::h3efbb541b1fd4a89
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/backtrace/libunwind.rs:53
Nov 28 14:57:53 ...:                  - backtrace::backtrace::trace::he86533e63137b32d
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/backtrace/mod.rs:42
Nov 28 14:57:53 ...:    1:   0x812f1f - backtrace::capture::Backtrace::new_unresolved::h1e0ea6bd8272aa64
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.9/src/capture.rs:88
Nov 28 14:57:53 ...:    2:   0x812747 - failure::backtrace::internal::InternalBacktrace::new::hf30e7136ac39a801
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/backtrace/internal.rs:44
Nov 28 14:57:53 ...:    3:   0x812a2b - failure::backtrace::Backtrace::new::hbe74d198a344a1b6
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/backtrace/mod.rs:111
Nov 28 14:57:53 ...:                  - <failure::backtrace::Backtrace as core::default::Default>::default::h74085fe416c7ca1f
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/backtrace/mod.rs:125
Nov 28 14:57:53 ...:    4:   0x812a43 - failure::backtrace::Backtrace::new::hbe74d198a344a1b6
Nov 28 14:57:53 ...:    5:   0x5b918b - <failure::error::error_impl::ErrorImpl as core::convert::From<F>>::from::hf5461434cf9cbad6
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/error/error_impl.rs:19
Nov 28 14:57:53 ...:                  - <failure::error::Error as core::convert::From<F>>::from::h9373489268132011
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/error/mod.rs:36
Nov 28 14:57:53 ...:                  - failure::error_message::err_msg::ha9648b9e3acef653
Nov 28 14:57:53 ...:                 at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/error_message.rs:12
Nov 28 14:57:53 ...:                  - moonfire_db::raw::mark_sample_files_deleted::hd912400c9861c3a1
Nov 28 14:57:53 ...:                 at db/raw.rs:297
Nov 28 14:57:53 ...:    6:   0x4b829b - moonfire_db::db::LockedDatabase::flush::h3dc2c842b26129c2
Nov 28 14:57:53 ...:                 at /home/slamb/git/moonfire-nvr/db/db.rs:850
Nov 28 14:57:53 ...:    7:   0x509c67 - <moonfire_db::db::DatabaseGuard<'db, C>>::flush::h7b1c01d01aa74d02
Nov 28 14:57:53 ...:                 at /home/slamb/git/moonfire-nvr/db/db.rs:1883
Nov 28 14:57:53 ...:                  - <moonfire_db::writer::Syncer<C, D>>::flush::h3b5933ac754e19e8
Nov 28 14:57:53 ...:                 at /home/slamb/git/moonfire-nvr/db/writer.rs:454
Nov 28 14:57:53 ...:                  - <moonfire_db::writer::Syncer<C, D>>::run::h65b427485c2a355b
Nov 28 14:57:53 ...:                 at /home/slamb/git/moonfire-nvr/db/writer.rs:365
Nov 28 14:57:53 ...:    8:   0x4a32bf - moonfire_db::writer::start_syncer::{{closure}}::h8d8d9817454357db
Nov 28 14:57:53 ...:                 at /home/slamb/git/moonfire-nvr/db/writer.rs:147
Nov 28 14:57:53 ...:                  - std::sys_common::backtrace::__rust_begin_short_backtrace::h478cfad5bec097cb
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/sys_common/backtrace.rs:136
Nov 28 14:57:53 ...:    9:   0x47a023 - std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}}::h0bcfd3639b5817f7
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/thread/mod.rs:477
Nov 28 14:57:53 ...:                  - <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::hf8f01a225dda73a6
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/panic.rs:319
Nov 28 14:57:53 ...:                  - std::panicking::try::do_call::h6661548dfb451858
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/panicking.rs:310
Nov 28 14:57:53 ...:   10:   0x8e220b - __rust_maybe_catch_panic
Nov 28 14:57:53 ...:                 at src/libpanic_unwind/lib.rs:102
Nov 28 14:57:53 ...:   11:   0x44fd3b - std::panicking::try::h5b49cbb90fd9a1f2
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/panicking.rs:289
Nov 28 14:57:53 ...:                  - std::panic::catch_unwind::hdb03e368bff69de4
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/panic.rs:398
Nov 28 14:57:53 ...:                  - std::thread::Builder::spawn_unchecked::{{closure}}::h5c6ba7cb08b38b14
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/libstd/thread/mod.rs:476
Nov 28 14:57:53 ...:                  - <F as alloc::boxed::FnBox<A>>::call_box::h97a0e387b9befaf7
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/liballoc/boxed.rs:673
Nov 28 14:57:53 ...:   12:   0x8dbe6f - <alloc::boxed::Box<(dyn alloc::boxed::FnBox<A, Output=R> + 'a)> as core::ops::function::FnOnce<A>>::call_once::hd1734190ba15b47e
Nov 28 14:57:53 ...:                 at /rustc/400c2bc5ed292f77c49693320f4eda37bb375e90/src/liballoc/boxed.rs:683
Nov 28 14:57:53 ...:                  - std::sys_common::thread::start_thread::h30eac6e77e888779
Nov 28 14:57:53 ...:                 at src/libstd/sys_common/thread.rs:24
Nov 28 14:57:53 ...:                  - std::sys::unix::thread::Thread::new::thread_start::h6b3c4b2ce6075f65
Nov 28 14:57:53 ...:                 at src/libstd/sys/unix/thread.rs:90

ffmpeg pkg-config link path not respected [symptom: cargo test fails with 4 errors]

During building (8de7e39):

See below output:

$ RUST_TEST_THREADS=1 MOONFIRE_LOG=trace cargo test
    Finished dev [unoptimized + debuginfo] target(s) in 0.4 secs
     Running target/debug/deps/moonfire_nvr-ea606875e7c62cdf

running 48 tests
test cmds::config::tests::test_decode ... ok
test coding::tests::test_bad_varints ... ok
test coding::tests::test_correct_varints ... ok
test coding::tests::test_zigzag ... ok
test db::tests::test_adjust_days ... ok
test db::tests::test_day_bounds ... ok
test db::tests::test_drop_tx ... I1022 160352.363 db::tests::test_drop_tx moonfire_nvr::db] Loading video sample entries
I1022 160352.364 db::tests::test_drop_tx moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.365 db::tests::test_drop_tx moonfire_nvr::db] Loading cameras
I1022 160352.365 db::tests::test_drop_tx moonfire_nvr::db] Loaded 0 cameras
I1022 160352.368 db::tests::test_drop_tx moonfire_nvr::db] reserved d2b629c0-7662-4a8f-a20a-4300d08db8b8
I1022 160352.370 db::tests::test_drop_tx moonfire_nvr::db] reserved d8f0ad1c-1ef5-4a2c-becf-d5dbc71af2c0
ok
test db::tests::test_fresh_db ... I1022 160352.382 db::tests::test_fresh_db moonfire_nvr::db] Loading video sample entries
I1022 160352.383 db::tests::test_fresh_db moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.383 db::tests::test_fresh_db moonfire_nvr::db] Loading cameras
I1022 160352.384 db::tests::test_fresh_db moonfire_nvr::db] Loaded 0 cameras
ok
test db::tests::test_full_lifecycle ... I1022 160352.398 db::tests::test_full_lifecycle moonfire_nvr::db] Loading video sample entries
I1022 160352.399 db::tests::test_full_lifecycle moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.400 db::tests::test_full_lifecycle moonfire_nvr::db] Loading cameras
I1022 160352.401 db::tests::test_full_lifecycle moonfire_nvr::db] Loaded 1 cameras
I1022 160352.401 db::tests::test_full_lifecycle moonfire_nvr::db] Loading recordings for camera testcam
I1022 160352.402 db::tests::test_full_lifecycle moonfire_nvr::db] Loaded 0 recordings for camera testcam
I1022 160352.405 db::tests::test_full_lifecycle moonfire_nvr::db] reserved 15410fa9-e2c6-42e1-92ea-a24b8760cd4a
I1022 160352.405 db::tests::test_full_lifecycle moonfire_nvr::db] reserved 602ceb37-7fac-4bdb-9378-b0e21e06318c
I1022 160352.425 db::tests::test_full_lifecycle moonfire_nvr::db] Loading video sample entries
I1022 160352.427 db::tests::test_full_lifecycle moonfire_nvr::db] Loaded 1 video sample entries
I1022 160352.427 db::tests::test_full_lifecycle moonfire_nvr::db] Loading cameras
I1022 160352.428 db::tests::test_full_lifecycle moonfire_nvr::db] Loaded 1 cameras
I1022 160352.429 db::tests::test_full_lifecycle moonfire_nvr::db] Loading recordings for camera testcam
I1022 160352.430 db::tests::test_full_lifecycle moonfire_nvr::db] Loaded 1 recordings for camera testcam
ok
test db::tests::test_no_version ... ok
test db::tests::test_version_too_new ... ok
test db::tests::test_version_too_old ... ok
test dir::tests::adjust ... ok
test h264::tests::test_decode ... ok
test h264::tests::test_sample_entry_from_annex_b ... ok
test h264::tests::test_sample_entry_from_avc_decoder_config ... ok
test h264::tests::test_transform_sample_data ... ok
test mp4::tests::test_all_sync_frames ... I1022 160352.509 mp4::tests::test_all_sync_frames moonfire_nvr::db] Loading video sample entries
I1022 160352.509 mp4::tests::test_all_sync_frames moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.510 mp4::tests::test_all_sync_frames moonfire_nvr::db] Loading cameras
I1022 160352.511 mp4::tests::test_all_sync_frames moonfire_nvr::db] Loaded 1 cameras
I1022 160352.511 mp4::tests::test_all_sync_frames moonfire_nvr::db] Loading recordings for camera test camera
I1022 160352.512 mp4::tests::test_all_sync_frames moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160352.513 mp4::tests::test_all_sync_frames moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160352.592 mp4::tests::test_all_sync_frames moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=2..20, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 30,
    video_samples: 5,
    video_sync_samples: 5,
    sample_file_bytes: 45,
    run_offset: 0,
    flags: 0
}
T1022 160352.596 mp4::tests::test_all_sync_frames moonfire_nvr::db] cache miss for recording 1/1
D1022 160352.597 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] Estimated 21 slices; actually were 21 slices
D1022 160352.598 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] Estimated 2048 buf bytes; actually were 268
D1022 160352.598 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] segments: [
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 1,
            start: Time(
                128700576000000
            ),
            begin: Some(
                SampleIndexIterator {
                    i_and_is_key: 2147483652,
                    pos: 3,
                    start_90k: 2,
                    duration_90k: 4,
                    bytes: 6,
                    bytes_other: 0
                }
            ),
            file_end: 30,
            desired_range_90k: 2..20,
            frames: 3,
            key_frames: 3,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 1,
        num_subtitle_samples: 0
    }
]
D1022 160352.599 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] slices: 21 slices with overall length 704:
i       0: range [           0,           32) len           32: Static 0
i       1: range [          32,           68) len           36: Buf 0
i       2: range [          68,          144) len           76: Static 4
i       3: range [         144,          188) len           44: Buf 36
i       4: range [         188,          240) len           52: Static 5
i       5: range [         240,          288) len           48: Buf 80
i       6: range [         288,          321) len           33: Static 2
i       7: range [         321,          325) len            4: Buf 128
i       8: range [         325,          385) len           60: Static 6
i       9: range [         385,          409) len           24: Buf 132
i      10: range [         409,          509) len          100: VideoSampleEntry 0
i      11: range [         509,          525) len           16: Buf 156
i      12: range [         525,          549) len           24: Stts 0
i      13: range [         549,          597) len           48: Buf 172
i      14: range [         597,          609) len           12: Stsz 0
i      15: range [         609,          625) len           16: Buf 220
i      16: range [         625,          633) len            8: Co64 0
i      17: range [         633,          649) len           16: Buf 236
i      18: range [         649,          661) len           12: Stss 0
i      19: range [         661,          677) len           16: Buf 252
i      20: range [         677,          704) len           27: VideoSampleData 0
T1022 160352.603 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 0's range 0..8 / 32
T1022 160352.604 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /ftyp
T1022 160352.604 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for moov
T1022 160352.604 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 0's range 0..8 / 36
T1022 160352.605 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov
T1022 160352.605 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 0's range 8..16 / 36
T1022 160352.605 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/mvhd
T1022 160352.606 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for trak
T1022 160352.606 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 4..12 / 44
T1022 160352.607 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak
T1022 160352.607 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160352.608 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160352.608 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for tkhd
T1022 160352.608 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 20..21 / 44
T1022 160352.609 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 32..36 / 44
T1022 160352.609 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] found moov/trak/tkhd with id 1; want 1
T1022 160352.609 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for edts
T1022 160352.610 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 48
T1022 160352.610 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia
T1022 160352.610 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160352.611 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160352.611 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for mdia
T1022 160352.612 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 48
T1022 160352.612 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia
T1022 160352.612 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 16..24 / 48
T1022 160352.613 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/mdhd
T1022 160352.613 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for minf
T1022 160352.613 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 2's range 0..8 / 33
T1022 160352.614 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/hdlr
T1022 160352.614 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 128's range 0..4 / 4
T1022 160352.614 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 6's range 0..4 / 60
T1022 160352.615 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf
T1022 160352.615 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 6's range 4..12 / 60
T1022 160352.616 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/vmhd
T1022 160352.616 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for stbl
T1022 160352.616 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 6's range 24..32 / 60
T1022 160352.617 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/dinf
T1022 160352.617 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 132's range 0..8 / 24
T1022 160352.618 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl
T1022 160352.618 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 132's range 8..16 / 24
T1022 160352.618 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsd
T1022 160352.619 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for stts
T1022 160352.619 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 156's range 0..8 / 16
T1022 160352.619 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stts
T1022 160352.620 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] get_all: start=517, len=32
T1022 160352.620 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 156's range 8..16 / 16
T1022 160352.620 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Stts 0's range 0..24 / 24
T1022 160352.621 mp4::tests::test_all_sync_frames moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.621 mp4::tests::test_all_sync_frames moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 2
T1022 160352.622 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for stsz
T1022 160352.622 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 172's range 0..8 / 48
T1022 160352.623 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsc
T1022 160352.623 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 172's range 28..36 / 48
T1022 160352.623 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsz
T1022 160352.624 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] get_all: start=585, len=24
T1022 160352.624 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 172's range 36..48 / 48
T1022 160352.624 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Stsz 0's range 0..12 / 12
T1022 160352.625 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] looking for stss
T1022 160352.625 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 220's range 0..8 / 16
T1022 160352.626 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/co64
T1022 160352.626 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 236's range 0..8 / 16
T1022 160352.626 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stss
T1022 160352.627 mp4::tests::test_all_sync_frames moonfire_nvr::mp4::tests] get_all: start=641, len=20
T1022 160352.627 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 236's range 8..16 / 16
T1022 160352.627 mp4::tests::test_all_sync_frames moonfire_nvr::mp4] getting mp4 slice Stss 0's range 0..12 / 12
ok
test mp4::tests::test_half_sync_frames ... I1022 160352.642 mp4::tests::test_half_sync_frames moonfire_nvr::db] Loading video sample entries
I1022 160352.643 mp4::tests::test_half_sync_frames moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.644 mp4::tests::test_half_sync_frames moonfire_nvr::db] Loading cameras
I1022 160352.645 mp4::tests::test_half_sync_frames moonfire_nvr::db] Loaded 1 cameras
I1022 160352.646 mp4::tests::test_half_sync_frames moonfire_nvr::db] Loading recordings for camera test camera
I1022 160352.647 mp4::tests::test_half_sync_frames moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160352.648 mp4::tests::test_half_sync_frames moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160352.666 mp4::tests::test_half_sync_frames moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=12..20, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 30,
    video_samples: 5,
    video_sync_samples: 3,
    sample_file_bytes: 45,
    run_offset: 0,
    flags: 0
}
T1022 160352.675 mp4::tests::test_half_sync_frames moonfire_nvr::db] cache miss for recording 1/1
D1022 160352.676 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] Using edit list: [Entry { segment_duration: 8, media_time: 6 }]
D1022 160352.677 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] Estimated 21 slices; actually were 21 slices
D1022 160352.678 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] Estimated 2048 buf bytes; actually were 312
D1022 160352.678 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] segments: [
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 1,
            start: Time(
                128700576000000
            ),
            begin: Some(
                SampleIndexIterator {
                    i_and_is_key: 2147483654,
                    pos: 9,
                    start_90k: 6,
                    duration_90k: 6,
                    bytes: 9,
                    bytes_other: 6
                }
            ),
            file_end: 30,
            desired_range_90k: 12..20,
            frames: 2,
            key_frames: 1,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 1,
        num_subtitle_samples: 0
    }
]
D1022 160352.680 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] slices: 21 slices with overall length 722:
i       0: range [           0,           32) len           32: Static 0
i       1: range [          32,           68) len           36: Buf 0
i       2: range [          68,          144) len           76: Static 4
i       3: range [         144,          188) len           44: Buf 36
i       4: range [         188,          240) len           52: Static 5
i       5: range [         240,          332) len           92: Buf 80
i       6: range [         332,          365) len           33: Static 2
i       7: range [         365,          369) len            4: Buf 172
i       8: range [         369,          429) len           60: Static 6
i       9: range [         429,          453) len           24: Buf 176
i      10: range [         453,          553) len          100: VideoSampleEntry 0
i      11: range [         553,          569) len           16: Buf 200
i      12: range [         569,          585) len           16: Stts 0
i      13: range [         585,          633) len           48: Buf 216
i      14: range [         633,          641) len            8: Stsz 0
i      15: range [         641,          657) len           16: Buf 264
i      16: range [         657,          665) len            8: Co64 0
i      17: range [         665,          681) len           16: Buf 280
i      18: range [         681,          685) len            4: Stss 0
i      19: range [         685,          701) len           16: Buf 296
i      20: range [         701,          722) len           21: VideoSampleData 0
T1022 160352.685 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 0's range 0..8 / 32
T1022 160352.685 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /ftyp
T1022 160352.686 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for moov
T1022 160352.686 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 0's range 0..8 / 36
T1022 160352.687 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov
T1022 160352.687 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 0's range 8..16 / 36
T1022 160352.688 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/mvhd
T1022 160352.688 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for trak
T1022 160352.688 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 4..12 / 44
T1022 160352.689 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak
T1022 160352.689 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160352.690 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160352.690 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for tkhd
T1022 160352.691 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 20..21 / 44
T1022 160352.691 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 32..36 / 44
T1022 160352.692 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] found moov/trak/tkhd with id 1; want 1
T1022 160352.692 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for edts
T1022 160352.692 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 92
T1022 160352.693 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/edts
T1022 160352.693 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160352.694 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160352.694 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for mdia
T1022 160352.694 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 92
T1022 160352.695 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/edts
T1022 160352.695 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 52..60 / 92
T1022 160352.696 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia
T1022 160352.696 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 60..68 / 92
T1022 160352.697 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/mdhd
T1022 160352.697 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for minf
T1022 160352.698 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 2's range 0..8 / 33
T1022 160352.698 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/hdlr
T1022 160352.698 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 172's range 0..4 / 4
T1022 160352.699 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 6's range 0..4 / 60
T1022 160352.699 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf
T1022 160352.700 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 6's range 4..12 / 60
T1022 160352.700 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/vmhd
T1022 160352.701 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for stbl
T1022 160352.701 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Static 6's range 24..32 / 60
T1022 160352.701 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/dinf
T1022 160352.702 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 176's range 0..8 / 24
T1022 160352.702 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl
T1022 160352.703 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 16..24 / 92
T1022 160352.703 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/edts/elst
T1022 160352.704 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for elst
T1022 160352.704 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] get_all: start=264, len=28
T1022 160352.704 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 80's range 24..52 / 92
T1022 160352.705 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 176's range 8..16 / 24
T1022 160352.705 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsd
T1022 160352.706 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for stts
T1022 160352.706 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 200's range 0..8 / 16
T1022 160352.707 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stts
T1022 160352.707 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] get_all: start=561, len=24
T1022 160352.707 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 200's range 8..16 / 16
T1022 160352.708 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Stts 0's range 0..16 / 16
T1022 160352.708 mp4::tests::test_half_sync_frames moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.709 mp4::tests::test_half_sync_frames moonfire_nvr::recording] foreach on recording 1/1: 2 frames, actual_start_90k: 6
T1022 160352.709 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for stsz
T1022 160352.710 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 216's range 0..8 / 48
T1022 160352.710 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsc
T1022 160352.711 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 216's range 28..36 / 48
T1022 160352.711 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsz
T1022 160352.712 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] get_all: start=621, len=20
T1022 160352.712 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 216's range 36..48 / 48
T1022 160352.712 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Stsz 0's range 0..8 / 8
T1022 160352.713 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] looking for stss
T1022 160352.713 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 264's range 0..8 / 16
T1022 160352.714 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/co64
T1022 160352.714 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 280's range 0..8 / 16
T1022 160352.715 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stss
T1022 160352.715 mp4::tests::test_half_sync_frames moonfire_nvr::mp4::tests] get_all: start=673, len=12
T1022 160352.716 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Buf 280's range 8..16 / 16
T1022 160352.716 mp4::tests::test_half_sync_frames moonfire_nvr::mp4] getting mp4 slice Stss 0's range 0..4 / 4
ok
test mp4::tests::test_media_segment ... I1022 160352.733 mp4::tests::test_media_segment moonfire_nvr::db] Loading video sample entries
I1022 160352.734 mp4::tests::test_media_segment moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.734 mp4::tests::test_media_segment moonfire_nvr::db] Loading cameras
I1022 160352.735 mp4::tests::test_media_segment moonfire_nvr::db] Loaded 1 cameras
I1022 160352.736 mp4::tests::test_media_segment moonfire_nvr::db] Loading recordings for camera test camera
I1022 160352.737 mp4::tests::test_media_segment moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160352.738 mp4::tests::test_media_segment moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160352.754 mp4::tests::test_media_segment moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=12..21, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 30,
    video_samples: 5,
    video_sync_samples: 3,
    sample_file_bytes: 45,
    run_offset: 0,
    flags: 0
}
T1022 160352.758 mp4::tests::test_media_segment moonfire_nvr::db] cache miss for recording 1/1
D1022 160352.759 mp4::tests::test_media_segment moonfire_nvr::mp4] Estimated 21 slices; actually were 4 slices
D1022 160352.760 mp4::tests::test_media_segment moonfire_nvr::mp4] Estimated 2048 buf bytes; actually were 80
D1022 160352.760 mp4::tests::test_media_segment moonfire_nvr::mp4] segments: [
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 1,
            start: Time(
                128700576000000
            ),
            begin: Some(
                SampleIndexIterator {
                    i_and_is_key: 2147483654,
                    pos: 9,
                    start_90k: 6,
                    duration_90k: 6,
                    bytes: 9,
                    bytes_other: 6
                }
            ),
            file_end: 45,
            desired_range_90k: 12..21,
            frames: 3,
            key_frames: 2,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 1,
        num_subtitle_samples: 0
    }
]
D1022 160352.761 mp4::tests::test_media_segment moonfire_nvr::mp4] slices: 4 slices with overall length 188:
i       0: range [           0,           48) len           48: Buf 0
i       1: range [          48,          120) len           72: Truns 0
i       2: range [         120,          152) len           32: Buf 48
i       3: range [         152,          188) len           36: VideoSampleData 0
T1022 160352.762 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Buf 0's range 0..8 / 48
T1022 160352.763 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /moof
T1022 160352.763 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] looking for mdat
T1022 160352.764 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Buf 48's range 16..24 / 32
T1022 160352.764 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Buf 48's range 24..32 / 32
T1022 160352.765 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /mdat
T1022 160352.765 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] looking for moof
T1022 160352.765 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Buf 0's range 8..16 / 48
T1022 160352.766 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /moof/mfhd
T1022 160352.766 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] looking for traf
T1022 160352.766 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Buf 0's range 24..32 / 48
T1022 160352.767 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /moof/traf
T1022 160352.767 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Buf 0's range 32..40 / 48
T1022 160352.768 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /moof/traf/tfhd
T1022 160352.768 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] looking for trun
T1022 160352.768 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 0..8 / 72
T1022 160352.769 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.769 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.770 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /moof/traf/trun
T1022 160352.770 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 12..16 / 72
T1022 160352.770 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.771 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.771 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 16..20 / 72
T1022 160352.772 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.772 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.772 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 20..24 / 72
T1022 160352.773 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.773 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.774 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 24..28 / 72
T1022 160352.774 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.774 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.775 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 28..32 / 72
T1022 160352.775 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.776 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.776 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 32..36 / 72
T1022 160352.776 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.777 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.777 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 36..40 / 72
T1022 160352.778 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.778 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.779 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 40..48 / 72
T1022 160352.779 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.779 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.780 mp4::tests::test_media_segment moonfire_nvr::mp4::tests] positioned at /moof/traf/trun
T1022 160352.780 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 52..56 / 72
T1022 160352.781 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.781 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.781 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 56..60 / 72
T1022 160352.782 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.782 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.783 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 60..64 / 72
T1022 160352.783 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.783 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.784 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 64..68 / 72
T1022 160352.784 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.785 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
T1022 160352.785 mp4::tests::test_media_segment moonfire_nvr::mp4] getting mp4 slice Truns 0's range 68..72 / 72
T1022 160352.785 mp4::tests::test_media_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.786 mp4::tests::test_media_segment moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 6
ok
test mp4::tests::test_multi_segment ... I1022 160352.802 mp4::tests::test_multi_segment moonfire_nvr::db] Loading video sample entries
I1022 160352.803 mp4::tests::test_multi_segment moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.804 mp4::tests::test_multi_segment moonfire_nvr::db] Loading cameras
I1022 160352.805 mp4::tests::test_multi_segment moonfire_nvr::db] Loaded 1 cameras
I1022 160352.805 mp4::tests::test_multi_segment moonfire_nvr::db] Loading recordings for camera test camera
I1022 160352.806 mp4::tests::test_multi_segment moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160352.807 mp4::tests::test_multi_segment moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160352.823 mp4::tests::test_multi_segment moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=3..6, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 6,
    video_samples: 3,
    video_sync_samples: 2,
    sample_file_bytes: 6,
    run_offset: 0,
    flags: 0
}
T1022 160352.827 mp4::tests::test_multi_segment moonfire_nvr::db] cache miss for recording 1/1
T1022 160352.832 mp4::tests::test_multi_segment moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=0..4, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 2,
    duration_90k: 9,
    video_samples: 2,
    video_sync_samples: 1,
    sample_file_bytes: 9,
    run_offset: 0,
    flags: 0
}
T1022 160352.836 mp4::tests::test_multi_segment moonfire_nvr::db] cache miss for recording 1/2
D1022 160352.837 mp4::tests::test_multi_segment moonfire_nvr::mp4] Estimated 25 slices; actually were 25 slices
D1022 160352.838 mp4::tests::test_multi_segment moonfire_nvr::mp4] Estimated 2048 buf bytes; actually were 280
D1022 160352.838 mp4::tests::test_multi_segment moonfire_nvr::mp4] segments: [
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 1,
            start: Time(
                128700576000000
            ),
            begin: Some(
                SampleIndexIterator {
                    i_and_is_key: 2147483654,
                    pos: 3,
                    start_90k: 3,
                    duration_90k: 3,
                    bytes: 3,
                    bytes_other: 2
                }
            ),
            file_end: 6,
            desired_range_90k: 3..6,
            frames: 1,
            key_frames: 1,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 1,
        num_subtitle_samples: 0
    },
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 2,
            start: Time(
                128700576000000
            ),
            begin: Some(
                SampleIndexIterator {
                    i_and_is_key: 2147483650,
                    pos: 0,
                    start_90k: 0,
                    duration_90k: 4,
                    bytes: 4,
                    bytes_other: 0
                }
            ),
            file_end: 4,
            desired_range_90k: 0..4,
            frames: 1,
            key_frames: 1,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 2,
        num_subtitle_samples: 0
    }
]
D1022 160352.840 mp4::tests::test_multi_segment moonfire_nvr::mp4] slices: 25 slices with overall length 688:
i       0: range [           0,           32) len           32: Static 0
i       1: range [          32,           68) len           36: Buf 0
i       2: range [          68,          144) len           76: Static 4
i       3: range [         144,          188) len           44: Buf 36
i       4: range [         188,          240) len           52: Static 5
i       5: range [         240,          288) len           48: Buf 80
i       6: range [         288,          321) len           33: Static 2
i       7: range [         321,          325) len            4: Buf 128
i       8: range [         325,          385) len           60: Static 6
i       9: range [         385,          409) len           24: Buf 132
i      10: range [         409,          509) len          100: VideoSampleEntry 0
i      11: range [         509,          525) len           16: Buf 156
i      12: range [         525,          533) len            8: Stts 0
i      13: range [         533,          541) len            8: Stts 1
i      14: range [         541,          601) len           60: Buf 172
i      15: range [         601,          605) len            4: Stsz 0
i      16: range [         605,          609) len            4: Stsz 1
i      17: range [         609,          625) len           16: Buf 232
i      18: range [         625,          641) len           16: Co64 0
i      19: range [         641,          657) len           16: Buf 248
i      20: range [         657,          661) len            4: Stss 0
i      21: range [         661,          665) len            4: Stss 1
i      22: range [         665,          681) len           16: Buf 264
i      23: range [         681,          684) len            3: VideoSampleData 0
i      24: range [         684,          688) len            4: VideoSampleData 1
T1022 160352.844 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Static 0's range 0..8 / 32
T1022 160352.845 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /ftyp
T1022 160352.845 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] looking for moov
T1022 160352.846 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 0's range 0..8 / 36
T1022 160352.846 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov
T1022 160352.847 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 0's range 8..16 / 36
T1022 160352.847 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/mvhd
T1022 160352.847 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] looking for trak
T1022 160352.848 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 36's range 4..12 / 44
T1022 160352.848 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak
T1022 160352.848 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160352.849 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160352.849 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] looking for mdia
T1022 160352.850 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 48
T1022 160352.850 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia
T1022 160352.850 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 80's range 16..24 / 48
T1022 160352.851 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/mdhd
T1022 160352.851 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] looking for minf
T1022 160352.851 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Static 2's range 0..8 / 33
T1022 160352.852 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/hdlr
T1022 160352.852 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 128's range 0..4 / 4
T1022 160352.852 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Static 6's range 0..4 / 60
T1022 160352.853 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf
T1022 160352.853 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Static 6's range 4..12 / 60
T1022 160352.854 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/vmhd
T1022 160352.854 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] looking for stbl
T1022 160352.854 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Static 6's range 24..32 / 60
T1022 160352.855 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/dinf
T1022 160352.855 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 132's range 0..8 / 24
T1022 160352.856 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl
T1022 160352.856 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 132's range 8..16 / 24
T1022 160352.856 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsd
T1022 160352.857 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] looking for stss
T1022 160352.857 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 156's range 0..8 / 16
T1022 160352.857 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stts
T1022 160352.858 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 172's range 0..8 / 60
T1022 160352.858 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsc
T1022 160352.859 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 172's range 40..48 / 60
T1022 160352.859 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stsz
T1022 160352.859 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 232's range 0..8 / 16
T1022 160352.860 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/co64
T1022 160352.860 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 248's range 0..8 / 16
T1022 160352.860 mp4::tests::test_multi_segment moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl/stss
T1022 160352.861 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Buf 248's range 12..16 / 16
T1022 160352.861 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Stss 0's range 0..4 / 4
T1022 160352.862 mp4::tests::test_multi_segment moonfire_nvr::db] cache hit for recording 1/1
T1022 160352.862 mp4::tests::test_multi_segment moonfire_nvr::recording] foreach on recording 1/1: 1 frames, actual_start_90k: 3
T1022 160352.863 mp4::tests::test_multi_segment moonfire_nvr::mp4] getting mp4 slice Stss 1's range 0..4 / 4
T1022 160352.863 mp4::tests::test_multi_segment moonfire_nvr::db] cache hit for recording 1/2
T1022 160352.863 mp4::tests::test_multi_segment moonfire_nvr::recording] foreach on recording 1/2: 1 frames, actual_start_90k: 0
ok
test mp4::tests::test_round_trip ... I1022 160352.878 mp4::tests::test_round_trip moonfire_nvr::db] Loading video sample entries
I1022 160352.879 mp4::tests::test_round_trip moonfire_nvr::db] Loaded 0 video sample entries
I1022 160352.879 mp4::tests::test_round_trip moonfire_nvr::db] Loading cameras
I1022 160352.880 mp4::tests::test_round_trip moonfire_nvr::db] Loaded 1 cameras
I1022 160352.881 mp4::tests::test_round_trip moonfire_nvr::db] Loading recordings for camera test camera
I1022 160352.882 mp4::tests::test_round_trip moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160352.883 mp4::tests::test_round_trip moonfire_nvr::dir] test camera: have remaining quota of 1048576
I1022 160352.970 mp4::tests::test_round_trip moonfire_ffmpeg] Initialized ffmpeg. Versions:
avcodec compiled=56.60.100 running=56.1.0
avformat compiled=56.40.101 running=56.1.0
avutil compiled=54.31.100 running=54.3.0
W1022 160352.976 mp4::tests::test_round_trip moonfire_nvr::stream] While opening URL file:src/testdata/clip.mp4, some options were not understood: advanced_editlist=false
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x73eabd00] max_analyze_duration 5000000 reached
D1022 160353.015 mp4::tests::test_round_trip moonfire_nvr::stream] Video stream index is 0
I1022 160353.017 mp4::tests::test_round_trip moonfire_nvr::dir] Committing extra transaction because there's no cached uuid
I1022 160353.018 mp4::tests::test_round_trip moonfire_nvr::db] reserved 4d92ba20-77fa-45ce-8b77-d7c65698f025
FAILED
test mp4::tests::test_round_trip_with_edit_list ... I1022 160353.049 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] Loading video sample entries
I1022 160353.050 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.051 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] Loading cameras
D1022 160353.052 syncer moonfire_nvr::dir] test camera: have remaining quota of 1036339
I1022 160353.052 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] Loaded 1 cameras
I1022 160353.053 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.054 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.055 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::dir] test camera: have remaining quota of 1048576
I1022 160353.057 syncer moonfire_nvr::db] reserved a62b385b-f6e7-4e75-971d-8b8cfd515ae2
W1022 160353.061 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::stream] While opening URL file:src/testdata/clip.mp4, some options were not understood: advanced_editlist=false
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x742abd00] max_analyze_duration 5000000 reached
D1022 160353.099 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::stream] Video stream index is 0
I1022 160353.101 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::dir] Committing extra transaction because there's no cached uuid
I1022 160353.102 mp4::tests::test_round_trip_with_edit_list moonfire_nvr::db] reserved c0d93fd1-8997-4978-93d2-5d2b8f07d77f
FAILED
test mp4::tests::test_round_trip_with_shorten ... I1022 160353.191 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] Loading video sample entries
I1022 160353.192 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.192 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] Loading cameras
I1022 160353.193 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] Loaded 1 cameras
I1022 160353.194 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.195 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.196 mp4::tests::test_round_trip_with_shorten moonfire_nvr::dir] test camera: have remaining quota of 1048576
D1022 160353.196 syncer moonfire_nvr::dir] test camera: have remaining quota of 1036339
I1022 160353.199 syncer moonfire_nvr::db] reserved 44123158-e3fe-41a4-8892-eb64ad1f309d
W1022 160353.202 mp4::tests::test_round_trip_with_shorten moonfire_nvr::stream] While opening URL file:src/testdata/clip.mp4, some options were not understood: advanced_editlist=false
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x74691a00] max_analyze_duration 5000000 reached
D1022 160353.239 mp4::tests::test_round_trip_with_shorten moonfire_nvr::stream] Video stream index is 0
I1022 160353.241 mp4::tests::test_round_trip_with_shorten moonfire_nvr::dir] Committing extra transaction because there's no cached uuid
I1022 160353.242 mp4::tests::test_round_trip_with_shorten moonfire_nvr::db] reserved acb4a23e-a48a-41f6-85e6-f639ac908e11
FAILED
test mp4::tests::test_round_trip_with_subtitles ... I1022 160353.268 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] Loading video sample entries
I1022 160353.269 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.270 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] Loading cameras
I1022 160353.271 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] Loaded 1 cameras
I1022 160353.271 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.272 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.273 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::dir] test camera: have remaining quota of 1048576
D1022 160353.335 syncer moonfire_nvr::dir] test camera: have remaining quota of 1036339
I1022 160353.339 syncer moonfire_nvr::db] reserved 941d95ef-e53b-4b4d-b6cd-764004c5d6ea
W1022 160353.339 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::stream] While opening URL file:src/testdata/clip.mp4, some options were not understood: advanced_editlist=false
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x73ea0100] max_analyze_duration 5000000 reached
D1022 160353.376 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::stream] Video stream index is 0
I1022 160353.378 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::dir] Committing extra transaction because there's no cached uuid
I1022 160353.379 mp4::tests::test_round_trip_with_subtitles moonfire_nvr::db] reserved 0f9a65eb-d1d3-44a7-a001-0bdc32edca50
FAILED
test mp4::tests::test_zero_duration_recording ... I1022 160353.408 mp4::tests::test_zero_duration_recording moonfire_nvr::db] Loading video sample entries
I1022 160353.409 mp4::tests::test_zero_duration_recording moonfire_nvr::db] Loaded 0 video sample entries
D1022 160353.409 syncer moonfire_nvr::dir] test camera: have remaining quota of 1036339
I1022 160353.410 mp4::tests::test_zero_duration_recording moonfire_nvr::db] Loading cameras
I1022 160353.411 mp4::tests::test_zero_duration_recording moonfire_nvr::db] Loaded 1 cameras
I1022 160353.411 mp4::tests::test_zero_duration_recording moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.412 mp4::tests::test_zero_duration_recording moonfire_nvr::db] Loaded 0 recordings for camera test camera
I1022 160353.412 syncer moonfire_nvr::db] reserved d54ef9c0-12b9-44f5-a09c-7b2f2bcaad77
D1022 160353.413 mp4::tests::test_zero_duration_recording moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160353.422 mp4::tests::test_zero_duration_recording moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=1..5, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 5,
    video_samples: 2,
    video_sync_samples: 1,
    sample_file_bytes: 3,
    run_offset: 0,
    flags: 0
}
T1022 160353.426 mp4::tests::test_zero_duration_recording moonfire_nvr::db] cache miss for recording 1/1
T1022 160353.430 mp4::tests::test_zero_duration_recording moonfire_nvr::recording] recording::Segment::new fast path, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 2,
    duration_90k: 0,
    video_samples: 1,
    video_sync_samples: 1,
    sample_file_bytes: 3,
    run_offset: 0,
    flags: 0
}
D1022 160353.435 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] Using edit list: [Entry { segment_duration: 4, media_time: 1 }]
D1022 160353.436 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] Estimated 25 slices; actually were 25 slices
D1022 160353.436 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] Estimated 2048 buf bytes; actually were 324
D1022 160353.436 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] segments: [
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 1,
            start: Time(
                128700576000000
            ),
            begin: Some(
                SampleIndexIterator {
                    i_and_is_key: 2147483650,
                    pos: 0,
                    start_90k: 0,
                    duration_90k: 2,
                    bytes: 1,
                    bytes_other: 0
                }
            ),
            file_end: 3,
            desired_range_90k: 1..5,
            frames: 2,
            key_frames: 1,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 1,
        num_subtitle_samples: 0
    },
    mp4::Segment {
        s: Segment {
            camera_id: 1,
            recording_id: 2,
            start: Time(
                128700576000000
            ),
            begin: None,
            file_end: 3,
            desired_range_90k: 0..0,
            frames: 1,
            key_frames: 1,
            video_sample_entry_id_and_trailing_zero: 1
        },
        first_frame_num: 3,
        num_subtitle_samples: 0
    }
]
D1022 160353.438 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] slices: 25 slices with overall length 743:
i       0: range [           0,           32) len           32: Static 0
i       1: range [          32,           68) len           36: Buf 0
i       2: range [          68,          144) len           76: Static 4
i       3: range [         144,          188) len           44: Buf 36
i       4: range [         188,          240) len           52: Static 5
i       5: range [         240,          332) len           92: Buf 80
i       6: range [         332,          365) len           33: Static 2
i       7: range [         365,          369) len            4: Buf 172
i       8: range [         369,          429) len           60: Static 6
i       9: range [         429,          453) len           24: Buf 176
i      10: range [         453,          553) len          100: VideoSampleEntry 0
i      11: range [         553,          569) len           16: Buf 200
i      12: range [         569,          585) len           16: Stts 0
i      13: range [         585,          593) len            8: Stts 1
i      14: range [         593,          653) len           60: Buf 216
i      15: range [         653,          661) len            8: Stsz 0
i      16: range [         661,          665) len            4: Stsz 1
i      17: range [         665,          681) len           16: Buf 276
i      18: range [         681,          697) len           16: Co64 0
i      19: range [         697,          713) len           16: Buf 292
i      20: range [         713,          717) len            4: Stss 0
i      21: range [         717,          721) len            4: Stss 1
i      22: range [         721,          737) len           16: Buf 308
i      23: range [         737,          740) len            3: VideoSampleData 0
i      24: range [         740,          743) len            3: VideoSampleData 1
T1022 160353.442 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Static 0's range 0..8 / 32
T1022 160353.443 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /ftyp
T1022 160353.443 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for moov
T1022 160353.444 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 0's range 0..8 / 36
T1022 160353.444 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov
T1022 160353.444 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 0's range 8..16 / 36
T1022 160353.445 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/mvhd
T1022 160353.445 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for trak
T1022 160353.446 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 36's range 4..12 / 44
T1022 160353.446 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak
T1022 160353.446 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160353.447 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160353.447 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for tkhd
T1022 160353.448 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 36's range 20..21 / 44
T1022 160353.448 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 36's range 32..36 / 44
T1022 160353.448 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] found moov/trak/tkhd with id 1; want 1
T1022 160353.449 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for edts
T1022 160353.449 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 92
T1022 160353.449 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/edts
T1022 160353.450 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 36's range 12..20 / 44
T1022 160353.450 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/tkhd
T1022 160353.451 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for mdia
T1022 160353.451 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 8..16 / 92
T1022 160353.451 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/edts
T1022 160353.452 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 52..60 / 92
T1022 160353.452 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia
T1022 160353.452 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 60..68 / 92
T1022 160353.453 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/mdhd
T1022 160353.453 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for minf
T1022 160353.453 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Static 2's range 0..8 / 33
T1022 160353.454 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/hdlr
T1022 160353.454 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 172's range 0..4 / 4
T1022 160353.455 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Static 6's range 0..4 / 60
T1022 160353.455 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf
T1022 160353.455 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Static 6's range 4..12 / 60
T1022 160353.456 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/vmhd
T1022 160353.456 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for stbl
T1022 160353.457 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Static 6's range 24..32 / 60
T1022 160353.457 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/dinf
T1022 160353.457 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 176's range 0..8 / 24
T1022 160353.458 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/mdia/minf/stbl
T1022 160353.458 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 16..24 / 92
T1022 160353.459 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] positioned at /moov/trak/edts/elst
T1022 160353.459 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4::tests] looking for elst
T1022 160353.459 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 28..32 / 92
T1022 160353.460 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 32..40 / 92
T1022 160353.460 mp4::tests::test_zero_duration_recording moonfire_nvr::mp4] getting mp4 slice Buf 80's range 40..48 / 92
ok
test recording::tests::test_display_duration ... ok
test recording::tests::test_encode_example ... ok
test recording::tests::test_format_time ... ok
test recording::tests::test_iterator_errors ... ok
test recording::tests::test_parse_time ... ok
test recording::tests::test_round_trip ... ok
test recording::tests::test_segment_clipping_with_all_sync ... I1022 160353.688 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] Loading video sample entries
I1022 160353.689 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.690 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] Loading cameras
I1022 160353.691 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] Loaded 1 cameras
I1022 160353.691 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.692 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.693 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160353.773 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=2..20, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 30,
    video_samples: 5,
    video_sync_samples: 5,
    sample_file_bytes: 45,
    run_offset: 0,
    flags: 0
}
T1022 160353.778 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] cache miss for recording 1/1
T1022 160353.779 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::db] cache hit for recording 1/1
T1022 160353.779 recording::tests::test_segment_clipping_with_all_sync moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 2
ok
test recording::tests::test_segment_clipping_with_half_sync ... I1022 160353.795 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] Loading video sample entries
I1022 160353.796 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.797 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] Loading cameras
I1022 160353.798 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] Loaded 1 cameras
I1022 160353.799 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.799 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.801 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160353.819 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=12..20, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 30,
    video_samples: 5,
    video_sync_samples: 3,
    sample_file_bytes: 45,
    run_offset: 0,
    flags: 0
}
T1022 160353.827 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] cache miss for recording 1/1
T1022 160353.829 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::db] cache hit for recording 1/1
T1022 160353.829 recording::tests::test_segment_clipping_with_half_sync moonfire_nvr::recording] foreach on recording 1/1: 2 frames, actual_start_90k: 6
ok
test recording::tests::test_segment_clipping_with_trailing_zero ... I1022 160353.845 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] Loading video sample entries
I1022 160353.846 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.847 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] Loading cameras
I1022 160353.848 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] Loaded 1 cameras
I1022 160353.848 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.849 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.850 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160353.869 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=1..2, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 2,
    video_samples: 3,
    video_sync_samples: 3,
    sample_file_bytes: 6,
    run_offset: 0,
    flags: 0
}
T1022 160353.873 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] cache miss for recording 1/1
T1022 160353.874 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::db] cache hit for recording 1/1
T1022 160353.875 recording::tests::test_segment_clipping_with_trailing_zero moonfire_nvr::recording] foreach on recording 1/1: 2 frames, actual_start_90k: 1
ok
test recording::tests::test_segment_fast_path ... I1022 160353.891 recording::tests::test_segment_fast_path moonfire_nvr::db] Loading video sample entries
I1022 160353.892 recording::tests::test_segment_fast_path moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.892 recording::tests::test_segment_fast_path moonfire_nvr::db] Loading cameras
I1022 160353.893 recording::tests::test_segment_fast_path moonfire_nvr::db] Loaded 1 cameras
I1022 160353.894 recording::tests::test_segment_fast_path moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.894 recording::tests::test_segment_fast_path moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160353.895 recording::tests::test_segment_fast_path moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160353.974 recording::tests::test_segment_fast_path moonfire_nvr::recording] recording::Segment::new fast path, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 30,
    video_samples: 5,
    video_sync_samples: 3,
    sample_file_bytes: 45,
    run_offset: 0,
    flags: 0
}
T1022 160353.978 recording::tests::test_segment_fast_path moonfire_nvr::db] cache miss for recording 1/1
T1022 160353.979 recording::tests::test_segment_fast_path moonfire_nvr::recording] foreach on recording 1/1: 5 frames, actual_start_90k: 0
ok
test recording::tests::test_segment_fast_path_with_trailing_zero ... I1022 160353.995 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] Loading video sample entries
I1022 160353.996 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] Loaded 0 video sample entries
I1022 160353.997 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] Loading cameras
I1022 160353.998 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] Loaded 1 cameras
I1022 160353.998 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] Loading recordings for camera test camera
I1022 160353.999 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160354.000 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160354.020 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::recording] recording::Segment::new fast path, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 2,
    video_samples: 3,
    video_sync_samples: 3,
    sample_file_bytes: 6,
    run_offset: 0,
    flags: 0
}
T1022 160354.024 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::db] cache miss for recording 1/1
T1022 160354.025 recording::tests::test_segment_fast_path_with_trailing_zero moonfire_nvr::recording] foreach on recording 1/1: 3 frames, actual_start_90k: 0
ok
test recording::tests::test_segment_zero_desired_duration ... I1022 160354.041 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] Loading video sample entries
I1022 160354.042 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] Loaded 0 video sample entries
I1022 160354.043 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] Loading cameras
I1022 160354.044 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] Loaded 1 cameras
I1022 160354.044 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] Loading recordings for camera test camera
I1022 160354.045 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160354.046 recording::tests::test_segment_zero_desired_duration moonfire_nvr::dir] test camera: have remaining quota of 1048576
T1022 160354.066 recording::tests::test_segment_zero_desired_duration moonfire_nvr::recording] recording::Segment::new slow path, desired_range_90k=0..0, recording=ListRecordingsRow {
    start: Time(
        128700576000000
    ),
    video_sample_entry: VideoSampleEntry {
        data: [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        rfc6381_codec: "avc1.000000",
        id: 1,
        width: 1920,
        height: 1080,
        sha1: [
            237,
            74,
            119,
            209,
            181,
            106,
            17,
            137,
            56,
            120,
            143,
            197,
            48,
            55,
            117,
            155,
            108,
            80,
            30,
            61
        ]
    },
    camera_id: 1,
    id: 1,
    duration_90k: 1,
    video_samples: 1,
    video_sync_samples: 1,
    sample_file_bytes: 1,
    run_offset: 0,
    flags: 0
}
T1022 160354.070 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] cache miss for recording 1/1
T1022 160354.071 recording::tests::test_segment_zero_desired_duration moonfire_nvr::db] cache hit for recording 1/1
T1022 160354.072 recording::tests::test_segment_zero_desired_duration moonfire_nvr::recording] foreach on recording 1/1: 1 frames, actual_start_90k: 0
ok
test slices::tests::at_end ... ok
test slices::tests::everything ... ok
test slices::tests::exact_slice ... ok
test slices::tests::offset_first ... ok
test slices::tests::offset_mid ... ok
test slices::tests::size ... ok
test streamer::tests::basic ... W1022 160354.082 streamer::tests::basic moonfire_nvr::stream] While opening URL file:src/testdata/clip.mp4, some options were not understood: advanced_editlist=false
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x74696f00] max_analyze_duration 5000000 reached
D1022 160354.119 streamer::tests::basic moonfire_nvr::stream] Video stream index is 0
I1022 160354.133 streamer::tests::basic moonfire_nvr::db] Loading video sample entries
I1022 160354.134 streamer::tests::basic moonfire_nvr::db] Loaded 0 video sample entries
I1022 160354.134 streamer::tests::basic moonfire_nvr::db] Loading cameras
I1022 160354.136 streamer::tests::basic moonfire_nvr::db] Loaded 1 cameras
I1022 160354.136 streamer::tests::basic moonfire_nvr::db] Loading recordings for camera test camera
I1022 160354.137 streamer::tests::basic moonfire_nvr::db] Loaded 0 recordings for camera test camera
D1022 160354.138 streamer::tests::basic moonfire_nvr::dir] test camera: have remaining quota of 1048576
I1022 160354.214 streamer::tests::basic moonfire_nvr::streamer] test camera: Opening input: rtsp://foo:redacted@test-camera/main
T1022 160354.214 streamer::tests::basic moonfire_nvr::streamer::tests] MockOpener returning next stream
D1022 160354.216 streamer::tests::basic moonfire_nvr::streamer] test camera: video_sample_entry_id=1
D1022 160354.216 streamer::tests::basic moonfire_nvr::streamer] test camera: have first key frame
I1022 160354.217 streamer::tests::basic moonfire_nvr::dir] Committing extra transaction because there's no cached uuid
I1022 160354.217 streamer::tests::basic moonfire_nvr::db] reserved 439ef972-f328-4b70-9724-be8adccf1cbd
T1022 160354.219 streamer::tests::basic moonfire_nvr::streamer] test camera: write on normal rotation
I1022 160354.220 streamer::tests::basic moonfire_nvr::dir] Committing extra transaction because there's no cached uuid
I1022 160354.221 streamer::tests::basic moonfire_nvr::db] reserved 60a88837-d333-4217-ba65-669dfe3818fd
W1022 160354.222 streamer::tests::basic moonfire_nvr::streamer] test camera: sleeping for Duration { secs: 1, nanos: 0 } after error: Error: ffmpeg: End of file
cause: Some(Error(-1606004923))
I1022 160354.223 streamer::tests::basic moonfire_nvr::streamer] test camera: Opening input: rtsp://foo:redacted@test-camera/main
T1022 160354.223 streamer::tests::basic moonfire_nvr::streamer::tests] MockOpener shutting down
W1022 160354.224 streamer::tests::basic moonfire_nvr::streamer] test camera: sleeping for Duration { secs: 1, nanos: 0 } after error: Error: done
cause: None
I1022 160354.224 streamer::tests::basic moonfire_nvr::streamer] test camera: shutting down
D1022 160354.234 syncer moonfire_nvr::dir] test camera: have remaining quota of 1040301
I1022 160354.237 syncer moonfire_nvr::db] reserved 43236800-de46-4087-b28f-5dd62680bcac
D1022 160354.257 syncer moonfire_nvr::dir] test camera: have remaining quota of 1036339
T1022 160354.261 streamer::tests::basic moonfire_nvr::db] cache miss for recording 1/1
T1022 160354.262 streamer::tests::basic moonfire_nvr::db] cache miss for recording 1/2
ok
test strutil::tests::dehex_errors ... ok
test strutil::tests::round_trip ... ok
test web::tests::test_segments ... ok

failures:

---- mp4::tests::test_round_trip stdout ----
	thread 'mp4::tests::test_round_trip' panicked at 'unexpected input error: End of file', src/mp4.rs:1778:28
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- mp4::tests::test_round_trip_with_edit_list stdout ----
	thread 'mp4::tests::test_round_trip_with_edit_list' panicked at 'unexpected input error: End of file', src/mp4.rs:1778:28

---- mp4::tests::test_round_trip_with_shorten stdout ----
	thread 'mp4::tests::test_round_trip_with_shorten' panicked at 'unexpected input error: End of file', src/mp4.rs:1778:28

---- mp4::tests::test_round_trip_with_subtitles stdout ----
	thread 'mp4::tests::test_round_trip_with_subtitles' panicked at 'unexpected input error: End of file', src/mp4.rs:1778:28


failures:
    mp4::tests::test_round_trip
    mp4::tests::test_round_trip_with_edit_list
    mp4::tests::test_round_trip_with_shorten
    mp4::tests::test_round_trip_with_subtitles

test result: FAILED. 44 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--bin moonfire-nvr'
pi@moonfire:~/moonfire-nvr$

poor behavior when camera has audio enabled

There's an ffmpeg bug when a camera has audio enabled. I'll quote the troubleshooting guide below. Either we need this ffmpeg bug fixed (and the fixed version bundled with Moonfire NVR) or we need to switch RTSP libraries.

Error: pts not monotonically increasing; got 26615520 then 26539470

If your streams cut out with an error message like this one, there are a couple possibilities.

One is that your camera outputs B frames. If you believe this is the case, file a feature request; Moonfire NVR currently doesn't support B frames. You may be able to configure your camera to disable B frames in the meantime.

A more subtle problem occurs in cameras such as the Dahua Starlight series when the following is true:

  • Audio is enabled (thus a single RTSP session has two streams).
  • The camera's clock changes abruptly. Note that many cameras use SNTP rather than NTP to adjust time, so they consistently step time rather than slew it.
  • They send RTCP Sender Reports (these include the NTP time).

Moonfire NVR currently uses the ffmpeg library to talk to the cameras. ffmpeg doesn't properly support this situation. It uses the NTP time to adjust the PTS and DTS, and thus experiences jumps forward and backward. The forward jumps cause one frame to be artificially lengthened. The backward jumps create an impossible situation which causes Moonfire NVR to abort the session and retry.

In the long term, Moonfire NVR will likely implement its own RTSP support.

In the short term, you can use either of two workarounds:

  • Disable audio in the camera settings. Note that Moonfire NVR doesn't yet support recording audio anyway.
  • Disable time adjustment. You'll likely want to disable in-picture timestamps as well as they will become untrustworthy.

explicitly delete video segment

It'd be nice to have a way to explicitly delete a particular segment of video (potentially long before it's the oldest video), for example to redact some private event.

Consider containerizing Moonfire using Docker?

A benefit might be that it is easier to create the exact environment needed (dependent library versions etc.). A potential downside is that (a) docker would need to be installed (if not already) and (b) there might be some overhead that is not acceptable on the smallest of systems such as rPi.

moonifire-nvr config cannot operate when misconfigured

Just tried to use the config command when (right after building) the samples directory was missing:

/usr/local/bin/moonfire-nvr config
I0302 123829.587 main moonfire_nvr::db] Loading video sample entries
I0302 123829.587 main moonfire_nvr::db] Loaded 0 video sample entries
I0302 123829.587 main moonfire_nvr::db] Loading cameras
I0302 123829.587 main moonfire_nvr::db] Loaded 0 cameras
E0302 123829.588 main moonfire_nvr] Error: unable to open sample file dir /var/lib/moonfire-nvr/sample: No such file or directory (os error 2)
cause: None

This seems to in part defeat the purpose of the config command. I would expect, as long as moonfire has been correctly built, this command to always allow changing of settings.

recording time adjustment

I had to do some work on my Raspberry and shut down moonfire and then took the power off. Although not planned, is later powered up, and interrupted power without a clean shutdown. Either way, once I started up to resume service, the web UI kept showing a latest recording just after 9PM (see attachment) and did not seem to catch up with the actual time which was around 10:40PM. Eventually I clicked on the 9:09PM file and it shows that it contained a recent recording (based on camera time stamp).
So, it seems that in the face of an interruption of recording(s) the time index gets messed up.
screen shot 2017-08-14 at 22 41 35
screen shot 2017-08-14 at 22 41 42

Update: After a few hours the index had not corrected. I perform a systemctl stop and then a start and after a few minutes, that seems to have cured the issue.

H.265 support

I think this is fairly simple to add (very similar to src/h264.rs) but there are a couple caveats:

  • I haven't found a freely available spec. Old versions of most of the ISO/IEC 14496 standards are freely available but I haven't seen this. We could probably puzzle together what to do based on ffmpeg source code or something but that's not ideal.
  • cameras might always do B-frames along with H.265, which would require reworking the video_index format.

It'd be nice to have though. My Dahua camera supports H.265, and I understand it's a significant improvement in video quality per byte.

Implement CORS policy

In order to allow UI development from a system that is not the moonfire-nvr server itself CORS headers would need to be added as appropriately. Sample code for this can be found here in one of the later comments.

At this time it might make sense to simply allow origin "any" or (* in the header) since the API is unsecured anyway. In future we may need to think about this more.

Without this support, running the ui code from, let's say localhost:3000 will not allow API access and, effectively, makes development hard. It is possible, in Safari for example, to disable cross domain policy enforcement through the develop menu, but that disables it across the board, which is rather unsafe if you forget to put it back, or browse dangerous sites in the meanwhile.

does "smart codec" work?

My Dahua Starlight camera has an option called "smart codec" which I haven't ever tried. I'm a little afraid it will enable B-frames (which Moonfire NVR currently doesn't support) or some such. I should try this to see if it actually works.

crash with ffmpeg 3.x

Hello Scott,

first I'd like to thank you for sharing your awesome work!

I have compiled your project on my Raspberry Pi 3 and it starts well but after configuring my first camera, the moonfire-nvr stops working while opening the input stream. Here is the output:

I0502 172118.091 main moonfire_nvr::db] Loading video sample entries
I0502 172118.091 main moonfire_nvr::db] Loaded 0 video sample entries
I0502 172118.092 main moonfire_nvr::db] Loading cameras
I0502 172118.092 main moonfire_nvr::db] Loaded 1 cameras
I0502 172118.092 main moonfire_nvr::db] Loading recordings for camera Terrasse
I0502 172118.092 main moonfire_nvr::db] Loaded 0 recordings for camera Terrasse
I0502 172118.092 main moonfire_nvr::cmds::run] Database is loaded.
I0502 172118.104 stream-Terrasse moonfire_nvr::streamer] Terrasse: Opening input: rtsp://acrux:[email protected]:8554/acrux-cam-1
I0502 172118.104 main moonfire_nvr::cmds::run] Ready to serve HTTP requests
[rtsp @ 0x73e18000] Estimating duration from bitrate, this may be inaccurate
I0502 172118.616 stream-Terrasse moonfire_nvr::stream] Discarding the first packet to work around https://trac.ffmpeg.org/ticket/5018

I have tried to configure it for serval RTSP streams but it always stops with the same error (I also tried this one: rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov)

I'm using version 1.16.0 (30cf806ef 2017-03-10) of rustc.

Do you have any idea? If you need any more information please let me know! Thanks a lot!

Regards
Chris

auto-recovery from full sample file dir

If one of the sample file dirs is on a completely full filesystem, currently Moonfire NVR will fail to start, as it's not able to write a new meta.tmp file (and then rename it to meta).

A couple scenarios for how this can happen:

  1. The disk can fill because of repeated flush failures (see c271cfa for an example of how this can happen), so that GC never happens, and new recordings keep getting written (but never added to the database). In this case, once the underlying flush failure problem is solved, I'd like restarting moonfire-nvr to just recover with no additional manual work. It almost does except for this meta.tmp write failure. (If you manually garbage-collect a single recording, it can write the new meta and recover.)
  2. The disk could fill due to some external thing, like another process filling the disk, or an administrator mistake like not leaving any slack when configuring "Directories and retention" (as the guide says you should). In this case, I'd like to be able to open up moonfire-nvr config and shrink it.

I have a few ideas for how to improve this.

  1. Do garbage collection before writing the new metadata file. In particular, any files in the garbage database table, and any files for each stream with recording_id >= stream.next_recording_id are already allowed to be gone, so they could be deleted before updating the open for the database or the directory.
  2. Reserve some space particularly for the new meta.tmp file. Maybe as a final step of the open process, a new meta.tmp file can be created with padding, so that if the disk later fills, truncating this allows a new one to be opened. This would be sort of best-effort (if the disk fills at just the wrong moment, it can't be written, so it doesn't help) but would make the problem much less likely.
  3. Don't use a meta.tmp file. Instead, assume overwriting a single block is atomic. (I believe this is true, but I'd like to find a good reference first. There's some discussion on this stackoverflow thread but it doesn't look conclusive/authoritative.) Maybe alter the metadata format to have a length prefix, then the serialized DirMeta message, then padding up to 512 bytes.

Here's an example failure, on a system running commit 95a8c2e or so.

Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]: main moonfire_nvr] IoError(Os { code: 28, kind: Other, message: "No space left on device" })
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]: stack backtrace:
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    0: failure::backtrace::internal::InternalBacktrace::new::h66f8c54ff6056b4a (0x8e656b)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/backtrace/internal.rs:44
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    1: failure::backtrace::Backtrace::new::h876f056a50fcd631 (0x8e6863)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/backtrace/mod.rs:111
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       <failure::backtrace::Backtrace as core::default::Default>::default::h40dae9253a7b436e
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/backtrace/mod.rs:125
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    2: <failure::error::error_impl::ErrorImpl as core::convert::From<F>>::from::h6e632e49444aaccb (0x606cab)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/error/error_impl.rs:19
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       <failure::error::Error as core::convert::From<F>>::from::he33a5f69ebf4c896
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at /home/slamb/.cargo/registry/src/github.com-1ecc6299db9ec823/failure-0.1.3/src/error/mod.rs:36
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       moonfire_db::dir::write_meta::hb48f16c36842bd03
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at db/dir.rs:168
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    3: moonfire_db::dir::SampleFileDir::write_meta::h3b85e404c7496dd7 (0x607217)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at db/dir.rs:265
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       moonfire_db::dir::SampleFileDir::open::h5aac33e4d93872e9
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at db/dir.rs:190
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    4: moonfire_db::db::LockedDatabase::open_sample_file_dirs::h22ab4350ae969510 (0x5e2097)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at db/db.rs:1009
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    5: moonfire_nvr::cmds::run::run::h81b1d3717bd60175 (0x4c8557)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/cmds/run.rs:183
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    6: moonfire_nvr::cmds::Command::run::h0abbf4ae1ce453a0 (0x4e1a1f)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/cmds/mod.rs:62
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    7: moonfire_nvr::main::h44bb0b191820bbe6 (0x48f727)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/main.rs:108
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    8: std::rt::lang_start::{{closure}}::h5016b2e0fefece16 (0x458b4b)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at /rustc/4a45578bc58ff262864f72680cc02e83f5d2f5b3/src/libstd/rt.rs:74
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:    9: std::rt::lang_start_internal::{{closure}}::h506a35c73ad6511f (0x9053b3)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/libstd/rt.rs:59
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       std::panicking::try::do_call::hae1763164ad427b9
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/libstd/panicking.rs:306
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:   10: __rust_maybe_catch_panic (0x90f04f)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/libpanic_unwind/lib.rs:102
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:   11: std::panicking::try::h1a3656077a003cfd (0x905d43)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/libstd/panicking.rs:285
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       std::panic::catch_unwind::h96042a7830ee1a37
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/libstd/panic.rs:398
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:       std::rt::lang_start_internal::h383433ce5e1a9852
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:              at src/libstd/rt.rs:58
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:   12: main (0x48fb5b)
Jan 28 06:02:14 odroid.home.slamb.org moonfire-nvr[935]:   13: __libc_start_main (0xb58d6fe5)

calendar view should show unflushed recordings

As of schema version 3 (a5528e1), it's possible to view recordings before they're flushed to the database. Except...the UI won't let you select the day if it has only unflushed recordings, because they're not reflected in the days map.

We might want unflushed (or at least growing) recordings to be separate from the main days map to not interfere with #40 , as they're still changing. (anything unflushed can go away if the system restarts; and growing stuff can change in both duration and starting timestamp.) so possibly put them in a separate map which gets merged in Javascript.

non-redacted rtsp:// URLs in log

Building/installing the latest version (ignoring 4 test errors reported in another issue) results in operative UI, but no recordings being made. Relevant portion of the log file:

Oct 22 17:03:15 moonfire moonfire-nvr[27442]: avcodec compiled=56.60.100 running=56.1.0
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: avformat compiled=56.40.101 running=56.1.0
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: avutil compiled=54.31.100 running=54.3.0
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Front Left moonfire_nvr::streamer] Front Left: Opening input: rtsp://admin:[email protected]/Streaming/Channels/1
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Back moonfire_nvr::streamer] Back: Opening input: rtsp://admin:[email protected]/Streaming/Channels/1
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: main moonfire_nvr::cmds::run] Ready to serve HTTP requests
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Front Right moonfire_nvr::streamer] Front Right: Opening input: rtsp://admin:[email protected]/Streaming/Channels/1
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Side moonfire_nvr::streamer] Side: Opening input: rtsp://admin:[email protected]/Streaming/Channels/1
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Front Left moonfire_nvr::stream] While opening URL rtsp://admin:[email protected]/Streaming/Channels/1, some options were not understood: user-agent=moonfire-nvr, stimeout=10000000
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Front Right moonfire_nvr::stream] While opening URL rtsp://admin:[email protected]/Streaming/Channels/1, some options were not understood: user-agent=moonfire-nvr, stimeout=10000000
Oct 22 17:03:15 moonfire moonfire-nvr[27442]: stream-Back moonfire_nvr::stream] While opening URL rtsp://admin:[email protected]/Streaming/Channels/1, some options were not understood: user-agent=moonfire-nvr, stimeout=10000000
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: stream-Side moonfire_nvr::stream] While opening URL rtsp://admin:[email protected]/Streaming/Channels/1, some options were not understood: user-agent=moonfire-nvr, stimeout=10000000
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: [rtsp @ 0x72e19000] Estimating duration from bitrate, this may be inaccurate
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: stream-Front Right moonfire_nvr::streamer] Front Right: sleeping for Duration { secs: 1, nanos: 0 } after error: Error: ffmpeg: Unknown error -1
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: cause: Some(Error(1))
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: [rtsp @ 0x73019000] Estimating duration from bitrate, this may be inaccurate
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: stream-Back moonfire_nvr::streamer] Back: sleeping for Duration { secs: 1, nanos: 0 } after error: Error: ffmpeg: Unknown error -1
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: cause: Some(Error(1))
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: [rtsp @ 0x73419000] Estimating duration from bitrate, this may be inaccurate
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: stream-Front Left moonfire_nvr::streamer] Front Left: sleeping for Duration { secs: 1, nanos: 0 } after error: Error: ffmpeg: Unknown error -1
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: cause: Some(Error(1))
Oct 22 17:03:16 moonfire moonfire-nvr[27442]: [rtsp @ 0x72c19000] Estimating duration from bitrate, this may be inaccurate
Oct 22 17:03:17 moonfire moonfire-nvr[27442]: stream-Side moonfire_nvr::streamer] Side: sleeping for Duration { secs: 1, nanos: 0 } after error: Error: ffmpeg: Unknown error -1
Oct 22 17:03:17 moonfire moonfire-nvr[27442]: cause: Some(Error(1))

Notice that several URLs are logging without redacting the username/password (I redacted manually to list password "dolf----" above, but original output showed full password).

/etc/localtime not handled correctly

I tried to startup and received the following in the log file:

Oct 22 16:49:50 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loading video sample entries
Oct 22 16:49:50 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loaded 4 video sample entries
Oct 22 16:49:50 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loading cameras
Oct 22 16:49:50 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loaded 4 cameras
Oct 22 16:49:50 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loading recordings for camera Front Left
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loaded 12781 recordings for camera Front Left
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loading recordings for camera Front Right
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loaded 11659 recordings for camera Front Right
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loading recordings for camera Side
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loaded 11527 recordings for camera Side
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loading recordings for camera Back
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::db] Loaded 11908 recordings for camera Back
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: main moonfire_nvr::cmds::run] Database is loaded.
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: thread 'main' panicked at 'unable to read localtime symlink: Error { repr: Os { code: 22, message: "Invalid argument" } }', /checkout/src/libcore/result.rs:906:4
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: stack backtrace:
Oct 22 16:49:51 moonfire moonfire-nvr[27295]: 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
Oct 22 16:49:52 moonfire moonfire-nvr[27295]: at ./checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
Oct 22 16:49:52 moonfire moonfire-nvr[27295]: 1: std::sys_common::backtrace::_print
Oct 22 16:49:52 moonfire moonfire-nvr[27295]: at ./checkout/src/libstd/sys_common/backtrace.rs:71

It turns out that on my Raspbian Jesse system, /etc/localtime is a copy of the required file from /usr/share/zoneinfo and not a symlink to it. Seems to me that the code should be able to handle either scheme.
When I changed the situation, by hand, to be a symlink, startup became possible.

on-NVR video analytics

IMHO, this is superior to on-camera motion detection (#29) because from what I've seen on-camera motion detection kind of sucks:

  • it has a bunch of false negatives and positives; there at least exist algorithms I could try on the NVR that are somewhat better
  • it has completely different options between camera brands
  • it's very tedious to tune because you can't just save a bunch of video segments and try out different options on them
  • it's all a closed-source, mostly undocumented black box

on the other hand, on-NVR has more hardware needs (details TBD but significant work to do which scales with the number of cameras) and is much more complex to implement:

  • needs more schema work as noted in #28 to track config (algorithm, parameters, mask), progress (last segment handled, reference image), and perhaps output (if more detail is desired than just the on/off/unknown signal; maybe a number indicating how much motion is in each grid square or something)
  • needs a driver process that feeds it segments as they become available and probably skips some if it falls too far behind
  • needs H.264/H.265 decoding—not too hard to use ffmpeg for this but might want to take advantage of hardware decoding
  • needs some algorithm development, and there are a lot of possible algorithms (classical and machine learning!) out there with different pros and cons
  • to make a decent algorithm testbed, needs H.264/H.265 encoding so you can create a video that shows you the reference image and motion detection mask alongside the source image
  • might require using fancier instructions/hardware (SIMD, GPU, DSP, ISP, and/or TPU) for decent performance
  • might want to support offloading to another machine via RPC boundary

Possible incorrect test code

During a build in a Docker instance, I got test failures on code that was straight from github/master and built and tested fine on my rPi:

failures:

---- db::tests::test_adjust_days stdout ----
	thread 'db::tests::test_adjust_days' panicked at 'assertion failed: `(left == right)`
  left: `Some(CameraDayValue { recordings: 1, duration: Duration(5400000) })`,
 right: `None`', src/db.rs:1521:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- db::tests::test_day_bounds stdout ----
	thread 'db::tests::test_day_bounds' panicked at 'assertion failed: `(left == right)`
  left: `Time(135683424000000)..Time(135691200000000)`,
 right: `Time(135685692000000)..Time(135693468000000)`', src/db.rs:1563:9

---- recording::tests::test_format_time stdout ----
	thread 'recording::tests::test_format_time' panicked at 'assertion failed: `(left == right)`
  left: `"2006-01-02T15:04:05:00000-08:00"`,
 right: `"2006-01-02T23:04:05:00000-00:00"`', src/recording.rs:558:9

---- mp4::tests::test_round_trip_with_subtitles stdout ----
	thread 'mp4::tests::test_round_trip_with_subtitles' panicked at 'assertion failed: `(left == right)`
  left: `"de382684a471f178e4e3a163762711b0653bfd83"`,
 right: `"cb5ff51cda4d7dbae05b4a534afd578a0e589570"`', src/mp4.rs:2135:9

---- recording::tests::test_parse_time stdout ----
	thread 'recording::tests::test_parse_time' panicked at 'assertion failed: `(left == right)`
  left: `102261874050000`,
 right: `102259282050000`: parsing 2006-01-02T15:04:05', src/recording.rs:551:13


failures:
    db::tests::test_adjust_days
    db::tests::test_day_bounds
    mp4::tests::test_round_trip_with_subtitles
    recording::tests::test_format_time
    recording::tests::test_parse_time

test result: FAILED. 43 passed; 5 failed; 0 ignored; 0 measured; 0 filtered out

I realized that the Docker instance was on UTC time. I modified the Docker image to be on America/Los_Angeles and run the build again. This time no errors.

The initial built was run at approximately 2018-03-17 06:00 UTC or 2018-03-16 23:00 PDT, the second successful built approximately 30 minutes later (in case the actual time is relevant).

This makes me suspicious of the test code itself, but it may also point at an actual problem in the Moonfire code.

"pinned" recordings

Currently Moonfire NVR deletes recordings in strict FIFO order. It'd be nice to be able to explicitly say some section of video should be retained; also to have automatically increased retention when there's a motion detection event.

audio support

It'd be nice to support audio. I think there are some non-trivial things to work out, though:

  • ffmpeg's rtsp support has a nasty bug when an audio stream is present; see #36. [edit: see investigation here. This bug may be rarer than I realized so perhaps is not really a blocker for most people.]
  • time unit. I picked 90 kHz as the fundamental unit of time because that works out well for RTSP/H.264 video. But I think audio codecs do different rates (such as 8 kHz). Do we do the lowest common multiplier of the supported audio and video codecs? if it's much higher, when does that wrap / when does converting it to a float for Javascript lose precision? One option: have a higher frequency in the database schema for timestamps on recording rows. In the video index, keep 90 kHz or even less to save storage space. The final frame is implicitly the rest of the duration of the total recording.
  • does this affect when we can seek to / how we generate edit lists?
  • need to define an audio_index like video_index.
  • We have to interleave the video and audio at some reasonably fine-grained interval (every key frame?). does this significantly blow up the in-memory .mp4 data structures? how do we represent the interleaving?
  • generating the sample entry box, similar to what we do for H.264 video.
  • frequency adjustment: as described in design/time.md, Moonfire NVR adjusts the timestamps of video frames to correct for inaccurate clocks in the cameras. Can we do those adjustments on audio without noticeably changing the pitch? or would we have to decode/re-encode audio? how much CPU would this require?

First Run Database Install Error

Hi,

I attempted a fresh install on a new Ubuntu 18.04 environment from the master branch. script/build.sh went fine until this:

./scripts/script-functions.sh: line 292: /home/kristopher/code/moonfire-nvr/src/schema.sql: No such file or directory

and during startup:

Apr 30 08:23:16 Sal systemd[1]: Started Moonfire NVR.
Apr 30 08:23:16 Sal moonfire-nvr[16201]: main moonfire_nvr] SqliteFailure(Error { code: CannotOpen, extended_code: 14 }, Some("unable to open database file"))
Apr 30 08:23:16 Sal moonfire-nvr[16201]: stack backtrace:

I saw that schema.sql was removed from src, so I ran this command:

sudo -u moonfire-nvr sqlite3 ~moonfire-nvr/db/db < ~/code/moonfire-nvr/db/schema.sql

After which, the syslog returned:

Apr 30 08:29:08 Sal systemd[1]: Started Moonfire NVR.
Apr 30 08:29:08 Sal moonfire-nvr[17050]: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: QueryReturnedNoRows
Apr 30 08:29:08 Sal moonfire-nvr[17050]: stack backtrace:
Apr 30 08:29:08 Sal moonfire-nvr[17050]:    0:     0x55f82da4626e - backtrace::backtrace::libunwind::trace::hd98210360bf7305b

Attempting to run the config yeilds:

kristopher@Sal:~/code/moonfire-nvr$ sudo -u moonfire-nvr moonfire-nvr config
E0430 084330.569 main moonfire_nvr] QueryReturnedNoRows

Unfortunately I am stuck here and cannot get the NVR to load. Please advise. Thanks!

Arlo?

Could Moonfire support Arlo? Putting aside any debates about the usefulness of non-full-time streaming, it looks like others have decoded RTSP streams in Arlo. Could Moonfire record the Arlo streams?

event stream

I'd like to have an API endpoint which streams events as they happen, such as:

  • segment of recording was deleted
  • segment of recording was created. (with an additional flag to indicate the next segment of recording for that stream is in progress, so you can assume it has video from then to approximately now.)
  • a signal was changed

With this, the frontend UI could update itself without requiring the user to hit refresh.

It could be a multipart/mixed WebSockets stream (like the live view) of JSON events that happened in the current "open", each with a sequence number.

Other API calls like /api/?days=true or /api/camera/<uuid>/<stream>/recordings would have a HTTP header showing the matching sequence number. The frontend could use those together to compute the contents at any later point.

Add ability to serve gzip compressed resources

Using web pack, as we do, it is easy to generate duplicates of various bundles that are gzip-ed and have a name that is identical except for an additional suffix of .gz.

If a request comes in that contains the "Accept-Encoding: gzip" header, it would be nice if we would serve up any .gz version of a resource, if it exists. This does not require building on-the-fly gzip capability into the server.

It would come at the cost of an extra stat call to see if the gz resource exists unless we also have the server build a resource map at startup. Probably not important enough performance wise for now.

update UI deps

The UI dependencies are quite stale. github is giving me security warnings about them (although I think they're more relevant to node-js uses than to what Moonfire NVR is doing). Let's update them.

In theory this is just a yarn update but if I do that, following builds fail. I imagine the configs need to be reworked in some way, etc. See some previous mention at #62.

@dolfs

$ yarn build
yarn run v1.12.3
$ webpack --mode production --config webpack/prod.config.js
/Users/slamb/git/moonfire-nvr/node_modules/webpack-cli/bin/config-yargs.js:89
				describe: optionsSchema.definitions.output.properties.path.description,
				                                           ^

TypeError: Cannot read property 'properties' of undefined
    at module.exports (/Users/slamb/git/moonfire-nvr/node_modules/webpack-cli/bin/config-yargs.js:89:48)
    at /Users/slamb/git/moonfire-nvr/node_modules/webpack-cli/bin/webpack.js:60:27
    at Object.<anonymous> (/Users/slamb/git/moonfire-nvr/node_modules/webpack-cli/bin/webpack.js:515:3)
    at Module._compile (internal/modules/cjs/loader.js:722:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10)
    at Module.load (internal/modules/cjs/loader.js:620:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
    at Function.Module._load (internal/modules/cjs/loader.js:552:3)
    at Module.require (internal/modules/cjs/loader.js:658:17)
    at require (internal/modules/cjs/helpers.js:22:18)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

test failures with ffmpeg 3.x

Since 857a66f, Moonfire NVR compiles with ffmpeg 3.x and doesn't segfault, but tests are failing. It looks like the .mp4 output has changed in some fashion (I've only looked at the hashed, not full diffs), and the interpretation of edit lists may have changed.

failures:

---- mp4::tests::test_round_trip_with_shorten stdout ----
	thread 'mp4::tests::test_round_trip_with_shorten' panicked at 'assertion failed: `(left == right)`
  left: `"e0d28ddf08e24575a82657b1ce0b2da73f32fd88"`,
 right: `"c061c644f9f2188be34248da4eda5752bc916001"`', src/mp4.rs:2067:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- mp4::tests::test_round_trip_with_edit_list stdout ----
	thread 'mp4::tests::test_round_trip_with_edit_list' panicked at 'assertion failed: `(left == right)`
  left: `0`,
 right: `1`', src/mp4.rs:1810:12

---- mp4::tests::test_round_trip stdout ----
	thread 'mp4::tests::test_round_trip' panicked at 'assertion failed: `(left == right)`
  left: `"1e5331e8371bd97ac3158b3a86494abc87cdc70e"`,
 right: `"2059a2d0b797cb1b0551c1c1fddb25c788fe13ab"`', src/mp4.rs:2007:8

---- mp4::tests::test_round_trip_with_subtitles stdout ----
	thread 'mp4::tests::test_round_trip_with_subtitles' panicked at 'assertion failed: `(left == right)`
  left: `"de382684a471f178e4e3a163762711b0653bfd83"`,
 right: `"dec3fffbdb453e420dfeb20d37816e54a3936c8b"`', src/mp4.rs:2027:8


failures:
    mp4::tests::test_round_trip
    mp4::tests::test_round_trip_with_edit_list
    mp4::tests::test_round_trip_with_shorten
    mp4::tests::test_round_trip_with_subtitles

test result: FAILED. 42 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out

pure Rust RTSP client library

Drop ffmpeg's libavformat for RTSP. Use a pure Rust RTSP library instead. None seems to exist today, so probably write one.

Why?

  • make building and installing easier. This is pretty much obsoleted by the Docker build.
  • security. I don't like considering the cameras trusted—they're poorly written at best, hostile at worst. I'd like to interface with them using memory-safe Rust code rather than C to improve security.
  • Address ffmpeg missing features / bugs. Timeouts (not supported on Raspbian Jessie at least and buggy even on modern ffmpeg, see #126), audio problems (see #36), other buffering/pts oddities (https://trac.ffmpeg.org/ticket/5018). Some of the other errors folks have seen (mismatched CSeq and such) may or may not be due to ffmpeg problems; we haven't fully diagnosed them (see eg #114).
  • maybe add support for RTP/H.264 NAL unit types 25 (STAP-B), 26 (MTAP-16), 27 (MTAP-24), and 29 (FU-B). ffmpeg is missing these now, and one of my cameras occasionally logs errors about them as it drops the connection. I think it's very rare to actually use these; none of my cameras do. ffmpeg is just logging about them because the stream is getting corrupted either on the camera side or because of the timeout problem mentioned above. So I probably won't add this support unless someone actually needs it.
  • allow easily accessing timestamps in the 0xABAC ONVIF RTP extension and RTCP sender reports.
  • likely necessary for SVC support. Looks like no, at least with the "pseudo-SVC" that my Hikvision and Dahua cameras have. (Not standard SVC, just altering what H.264 frames are used as references, which with some work on my part could become temporal SVC.)
  • be a bit more efficient (less copying, no transforming into an intermediate Annex B format), although it's surely insignificant compared to the cost of on-NVR analytics.
  • future RTSP server/proxying support, as an alternative to Moonfire NVR's custom web socket/mp4 fragment live view protocol.

We'll still want ffmpeg's libavcodec for H.264 decoding for on-NVR video analytics, although that could happen in a separate process than the main moonfire-nvr one.

"signals" schema (for motion detection and such)

There needs to be some schema for motion detection events, and ideally some similar things like events from my Elk alarm system. I think it'd just say at this wall time, the signal is "on", "off", or "unknown", with support for long-lived and momentary on events. If the system's wall clock is suspect, the data is useless, and that's okay.

It could be used:

  • directly by something that does on-camera motion detection with ONVIF
  • directly by something that manipulates events with a JSON interface, such as the Elk alarm watcher.
  • indirectly by something that does on-NVR motion detection. I think this would just be part of the schema. At least it needs some additional configuration (mask, sensitivity) and state (last recording processed, current reference frame). It might also track motion in a grid on a recording-by-recording basis so you could recompute the mask or something.

Here's my first idea of schema.

create table signal (
  id integer primary key,

  uuid blob primary key check (length(uuid) = 16),

  -- a uuid describing the originating object, such as the uuid of the camera
  -- for built-in motion detection. There will be a JSON interface for adding
  -- events; it will require this UUID to be supplied. An external uuid might
  -- indicate "my house security system's zone 23".
  source_uuid blob not null check (length(uuid) = 16),

  -- a uuid describing the type of event. A registry (TBD) will list built-in
  -- supported types, such as "Hikvision on-camera motion detection", or
  -- "ONVIF on-camera motion detection". External programs can use their own
  -- uuids, such as "Elk security system watcher".
  type_uuid blob not null check (length(uuid) = 16),

  -- a short human-readable description of the event to use in mouseovers or event
  -- lists, such as "driveway motion" or "front door open".
  short_name not null,

  unique (source_uuid, type_uuid)
);

-- Associations between event sources and cameras.
-- For example, if two cameras have overlapping fields of view, they might be
-- configured such that each camera is associated with both its own motion and
-- the other camera's motion.
create table signal_camera (
  signal_id integer references signal (id),
  camera_id integer references camera (id),

  -- type:
  --
  -- 0 means direct association, as if the event source if the camera's own
  -- motion detection. Here are a couple ways this could be used:
  --
  -- * when viewing the camera, hotkeys to go to the start of the next or
  --   previous event should respect this event.
  -- * a list of events might include the recordings associated with the
  --   camera in the same timespan.
  --
  -- 1 means indirect association. A screen associated with the camera should
  -- given some indication of this event, but there should be no assumption
  -- that the camera will have a direct view of the event. For example, all
  -- cameras might be indirectly associated with a doorknob press. Cameras at
  -- the back of the house shouldn't be expected to have a direct view of this
  -- event, but motion events shortly afterward might warrant extra scrutiny.
  type integer not null,

  primary key (signal_id, camera_id)
) without rowid;

-- State of signals as of a given timestamp.
create table signal_state (
  -- seconds since 1970-01-01 00:00:00 UTC.
  time_sec integer primary key,

  -- Changes at this timestamp, if any.
  --
  -- It's possible for a single signal to be in both newly_active and either
  -- newly_inactive or newly_unknown; this means that the signal is
  -- momentarily active.
  --
  -- The blobs each encode a list of signal ids.
  -- They do so as delta-encoded varints. For example,
  -- input signals: 1    3    200 (must be sorted)
  -- deltas:        1    2    197
  -- varint:        \x01 \x02 0xc5 0x01
  newly_active blob,
  newly_inactive blob,
  newly_unknown blob,
);

On startup, we'd do a sequential scan of the whole thing and compute the days map. Need to ensure this doesn't make startup time unreasonable. If it's too bad, we'll need to store the days map instead, which means ensuring the timezone information doesn't change from run to run, which may not be easy to do. (We'd also have to rows indicating the full state of all signals at some interval, but that's relatively easy.) Or we could switch to a faster database (#44).

I put together all the changes at a single timestamp in one row because I'm imagining there being times when many/all signals change at once, such as on startup or shutdown. This would be more efficient in that scenario.

During normal operation, there should be a bounded amount of IO to do on this. The JSON API for manipulating this should probably let you change a signal's state for no more than a day at a time or some such.

There needs to be a frontend interface to make this useful. The simplest one would be to just show you a expandable thing for each event with all the recordings in it +/- a minute or something.

Related schema change: ideally you could annotate a region of video or an signal-on event or some such with a bit of text.

good Internet-facing webserver

I want Moonfire to be a good Internet-facing webserver.

  • support https
  • support https...with automatic ACME (letsencrypt) support for HTTP-01 and/or TLS-ALPN-01 challenges.
  • access logs: similar to nginx or Apache keep, ideally also with a field showing the logged-in user.

In the meantime, we have a guide for setting up a proxy in front: Security Moonfire NVR and exposing it to the Internet.

letsencrypt details

I want to serve everything over https, ideally automatically setting up new key pairs via letsencrypt + the acme-client crate.

I'd love it if someone were to write a crate (or integrate into some framework like rocket) something that uses acme-client, hyper, and a storage hook just make sure the http port responds to the challenges and the https port uses the certificate it gets. Moonfire NVR would plug in a storage hook that puts stuff in the SQLite database. This would be by far the slickest way to do https.

Consider enabling HTTP Strict Transport Security. Maybe a pref for that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.