Quick Start
Get ACL Pack running in your Android arm64-v8a or Linux aarch64 project in 5 minutes.
Prerequisites
Common
- C++17 compiler (commercial libacl.a builds with
-std=c++17; your project must also be ≥ C++17) - An ACL Pack SDK zip for your platform (Android or Linux — sold separately)
license.datshipped with the SDK (every tier, including Trial, requires it)
Android target
- Android NDK 26.1+ (Clang toolchain)
- arm64-v8a target device or emulator
Linux target
gcc-aarch64-linux-gnu9+ (Ubuntu 20.04 ships 9.4) or an equivalent clang cross toolchain- aarch64 glibc target system (Jetson / RK3588 / Raspberry Pi 4+ / any ARM64 SBC running a glibc Linux distro)
Android arm64-v8a
1. Add to Your Project
Copy the SDK files into your project:
your_project/
include/acl/ ← Copy from SDK
lib/arm64-v8a/libacl.a ← Copy from SDK
your_code.cpp2. Build Setup
Android.mk
LOCAL_PATH := $(call my-dir)
# ACL Pack static library
include $(CLEAR_VARS)
LOCAL_MODULE := acl
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libacl.a
include $(PREBUILT_STATIC_LIBRARY)
# Your module
include $(CLEAR_VARS)
LOCAL_MODULE := your_module
LOCAL_SRC_FILES := your_code.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := acl
LOCAL_LDLIBS := -lm
include $(BUILD_SHARED_LIBRARY)Or CMake
add_library(acl STATIC IMPORTED)
set_target_properties(acl PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/lib/${ANDROID_ABI}/libacl.a)
target_include_directories(your_target PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_link_libraries(your_target acl m)Or direct NDK command
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android25-clang++ \
-O2 -std=c++17 -Iinclude -o demo demo.cpp lib/arm64-v8a/libacl.a -lm3. Initialize
#include <acl/acl.h>
// Call once at app startup. Every tier (Trial included) ships with its
// own license file — pass the path you received with the SDK.
int ret = acl::init("/path/to/license.dat");
if (ret != 0) {
// Handle license error (see <acl/err.h> for codes)
}The full init signature also accepts an optional Android JNIEnv* and jobject (application context) for installations that bind license state to the running JVM. Leave them at the default nullptr for plain native use:
namespace acl {
int init(const char* licensePath, JNIEnv* env = nullptr, jobject context = nullptr);
const char* version(); // returns "1.0.3"
}Linux aarch64
1. Add to Your Project
Copy the SDK files into your project:
your_project/
include/acl/ ← Copy from SDK
lib/linux-aarch64/libacl.a ← Copy from SDK
your_code.cpp2. Build Setup
Direct cross-compile command (simplest)
aarch64-linux-gnu-g++ \
-O2 -std=c++17 -Iinclude \
-o demo demo.cpp lib/linux-aarch64/libacl.a \
-lm -lpthreadOr CMake with a toolchain file
Create toolchains/linux-aarch64.cmake:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
add_compile_options(-march=armv8-a)Then in your CMakeLists.txt:
add_library(acl STATIC IMPORTED)
set_target_properties(acl PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/lib/linux-aarch64/libacl.a)
target_include_directories(your_target PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_link_libraries(your_target acl m pthread)Configure with:
cmake -DCMAKE_TOOLCHAIN_FILE=toolchains/linux-aarch64.cmake -DCMAKE_BUILD_TYPE=Release ..3. Initialize
#include <acl/acl.h>
// Call once at app startup.
int ret = acl::init("/path/to/license.dat");
if (ret != 0) {
// Handle license error (see <acl/err.h> for codes)
}Linux builds can ignore the JNIEnv* / jobject parameters (default nullptr) — just pass the license path. The signature is identical to Android:
namespace acl {
int init(const char* licensePath, JNIEnv* env = nullptr, jobject context = nullptr);
const char* version(); // returns "1.0.3"
}Your First API Call
Trial tier
Trial ships only 2 fixed-parameter entry points (declared in <acl/api.h> under the acl::trial:: namespace): bilinear 2× downscale — in _cpp and _neon variants. Inputs must be exactly 1920×1280 uint8 single-channel; other sizes return ACL_ERR_RESOLUTION_LIMIT (-1006). Output carries an "ACL Pack Trial" watermark.
The general-purpose API shown below applies to the Starter / Pro / Business tiers.
NEON simplified (fixed 3x3 / 5x5 / 11x11 kernels, fastest path)
#include <acl/api.h> // all operator declarations live here
// 3x3 Gaussian blur on a 640x480 grayscale image
uint8_t* src = /* your image data */;
uint8_t* dst = new uint8_t[640 * 480];
int result = acl::neon::filter::gaussianBlur3x3(src, dst, 640, 480);
if (result != 0) {
// Handle error (e.g. ACL_ERR_INVAL = -2 for bad parameters)
}
delete[] dst;Full signature (all kernel sizes follow the same pattern):
int gaussianBlur3x3(const uint8_t* srcImage, uint8_t* dstImage,
int width, int height,
int srcStride = 0, int dstStride = 0,
uint8_t constant = 0,
acl::BorderType bt = acl::BorderType::BORDER_REFLECT_101);Matching NEON entries (1-channel uint8):
gaussianBlur3x3,gaussianBlur5x5,gaussianBlur11x11— same signature, different kernel sizegaussianBlur3x3_3ch,gaussianBlur5x5_3ch— 3-channel variants (RGB / BGR)gaussianBlur(src, dst, w, h, srcStride, dstStride, kRadiusX, kRadiusY, sigmaX=0, sigmaY=0, constant=0, bt=BORDER_REFLECT_101)— generic entry for arbitrary radius / sigma (1-channel uint8 only; internally dispatches to the 3x3 / 5x5 / 11x11 fast paths when sigma=0 and the kernel size matches, otherwise falls back tosepFilter2D)
CPP generic (arbitrary radius / sigma)
#include <acl/api.h> // same single header — scalar entry lives under acl::filter::
// 5x5 Gaussian blur with custom sigma on a 640x480 grayscale image
uint8_t* src = /* your image data */;
uint8_t* dst = new uint8_t[640 * 480];
int result = acl::filter::gaussianBlur<uint8_t, uint8_t>(
src, dst,
640, 480, // width, height
1, // cn (channels, 1 = grayscale)
0, 0, // srcStride, dstStride (0 = contiguous)
2, 2, // kRadiusX, kRadiusY (2 = 5x5 kernel)
1.5, 1.5, // sigmaX, sigmaY (double)
nullptr, // constant (nullptr = default BORDER fill value)
acl::BorderType::BORDER_REFLECT_101 // bt
);
delete[] dst;The CPP variant is a portable scalar path — functionally equivalent to NEON but not vectorized.
Key Concepts
Stride
Stride is the row size in bytes. For contiguous memory, stride = width * channels * sizeof(type). Pass 0 for auto-detect.
NEON vs CPP Tier
acl::neon::*— ARM NEON vectorized, best performance, ARM64 only (both Android arm64-v8a and Linux aarch64)acl::{module}::*— Portable C++ scalar, functionally equivalent to NEON, used for functional verification or non-vectorized fallback paths
Single header, two namespaces
Every operator declaration ships in one header — <acl/api.h>. You always #include <acl/api.h>; the namespace tells you which implementation you're calling:
acl::neon::{module}::op(...)→ NEON vectorizedacl::{module}::op(...)→ portable scalar (note: the namespace does not include acpp::segment, even though we internally call this path "the CPP layer")
Utility modules (math, utils, memory::AutoBuffer, …) are the exception and sit under acl::{module}:: (e.g. acl::memory::) without a neon:: prefix.
Kernel Radius
ACL Pack uses radius, not full kernel size:
- Radius 1 = 3x3 kernel
- Radius 2 = 5x5 kernel
- Radius 3 = 7x7 kernel
Error Codes
| Code | Macro | Meaning |
|---|---|---|
0 | ACL_OK | Success |
-1 | ACL_ERR_GENERIC | Unclassified failure |
-2 | ACL_ERR_INVAL | Invalid argument (null pointer, zero size, out-of-range enum) |
-3 | ACL_ERR_NOMEM | Out of memory / allocation failed |
-4 | ACL_ERR_NOSUP | Unsupported type / parameter combination |
-5 | ACL_ERR_IO | File / port open or I/O failure |
-1005 | ACL_ERR_NOT_LICENSED | Operator not available in the current tier |
-1006 | ACL_ERR_RESOLUTION_LIMIT | Resolution does not match the Trial fixed size (1920×1280) |
Full error-code definitions: <acl/err.h> or the API Reference.
Next Steps
- API Reference — Full documentation for the callable API
- OpenCV Migration Guide — Convert existing OpenCV code
- Performance Whitepaper — Detailed benchmarks