ROC SDK  2.4.0
Scalable Face Recognition Software
API Wrappers

Java, C#, Python 2/3, Go and NodeJS interfaces that wrap our C API, and information on setting up Visual Studio, Android, iOS and CUDA projects.

Overview

The ROC SDK ships with API wrappers for the Java, C#, Python and Go programming languages. The wrappers live in the java, csharp, python2, python3 and go subdirectories of the SDK respectively. In addition to the language-specific interface files, each folder also contains translations of the C examples programs prefixed with roc_example_. Lastly, source code for the API translation is provided in the roc_swig.cpp and roc_swig_video.cpp files as a reference for resolving specific technical questions.

Reproducibility

The wrappers are generated automatically using SWIG, thus it is trivial to reproduce them or generate new wrappers for other programming languages. The general syntax is:

$ cd include
$ swig -<language> -module roc roc.h
$ swig -<language> -module roc_video -DSWIG_ROC_VIDEO roc.h

If targeting Python 3 be sure to use SWIG version 4. To silence Warning 451, which is not a concern in this case, add -w451 to the swig command.

Help

To the extent possible, symbol names are identical between the wrappers and the C API, thus the Application Programming Interface documentation should continue to serve as the primary reference. A reading of SWIG Basics and the language specific documentation for Java, C# and Python is strongly encouraged.

Array Element Modification

A common gotcha when using the SWIG-generated API wrappers relates to modifying array elements. The following psudocode highlights the access pattern to be mindful of:

my_array = new_roc_array(my_size)
...
my_element = roc_array_getitem(my_array, my_index)
modify(my_element)
// IMPORTANT -- Update the array with the modified element so that the array
// is not referencing stale data.
roc_array_setitem(my_array, my_index, my_element)
...
my_element_later = roc_array_getitem(my_array, my_index)

SWIG will make a shallow copy of the element when getitem is called, and modifications to the element will not automatically be reflected in the array. If the modification involves a memory reallocation, and the stale array element is accessed again later, the application will crash. The solution is to update the array after modifying an element by calling setitem so that the array reflects the modified element.

Passing By Value & Address

The most difficult aspect of these wrappers is understanding how SWIG handles passing by value and by address.

Let's consider the following example. In the ROC SDK C API, a roc_gallery is a pointer to an opaque roc_gallery_type struct:

typedef struct roc_gallery_type *roc_gallery;

In C this leads to natural code, where a gallery is passed by either address or value depending on the context:

roc_gallery my_gallery; // Stack allocate a gallery container
roc_open_gallery(&my_gallery); // By address is used when initializing an object
roc_size(my_gallery); // By value is used when querying an object
roc_close_gallery(my_gallery); // Destruct the gallery initialized by roc_open_gallery

Unfortunately, most languages don't support the & address-of operator, so instead SWIG wrappers expect an extra level of indirection:

roc_gallery *my_gallery = (roc_gallery*) malloc(sizeof(roc_gallery)); // Heap allocate a roc_gallery container
roc_open_gallery(my_gallery); // Pass by address is now the default
roc_size(*my_gallery); // Pass by value requires an explicit dereference
roc_close_gallery(*my_gallery);
free(my_gallery); // Deallocate the container

For example, in C# the code looks like this:

SWIGTYPE_p_p_roc_gallery_type my_gallery = new_roc_gallery();
roc_open_gallery(my_gallery);
roc_size(roc_gallery_value(my_gallery));
roc_close_gallery(roc_gallery_value(my_gallery));
delete_roc_gallery(my_gallery);
  • new_roc_gallery and delete_roc_gallery are SWIG's analogy to malloc and free.
  • In SWIGTYPE_p_p_roc_gallery_type, "p_" means "pointer to", so this type translates to roc_gallery_type**, also known as roc_gallery*.
  • SWIG provides roc_gallery_value because there is no * dereference operator.

Cross-referencing the following documents will offer additional clarity:

  1. The SWIG documentation for %pointer_functions.
  2. The use of %pointer_functions in roc.h.
  3. The provided examples that make use of these functions.

Exporting Path

Before executing the examples you will need to ensure that your system can find the ROC software libraries.

Windows
set PATH=..\bin;%PATH%
Linux
export LD_LIBRARY_PATH=../lib
macOS
export DYLD_LIBRARY_PATH=../lib

Java

Incorporating the ROC SDK into your development environment takes two steps:

  1. Copy ROC SDK's java/io folder into your project source tree.
  2. Set -Djava.library.path="/path/to/ROC_SDK/java" in your IDE's VM settings.
  3. On Windows set the PATH environment variable to include the path to the ROC SDK bin folder.

Make sure the line static { System.loadLibrary("_roc"); } occurs at the top of your class, before any static variables referencing ROC SDK values.

Examples

cd java
javac *.java
java -Djava.library.path=. roc_example_convert_image ../data/josh_1.jpg
java -Djava.library.path=. roc_example_verify ../data/josh_1.jpg ../data/josh_2.jpg
java -Djava.library.path=. roc_example_search ../data/roc.jpg ../data/josh_2.jpg
java -Djava.library.path=. roc_example_flatten ../data/josh_1.jpg
java -Djava.library.path=. roc_example_track ../data/josh.mp4
java -Djava.library.path=. roc_example_host_id

C#

Visual Studio

The C# wrapper is compatible with Visual Studio 2015 and later. From the Visual Studio Solution Explorer, add the .cs files provided in the csharp directory into your project tree, excluding those that begin with roc_example_. Developers who have not integrated a native third-party library into their application before should take careful note of the following common pitfalls:

  • Decide if you are running a 32-bit or 64-bit application and make sure to download a copy of the ROC SDK for the correct architecture (x86 or x64 respectively).
  • Double check your project settings to confirm you are in fact running a 32-bit or 64-bit application.
  • Ensure that bin/roc.dll and the other DLLs in this folder can be discovered at runtime by either appending this directory to your PATH environment variable or by copying all the DLLs in this folder to your application's working directory.
  • There is no need to add roc.dll as a "Reference" in your project settings.

Mono

  • When calling mono on macOS include the --arch=64 flag.
  • When calling mono on Windows x64 there is no support for -pkg:dotnet so remove this flag and delete the file roc_example_convert_image.cs which can't be compiled for this platform. This example does work when compiled with Visual Studio.

Examples

Using the Mono compiler.

cd csharp
mcs -pkg:dotnet -platform:x64 *.cs examples/roc_example_convert_image.cs -m:roc_example_convert_image -out:roc_example_convert_image.exe
mcs -pkg:dotnet -platform:x64 *.cs examples/roc_example_verify.cs -m:roc_example_verify -out:roc_example_verify.exe
mcs -pkg:dotnet -platform:x64 *.cs examples/roc_example_search.cs -m:roc_example_search -out:roc_example_search.exe
mcs -pkg:dotnet -platform:x64 *.cs examples/roc_example_flatten.cs -m:roc_example_flatten -out:roc_example_flatten.exe
mcs -pkg:dotnet -platform:x64 *.cs examples/roc_example_track.cs -m:roc_example_track -out:roc_example_track.exe
mcs -pkg:dotnet -platform:x64 *.cs examples/roc_example_host_id.cs -m:roc_example_host_id -out:roc_example_host_id.exe
mono roc_example_convert_image.exe ../data/josh_1.jpg
mono roc_example_verify.exe ../data/josh_1.jpg ../data/josh_2.jpg
mono roc_example_search.exe ../data/roc.jpg ../data/josh_2.jpg
mono roc_example_flatten.exe ../data/josh_1.jpg
mono roc_example_track.exe ../data/josh.mp4
mono roc_example_host_id.exe

Python 2

  • Supports Python 2.7 off-the-shelf on Linux.
  • On Windows x64 be sure to use a 64-bit installation of Python.
  • On macOS be sure to use the Python executable supplied by Apple: /usr/bin/python.
  • The roc_example_convert_image.py example requires an installation of Pillow.

Homebrew Python

By default the ROC SDK Python wrapper links against Apple's Python installation. To use Homebrew's Python installation:

cd roc-osx-x64-sse2/python2
install_name_tool -change /System/Library/Frameworks/Python.framework/Versions/2.7/Python /usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib _roc.so
install_name_tool -change /System/Library/Frameworks/Python.framework/Versions/2.7/Python /usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib _roc_video.so

Changing 2.7.13 to the version installed on your machine.

Examples

cd python2
python roc_example_convert_image.py ../data/josh_1.jpg
python roc_example_verify.py ../data/josh_1.jpg ../data/josh_2.jpg
python roc_example_search.py ../data/roc.jpg ../data/josh_2.jpg
python roc_example_flatten.py ../data/josh_1.jpg
python roc_example_track.py ../data/josh.mp4
python roc_example_host_id.py

Python 3

  • Supports Python 3.6 off-the-shelf in the Linux x64 FMA3 and ARMv8 NEON SDKs (Ubuntu 18.04).
  • On Windows x64 be sure to use a 64-bit installation of Python 3.
  • The roc_example_convert_image.py example requires an installation of Pillow.

Upgrading to newer Python versions

The ROC SDK's Python 3 wrapper will need to be recompiled as follows. Replace the references to Python 3.6 with the version of Python 3 installed on your system.

Linux
cd python3
gcc -c -Wall -Werror -fPIC -I../include -I/usr/include/python3.6m/ roc_swig.cpp
gcc -shared -o _roc.so roc_swig.o -L../lib -L/usr/lib/x86_64-linux-gnu/ -lroc -lpython3.6m -Wl,-rpath,'$ORIGIN/../lib:../lib'
MacOS
cd python3
gcc -c -Wall -Werror -fPIC -I../include -I/usr/include/python3.6m/ roc_swig.cpp
ld -bundle -flat_namespace -undefined suppress -o _roc.so roc_swig.o ../lib/libroc.dylib
Windows
cd python3
cl /LD roc_swig.cpp /I ../include/ /I C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python36\include C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python36\libs\python36.lib ..\lib\roc.lib /Fe_roc.pyd
cl /LD roc_swig_video.cpp /I ../include/ /I C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python36\include C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python36\libs\python36.lib ..\lib\roc_video.lib /Fe_roc_video.pyd
Starting in Python 3.8 DLLs are no longer resolved relative to the PATH environment variable, see add_dll_directory for details. The workaround is to copy the .dll files in the ROC SDK bin folder, and the .pyd files in the ROC SDK python3 folder, into your application's working directory.

Examples

cd python3
python3 roc_example_convert_image.py ../data/josh_1.jpg
python3 roc_example_verify.py ../data/josh_1.jpg ../data/josh_2.jpg
python3 roc_example_search.py ../data/roc.jpg ../data/josh_2.jpg
python3 roc_example_flatten.py ../data/josh_1.jpg
python3 roc_example_track.py ../data/josh.mp4
python3 roc_example_host_id.py

Go

  • Unlike the other language wrappers, the Go wrapper does not use SWIG, but instead makes use of the excellent built-in cgo bridge.
  • Windows users must install a copy of GCC to use cgo and add it to their PATH environment variable. We recommend this MinGW-w64 build.

Examples

cd go
export CGO_CFLAGS=-I../include
export CGO_LDFLAGS=-L../lib
go run roc_example_convert_image.go ../data/josh_1.jpg
go run roc_example_verify.go ../data/josh_1.jpg ../data/josh_2.jpg
go run roc_example_search.go ../data/roc.jpg ../data/josh_2.jpg
go run roc_example_flatten.go ../data/josh_1.jpg
go run roc_example_track.go ../data/josh.mp4
go run roc_example_host_id.go

NodeJS

Unlike the other API wrappers that are auto-generated, the NodeJS wrapper is written and maintained by hand in order to support asyncronous operations where appropriate. This wrapper mirrors the Application Programming Interface verbatim, but deviates in the following conventions for a more native JavaScript feel:

  1. A ROC API function call that results in a non-NULL roc_error will trigger a JavaScript exception with the error message.
  2. The function call's result is returned directly instead of pass by reference.
  3. Allocated objects are reference counted and freed automatically.
  4. Slow functions return promises.

This wrapper does not support every API call in the C API. To list the currently supported functions:

cd nodejs
node -e "console.log(require('roc.node'))"

Please contact suppo.nosp@m.rt@r.nosp@m.ankon.nosp@m.e.io to request support for any additional functions.

Examples

cd nodejs
export NODE_PATH=${pwd}
node roc_example_verify.js ../data/josh_1.jpg ../data/josh_2.jpg
node roc_example_search.js ../data/roc.jpg ../data/josh_1.jpg
node roc_example_read_frame.js ../data/josh.mp4 josh.jpg
node roc_example_cuda_utilization.js

Android

  • The Android SDK is provided as native binaries for arm32v7a and arm64v8a CPUs to run on mobile devices, and x86 and x64 CPUs to run as Android Virtual Device (AVD). Multiple architectures can be added to a single Android Studio project.
  • When configuring an AVD device, ensure that the selected System Image architecture matches one of the ROC SDK architecures added to your project.
  • An APK for testing the Face Liveness algorithm will be made available upon request. Source code for this application can be found inside the java/android_liveness folder of the SDK.
  • The ROC SDK function roc_get_host_id uses Android's ANDROID_ID setting as the Host ID. Please read the linked Google documentation for this value to understand the limitations of this approach. You will need a new license file if the value of this setting changes.
  • roc_ensure prints error messages to STDERR which isn't captured in logcat by default. If you notice your code is crashing in this function we recommend replacing it with your own error handling logic to check and print the roc_error, as illustrated below.
  • As Android applications can be opened and closed multiple times within the context of a single long-running process, the only correct place to call roc_initialize and roc_finalize is in the Main Activity's onCreate() and onDestroy() routines.
  • roc_preinitialize_android must be called before roc_initialize, this means it is not possible to develop C/C++ command line applications for Android. Use our ARM Linux SDK instead if you need this.
How to add the ROC SDK to an Android Studio project
  1. Copy the roc-android/java/io/rankone/rocsdk folder into your project directory app/src/main/java/io/rankone/rocsdk.
  2. Copy all of the .so files in roc-android/lib into your project directory app/src/main/jniLibs/$ARCH where $ARCH is one of armeabi-v7a, arm64-v8a, x86, or x86_64, corresponding to the architecture specified in the filename of the zipped ROC SDK you downloaded.
  3. Copy roc-android/java/lib_roc.so into the same app/src/main/jniLibs/$ARCH directory, this is the Java-to-C wrapper library.
  4. Copy the roc-android/java/QtAndroid.jar file into your project directory app/libs.
  5. In the file app/build.gradle, inside the object android.defaultConfig, add the line:
    ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } // remove the ones you aren't using
    Also confirm the line:
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    exists inside the dependencies object, adding it if necessary.
  6. After obtaining a valid ROC.lic license file, copy it into your project directory app/src/main/assets.
  7. Note the following important lines from the provided Java example applications to import the ROC module.
    import io.rankone.rocsdk.*;
    public class roc_example {
    static {
    System.loadLibrary("_roc");
    }
  8. Pass the contents of ROC.lic to roc_initialize.
    public static Bitmap toBitmap(roc_image image)
    {
    byte[] bytes = new byte[4 * (int) image.getWidth() * (int) image.getHeight()];
    roc.roc_to_rgba(rocImage, bytes);
    Bitmap bitmap = Bitmap.createBitmap((int) rocImage.getWidth(), (int) rocImage.getHeight(), Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(bytes));
    return bitmap;
    }
    public static roc_image fromBitmap(Bitmap bitmap)
    {
    ByteBuffer byteBuffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
    bitmap.copyPixelsToBuffer(byteBuffer);
    roc_image image = new roc_image();
    roc.roc_from_rgba(byteBuffer.array(), bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes(), image);
    return image;
    }
    public static roc_image fromImage(Image image)
    {
    Image.Plane yPlane = image.getPlanes()[0];
    Image.Plane uPlane = image.getPlanes()[1];
    Image.Plane vPlane = image.getPlanes()[2];
    ByteBuffer yBuffer = yPlane.getBuffer();
    ByteBuffer uBuffer = uPlane.getBuffer();
    ByteBuffer vBuffer = vPlane.getBuffer();
    byte[] yBytes = new byte[yBuffer.capacity()];
    yBuffer.get(yBytes);
    byte[] uBytes = new byte[uBuffer.capacity()];
    uBuffer.get(uBytes);
    byte[] vBytes = new byte[vBuffer.capacity()];
    vBuffer.get(vBytes);
    roc_image rocImage = new roc_image();
    roc.roc_from_yuv(yBytes, uBytes, vBytes, yPlane.getRowStride(), uPlane.getRowStride(), uPlane.getPixelStride(), image.getWidth(), image.getHeight(), rocImage);
    return rocImage;
    }
    public byte[] readAssetFile(String fileName)
    {
    try {
    InputStream is = getAssets().open(fileName);
    int size = is.available();
    byte[] buffer = new byte[size];
    is.read(buffer);
    is.close();
    return buffer;
    } catch (IOException ioe) {
    return null;
    }
    }
    public static void ensure(String error)
    {
    if (error != null) {
    Log.e("ROC SDK", error);
    System.exit(1);
    }
    }
    public void init()
    {
    ensure(roc.roc_preinitialize_android(this)); // Where "this" is an Android Activity class
    ensure(roc.roc_initialize(new String(readAssetFile("ROC.lic")), null));
    }

Camera Preview

Note that the roc_convert_nv21 function is offered as an efficient way to use images from the camera preview in the ROC SDK.

iOS

  • The ROC SDK for iOS supports only arm64 devices running iOS 12 or later.
  • Support for arm64 devices running iOS 8 or later, which covers any device released since September 2013, is possible on request.
  • The ROC SDK function roc_get_host_id calls Apple's identifierForVendor function to obtain the Host ID. Please read the linked Apple documentation for this function to understand the limitations of this approach. You will need a new license file if the value returned by this function changes.

The following steps cover how to add the ROC SDK to an XCode Objective-C/Swift project:

  1. Run make_framework.sh in the ROC SDK folder.
  2. In your project's General page drag and drop roc.framework into Embedded Binaries.
  3. In your project's Build Settings page find the Framework Search Paths setting under the Search Paths section and add the full path to the folder containing roc.framework. All needs to be selected.
  4. In your project's Build Settings page find the Enable Bitcode setting under the Build Options section and set it to No.

For Objective-C:

  1. Add
    #import "roc/roc.h"
    to your files which will call ROC API functions.
  2. At runtime call roc_get_host_id and email bd@ra.nosp@m.nkon.nosp@m.e.io the value of host_id. We will respond with a ROC.lic license file.
  3. In your project's Build Phases page drag and drop ROC.lic into Copy Bundle Resources. Call roc_initialize be passing the contents of the bundled license file:
    roc_ensure(roc_initialize([[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ROC" ofType:@"lic"] encoding:NSUTF8StringEncoding error:nil] UTF8String], NULL));

Since Objective-C is interoperable with C, consult the source code in the examples folder for reference implementations of common use cases.

For Swift:

  1. In your project's Build Settings page find the Objective-C Bridging Header setting under Swift Compiler - General and add the path of roc.h.
  2. At runtime call roc_get_host_id and email bd@ra.nosp@m.nkon.nosp@m.e.io the value of host_id. We will respond with a ROC.lic license file.
    private func getHostID() -> String
    {
    var hostID:roc_string?
    roc_get_host_id(&hostID)
    return String(cString: hostID!)
    }
  3. In your project's Build Phases page drag and drop ROC.lic into Copy Bundle Resources.
  4. Call roc_initialize by passing the contents of the bundled license file:
    roc_ensure(roc_initialize(String(contentsOfFile: Bundle.main.url(forResource: "ROC", withExtension: "lic")!.path), nil)))

Swift Image Conversion

The following code illustrates how to construct a roc_image from iOS camera buffers.

import UIKit
import AVFoundation
class ViewController: UIViewController,
AVCaptureVideoDataOutputSampleBufferDelegate,
UINavigationControllerDelegate
{
@IBOutlet weak var imageView: UIImageView!
var session: AVCaptureSession?
private let context = CIContext()
override func viewDidLoad() {
super.viewDidLoad()
session = AVCaptureSession()
session!.sessionPreset = AVCaptureSession.Preset.photo
var error: NSError?
var input: AVCaptureDeviceInput!
do {
input = try AVCaptureDeviceInput(device: AVCaptureDevice.default(for: AVMediaType.video)!)
} catch let error1 as NSError {
error = error1
input = nil
print(error!.localizedDescription)
}
if error == nil && session!.canAddInput(input) {
session!.addInput(input)
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable as! String: NSNumber(value: kCVPixelFormatType_32BGRA)]
videoOutput.alwaysDiscardsLateVideoFrames = true
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "sample buffer"))
guard session!.canAddOutput(videoOutput) else { return }
session!.addOutput(videoOutput)
guard let connection = videoOutput.connection(with: AVFoundation.AVMediaType.video) else { return }
guard connection.isVideoOrientationSupported else { return }
guard connection.isVideoMirroringSupported else { return }
connection.videoOrientation = .portrait
}
session!.startRunning()
}
func rocImageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> roc_image? {
var rocImage = roc_image()
let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
let height = CVPixelBufferGetHeight(pixelBuffer)
let width = CVPixelBufferGetWidth(pixelBuffer)
let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
let int8Buffer = unsafeBitCast(CVPixelBufferGetBaseAddress(pixelBuffer), to: UnsafeMutablePointer<UInt8>.self)
roc_from_bgra(int8Buffer, width, height, bytesPerRow, &rocImage);
CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)
return rocImage;
}
func toRocImage(_ imageIn:UIImage, degrees:Int = 0) -> roc_image? {
guard let imageRef = imageIn.cgImage else { return nil }
guard let rawData = imageRef.dataProvider!.data else { return nil }
var rocImage = roc_image()
if let error = roc_from_rgba(CFDataGetBytePtr(rawData),
imageRef.width,
imageRef.height,
imageRef.bytesPerRow,
&rocImage) {
print(String(cString: error))
return nil
}
if let error = roc_rotate(&rocImage, Int32(degrees)) {
roc_free_image(rocImage)
print(String(cString: error))
return nil
}
return rocImage
}
func toUIImage(_ rocImage:roc_image) -> UIImage?
{
// roc_image uses BGR, convert to RGB
var rocImageRGB = roc_image()
rocImageRGB.data = nil
if let error = roc_copy_image(rocImage, &rocImageRGB) {
print(String(cString: error))
return nil
}
if let error = roc_swap_channels(rocImageRGB) {
print(String(cString: error))
return nil
}
let numComponents = 3
let rgbData = CFDataCreate(nil, rocImageRGB.data, rocImageRGB.height*rocImageRGB.width*numComponents)!
guard let provider = CGDataProvider(data: rgbData) else {
return nil
}
let rgbImageRef = CGImage(width: rocImageRGB.width,
height: rocImageRGB.height,
bitsPerComponent: 8,
bitsPerPixel: 8 * numComponents,
bytesPerRow: rocImageRGB.width * numComponents,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: CGColorRenderingIntent.defaultIntent)!
defer {
roc_free_image(rocImageRGB)
}
return UIImage(cgImage: rgbImageRef)
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
DispatchQueue.main.async { [unowned self] in
guard let rocImage = self.rocImageFromSampleBuffer(sampleBuffer: sampleBuffer) else { return }
guard let outputImage = self.uiImageFromRocImage(rocImage) else { return }
let newROCImage = self.rocImageFromUIImage(image: outputImage)!
guard let displayImage = self.uiImageFromRocImage(newROCImage) else { return }
self.imageView.image = displayImage
roc_free_image(rocImage)
roc_free_image(newROCImage)
}
}
}

Swift Unflatten Template

The following code illustrates how to call roc_unflatten on a Swift Data type and construct a roc_template.

do {
var data = try Data(contentsOf: "PATH/TO/GALLERY.t", options: .alwaysMapped)
data.withUnsafeBytes { (unsafeBytes) in
let bytes = unsafeBytes.bindMemory(to: UInt8.self).baseAddress!
var newTemplate = roc_template()
roc_unflatten(bytes, &newTemplate);
}
} catch let error as NSError {
print(error.debugDescription)
}

Swift Save Image

The following code illustrates how to save a roc_image to disk. The file location in thie example will be the applications documents directory on the device. The filename will be the current date-time.

func getDateTimeStamp() -> String
{
let now = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.dateFormat = "yyyy-MM-dd_HH:mm:ss:SSSS"
return formatter.string(from: now)
}
func saveROCImage(image:roc_image){
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsURL.appendingPathComponent(getDateTimeStamp()).appendingPathExtension("png")
do {
var buffer:roc_buffer?
var buffer_length = size_t()
if let error = roc_encode_image(image, ".png", 0, &buffer, &buffer_length) {
print(String(cString: error))
return
}
let imageData = Data(bytes: buffer!, count:buffer_length)
try imageData.write(to: fileURL)
roc_free_buffer(&buffer)
} catch {
print("Failed to write to disk")
}
}