Sequence Frame Source

Defined in package com.scandit.datacapture.core.source

SequenceFrameSourceProcessListener
interface SequenceFrameSourceProcessListener

Added in version 6.14.0

A listener that reports when a frame buffer has finished processing by a SequenceFrameSource, so that an application can tell when the buffer is no longer in use. An implementation of this should be passed to SequenceFrameSource.create().

processingFinished(buffer)
fun processingFinished(buffer: ByteArray)

Added in version 6.14.0

Called once the Scandit Data Capture SDK no longer reads from buffer, either because the frame built from it has been processed or because it was dropped from a full queue without ever being processed. Until then the buffer handed to SequenceFrameSource.addFrame() is in use by the Scandit Data Capture SDK and must not be written to.

For a frame added as an Image, buffer is the Scandit Data Capture SDK-owned array the image was converted into rather than one your application supplied.

This is normally not called on the calling thread, but under some circumstances it might be. Do not assume either.

SequenceFrameSource
class SequenceFrameSource : FrameSource

Added in version 6.14.0

Emits frames added via addFrame().

Use this class when your application, and not the Scandit Data Capture SDK, owns the camera.

That is the case when the frames come from a framework that runs its own capture session, such as ARCore, or from a Camera API 2 session your application configures itself.

Register an instance of this class as the frame source via DataCaptureContext.frameSource, switch it to ON, and then add the frames coming from the camera via addFrame(). The frame source never opens, selects or configures a camera itself — it only forwards the frames you push into it.

Frames reach the Scandit Data Capture SDK only while FrameSource.currentState is ON and the frame source is attached to a DataCaptureContext, which is why the state has to be switched explicitly, just as it is for Camera. A frame added before both conditions are true stays in a short internal queue and is emitted as soon as they are. If the queue fills up, the oldest frames are dropped first. Switching the frame source OFF again stops processing without discarding that queue.

Only one frame is in flight at a time — the next queued frame is emitted once the DataCaptureContext has finished with the previous one. Pushing frames faster than they can be processed therefore drops frames rather than building up latency.

Note

Register the frame source and switch it on once, outside of your frame loop, and then call addFrame() for each frame. Do not create a frame source per frame, and do not set one on the DataCaptureContext from inside the frame loop. In particular, do not feed a continuous camera stream through BitmapFrameSource — it is meant for single images and turns off after each one.

Note

The only pixel format type supported is NV21.

create(cameraPosition)
fun SequenceFrameSource.create(cameraPosition: CameraPosition): SequenceFrameSource

Added in version 6.14.0

Constructs a new SequenceFrameSource. It requires the position of the capture device in the form of a CameraPosition, which is a direct translation from the native Android camera position (Camera API 1 - https://developer.android.com/reference/android/hardware/Camera.CameraInfo#facing, Camera API 2 - https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#LENS_FACING). Defaults to a 90º orientation for the mounted camera (Camera API 1 - https://developer.android.com/reference/android/hardware/Camera.CameraInfo#orientation, Camera API 2 - https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#SENSOR_ORIENTATION).

The capture device position neither selects nor opens a camera. Instead, it tells the Scandit Data Capture SDK how to interpret the frames you push: frames declared as coming from a user-facing camera are treated as mirrored. Pass the position of the camera your application is actually reading from.

create(cameraPosition, captureDeviceOrientation, sequenceFrameSourceProcess)
fun SequenceFrameSource.create(cameraPosition: CameraPosition,
        captureDeviceOrientation: Int,
        sequenceFrameSourceProcess: SequenceFrameSourceProcessListener): SequenceFrameSource

Added in version 6.14.0

Constructs a new SequenceFrameSource that reports finished frame buffers back to your application.

cameraPosition is the position of the capture device the frames come from, a direct translation of the native Android camera position (Camera API 1 - https://developer.android.com/reference/android/hardware/Camera.CameraInfo#facing, Camera API 2 - https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#LENS_FACING). As in other create methods, it decides whether the frames are treated as mirrored rather than opening a camera.

captureDeviceOrientation is the mounted orientation of that camera in degrees (Camera API 1 - https://developer.android.com/reference/android/hardware/Camera.CameraInfo#orientation, Camera API 2 - https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#SENSOR_ORIENTATION). create(cameraPosition) assumes 90, the value most phone cameras report: the frame has to be rotated a quarter turn clockwise to be upright in the device’s natural orientation.

sequenceFrameSourceProcess is called back with each frame buffer once the Scandit Data Capture SDK has finished with it, which is what lets an application recycle its own buffers. See SequenceFrameSourceProcessListener.processingFinished() for exactly when that happens. create(cameraPosition) discards that signal, so use this overload when you reuse the byte arrays you pass to addFrame().

desiredState
val desiredState: FrameSourceState

Added in version 6.14.0

Implemented from FrameSource. See FrameSource.desiredState.

currentState
val currentState: FrameSourceState

Added in version 6.14.0

Implemented from FrameSource. See FrameSource.currentState.

addListener(listener)
fun addListener(listener: FrameSourceListener)

Added in version 6.14.0

Implemented from FrameSource. See FrameSource.addListener().

removeListener(listener)
fun removeListener(listener: FrameSourceListener)

Added in version 6.14.0

Implemented from FrameSource. See FrameSource.removeListener().

switchToDesiredState(desiredState, whenDone)
fun switchToDesiredState(desiredState: FrameSourceState, whenDone: Callback<Boolean>?)

Added in version 6.14.0

Implemented from FrameSource. See FrameSource.switchToDesiredState().

addFrame(width, height, buffer)
fun addFrame(width: Int,
        height: Int,
        buffer: ByteArray)

Added in version 6.14.0

Adds an image byte buffer with a given width and height. If this frame source is ON and connected to a DataCaptureContext this is the next frame that will be processed.

The only pixel format supported is NV21 — the full-resolution Y plane followed by interleaved V and U samples at half resolution, tightly packed. A buffer whose length is not width * height * 3 / 2 is rejected with an AssertionError.

The Scandit Data Capture SDK keeps a reference to the array until it is done with the frame, so do not write to it before then. Construct the frame source with create() and an SequenceFrameSourceProcessListener to be told when that happens. A reported array is free to reuse unless your application also adds frames as an Image: those draw from the same internal pool the array is returned to, and can be written into it.

addFrame(frame)
fun addFrame(frame: Image)

Added in version 6.14.0

Adds an Image to the frame source. This type is usually provided by the Camera API 2. If this frame source is ON and connected to a DataCaptureContext this is the next frame that will be processed.

The image must be in YUV_420_888 format — the format the Camera API 2 delivers — and any other format is rejected with an AssertionError. Unlike the byte-buffer overload, the planes are copied into a buffer owned by the Scandit Data Capture SDK before the call returns, so the Image can be closed right afterwards.

Only a small number of those buffers exist. While they are all still held by frames that have not been processed yet, further images are dropped instead of queued, so feed frames at the rate your camera delivers them rather than in a tight loop.