DeepMedia logodeepmedia

Camera SDK

Version 0.8.5

Search

Choose platform

Other versions of this page

Preview

Camera previews let you embed a real-time view of the camera stream in your UI.

⚠️

Make sure you declare CameraFeature.PreviewCameraFeature.preview during manager initialization.

Surface management

Creating surfaces

Surfaces are declared by using CameraManager.createSurface and CameraManager.destroySurface. These APIs are designed to be framework-agnostic so they can work, for instance, with both android.view.View and Jetpack Composeboth UIKit and SwiftUI.

Instead of a View, the API requires a android.view.Surface:

kotlin logokotlin
// CameraManager API fun createSurface( name: String, target: Surface, display: Int?, preview: Boolean = true, video: Boolean = false, )

Instead of a view or view controller, the API requires a CAMetalLayer:

swift
// CameraManager API func createSurface( _ name: String, target: CAMetalLayer, screen: UIScreen?, preview: Bool = true, video: Bool = false )

Let's go through the arguments and their meaning:

  • name: an user-defined identifier for this surface. Used later during destroy
  • target: will be forwarded image frames from the camera stream
  • display: the ID of the android.view.Display owning the preview view. Very important in multi-display scenarios.
    screen: the UIScreen owning the preview view.
  • (optional) preview: whether this surface should receive preview frames. Defaults to true.
  • (optional) video: whether this surface should receive video recording frames. Defaults to false.

Keep reading below to see a real-word example.

Destroying surfaces

For proper resource management, it is fundamental that you also destroy the surface once the owner view is disposed:

kotlin logokotlin
// CameraManager API fun destroySurface(name: String)
swift
// CameraManager API func destroySurface(_ name: String)

UI Integration

The code below shows one of the possible ways you can integrate previews in your KotlinSwift application. Note that Multiple previews for the same camera are allowed: just make sure to use a different surface name.

For UIKit-based apps, you may use the following view implementation:

swift
class CameraPreview : UIView { let manager: CameraManager let name: String init(manager: CameraManager, name: String = "DefaultCameraPreview") { self.manager = manager self.name = name super.init(frame: .zero) backgroundColor = .clear } required init?(coder: NSCoder) { return nil } override class var layerClass: AnyClass { CAMetalLayer.self } override var layer: CAMetalLayer { super.layer as! CAMetalLayer } override func willMove(toWindow newWindow: UIWindow?) { if newWindow == nil { manager.destroySurface(name) } super.willMove(toWindow: newWindow) } override func didMoveToWindow() { super.didMoveToWindow() if let window { layer.contentsScale = window.screen.scale resizeLayer() manager.createSurface(name, target: layer, screen: window.screen) } } override func layoutSubviews() { super.layoutSubviews() resizeLayer() } private func resizeLayer() { layer.drawableSize = .init(width: layer.frame.width * layer.contentsScale, height: layer.frame.height * layer.contentsScale) } }

For SwiftUI, you can simply wrap the view above in a UIViewRepresentable.

For android.view.*-based apps, you may use a SurfaceView:

kotlin logokotlin
class SurfaceHolderCallback( private val surfaceView: SurfaceView, private val manager: CameraManager, private val name: String = "DefaultCameraPreview" ) : SurfaceHolder.Callback { override fun surfaceCreated(holder: SurfaceHolder) { manager.createSurface( name = name, target = holder.surface, display = surfaceView.display.displayId ) } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { // Nothing to do } override fun surfaceDestroyed(holder: SurfaceHolder) { manager.destroySurface(name) } } val surfaceView = SurfaceView(context) // or findViewById() surfaceView.holder.addCallback(SurfaceHolderCallback(surfaceView, manager)) // Don't forget to add the SurfaceView to your view hierarchy, if it's not there already.

For Jetpack Compose apps, simply wrap the SurfaceView above in an AndroidView:

kotlin logokotlin
AndroidView( modifier = modifier, factory = { val surfaceView = SurfaceView(it) surfaceView.holder.addCallback(SurfaceHolderCallback(surfaceView, manager)) surfaceView } )

Subscribe to the DeepMedia Newsletter

The latest news about DeepMedia products, open source projects and software development at our company.

By clicking “Subscribe”, you agree that DeepMedia may use your email address to send you newsletters, including commercial communications, and to process your personal data for this purpose. You agree that DeepMedia may process said data using third-party services for this purpose in accordance with the DeepMedia Privacy Policy. You can revoke this consent at any time using the unsubscribe link included in each email or by writing at contact@deepmedia.io.