EyeQ Docs

Troubleshooting

Common issues and solutions for the Video Mobile SDK.

This guide covers common issues you may encounter when integrating the Video Mobile SDK and how to resolve them.

License errors

License-related issues are the most common cause of SDK failures. These errors typically occur during initialization or when processing images, resulting in black output or exceptions.

Expired certificate

The SDK validates your license on every initialization. An expired certificate will prevent image processing from working correctly.

Symptom: checkCertificate() returns -1 (Android) or checkStatus() returns -1 (iOS). Processed images appear completely black.

Cause: The certificate has passed its expiration date.

Solution:

  1. Contact EyeQ to obtain a new certificate.
  2. Update your app with the new credentials.
  3. If testing, then verify your device date/time is set correctly as incorrect system time can cause valid certificates to appear expired.

Invalid API key or certificate

Mismatched or malformed credentials will prevent the SDK from initializing properly.

Symptom: checkCertificate() returns -2 for Android or checkStatus() returns -2 for iOS. SDK initialization fails silently.

Cause: The API key and certificate don't match, or one is incorrectly formatted.

Solution:

  1. Verify the API key and certificate are from the same license.

  2. Check for copy/paste errors such as extra whitespace, missing characters, or truncated strings.

  3. On iOS, use raw string literals to avoid escape character issues.

  4. On Android, verify credentials in your setLicence() call:

dynamicProcessor.setLicence(
    apiKey = "2128501",  // Digits only
    cert = "d\\YjDX}mJz...",  // Escape backslashes or use raw string
    recreate = false
)

Checking license status

Always verify your license before processing images. This helps catch configuration issues early.

Android:

val status = dynamicProcessor.checkCertificate(apiKey, cert)
when {
    status > 0 -> Log.d("License", "Valid for $status days")
    status == -1 -> Log.e("License", "Certificate expired")
    status == -2 -> Log.e("License", "Invalid API key or certificate")
    else -> Log.e("License", "Unknown error: $status")
}

// Also check days remaining
val daysLeft = dynamicProcessor.getDaysLeft()

iOS:

let status = pfcDynamic.checkStatus()
switch status {
case 0:
    print("SDK initialized successfully")
case -1:
    print("Certificate expired")
case -2:
    print("Invalid API key or certificate")
case -3:
    print("Failed to initialize AI model")
case -4:
    print("Failed to load model file")
case -5:
    print("Failed to create context")
default:
    print("Unknown error: \(status)")
}

Initialization failures

These errors occur when the SDK cannot load or initialize its neural network model. They typically indicate missing dependencies or corrupted framework files.

Failed to initialize AI model

The neural network model requires specific runtime dependencies to execute properly.

Symptom: checkStatus() returns -3 (iOS) or init() throws an exception (Android).

Cause: The TensorFlow Lite runtime could not initialize the neural network model.

Solution for Android:

  1. Ensure TensorFlow Lite dependencies are included in your build.gradle:
dependencies {
    implementation("org.tensorflow:tensorflow-lite:2.8.0")
    implementation("org.tensorflow:tensorflow-lite-gpu:2.8.0")
}
  1. Try CPU fallback if GPU initialization fails:
val gpuSupported = dynamicProcessor.isDelegateSupported()

if (gpuSupported) {
    dynamicProcessor.init(useGpu = true)
} else {
    dynamicProcessor.init(useGpu = false)
}
  1. On some devices, GPU delegate may be supported but unstable. Use try-catch as a safety net:
try {
    dynamicProcessor.init(useGpu = true)
} catch (e: Exception) {
    Log.w("SDK", "GPU init failed, falling back to CPU", e)
    dynamicProcessor.init(useGpu = false)
}

Solution for iOS: The iOS framework bundles all required dependencies. If you see this error, then ensure the XCFramework is properly embedded in your target.

Failed to load model file

The SDK requires a bundled model file to perform image processing.

Symptom: checkStatus() returns -4 (iOS).

Cause: The PFCDynamicModel.pnnc file is missing from the framework bundle.

Solution:

  1. Re-download the SDK package from EyeQ.
  2. Verify the XCFramework contains the model file at DynamicFramework.framework/PFCDynamicModel.pnnc.
  3. In Xcode, clean the build folder (Product → Clean Build Folder) and rebuild.
  4. Ensure the framework is set to "Embed & Sign" in your target's General settings.

Failed to create context

The SDK requires a GPU context for rendering processed images.

Symptom: checkStatus() returns -5 in iOS.

Cause: OpenGL or Metal context creation failed, typically on simulator or restricted environments.

Solution:

  1. Test on a physical device instead of the simulator.
  2. Ensure no other frameworks are holding exclusive GPU resources.
  3. Check that your app has the necessary entitlements for GPU access.

Build errors

Build-time issues typically relate to project configuration or missing dependencies.

Android: Model file compression

Android's build system may compress SDK model files, corrupting them and preventing the SDK from loading.

Symptom: Model loading fails at runtime with cryptic errors. init() throws an exception.

Solution: Add the noCompress directive to prevent compression of model files:

android {
    androidResources {
        noCompress("pnn", "pnne")
    }
}

Android: ProGuard/R8 obfuscation

Code obfuscation can break SDK internals if classes are renamed or removed.

Symptom: SDK works in debug builds but crashes in release builds.

Solution: Add keep rules to your ProGuard configuration:

# Keep SDK classes
-keep class photos.eyeq.dynamic.** { *; }
-keep class photos.eyeq.dynamic.model.** { *; }
-keep class photos.eyeq.dynamic.bench.** { *; }
-keep class photos.eyeq.dynamic.eglx.** { *; }

# Keep TensorFlow Lite
-keep class org.tensorflow.** { *; }
-keepclassmembers class org.tensorflow.** { *; }

iOS: Bitcode errors

The SDK framework does not include Bitcode, which can cause archive failures.

Symptom: Build fails with "Bitcode bundle could not be generated" error when archiving.

Solution:

  1. Select your project in the navigator.
  2. Go to Build Settings.
  3. Search for "Enable Bitcode".
  4. Set to No for your target.

iOS: Framework embedding issues

Incorrect framework configuration causes runtime crashes on app launch.

Symptom: App crashes immediately on launch with "Library not loaded" or "image not found" errors.

Solution:

  1. Select your target in Xcode.
  2. Go to General → Frameworks, Libraries, and Embedded Content.
  3. Ensure DynamicFramework.xcframework is set to Embed & Sign.
  4. If using CocoaPods or SPM, then ensure the framework is properly linked.

Performance issues

If you're experiencing slow frame rates, laggy preview, or excessive battery drain, then these optimizations can help.

Slow processing speed

Processing speed depends on image resolution, device hardware, and whether GPU acceleration is active.

Diagnosis: Use benchmarking to identify which stage is the bottleneck.

Android:

dynamicProcessor.setBenchListener(object : EyeQBenchListener {
    override fun onDynamic(bench: BenchDynamic) {
        Log.d("Perf", "Scale: ${bench.scaleTime}ms")
        Log.d("Perf", "Read bitmap: ${bench.readFromBitmap}ms")
        Log.d("Perf", "Normalize: ${bench.normalizeTime}ms")
        Log.d("Perf", "Inference: ${bench.inferenceTime}ms")
        Log.d("Perf", "Adjust: ${bench.adjustTime}ms")
    }
    
    override fun onEgl(bench: BenchEgl) {
        Log.d("Perf", "Texture: ${bench.textureTime}ms")
        Log.d("Perf", "Render: ${bench.renderTime}ms")
    }
    
    override fun onDeflicker(consumeTime: Long) {
        Log.d("Perf", "Deflicker: ${consumeTime}ms")
    }
})

Optimizations:

  1. Verify GPU is active: Check that GPU delegate is supported and being used:
val gpuSupported = dynamicProcessor.isDelegateSupported()
Log.d("SDK", "GPU supported: $gpuSupported")
  1. Use frame skipping: For video processing, skip frames to reduce load:
// Skip 1 frame between inferences (process every other frame)
dynamicProcessor.setDeflickerParams(1, 0.08f, 0.9f)
  1. Use preview methods: For display purposes, use processImagePreview() or processCameraFrame() instead of processImage().

iOS optimizations:

  1. Enable frame skipping: Reduce processing load on lower-end devices:
// Skip 1 frame between inferences
pfcDynamic.setParams(deflickerCurve: 0.08, deflickerImage: 0.9, skip: 1)
  1. Process on background queue: Never block the main thread:
videoQueue.async {
    let processed = try? self.pfcDynamic.processImage(cgImage, strength: 0.8)
    
    DispatchQueue.main.async {
        self.imageView.image = UIImage(cgImage: processed)
    }
}

Video flickering

Flickering in video output occurs when correction parameters vary frame-to-frame without temporal smoothing.

Cause: Deflickering not configured, or resetDeflicker() called too frequently.

Solution:

  1. Enable deflickering: Before processing video frames:
// iOS
pfcDynamic.setParams(deflickerCurve: 0.08, deflickerImage: 0.9, skip: 0)
// Android
dynamicProcessor.setDeflickerParams(0, 0.08f, 0.9f)
  1. Only reset when necessary: Call resetDeflicker() only in these situations:
ScenarioAction
Switching camerasCall resetDeflicker()
Starting new videoCall resetDeflicker()
Seeking in videoCall resetDeflicker()
Each frame❌ Never call per-frame
  1. Don't call during active processing: Calling setDeflickerParams() while processing frames can cause visual discontinuities.

Memory issues

Processing high-resolution images can consume significant memory, especially on older devices.

Android:

// Recycle bitmaps when done
processedBitmap.recycle()

// For camera processing, close ImageProxy promptly
imageProxy.close()

iOS:

// Use autoreleasepool for batch processing
for image in images {
    autoreleasepool {
        let processed = try? pfcDynamic.processImage(image, strength: 0.8)
        // Use processed image
    }
}

Platform-specific issues

Some issues only occur on specific platforms due to framework conflicts or platform limitations.

iOS: Simulator limitations

The iOS Simulator has limited GPU capabilities and no camera access.

What works: Basic image processing with processImage().

What doesn't work: Camera capture, real-time video processing, accurate performance testing.

Solution: Always test video and camera features on a physical device.

iOS: GPUImage conflicts

The SDK uses GPUImage internally, which can conflict with external GPUImage dependencies.

Symptom: Crashes or undefined behavior when using GPUImage framework alongside the SDK.

Solution:

  1. Remove external GPUImage dependency if possible.
  2. If you must use GPUImage, then isolate SDK usage in a separate module or process.
  3. Contact EyeQ support for guidance on specific conflict scenarios.

Android: Camera2/CameraX compatibility

Some camera implementations produce image formats that require conversion before SDK processing.

Symptom: Processed images appear corrupted or have wrong colors.

Solution: Use the SDK's YuvToRgbConverter for camera frames:

val converter = YuvToRgbConverter(context)
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)

// Convert camera frame
converter.yuvToRgb(image, bitmap)

// Process converted bitmap
val outputs = dynamicProcessor.processCameraFrame(bitmap, 0.8f)

Getting help

If you encounter issues not covered in this guide, here's how to get additional support.

Before contacting support:

  1. Review the sample projects for working implementation examples.
  2. Check the API reference for Android or iOS.
  3. Verify your SDK version matches the documentation.

When contacting EyeQ support, include:

  • SDK version number
  • Platform and OS version, for example, Android 16, iOS 18
  • Device model
  • Complete error message or stack trace
  • Minimal code sample that reproduces the issue
  • Output of checkCertificate() or checkStatus()

VIDEO-SDK Version 1.0.0.23 built from aa5eef97017e23db1d3051b079500606825ef474 on 5-6-2023.

Copyright © 2026 EyeQ Imaging Inc. All rights reserved.

On this page