EyeQ Docs
Guides

Video processing

Install the Video Mobile SDK and apply your first image correction on Android.

This guide covers real-time video processing, including camera preview, video playback, and transcoding workflows.

Understanding deflickering

When processing video frames, the correction applied to each frame can vary based on the frame's content. Without temporal smoothing, this causes visible flickering between frames.

The SDK provides deflickering parameters that smooth corrections across frames:

ParameterAndroidiOSPurposeRecommended
Frames to skipframesskipProcess every Nth frame (0 = all)0–1
Curve smoothingcurveAvgdeflickerCurveSmooths tone curve adjustments0.08
Image smoothingimgAvgdeflickerImageSmooths overall corrections0.9

Deflickering has a cumulative effect. Call resetDeflicker() when switching cameras, starting a new video, or seeking to a different position.

Android video processing

The Android SDK provides specialized methods for processing camera frames. The processCameraFrame method returns DynamicOutputs which you can use with DynamicView for efficient GPU-accelerated rendering.

Camera preview with CameraX

Process live camera frames using CameraX:

package com.example.yourapp

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import androidx.fragment.app.Fragment
import photos.eyeq.dynamic.DynamicProcessor
import photos.eyeq.dynamic.model.DynamicOutputs
import photos.eyeq.dynamic.eglx.image.DynamicView

class CameraFragment : Fragment() {
    
    private lateinit var dynamicView: DynamicView
    
    private val imageAnalyzer = ImageAnalysis.Analyzer { imageProxy ->
        processFrame(imageProxy)
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // Get DynamicView from layout
        dynamicView = view.findViewById(R.id.dynamicView)
        
        // Configure deflickering for video
        // Parameters: frames to skip, curveAvg, imgAvg
        App.dynamicProcessor.setDeflickerParams(0, 0.08f, 0.9f)
        
        setupCamera()
    }
    
    private fun processFrame(imageProxy: ImageProxy) {
        // Convert ImageProxy to Bitmap
        val bitmap = imageProxy.toBitmap()
        
        // Process the frame - returns DynamicOutputs for use with DynamicView
        val outputs: DynamicOutputs = App.dynamicProcessor.processCameraFrame(
            bitmap,
            0.8f  // strength
        )
        
        // Render using DynamicView (GPU-accelerated)
        activity?.runOnUiThread {
            dynamicView.setBitmap(bitmap)
            dynamicView.setParams(outputs.global, outputs.local, outputs.fusion)
            dynamicView.requestRender()
        }
        
        imageProxy.close()
    }
    
    private fun setupCamera() {
        // CameraX setup code here
        // Attach imageAnalyzer to ImageAnalysis use case
    }
    
    fun switchCamera() {
        // Reset deflicker when switching cameras
        App.dynamicProcessor.resetDeflicker()
    }
    
    override fun onDestroyView() {
        super.onDestroyView()
        App.dynamicProcessor.resetDeflicker()
    }
}

Layout for camera preview

The fragment_camer.xml file is updated with a layout:

res/layout/fragment_camera.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <photos.eyeq.dynamic.eglx.image.DynamicView
        android:id="@+id/dynamicView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

Frame skipping for performance (Android)

Use frame skipping to reduce processing load on lower-end devices:

// Process all frames (highest quality, most CPU)
App.dynamicProcessor.setDeflickerParams(0, 0.08f, 0.9f)

// Skip every other frame (good balance)
App.dynamicProcessor.setDeflickerParams(1, 0.08f, 0.9f)

// Skip 2 frames between processed frames (performance mode)
App.dynamicProcessor.setDeflickerParams(2, 0.08f, 0.9f)

iOS video processing

The iOS SDK processes video frames using the same processImage method, with deflickering parameters configured via setParams.

Camera preview with AVCaptureSession

The AVCaptureSession object to perform real-time capture and process video:

class CameraViewController: UIViewController {
    
    private let pfcDynamic: PFCDynamic
    private let session = AVCaptureSession()
    private let videoOutput = AVCaptureVideoDataOutput()
    private let videoQueue = DispatchQueue(label: "video.processing")
    
    private var previewImageView: UIImageView!
    private var dynamicStrength: Float = 0.8
    
    init(apiKey: String, certificate: String) {
        self.pfcDynamic = PFCDynamic(apiKey: apiKey, certificate: certificate)
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Verify initialization
        let status = pfcDynamic.checkStatus()
        if status != 0 {
            print("SDK initialization failed with code: \(status)")
            return
        }
        
        // Configure deflickering for video
        pfcDynamic.setParams(
            deflickerCurve: 0.08,
            deflickerImage: 0.9,
            skip: 0
        )
        
        setupCamera()
    }
    
    @objc func switchCamera() {
        // Reset deflicker when switching cameras
        pfcDynamic.resetDeflicker()
        
        // Switch camera logic...
    }
}

extension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
    
    func captureOutput(
        _ output: AVCaptureOutput,
        didOutput sampleBuffer: CMSampleBuffer,
        from connection: AVCaptureConnection
    ) {
        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
              let cgImage = createCGImage(from: imageBuffer) else { return }
        
        do {
            let processed = try pfcDynamic.processImage(
                cgImage,
                strength: dynamicStrength
            )
            
            let image = UIImage(cgImage: processed)
            
            DispatchQueue.main.async {
                self.previewImageView.image = image
            }
        } catch {
            print("Frame processing error: \(error)")
        }
    }
    
    private func createCGImage(from imageBuffer: CVImageBuffer) -> CGImage? {
        let ciImage = CIImage(cvImageBuffer: imageBuffer)
        let context = CIContext()
        return context.createCGImage(ciImage, from: ciImage.extent)
    }
    
    private func setupCamera() {
        // AVCaptureSession setup code here
    }
}

Frame skipping for performance (iOS)

Use the skip parameter to reduce processing load:

// Process all frames (highest quality, most CPU)
pfcDynamic.setParams(deflickerCurve: 0.08, deflickerImage: 0.9, skip: 0)

// Skip every other frame (good balance)
pfcDynamic.setParams(deflickerCurve: 0.08, deflickerImage: 0.9, skip: 1)

// Skip 2 frames between processed frames (performance mode)
pfcDynamic.setParams(deflickerCurve: 0.08, deflickerImage: 0.9, skip: 2)

When skipping frames, the SDK reuses the previous frame's correction for skipped frames, maintaining visual consistency.

When to reset deflicker

Always call resetDeflicker() in these situations:

ScenarioPlatformMethod
Switch camera (front/back)BothresetDeflicker()
Start new video recordingBothresetDeflicker()
Seek in video playerBothresetDeflicker()
Load new video fileBothresetDeflicker()
Resume from backgroundBothresetDeflicker()

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