Welcome to oZone’s documentation!

oZone is a powerful framework to develop innovative solutions around video surveillance. At its core, it offers powerful components that implement important functions (such as reading video feeds from multiple sources, performing motion/face/people detection, event recording and more), allowing easy daisy-chaining of components with each other. It also allows developers to create their own components to implement innovative solutions on top of the provided base primitives.

oZone is light enough to be embedded inside a camera and scalable enough to be used as a base for a cloud based NVR.

Architecture

Introduction

oZone is a powerful, yet simple to use framework for developers looking to create their own NVR system.

The next few sections will introduce key architectural principles of oZone.

Key Architecture Principles

Frames

oZone centers around the concept of passing Frames between Components. A ‘Frame’ is really just an abstract concept. Common types of frames may be:

  • A video frame - a special type of frame that contains one frame of a video stream
  • An audio frame - a special type of frame that contains one frame of audio from a video/audio stream
  • A data frame - may contain any kind of data
  • A notification frame - this is really a type of data frame, but its important to bring this out as it serves a specific purpose - an ability of one component to notify another component (if it is interested) of an event of interest.

Components

Now that we understand the core data structure of inter-component-communication, lets understand what “Components” are.

Components are cohesive objects that serve specific functions. Specific to the purpose of oZone, examples of components are:

  • A component that can read audio/video frames from a camera
  • A component that can perform motion detection from the ‘frames’ received from the component above (see how chaining works?)
  • A component that can record motion frames to disk when a defined threshold of movement is detected? (Example, only store frames that involve people moving around, not your cats or dogs. Again, see how we keep chaining components?)
Types of Components

Given that components are a critical part of oZone, lets talk about the types of components you can use.

  • Providers
  • Consumers
  • Processors
  • Listeners
  • Controllers

A Provider is a type of component that “generates” frames. A perfect example of a Provider is AVInput, which is able to connect to a source like /dev/video0 for a local webcam, /path/to/file/fulldayrecording.mp4 for a recorded video, or, rtsp://myliveurl for a RTSP camera. It can connect to any such input source and produces audio and/or video frame, completely abstracting the nature of the source for other components down the chain.

A Consumer is a type of component that “consumes” frames. Unlike a Provider, it doesn’t generate any frames, so there is no point “registering” for frames with a consumer. A good example of a Consumer is EventRecorder, that writes motion events to disk.

Note

It’s not totally true that consumers don’t generate frames. An exception is that it can generate notification frames - example, when you want to notify a downstream component that a new event is about to be written to disk (maybe you want to update your UI)

A Processor is really a hybrid between a Provider and a Consumer. A Processor accepts frames and generates frames. Can you think of an example for this? MotionDetector is a good example! It typically ‘registers’ with a Provider, analyzes the frames and outputs then overlayed with motion information for further downstream processing. Or take for example, the uber awesome MatrixVideo processor which accepts frames from N components and creates a configurable NxM matrix of frames stitched together and outputs it as a single frame for downstream display!

Finally, Listeners and Controllers are somewhat specialized in its purpose. A Listener listens for data. A Listener connects to a Controller that controls what needs to be done when the listener receives data. For example, HttpController is a controller that can be attached to a listener like so:

HttpController httpController( "watch", 9292 );
httpController.addStream("watchcam1",cam1);

This bit of code would allow for browsers to connect to port 9292 and render the output of a camera feed as MJPEG, automagically.

_images/basic_arch.png

An abstract view of application linking components

_images/ozone_component.png

An application specific instance of chaining components

Application Lifeycle

This chapter will describe the application lifecycle of the oZone framework, from init->run->termination.

Summary

At a conceptual level, initializing the oZone framework involves:

  • Initializing the debug/logging subsystem
  • Initializing various audio/video handlers to manage streams/decoding/encoding
  • Instantiating an Application object to manage application lifecycle
  • Instantiating various components per your need
  • Registering various components with each other to establish a workflow
  • Adding all components to the Application object so they can be started
  • Invoke the Application object’s run() method
_images/applicationlifecycle.png

A high level view of the application lifecycle

The Application object can be thought of as the master object that keeps track of all the components. When components are instantiated, they register with the Application object by invoking its addThread() method. This essentially adds the object to the Application queue.

When you invoke the Application run() method, it iterates through the list of components and invokes the start() methof of each object, which essentially launches a thread for each component. Following this, it invokes the run() method of each component, which is what is expected to be the entry point of each component’s functionality.

Note that the Application object is just a convenience. You can easily invoke the start() method of each component yourelf. The latter approach is typically useful when you dynamically create new components and remove them after you start the application.

The Listerner and HTTPController components are used when you need to convert the frames of a component into a browser viewable version. Listerner along with HTTPController are an easy way to create MJPEG images which you can display on the browser with a simple <img src=""> tag.

More details

Application Life Cycle Manager

The Application object is really very simple. It’s implementation simply keeps a list of components. Components are added to the Application object by invoking its addThread() method which simply pushes a pointer to the component into its internal queue.

Once you connect all the components to the Application object, and you invoke the run() method, all it really does is iterate through the list and invoke the run() method of each component in a new thread (yes, each component must have a run method) and then waits for them to terminate.

Component Chaining

We also talked about how components could chain to each other to create workflows. Chaining is achieved by invoking a registerProvider method of a component.

Here is a live example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 Application app;

 AVInput input( "input", "http://kxhcm10/nphMotionJpeg?Resolution=640x480&Quality=Standard");
 app.addThread( &input );

 FaceDetector detector( "detector" );
 detector.registerProvider( input );
 app.addThread( &detector );

 VideoParms videoParms( 320, 240 );
 AudioParms audioParms;
 MovieFileOutput movie( detector.cname(), "/transfer", "mp4", 60, videoParms, audioParms );
 output2.registerProvider( detector );
 app.addThread( &movie );

 app.run();

Explanation:

  • line 1 - create Application object (app)
  • line 3-4: create a provider component (input) that reads video feeds from a URL and add it to the application object
  • line 6 - create a FaceDetector processor component (detector)
  • line 7 - register the provider component of line 3 (input) to be the frame provider for this new face detector component
  • line 8 - also add this facedetector component to the master Application object (app)
  • line 10-12: instantiate a consumer component that will create video files (movie)
  • line 13: register the provider component of movie to be the facedetector component
  • line 14: add this output component to the master Application object (app)

Note

What just happened?

  • input will read frames from that URL
  • detector will attempt to detect faces in the frames input provides above
  • movie will attempt to create video files which will essentially be the same frames generated by input, but overlayed with face detection markers detector creates
  • line 16: launch all the threads and have fun!

Installation

The examples below are for a typical Ubuntu/Debian system.

Installation of oZone libraries and examples

oZone is a portable solution with a very easy installation process. This example assumes you want all the ozone libraries (including dependencies) to be installed at ~/ozoneroot. This is a great way to isolate your install from other libraries you may already have installed.

There are two parts, a one time process and then building just the ozone library repeatedly (if you are making changes to the examples or core code)

One time setup:

# -------------------install dependencies------------------------

sudo apt-get update
sudo apt-get install git cmake nasm libjpeg-dev libssl-dev
sudo apt-get install libatlas-base-dev libfontconfig1-dev libv4l-dev

# ---------------------clone codebase----------------------------

git clone https://github.com/ozonesecurity/ozonebase
cd ozonebase
git submodule update --init --recursive

# --------------- build & install --------------------------------
export INSTALLDIR=~/ozoneroot/ # change this to whatever you want
./ozone-build.sh

Note

if you face compilation issues with ffmpeg not finding fontconfig or other package files, you need to search for libv4l2.pc, fontconfig.pc files and copy then to the lib/pkgconfig directory of your INSTALL_DIR path

Once the one time setup is done, you don’t need to keep doing it (building external dependencies take a long time) For subsequent changes, you can keep doing these steps:

# ---- Optional: For ad-hoc in-source re-building----------------
cd server
cmake -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DOZ_EXAMPLES=ON -DCMAKE_INCLUDE_PATH=$INSTALLDIR/include
make
make install

# ----- Optional: build nvrcli - a starter NVR example ----------
cd server
edit src/examples/CMakeLists.txt and uncomment lines 14 and 27 (add_executable for nvrcli and target_link_libraries for nvrcli

make

That’s all!

Dlib optimizations

If your processor supports AVX instructions, (cat /proc/cpuinfo | grep avx) then add -mavx in server/CMakeLists.txt to CMAKE_C_FLAGS_RELEASE and CMAKE_CXX_FLAGS_RELEASE and rebuild. Note, please check before you add it, otherwise your code may core dump.

Building Documentation

oZone documentation has two parts:

  • The API document that uses Doxygen
  • The User Guide which is developed using Sphinx

API docs

To build the APIs all you need is Doxygen and simply run doxygen inside ozonebase/server. This will generate HTML documents. oZone uses dot to genarate API class and relationship graphs, so you should also install dot, which is typically part of the graphviz package.

User docs

You need sphinx and dependencies for generating your own user guide. The user guide source files are located in ozonebase/docs/server/guide

# Install dependencies
sudo apt-get install python-sphinx
sudo apt-get install python-pip
pip install sphinx_rtd_theme

And then all you need to do is make html inside ozonebase/docs/server/guide and it generates beautiful documents inside the build directory.

Using oZone libraries in your own app

Take a look at nvrcli’s sample Makefile here and modify it for your needs.

Examples

The examples directory contain a series of simple examples that help you get started. A good place to start is starter_example.cpp/html. In general, the code you write with ozone is the ‘backend’ code. It doesn’t start a UI. Its job is to connect to a video source and process it. So in the case of starter_example:

  • starter_example.cpp is a process that connects to two video sources: first, it connects to a public traffic camera and second, it tries to load a file called “face-input”.mp4. Once it loads the two files, it does motion detect on one, and does a face detection on another. It also instantiates a http server that when connected to should display 4 windows - two video windows + 1 motion detection window on the traffic camera + 1 face detection window on “face-input.mp4”
  • Make sure the start_example process runs successfully - look at the logs to make sure its not erroring (see source code on how to see logs)
  • start_example.html is the browser HTML that you can open to display the windows - open it in a browser, but before you do, change its $scope.baseurl IP to the IP where you are running starter_example process.
  • Please read through the source code to understand more - this framework is really meant for developers.

You’ll notice that this example won’t run - it will complain that it can’t find “shape_predictor”. Read this

You might also want to know where “face-input.mp4” is. Its any video file you download/have that has faces (easily understandable) to detect.

API

The APIs are automatically generated from the source code and generated via Doxygen. Make sure you have read the Architecture before you dive into the API.

The APIs are located >HERE< and will be frequently re-generated as we add more functionality. So please feel free to revisit every once in a while.

http://imgs.xkcd.com/comics/api.png

FAQ

Work in progress.

You have questions? We have answers! Time is what is missing for now.

Contributing

Contributions to oZonebase does not grant any rights to the contributor for any renumeration. Any contributions made by 3rd parties will automatically be dual licensed as follows:

License 1: Free for personal use, under GPLv3

License 2: Non GPL, for commercial use. Please send us an email for licensing for commercial terms. Ozone is intended for developers and OEMs/ISVs building their own security solutions

Architecture
Understanding the oZone architecture is an important part of developing your own NVR app.
Installation
How to download and install oZone
Examples
Walks you through creating a live example using code snippets with annotation.
API
Interface document for oZone
FAQ
Frequently Asked Questions
Contributing
How to contribute to oZone.