![]()
RpiTrackerOnboard application
v1.1.1
Table of contents
- Overview
- Versions
- Source code files
- Config file
- How to copy RpiTrackerOnboard to RPI
- Run application
- Build application
- Raspberry PI configuration
- Source code
Overview
RpiTrackerOnboard application implements video processing pipeline: video capture > tracking > streaming. The application combines libraries: VSourceLibCamera (video capture from Libcamera API compatible devices), VCodecLibav (H264, H265 and JPEG encoders for RPI5 since it does not have any hardware codec), CvTracker (video tracker library) and UdpDataChannel. The application shows how to use a combination of the libraries listed above. It is built for Raspberry PI5 (with Debian Bookworm 12 x64 OS support). It provides real-time video processing. Structure of video processing pipeline:
![]()
After starting, the application reads a JSON config file which includes video capture parameters, tracker parameters and communication port. If there is no config file, the application will create a new one with default parameters. When the config file is read, the application initializes the video source. Then the application creates and initializes a CvTracker class object using parameters from the JSON config file. Then the application creates and initializes the codec using parameters from the JSON config file. When all modules are initialized, the application executes the video processing pipeline: capture video frame from video source - tracking - stream. Additionally, the application creates a “Log” folder to write log information. In order to prepare tracker commands from a remote connection, refer to the VTracker interface library. The interface includes static methods such as encodeCommand(…) and encodeSetParamCommand(…) for constructing a buffer that holds the required command.
The application reads the input buffer for incoming commands through UdpDataServer before processing each frame for tracking. The UdpDataServer provides a thread-safe get(…) method, which returns the buffer of commands if there are any.
Versions
Table 1 - Application versions.
| Version | Release date | What’s new |
|---|---|---|
| 1.0.0 | 31.05.2024 | First version. |
| 1.0.1 | 06.08.2024 | - Submodules updated. |
| 1.0.2 | 18.09.2024 | - CvTracker submodule updated. - VCodecLibav submodule updated. |
| 1.0.3 | 04.12.2024 | - CvTracker submodule updated. - VCodecLibav submodule updated. |
| 1.0.4 | 15.12.2024 | - Submodules updated. |
| 1.0.5 | 24.02.2025 | - CvTracker submodule update. - UdpDataChannel submodule update. |
| 1.0.6 | 18.03.2025 | - Update CvTracker submodule. |
| 1.0.7 | 03.04.2025 | - Multiple submodules update. |
| 1.0.8 | 15.05.2025 | - CvTracker submodule update. |
| 1.0.9 | 22.06.2025 | - UdpDataChannel submodule update. |
| 1.0.10 | 19.07.2025 | - CvTracker submodule update. |
| 1.0.11 | 10.08.2025 | - CvTracker submodule update. |
| 1.1.0 | 16.08.2025 | - CMake structure changed. |
| 1.1.1 | 29.03.2026 | - Fixed compilation errors. |
Source code files
The application is supplied by source code only. The user is given a set of files in the form of a CMake project (repository). The repository structure is shown below:
CMakeLists.txt --------------------- Main CMake file.
3rdparty --------------------------- Folder with third-party libraries.
CMakeLists.txt ----------------- CMake file to include third-party libraries.
UdpDataChannel ----------------- Folder with UdpDataChannel library source code.
VCodecLibav -------------------- Folder with VCodecLibav library source code.
VSourceLibCamera --------------- Folder with VSourceLibCamera library source code.
CvTracker ---------------------- Folder with CvTracker library source code.
FormatConverterOpenCv ---------- Folder with FormatConverterOpenCv library source code.
src -------------------------------- Folder with application source code.
CMakeLists.txt ----------------- CMake file.
RpiTrackerOnboardVersion.h ----- Header file with application version.
RpiTrackerOnboardVersion.h.in -- File for CMake to generate version header.
main.cpp ----------------------- Application source code file.
Config file
RpiTrackerOnboard application reads the config file RpiTrackerOnboard.json in the same folder as the application executable file. Config file content:
{
"Params":
{
"codec":
{
"bitrateKbps": 3000,
"fps": 30,
"gopSize": 30
},
"communication":
{
"dataUdpPort": 50021
},
"videoSource":
{
"cameraIndex": 0,
"fps": 30,
"height": 720,
"pixelFormat": "YUYV",
"width": 1280
},
"videoTrackerParams":
{
"custom1": 0.0,
"custom2": 0.0,
"custom3": 0.0,
"frameBufferSize": 128,
"lostModeOption": 0,
"maxFramesInLostMode": 128,
"multipleThreads": false,
"numChannels": 3,
"rectAutoPosition": false,
"rectAutoSize": false,
"rectHeight": 72,
"rectWidth": 72,
"searchWindowHeight": 256,
"searchWindowWidth": 256,
"type": 0
}
}
}
Table 2 - Config file parameters description.
| Parameter | Type | Description |
|---|---|---|
| Codec: | ||
| bitrateKbps | int | H264 encoding bitrate of codec. |
| fps | int | Encoding FPS. |
| gopSize | int | GOP size of encoder. |
| Communication: | ||
| dataUdpPort | int | UDP port number to get commands for tracker and send video stream. |
| Video source parameters: | ||
| cameraIndex | int | Camera index. If only one camera is connected to the system, it is going to be 0. |
| fps | int | FPS of video source. |
| width | int | Video source width. |
| height | int | Video source height. |
| pixelFormat | string | Video source pixel format. (For example : “YUYV” , “NV12”, “BGR24”, “RGB24”) |
| Tracker parameters: | ||
| rectWidth | int | Tracking rectangle width, pixels. Set by user or can be changed by tracking algorithm if rectAutoSize == 1. |
| rectHeight | int | Tracking rectangle height, pixels. Set by user or can be changed by tracking algorithm if rectAutoSize == 1. |
| searchWindowWidth | int | Width of search window, pixels. Set by user. |
| searchWindowHeight | int | Height of search window, pixels. Set by user. |
| lostModeOption | int | Option for LOST mode. Parameter that defines the behavior of the tracking algorithm in LOST mode. Default is 0. Possible values: 0. In LOST mode, the coordinates of the center of the tracking rectangle are not updated and remain the same as before entering LOST mode. 1. The coordinates of the center of the tracking rectangle are updated based on the components of the object’s speed calculated before going into LOST mode. If the tracking rectangle “touches” the edge of the video frame, the coordinate updating for this component (horizontal or vertical) will stop. 2. The coordinates of the center of the tracking rectangle are updated based on the components of the object’s speed calculated before going into LOST mode. The tracking is reset if the center of the tracking rectangle touches any of the edges of the video frame. |
| rectAutoSize | bool | Use tracking rectangle auto size flag: false - no use, true - use. Set by user. |
| rectAutoPosition | bool | Use tracking rectangle auto position: false - no use, true - use. Set by user. |
| numChannels | int | Number of channels for processing. E.g., number of color channels. Set by user. |
| multipleThreads | bool | Use multiple threads for calculations. false - one thread, true - multiple. Set by user. |
| custom1 | float | Custom parameter for tracker. Not used. |
| custom2 | float | Custom parameter for tracker. Not used. |
| custom3 | float | Custom parameter for tracker. Not used. |
| frameBufferSize | int | Size of frame buffer (number of frames to store). Set by user. |
| maxFramesInLostMode | int | Maximum number of frames in LOST mode to auto reset of algorithm. Set by user. |
| type | int | Not supported by CvTracker. |
How to copy RpiTrackerOnboard Executable to Raspberry PI
In order to copy the ready application to the Raspberry Pi, follow these steps. Run the commands on your Windows computer where you have the RpiTrackerOnboard file.
cd <directory where you have RpiTrackerOnboard>
For example, if you downloaded the RpiTrackerOnboard application, you can copy the file to the Raspberry Pi:
scp ./RpiTrackerOnboard pi@192.168.1.100:/home/pi
Enter the password.
The file will be copied to the Raspberry Pi’s home directory.
Note: The procedure described above can be carried out without the command line. It is much easier. Please check the WinSCP application. It does not require any command line interaction.
Now it needs to be made executable, as it is currently just a raw file for the Raspberry Pi. Run the following commands on the Raspberry Pi.
Go to the home directory where we have RpiTrackerOnboard.
Make the file executable.
chmod +x ./RpiTrackerOnboard
Now the application is ready to run.
Run application
Copy the application (RpiTrackerOnboard executable and RpiTrackerOnboard.json) to any folder and run:
./RpiTrackerOnboard -vv
-vv or -v arguments enable the logger to print logs to console and file.
When the application is started for the first time, it creates a configuration file named RpiTrackerOnboard.json if the file does not exist (refer to the Config file section). If the application is run as a superuser using sudo, the file will be owned by the root user. Therefore, to modify the configuration file, superuser privileges will be necessary. You can run the application manually or you can add the application to auto start as a systemd service. To add the application as a systemd service, create a service file:
sudo nano /etc/systemd/system/rpitrackeronboard.service
and add content:
[Unit]
Description=RpiTrackerOnboard
Wants=network.target
After=syslog.target network-online.target
[Service]
Type=simple
ExecStart=/home/pi/App/RpiTrackerOnboard
Restart=on-failure
RestartSec=10
KillMode=control-group
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target
Save ctrl + s and close ctrl + x.
Reload systemd services:
sudo systemctl daemon-reload
Command to control service:
Start service:
sudo systemctl start rpitrackeronboard
Enable for auto start:
sudo systemctl enable rpitrackeronboard
Stop service:
sudo systemctl stop rpitrackeronboard
Check status:
sudo systemctl status rpitrackeronboard
Build application
Before building, the user should configure the Raspberry Pi (Raspberry PI configuration). Typical build commands:
cd RpiTrackerOnboard
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
Raspberry PI configuration
OS install
-
Download Raspberry PI imager.
-
Choose Operating System: Raspberry Pi OS (other) -> Raspberry Pi OS Lite (64-bit) Debian Bookworm 12.
-
Choose the storage (MicroSD) card. If possible, use a 128 GB MicroSD.
-
Set additional options: do not set hostname “raspberrypi.local”, enable SSH (Use password authentication), set username ”pi” and password ”pi”, configure wireless LAN according to your settings. You will need Wi-Fi for software installation, set appropriate time zone and wireless zone.
-
Save changes and push the “Write” button. After that, push “Yes” to rewrite data on MicroSD. At the end, remove the MicroSD.
-
Insert the MicroSD into the Raspberry Pi and power it up.
LAN configuration
-
Configure LAN IP address on your PC. For Windows 11, go to Settings -> Network & Internet -> Advanced Network Settings -> More network adapter options. Right-click on the LAN connection used to connect to Raspberry Pi and choose “Properties”. Double-click on “Internet Protocol Version 4 (TCP/IPv4)”. Set static IP address 192.168.0.1 and mask 255.255.255.0.
-
Connect the Raspberry Pi via LAN cable. After power up, you don’t know the IP address of the Raspberry Pi board, but you can connect to it via SSH using the “raspberrypi” name. In Windows 11, open Windows Terminal or PowerShell terminal and type the command ssh pi@raspberrypi. After connection, type yes to establish authenticity. WARNING: If you work with Windows, we recommend deleting information about previous connections. Go to folder C:/Users/[your user name]/.ssh. Open file known_hosts if it exists in a text editor. Delete all lines containing ”raspberrypi”.
-
You have to set a static IP address on the Raspberry Pi, but not NOW. After setting the static IP, you will lose the Wi-Fi connection, which you need for software installation.
Install dependencies
-
Connect to the Raspberry Pi via SSH: ssh pi@raspberrypi. WARNING: If you work with Windows, we recommend deleting information about previous connections. Go to folder C:/Users/[your user name]/.ssh. Open file known_hosts if it exists in a text editor. Delete all lines containing ”raspberrypi”.
-
Install libraries:
sudo apt-get update sudo apt install cmake build-essential libopencv-devsudo apt-get install -y cmake meson ninja-build python3 python3-pip python3-setuptools python3-wheel git pkg-config libgnutls28-dev openssl libjpeg-dev libyuv-dev libv4l-dev libudev-dev libexpat1-dev libssl-dev libdw-dev libunwind-dev doxygen graphvizpip3 install ply PyYAML- If you get an error for ply and PyYAML, run the following command.
sudo apt-get install -y python3-ply python3-yaml
- If you get an error for ply and PyYAML, run the following command.
-
RpiTrackerOnboard application uses a specific libcamera version. In order to have the proper libcamera version, run the provided commands one by one:
- Remove everything related to libcamera.
sudo apt-get remove --auto-remove libcamera* libcamera-apps* - Get libcamera
git clone https://github.com/raspberrypi/libcamera.git cd libcamera - Checkout v0.1.0 version
git checkout v0.1.0+rpt20231122 - Build libcamera
meson build ninja -C build - Install libcamera
sudo ninja -C build install - Update linker cache
sudo ldconfig - Remove source code.
cd ../ sudo rm -rf libcamera
- Remove everything related to libcamera.
-
Install the required libraries for the libav codec.
-
Run command :
sudo apt-get install -y ffmpeg libavcodec-dev libavutil-dev libavformat-dev libavdevice-dev libavfilter-dev libcurl4
-
Reboot the system.
sudo reboot
Setup high performance mode (overclock) if necessary
-
Open config file:
sudo nano /boot/firmware/config.txt -
Add line at the end of file:
force_turbo=1 over_voltage_delta=500000 arm_freq=3000 gpu_freq=800 -
Save changes ctrl+s and close ctrl+x. Reboot raspberry sudo reboot.
Static IP configuration on Raspberry.
-
Connect to the Raspberry Pi via SSH ssh pi@raspberrypi after reboot. WARNING: If you work with Windows, we recommend deleting information about previous connections. Go to folder C:/Users/[your user name]/.ssh. Open file known_hosts if it exists in a text editor. Delete all lines containing ”raspberrypi”.
-
Open config file:
sudo nano /etc/dhcpcd.conf -
Scroll down in the file and delete the comments in the following lines and set IP 192.168.0.2:
interface eth0 static ip_address=192.168.0.2/24 static ip6_address=fd51:42f8:caae:d92e::ff/64 static routers=192.168.0.2 static domain_name_servers=192.168.0.2 8.8.8.8 fd51:42f8:caae:d92e::1 -
Save changes ctrl + s and exit ctrl + x. Reboot after sudo reboot.
-
After configuring the static IP, you can connect to the Raspberry Pi by IP.
ssh pi@192.168.0.2
Source code
Below is the source code of the main.cpp file:
#include <iostream>
#include "CvTracker.h"
#include "VSourceLibCamera.h"
#include "FormatConverterOpenCv.h"
#include "VCodecLibav.h"
#include "Logger.h"
#include "UdpDataServer.h"
#include "RpiTrackerOnboardVersion.h"
/// Max command size, bytes.
constexpr int MAX_COMMAND_SIZE = 128;
/// Log folder.
#define LOG_FOLDER "Log"
/// Config file name.
#define CONFIG_FILE_NAME "RpiTrackerOnboard.json"
/// Application parameters.
class Params
{
public:
/// Video source params.
class VideoSource
{
public:
/// Camera index.
int cameraIndex{0};
/// Frame width.
int width{1280};
/// Frame height.
int height{720};
/// Frame rate.
int fps{30};
/// Pixel format.
std::string pixelFormat{"YUYV"};
JSON_READABLE(VideoSource, cameraIndex, width, height, fps, pixelFormat)
};
/// Codec params.
class Codec
{
public:
/// Bitrate.
int bitrateKbps{3000};
/// GOP size.
int gopSize{30};
/// Frame rate.
int fps{30};
JSON_READABLE(Codec, bitrateKbps, gopSize, fps)
};
/// Communication.
class Communication
{
public:
/// Output UDP port.
int dataUdpPort{50021};
JSON_READABLE(Communication, dataUdpPort)
};
/// Video source.
VideoSource videoSource;
/// Control channel.
Communication communication;
/// Video tracker.
cr::vtracker::VTrackerParams videoTrackerParams;
/// Codec params.
Codec codec;
JSON_READABLE(Params, communication, videoSource, videoTrackerParams, codec)
};
/// Application params.
Params g_params;
/// Log flag.
cr::utils::PrintFlag g_logFlag{cr::utils::PrintFlag::DISABLE};
/// Telemetry data buffer size.
const int g_trackerResultsMaxSize = sizeof(cr::vtracker::VTrackerParams) + 64;
/// Init buffer for telemetry data.
uint8_t g_trackerResults[g_trackerResultsMaxSize];
/// Telemetry data size.
int g_trackerResultsSize{0};
/// Shared frame.
cr::video::Frame g_sharedFrame;
/// Logger.
cr::utils::Logger g_log;
/// Shared frame sync mutex.
std::mutex g_sharedFrameMutex;
/// Shared frame sync condition.
std::condition_variable g_sharedFrameCond;
/// Shared frame condition mutex.
std::mutex g_sharedFrameCondMutex;
/// Shared frame condition flag.
std::atomic<bool> g_sharedFrameCondFlag = false;
/// Shared telemetry data sync mutex.
std::mutex g_trackerResultsMutex;
/// Shared telemetry data sync condition.
std::condition_variable g_trackerResultsCond;
/// Shared telemetry data condition mutex.
std::mutex g_tackerResultsCondMutex;
/// Shared telemetry data condition flag.
std::atomic<bool> g_trackerResultsCondFlag = false;
/// Udp server for sending data and receiving commands.
cr::clib::UdpDataServer g_server;
/**
* @brief Load configuration params from JSON file.
* @return TRUE if parameters loaded or FALSE if not.
*/
bool loadConfig();
/**
* @brief Encoding thread function.
*/
void encodingThreadFunc();
int main(int argc, char **argv)
{
// Configure logger.
cr::utils::Logger::setSaveLogParams(LOG_FOLDER, "log", 20, 1);
// Welcome message.
g_log.print(cr::utils::PrintColor::YELLOW, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] " <<
"RpiTrackerOnboard application v" << RPI_TRACKER_ONBOARD_VERSION << std::endl;
// Check arguments and set console output if necessary.
if (argc > 1)
{
std::string str = std::string(argv[1]);
if (str == "-v" || str == "-vv")
{
g_logFlag = cr::utils::PrintFlag::CONSOLE_AND_FILE;
}
}
// Load config file.
if (!loadConfig())
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't load config file." << std::endl;
return -1;
}
g_log.print(cr::utils::PrintColor::CYAN, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] " <<
"Config file loaded." << std::endl;
// Init video source.
cr::video::VSource* videoSource = new cr::video::VSourceLibCamera();
std::string initSource = std::to_string(g_params.videoSource.cameraIndex) + ";"
+ std::to_string(g_params.videoSource.width) + ";"
+ std::to_string(g_params.videoSource.height) + ";"
+ std::to_string(g_params.videoSource.fps) + ";"
+ g_params.videoSource.pixelFormat;
if (!videoSource->openVSource(initSource))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't initialise video source." << std::endl;
return -1;
}
g_log.print(cr::utils::PrintColor::CYAN, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] INFO: " <<
"Video source init." << std::endl;
// Init command UDP server.
if (!g_server.init(g_params.communication.dataUdpPort, 2000000))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't init command UDP server." << std::endl;
return false;
}
// Init video tracker.
cr::vtracker::CvTracker tracker;
if (!tracker.initVTracker(g_params.videoTrackerParams))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't init video tracker." << std::endl;
return -1;
}
// Init frame.
cr::video::Frame sourceFrame;
// Get one frame to obtain proper frame info from source.
if (!videoSource->getFrame(sourceFrame, 1000))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"No input video frame" << std::endl;
}
// Initialize shared frame with source frame parameters.
g_sharedFrame = cr::video::Frame(sourceFrame.width, sourceFrame.height, sourceFrame.fourcc);
// Start encoding thread.
std::thread encodingThread(encodingThreadFunc);
// Command data buffer.
uint8_t commandData[MAX_COMMAND_SIZE];
cr::vtracker::VTrackerParams trackerParams;
while (true)
{
// Wait new video frame.
if (!videoSource->getFrame(sourceFrame, 1000))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"No input video frame" << std::endl;
continue;
}
g_sharedFrameMutex.lock();
g_sharedFrame = sourceFrame; // copy frame to shared frame.
g_sharedFrameMutex.unlock();
// Notify encoding thread about new frame.
std::unique_lock<std::mutex> lock(g_sharedFrameCondMutex);
g_sharedFrameCondFlag.store(true);
g_sharedFrameCond.notify_one();
lock.unlock();
// Execute tracker commands.
int commandSize = 0;
if (g_server.get(commandData, MAX_COMMAND_SIZE, commandSize))
{
// Execute command.
if (!tracker.decodeAndExecuteCommand(commandData, commandSize))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't execute command" << std::endl;
}
}
// Video tracking.
tracker.processFrame(sourceFrame);
// Get tracker results.
tracker.getParams(trackerParams);
// Encode tracker data.
g_trackerResultsMutex.lock();
trackerParams.encode(g_trackerResults, g_trackerResultsMaxSize, g_trackerResultsSize);
g_trackerResultsMutex.unlock();
// Notify encoding thread about new telemetry data.
std::unique_lock<std::mutex> lockTelemetry(g_tackerResultsCondMutex);
g_trackerResultsCondFlag.store(true);
g_trackerResultsCond.notify_one();
lockTelemetry.unlock();
}
// Wait for encoding thread.
encodingThread.join();
return 1;
}
void encodingThreadFunc()
{
cr::video::VCodecLibav codec;
codec.setParam(cr::video::VCodecParam::TYPE, 1); // Raspberry Pi 5 doesn't support hardware codec.
codec.setParam(cr::video::VCodecParam::BITRATE_KBPS, g_params.codec.bitrateKbps);
codec.setParam(cr::video::VCodecParam::GOP, g_params.codec.gopSize);
codec.setParam(cr::video::VCodecParam::FPS, g_params.codec.fps);
// Init frames.
cr::video::Frame h264Frame(g_sharedFrame.width, g_sharedFrame.height, cr::video::Fourcc::H264);
cr::video::Frame nv12Frame(g_sharedFrame.width, g_sharedFrame.height, cr::video::Fourcc::NV12);
// Output data buffer.
uint8_t* outputData = new uint8_t[(g_sharedFrame.size + g_trackerResultsMaxSize) * 2]; // Enough big.
// Format converter.
cr::video::FormatConverterOpenCv converter;
while (1)
{
// Wait frame from main thread.
if(!g_sharedFrameCondFlag.load())
{
std::unique_lock<std::mutex> lock(g_sharedFrameCondMutex);
while(!g_sharedFrameCondFlag.load())
g_sharedFrameCond.wait(lock);
lock.unlock();
}
// Encode frame.
g_sharedFrameMutex.lock();
converter.convert(g_sharedFrame, nv12Frame);
g_sharedFrameCondFlag.store(false); // reset flag for next frame.
g_sharedFrameMutex.unlock();
if(!codec.transcode(nv12Frame, h264Frame))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't encode frame." << std::endl;
continue;
}
// Wait tracker results from main thread.
if(!g_trackerResultsCondFlag.load())
{
std::unique_lock<std::mutex> lock(g_tackerResultsCondMutex);
while(!g_trackerResultsCondFlag.load())
g_trackerResultsCond.wait(lock);
lock.unlock();
}
// Prepare output data by using encoded frame and tracker results.
int outDataSize = 0;
g_trackerResultsMutex.lock();
memcpy(outputData, &g_trackerResultsSize, sizeof(int));
memcpy(&outputData[sizeof(int)], g_trackerResults, g_trackerResultsSize);
g_trackerResultsCondFlag.store(false); // reset flag for next telemetry data.
g_trackerResultsMutex.unlock();
// Copy encoded frame to output data.
int frameSerializedSize;
h264Frame.serialize(&outputData[sizeof(int) + g_trackerResultsSize + sizeof(int)], frameSerializedSize);
memcpy(&outputData[sizeof(int) + g_trackerResultsSize], &frameSerializedSize, sizeof(int));
outDataSize = (sizeof(int) + g_trackerResultsSize + sizeof(int) + frameSerializedSize );
// Send data to client.
if (!g_server.send(outputData, outDataSize))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Can't send data." << std::endl;
continue;
}
}
}
bool loadConfig()
{
// Init variables.
cr::utils::ConfigReader config;
// Open config json file (if not exist - create new and exit).
if(config.readFromFile(CONFIG_FILE_NAME))
{
// Read values and set to params
if(!config.get(g_params, "Params"))
{
g_log.print(cr::utils::PrintColor::RED, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "] ERROR: " <<
"Params were not read" << std::endl;
return false;
}
}
else
{
// Set default params.
config.set(g_params, "Params");
// Save config file.
if (!config.writeToFile(CONFIG_FILE_NAME))
{
g_log.print(cr::utils::PrintColor::CYAN, g_logFlag) <<
"[" << __LOGFILENAME__ << "][" << __LINE__ << "]: " <<
"Config file created." << std::endl;
return false;
}
}
return true;
}