Documentation

Plugins API

The Plugins API provides access to the camera frame as a native pointer. This allows you to do additional processing on it, either in C#, or in native code (C++, Objective C, Java).

Unity interface

To enable plugins, you need to add the Plugin script to a GameObject. Then, you simply subscribe to the On Camera Frame Available event and you will be notified when a new camera frame is ready for additional processing. Please be aware that this event could be called from another thread.

You will receive as a parameter to the callback a Wikitude.CameraFrame class which contains all the information about the frame.

public class CameraFrame
{
    public long ID;
    public long ColorTimestamp;
    public ColorCameraFrameMetadata ColorMetadata;
    public List<CameraFramePlane> ColorData;
}

The ColorMetadata contains additional information about the camera frame, such as size and format.

    public struct ColorCameraFrameMetadata {
        public float HorizontalFieldOfView;
        public int Width;
        public int Height;
        public CaptureDevicePosition CameraPosition;
        public FrameColorSpace ColorSpace;
        public int TimestampScale;

    }

The ColorData list contains the raw IntPtr to the actual native memory that is used to store the frame data for each of the planes contained in the camera frame.

The native pointer is only valid during the duration of the current On Camera Frame Available call and you should never delete or change the data it's pointing to. You can pass this pointer to your own native plugins, or transfer the data in C# using Marshal.Copy functions.

using UnityEngine;
using System;
using Wikitude;
using System.Runtime.InteropServices;

public class PluginController : MonoBehaviour
{
    public void OnCameraFrameAvailable(Frame frame) {

        // Example of how to transfer data from native memory
        // to a C# array

        byte[] data = new byte[frame.DataSize];
        Marshal.Copy(frame.Data, data, 0, frame.DataSize);
    }
}

Sample explanation

The Plugins - Barcode sample shows how to integrate the popular barcode library ZXing.Net into Unity and use the Plugins API to send camera frames to it for processing.

The PluginController.cs script controls the sample. It is registered in the editor to receive OnCameraFrameAvailable. First, it creates a new thread that will be used to do the scanning on. This is required because scanning might take too long on some older devices, which would make the app seem unresponsive.

In the Update method, we only check if we have any new scanning results, and display them if that is the case.

void Update() {
    if (_scanningInProgress) {
        return;
    }

    if (_scanningResult != null) {
        ResultText.text = _scanningResult;
        _scanningResult = null;
    }
}

When the OnCameraFrameAvailable event is triggered, we first check if scanning is already in progress. If not, we convert the raw data into a Color32 array, and then we trigger a new scan.

public void OnCameraFrameAvailable(CameraFrame frame) {
    if (_scanningInProgress) {
        return;
    }

    var metadata = frame.ColorMetadata;
    var data = new Color32[metadata.Width * metadata.Height];
    if (metadata.ColorSpace == FrameColorSpace.RGBA) {
        var rawBytes = new byte[frame.ColorData[0].DataSize];
        Marshal.Copy(frame.ColorData[0].Data, rawBytes, 0, (int)frame.ColorData[0].DataSize);

        for (int i = 0; i < metadata.Width * metadata.Height; ++i) {
            data[i] = new Color32(rawBytes[i * 4], rawBytes[i * 4 + 1], rawBytes[i * 4 + 2], rawBytes[i * 4 + 3]);
        }
    } else if (metadata.ColorSpace == FrameColorSpace.RGB) {
        /* conversion code */
    } else if (metadata.ColorSpace == FrameColorSpace.YUV_420_NV12 ||
               metadata.ColorSpace == FrameColorSpace.YUV_420_NV21 ||
               metadata.ColorSpace == FrameColorSpace.YUV_420_YV12) {
        /* conversion code */
    }

    // Trigger a new scan
    Monitor.Pulse(_monitor);
}

Finally, when triggering a new scan, we call the Decode method and get the scan result back. We enable the AutoRotate option so that scanning works both in Landscape, as well as in Portraits modes.

private string Decode(Color32[] colors, int width, int height) {
    var reader = new BarcodeReader();
    reader.AutoRotate = true;
    var result = reader.Decode(colors, width, height);
    if (result != null) {
        return result.Text;
    } else {
        return null;
    }
}

Please note that the code snippets above have been simplified for clarity. Please see the full source code for more information on thread synchronization and error handling, as well as other integration details.