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:
| Parameter | Android | iOS | Purpose | Recommended |
|---|---|---|---|---|
| Frames to skip | frames | skip | Process every Nth frame (0 = all) | 0–1 |
| Curve smoothing | curveAvg | deflickerCurve | Smooths tone curve adjustments | 0.08 |
| Image smoothing | imgAvg | deflickerImage | Smooths overall corrections | 0.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:
<?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:
| Scenario | Platform | Method |
|---|---|---|
| Switch camera (front/back) | Both | resetDeflicker() |
| Start new video recording | Both | resetDeflicker() |
| Seek in video player | Both | resetDeflicker() |
| Load new video file | Both | resetDeflicker() |
| Resume from background | Both | resetDeflicker() |
VIDEO-SDK Version 1.0.0.23 built from aa5eef97017e23db1d3051b079500606825ef474 on 5-6-2023.
Copyright © 2026 EyeQ Imaging Inc. All rights reserved.