camera freezes, preview rotated wrong, capture slow, session interrupted, black preview, front camera mirrored, camera not starting, AVCaptureSession errors, startRunning blocks, phone call interrupts camera
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
camera freezes, preview rotated wrong, capture slow, session interrupted, black preview, front camera mirrored, camera not starting, AVCaptureSession errors, startRunning blocks, phone call interrupts camera
license
MIT
compatibility
iOS 17+, iPadOS 17+, macOS 14+, tvOS 17+
metadata
{"version":"1.0.0","last-updated":"2026-01-03"}
Camera Capture Diagnostics
Systematic troubleshooting for AVFoundation camera issues: frozen preview, wrong rotation, slow capture, session interruptions, and permission problems.
Overview
Core Principle: When camera doesn't work, the problem is usually:
Threading (session work on main thread) - 35%
Session lifecycle (not started, interrupted, not configured) - 25%
let status =AVCaptureDevice.authorizationStatus(for: .video)
print("🔐 Camera permission: \(status.rawValue)")
switch status {
case .authorized: print(" ✅ Authorized")
case .notDetermined: print(" ⚠️ Not yet requested")
case .denied: print(" ❌ Denied by user")
case .restricted: print(" ❌ Restricted (parental controls?)")
@unknowndefault: print(" ❓ Unknown")
}
Camera not working as expected?
│
├─ Black/frozen preview?
│ ├─ Check Step 1 (session state)
│ │ ├─ isRunning = false → See Pattern 1 (session not started)
│ │ ├─ inputs = 0 → See Pattern 2 (no camera input)
│ │ └─ isRunning = true, inputs > 0 → See Pattern 3 (preview layer)
│
├─ UI freezes when opening camera?
│ └─ Check Step 2 (threading)
│ └─ Main thread → See Pattern 4 (move to session queue)
│
├─ Camera freezes during use?
│ ├─ After phone call → See Pattern 5 (interruption handling)
│ ├─ In Split View (iPad) → See Pattern 6 (multitasking)
│ └─ Random freezes → See Pattern 7 (thermal pressure)
│
├─ Preview/photo rotated wrong?
│ ├─ Preview rotated → See Pattern 8 (RotationCoordinator preview)
│ ├─ Captured photo rotated → See Pattern 9 (capture rotation)
│ └─ Front camera "wrong" → See Pattern 10 (mirroring expected)
│
├─ Capture too slow?
│ ├─ 2+ seconds delay → See Pattern 11 (quality prioritization)
│ └─ Slight delay → See Pattern 12 (deferred processing)
│
├─ Permission issues?
│ ├─ Status: notDetermined → See Pattern 13 (request permission)
│ └─ Status: denied → See Pattern 14 (settings prompt)
│
└─ Crash on some devices?
└─ See Pattern 15 (API availability)
Diagnostic Patterns
Pattern 1: Session Not Started
Symptom: Black preview, isRunning = false
Common causes:
startRunning() never called
startRunning() called but session has no inputs
Session stopped and never restarted
Diagnostic:
// Check if startRunning was calledprint("isRunning before start: \(session.isRunning)")
session.startRunning()
print("isRunning after start: \(session.isRunning)")
Fix:
// Ensure session is started on session queuefuncstartSession() {
sessionQueue.async { [self] inguard!session.isRunning else { return }
// Verify we have inputs before startingguard!session.inputs.isEmpty else {
print("❌ Cannot start - no inputs configured")
return
}
session.startRunning()
}
}
Time to fix: 10 min
Pattern 2: No Camera Input
Symptom: session.inputs.count = 0
Common causes:
Camera permission denied
AVCaptureDeviceInput creation failed
canAddInput() returned false
Configuration not committed
Diagnostic:
// Step through input setupguardlet camera =AVCaptureDevice.default(for: .video) else {
print("❌ No camera device found")
return
}
print("✅ Camera: \(camera.localizedName)")
do {
let input =tryAVCaptureDeviceInput(device: camera)
print("✅ Input created")
if session.canAddInput(input) {
print("✅ Can add input")
} else {
print("❌ Cannot add input - check session preset compatibility")
}
} catch {
print("❌ Input creation failed: \(error)")
}
Fix: Ensure permission is granted BEFORE creating input, and wrap in configuration block:
session.beginConfiguration()
// Add input here
session.commitConfiguration()
Time to fix: 15 min
Pattern 3: Preview Layer Not Connected
Symptom: isRunning = true, inputs configured, but preview is black
// Ensure preview layer is properly configured
previewLayer.session = session
previewLayer.videoGravity = .resizeAspectFill
// Ensure frame is set (common in SwiftUI)
previewLayer.frame = view.bounds
Time to fix: 10 min
Pattern 4: Main Thread Blocking
Symptom: UI freezes for 1-3 seconds when camera opens
Root cause: startRunning() is a blocking call executed on main thread
Diagnostic:
// If this prints on main thread, that's the problemprint("startRunning on thread: \(Thread.current)")
session.startRunning()
Fix:
// Create dedicated serial queueprivatelet sessionQueue =DispatchQueue(label: "camera.session")
funcstartSession() {
sessionQueue.async { [self] in
session.startRunning()
}
}
Time to fix: 15 min
Pattern 5: Phone Call Interruption
Symptom: Camera works, then freezes when phone call comes in
Root cause: Session interrupted but no handling/UI feedback
Diagnostic:
// Check if session is still running after returning from callprint("Session running: \(session.isRunning)")
// Will be false during active call, true after call ends
Fix: Add interruption observers (see camera-capture skill Pattern 5)
Key point: Session AUTOMATICALLY resumes after interruption ends. You don't need to call startRunning() again. Just update your UI.
Time to fix: 30 min
Pattern 6: Split View Camera Unavailable
Symptom: Camera stops working when iPad enters Split View
Root cause: Camera not available with multiple foreground apps
case .videoDeviceNotAvailableDueToSystemPressure:
// Reduce quality
session.sessionPreset = .medium
showMessage("Camera quality reduced due to device temperature")
Time to fix: 20 min
Pattern 8: Preview Rotation Wrong
Symptom: Preview is rotated 90° from expected
Root cause: Not using RotationCoordinator (iOS 17+) or not observing updates
Time to fix: 5 min (explanation) or 15 min (if mirroring required)
Pattern 11: Slow Capture (Quality Priority)
Symptom: Photo capture takes 2+ seconds
Root cause: photoQualityPrioritization = .quality (default for some devices)
Diagnostic:
print("Max quality prioritization: \(photoOutput.maxPhotoQualityPrioritization.rawValue)")
// Check what you're requesting in AVCapturePhotoSettings
Fix:
var settings =AVCapturePhotoSettings()
// For fast capture (social/sharing)
settings.photoQualityPrioritization = .speed
// For balanced (general use)
settings.photoQualityPrioritization = .balanced
// Only use .quality when image quality is critical
Time to fix: 5 min
Pattern 12: Deferred Processing
Symptom: Want maximum responsiveness (zero-shutter-lag)
Solution: Enable deferred processing (iOS 17+)
photoOutput.isAutoDeferredPhotoDeliveryEnabled =true// Then handle proxy in delegate:// - didFinishProcessingPhoto gives proxy for immediate display// - didFinishCapturingDeferredPhotoProxy gives final image later
Time to fix: 30 min
Pattern 13: Permission Not Requested
Symptom: authorizationStatus = .notDetermined
Fix:
// Must request before setting up sessionTask {
let granted =awaitAVCaptureDevice.requestAccess(for: .video)
if granted {
setupSession()
}
}
Time to fix: 10 min
Pattern 14: Permission Denied
Symptom: authorizationStatus = .denied
Fix: Show settings prompt
funcshowSettingsPrompt() {
let alert =UIAlertController(
title: "Camera Access Required",
message: "Please enable camera access in Settings to use this feature.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Settings", style: .default) { _iniflet url =URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert, animated: true)
}
Time to fix: 15 min
Pattern 15: API Availability Crash
Symptom: Crash on iOS 16 or earlier
Root cause: Using iOS 17+ APIs without availability check