9 Commits

Author SHA1 Message Date
Scott Lamb
292bcbaad5 Add helper for adjusting date-to-duration map.
The helper isn't used yet. The goal is to export this on /camera/<uuid>/ as
described in a TODO in design/api.md.

The next step is to keep MoonfireDatabase::CameraData::days up-to-date:

* Init: call on every recording (replacing the current aggregated query with
  a recording-by-recording query)
* InsertRecording, DeleteRecordings: call for added/removed recordings

then return it from GetCamera and pass it along to the client in
WebInterface::HandleJsonCameraDetail.
2016-05-01 21:26:17 -07:00
Scott Lamb
3b0dc5368e Write using the shiny new schema
There's a lot of work left to do on this:

* important latency optimization: the recording threads block
  while fsync()ing sample files, which can take 250+ ms. This
  should be moved to a separate thread to happen asynchronously.

* write cycle optimizations: several SQLite commits per camera per minute.

* test coverage: this drops testing of the file rotation, and
  there are several error paths worth testing.

* ffmpeg oddities to investigate:

  * the out-of-order first frame's pts
  * measurable delay before returning packets
  * it sometimes returns an initial packet it calls a "key" frame that actually
    has an SEI recovery point NAL but not an IDR-coded slice NAL, even though
    in the input these always seem to come together. This makes playback
    starting from this recording not work at all on Chrome. The symptom is
    that it loads a player-looking thing with the proper dimensions but
    playback never actually starts.

  I imagine these are all related but haven't taken the time to dig through
  ffmpeg code and understand them. The right thing anyway may be to ditch
  ffmpeg for RTSP streaming (perhaps in favor of the live555 library), as
  it seems to have other omissions like making it hard/impossible to take
  advantage of Sender Reports. In the meantime, I attempted to mitigate
  problems by decreasing ffmpeg's probesize.

* handling overlapping recordings: right now if there's too much time drift or
  a time jump, you can end up with recordings that the UI won't play without
  manual database changes. It's not obvious what the right thing to do is.

* easy camera setup: currently you have to manually insert rows in the SQLite
  database and restart.

but I think it's best to get something in to iterate from.

This deletes a lot of code, including:

* the ffmpeg video sink code (instead now using a bit of extra code in Stream
  on top of the SampleFileWriter, SampleIndexEncoder, and MoonfireDatabase
  code that's been around for a while)

* FileManager (in favor of new code using the database)

* the old UI

* RealFile and friends

* the dependency on protocol buffers, which was used for the config file
  (though I'll likely have other reasons for using protocol buffers later)

* even some utilities like IsWord that were just for validating the config
2016-02-03 23:22:37 -08:00
Scott Lamb
8ee1ab1c7b Extend ListCameras to return more ifno
In particular, this returns all the extra configuration data that will be
necessary to actually instantiate streams from the database rather than the
soon-to-be-removed configuration file.
2016-01-31 23:27:52 -08:00
Scott Lamb
1bd5c8aafe Sanify sample directory references.
Before, I had a gross hardcoded path in moonfire-db.cc + a hacky
Recording::sample_file_path (which is StrCat(sample_file_dir, "/", uuid),
essentially). Now, things expect to take a File* to the sample file directory
and use openat(2). Several things had to change in the process:

* RealFileSlice now takes a File* dir.
* File has an Open that returns an fd (for RealFileSlice's benefit).
* BuildMp4 now is in WebInterface rather than MoonfireDatabase. The latter
  only manages the SQLite database, so it shouldn't know anything about the
  sample file directory.
2016-01-31 22:41:30 -08:00
Scott Lamb
708bbf5eb2 Revert "clang-format-3.7 --style=Google -i."
This reverts commit ad4beac464f6275bf78ce5b8d6958d9e7f232f36.
That commit wasn't as advertised; I had several other changes mixed in my
working copy. I'd also copied a working copy from one path to another, and
it turns out the cmake build subdir was still referring to the original, so
I hadn't realized this commit didn't even build. :(
2016-01-31 21:53:43 -08:00
Scott Lamb
ad4beac464 clang-format-3.7 --style=Google -i. 2016-01-31 21:16:33 -08:00
Scott Lamb
699ffe7777 Expanded, reasonably efficient SQL operations.
* Schema revisions. The most dramatic is the addition of a covering index on
  (camera_id, start_time_90k) that avoids the need to make sparse accesses
  into the recording table (where the desired data is intermixed with both
  the large blobs and rows from other cameras). A query over a year's data
  previously took many seconds (6+ even in a form without the video_index)
  and now is roughly 10X faster. Queries for a couple weeks now should be
  unnoticeably fast.

  Other changes to shrink the rows, such as duration_90k instead of
  end_time_90k (more compact varint encoding) and video_sample_entry_id
  (typically 1 byte) instead of video_sample_entry_sha1 (20 bytes).
  And more CHECK constraints for good measure.

* Caching of expensive computations and logic to keep them up to date.
  The top-level web view previously went through the entire recording table,
  which was even slower. Now it is served from a small map in RAM.

* Expanded the scope of operations to cover (hopefully) everything needed for
  recording into the SQLite database.

* Added tests of MoonfireDatabase. These are basic tests that don't
  exercise a lot of error cases, but at least they exist.

The main MoonfireDatabase functionality still missing is support for quickly
seeing what calendar days have data over the full timespan of a camera. This
is more data to compute and cache.
2016-01-24 17:57:46 -08:00
Scott Lamb
b9d6526492 Optimize the SQLite query for building .mp4s.
On my laptop, with a month's data, a test query would take 0.1 to 0.2 seconds
before. Now it takes 0.001 to 0.004 seconds.

I improved this by creating and taking advantage of an index on start time.
It's a little more complicated than that because the desired timespan is
specified in terms of a recording's start and end time, not start time alone.
I defined a maximum duration of a recording (5 minutes) and specified this
with an extra condition in the query so that the end time can be used to
narrow the valid range of start times.

"explain query plan select ..." output confirms it's using the index with
both > and < comparisons:

0|0|0|SEARCH TABLE recording USING INDEX recording_start_time_90k (start_time_90k>? AND start_time_90k<?)
0|1|1|SEARCH TABLE video_sample_entry USING INDEX sqlite_autoindex_video_sample_entry_1 (sha1=?)

I also refactored ListMp4Recordings out of BuildMp4File to make the measurement
easier.
2016-01-17 01:14:29 -08:00
Scott Lamb
40cd983355 Web interface to the new SQLite schema.
This is almost certain to have performance problems with large databases,
but it's a useful starting point.

No tests yet. It shouldn't be too hard to add some for moonfire-db.h, but
I'm impatient to fake up enough data to check on the performance and see
what needs to change there first.
2016-01-16 22:54:16 -08:00