2016-01-02 01:06:47 -05:00
|
|
|
# This file is part of Moonfire NVR, a security camera digital video recorder.
|
|
|
|
# Copyright (C) 2016 Scott Lamb <slamb@slamb.org>
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# In addition, as a special exception, the copyright holders give
|
|
|
|
# permission to link the code of portions of this program with the
|
|
|
|
# OpenSSL library under certain conditions as described in each
|
|
|
|
# individual source file, and distribute linked combinations including
|
|
|
|
# the two.
|
|
|
|
#
|
|
|
|
# You must obey the GNU General Public License in all respects for all
|
|
|
|
# of the code used other than OpenSSL. If you modify file(s) with this
|
|
|
|
# exception, you may extend this exception to your version of the
|
|
|
|
# file(s), but you are not obligated to do so. If you do not wish to do
|
|
|
|
# so, delete this exception statement from your version. If you delete
|
|
|
|
# this exception statement from all source files in the program, then
|
|
|
|
# also delete it here.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
# CMakeLists.txt: top-level definitions for building Moonfire NVR.
|
|
|
|
|
|
|
|
cmake_minimum_required(VERSION 3.0.2)
|
|
|
|
project(moonfire-nvr)
|
|
|
|
|
|
|
|
if(CMAKE_VERSION VERSION_LESS "3.1")
|
|
|
|
set(CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}")
|
|
|
|
else()
|
|
|
|
set(CMAKE_CXX_STANDARD 11)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
set(CMAKE_CXX_FLAGS "-Wall -Werror -pedantic-errors ${CMAKE_CXX_FLAGS}")
|
2016-01-14 19:14:53 -05:00
|
|
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb")
|
2016-01-02 01:06:47 -05:00
|
|
|
|
|
|
|
#
|
|
|
|
# Dependencies.
|
|
|
|
#
|
|
|
|
|
|
|
|
# https://gflags.github.io/gflags/#cmake mentions a cmake module, but at
|
|
|
|
# least on Ubuntu 15.10, libgflags-dev does not include it. There's no
|
|
|
|
# pkgconfig either. Do this by hand.
|
|
|
|
find_library(GFLAGS_LIBRARIES gflags)
|
|
|
|
find_library(RE2_LIBRARIES re2)
|
|
|
|
find_library(PROFILER_LIBRARIES profiler)
|
|
|
|
|
|
|
|
# https://cmake.org/cmake/help/v3.0/module/FindPkgConfig.html
|
|
|
|
find_package(PkgConfig)
|
|
|
|
pkg_check_modules(FFMPEG REQUIRED libavutil libavcodec libavformat)
|
Construct HTTP responses incrementally.
This isn't as much of a speed-up as you might imagine; most of the large HTTP
content was mmap()ed files which are relatively efficient. The big improvement
here is that it's now possible to serve large files (4 GiB and up) on 32-bit
machines. This actually works: I was just able to browse a 25-hour, 37 GiB
.mp4 file on my Raspberry Pi 2 Model B. It takes about 400 ms to start serving
each request, which isn't exactly zippy but might be forgivable for such a
large file. I still intend for the common request from the web interface to be
for much smaller fragmented .mp4 files.
Speed could be improved later through caching. Right now my test code is
creating a fresh VirtualFile from a database query on each request, even
though it hasn't changed. The tricky part will be doing cache invalidation
cleanly if it does change---new recordings are added to the requested time
range, recordings are deleted, or existing recordings' timestamps are changed.
The downside to the approach here is that it requires libevent 2.1 for
evhttp_send_reply_chunk_with_cb. Unfortunately, Ubuntu 15.10 and Debian Jessie
still bundle libevent 2.0. There are a few possible improvements here:
1. fall back to assuming chunks are added immediately, so that people with
libevent 2.0 get the old bad behavior and people with libevent 2.1 get the
better behavior. This is kind of lame, though; it's easy to go through
the whole address space pretty fast, particularly when the browsers send
out requests so quickly so there may be some unintentional concurrency.
2. alter the FileSlice interface to return a pointer/destructor rather than
add something to the evbuffer. HttpServe would then add each chunk via
evbuffer_add_reference, and it'd supply a cleanupfn that (in addition to
calling the FileSlice-supplied destructor) notes that this chunk has been
fully sent. For all the currently-used FileSlices, this shouldn't be too
hard, and there are a few other reasons it might be beneficial:
* RealFileSlice could call madvise() to control the OS buffering
* RealFileSlice could track when file descriptors are open and thus
FileManager's unlink() calls don't actually free up space
* It feels dirty to expose libevent stuff through the otherwise-nice
FileSlice interface.
3. support building libevent 2.1 statically in-tree if the OS-supplied
libevent is unsuitable.
I'm tempted to go with #2, but probably not right now. More urgent to commit
support for writing the new format and the wrapper bits for viewing it.
2016-01-15 01:41:49 -05:00
|
|
|
pkg_check_modules(LIBEVENT REQUIRED libevent>=2.1)
|
2016-01-02 01:06:47 -05:00
|
|
|
pkg_check_modules(GLOG REQUIRED libglog)
|
2016-01-07 02:27:44 -05:00
|
|
|
pkg_check_modules(OPENSSL REQUIRED libcrypto)
|
2016-01-08 01:59:34 -05:00
|
|
|
pkg_check_modules(SQLITE REQUIRED sqlite3)
|
2016-01-12 12:46:21 -05:00
|
|
|
pkg_check_modules(UUID REQUIRED uuid)
|
2016-01-02 01:06:47 -05:00
|
|
|
|
|
|
|
# Check if ffmpeg support "stimeout".
|
|
|
|
set(CMAKE_REQUIRED_INCLUDES ${FFMPEG_INCLUDES})
|
|
|
|
set(CMAKE_REQUIRED_LIBRARIES ${FFMPEG_LIBRARIES})
|
|
|
|
include(CheckCSourceRuns)
|
|
|
|
check_c_source_runs([[
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <libavutil/opt.h>
|
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
av_register_all();
|
|
|
|
AVInputFormat *input = av_find_input_format("rtsp");
|
|
|
|
const AVClass *klass = input->priv_class;
|
|
|
|
const AVOption *opt =
|
|
|
|
av_opt_find2(&klass, "stimeout", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL);
|
|
|
|
return (opt != NULL) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
]] HAVE_STIMEOUT)
|
|
|
|
if(NOT HAVE_STIMEOUT)
|
|
|
|
message(WARNING [[
|
|
|
|
Your libavformat library lacks support for the "stimeout" rtsp option.
|
|
|
|
Moonfire NVR will not be able to detect network partitions or retry.
|
|
|
|
Consider installing a recent ffmpeg, from source if necessary.
|
|
|
|
]])
|
|
|
|
else()
|
|
|
|
message(STATUS "libavformat library has support for \"stimeout\" - good.")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
enable_testing()
|
|
|
|
|
|
|
|
# http://www.kaizou.org/2014/11/gtest-cmake/
|
|
|
|
find_package(Threads REQUIRED)
|
|
|
|
include(ExternalProject)
|
|
|
|
ExternalProject_Add(
|
|
|
|
GMockProject
|
|
|
|
URL "https://googlemock.googlecode.com/files/gmock-1.7.0.zip"
|
|
|
|
URL_HASH "SHA1=f9d9dd882a25f4069ed9ee48e70aff1b53e3c5a5"
|
|
|
|
INSTALL_COMMAND "")
|
|
|
|
ExternalProject_Get_Property(GMockProject source_dir binary_dir)
|
|
|
|
set(GTest_INCLUDE_DIR ${source_dir}/gtest/include)
|
|
|
|
add_library(GTest STATIC IMPORTED)
|
|
|
|
add_dependencies(GTest GMockProject)
|
|
|
|
set_target_properties(GTest PROPERTIES
|
|
|
|
IMPORTED_LOCATION "${binary_dir}/gtest/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
|
|
|
IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
|
|
|
|
set(GMock_INCLUDE_DIR ${source_dir}/include)
|
|
|
|
add_library(GMock STATIC IMPORTED)
|
|
|
|
add_dependencies(GMock GMockProject)
|
|
|
|
set_target_properties(GMock PROPERTIES
|
|
|
|
IMPORTED_LOCATION "${binary_dir}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
|
|
|
IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
|
|
|
|
|
|
|
|
#
|
|
|
|
# Subdirectories.
|
|
|
|
#
|
|
|
|
|
|
|
|
add_subdirectory(src)
|