Реализация мультикамерной съемки в мобильном приложении
Одновременная запись с фронтальной и задней камеры — функция, которую поддерживают не все устройства, и именно здесь разработчики чаще всего обнаруживают, что API сложнее, чем кажется по документации.
Ограничения по железу
На iOS AVCaptureMultiCamSession доступен только на iPhone XS и новее (A12+). AVCaptureMultiCamSession.isMultiCamSupported — первое, что проверяем. На более старых устройствах — graceful degradation: только одна камера или последовательная запись.
На Android мультикамерность через Camera2 API: CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_TYPE и список физических камер через getPhysicalCameraIds(). Одновременный захват с двух физических камер доступен с Android 9 (API 28), но реальная поддержка зависит от производителя — Samsung и Pixel работают стабильно, некоторые MediaTek-устройства имеют ограничения.
iOS: AVCaptureMultiCamSession
let session = AVCaptureMultiCamSession()
// Задняя камера
let backInput = try AVCaptureDeviceInput(device: backCamera)
let backOutput = AVCaptureMovieFileOutput()
let backConnection = AVCaptureMultiCamSession.Connection(
inputPort: backInput.ports[0], output: backOutput)
// Фронтальная камера
let frontInput = try AVCaptureDeviceInput(device: frontCamera)
let frontOutput = AVCaptureMovieFileOutput()
session.addInputWithNoConnections(backInput)
session.addOutput(backOutput)
session.addInputWithNoConnections(frontInput)
session.addOutput(frontOutput)
session.addConnection(backConnection)
Важно: hardwareCost и systemPressureCost сессии могут превысить допустимый предел. Уменьшаем разрешение одной из камер до 720p, если hardwareCost > 1.0. Иначе startRunning() завершится с ошибкой без явного сообщения.
Picture-in-Picture при записи
Два видеопотока записываются в отдельные файлы. Для финального PiP-видео — AVMutableComposition: основной поток на весь экран, второй — масштабируем через AVMutableVideoCompositionLayerInstruction.setTransform() в угол. AVVideoCompositionInstruction с двумя layerInstructions собирает итоговый файл.
Android: Camera2 мультикамера
val cameraManager = getSystemService(CameraManager::class.java)
val multiCameraId = cameraManager.cameraIdList.firstOrNull { id ->
val chars = cameraManager.getCameraCharacteristics(id)
chars.get(REQUEST_AVAILABLE_CAPABILITIES)
?.contains(REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) == true
}
Открываем CameraDevice, создаём CaptureSession с поверхностями обеих камер. Для CameraX — CameraSelector с физическим ID через CameraSelector.Builder().addCameraFilter().
Flutter
Прямой мультикамерный захват через camera (pub.dev) не поддерживается в полном смысле. Решение — MethodChannel + нативная реализация на Swift/Kotlin, которую передаём во Flutter через Texture виджет.
Управление ресурсами
AVCaptureMultiCamSession потребляет значительно больше энергии и памяти, чем одиночная сессия. На iPhone 12 mini session.hardwareCost при двух потоках в 1080/30fps может достигать 0.9–1.0. Превышение значения 1.0 приведёт к тому, что startRunning() молча вернёт ошибку без вызова делегата. Решение: уменьшаем разрешение одной из камер до 720p или снижаем frameRate до 24fps — AVCaptureDevice.Format выбираем с минимальным videoSupportedFrameRateRanges.
systemPressureCost — тепловой показатель. Подписываемся на AVCaptureSession.systemPressureStateNotification, при level == .critical снижаем frameRate до 15fps, при level == .shutdown останавливаем запись — иначе система принудительно убьёт сессию.
Сроки
3–5 дней: реализация на iOS (основной объём) + базовая версия на Android. PiP-композиция финального видео — плюс 1–2 дня.







