Skip to content

Instantly share code, notes, and snippets.

@thatseeyou
Last active August 10, 2023 13:45
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save thatseeyou/caa8db15f39963dc1060 to your computer and use it in GitHub Desktop.
How to capture video frames from the camera as images using AV Foundation on iOS
//
// ViewController.swift
//
// Technical Q&A QA1702
// How to capture video frames from the camera as images using AV Foundation on iOS
//
import UIKit
import AVFoundation
import CoreMedia
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate
{
let mainGroup = UIStackView()
let imageView = UIImageView(frame: CGRectZero)
override func viewDidLoad()
{
super.viewDidLoad()
// 1. Layout Views
view.addSubview(mainGroup)
mainGroup.axis = UILayoutConstraintAxis.Vertical
mainGroup.distribution = UIStackViewDistribution.Fill
mainGroup.addArrangedSubview(imageView)
imageView.contentMode = UIViewContentMode.ScaleAspectFit
// 2. Create session & configure
let captureSession = AVCaptureSession()
captureSession.sessionPreset = AVCaptureSessionPresetMedium
// 3. set input
let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
do {
let input = try AVCaptureDeviceInput(device: backCamera)
captureSession.addInput(input)
}
catch {
print("can't access camera")
return
}
// although we don't use this, it's required to get captureOutput invoked
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
view.layer.addSublayer(previewLayer)
// 4. set output & configure
let videoOutput = AVCaptureVideoDataOutput()
if captureSession.canAddOutput(videoOutput) {
captureSession.addOutput(videoOutput)
}
let queue = dispatch_queue_create("sample buffer delegate", nil)
videoOutput.setSampleBufferDelegate(self, queue: queue)
// 5. Specify the pixel format
videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey : UInt(kCVPixelFormatType_32BGRA)]
// 6. start running session
captureSession.startRunning()
}
override func viewDidLayoutSubviews()
{
let topMargin = topLayoutGuide.length
mainGroup.frame = CGRect(x: 0, y: topMargin, width: view.frame.width, height: view.frame.height - topMargin).insetBy(dx: 5, dy: 5)
}
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!)
{
let image = imageFromSampleBuffer(sampleBuffer)
dispatch_async(dispatch_get_main_queue())
{
print(image.CGImage)
self.imageView.image = image
}
}
func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage {
let imageBuffer:CVImageBuffer! = CMSampleBufferGetImageBuffer(sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer, 0)
let baseAddress: UnsafeMutablePointer<Void> = CVPixelBufferGetBaseAddress(imageBuffer)
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
let width = CVPixelBufferGetWidth(imageBuffer)
let height = CVPixelBufferGetHeight(imageBuffer)
let colorSpace = CGColorSpaceCreateDeviceRGB();
// Create a bitmap graphics context with the sample buffer data
let context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue);
let quartzImage = CGBitmapContextCreateImage(context)
CVPixelBufferUnlockBaseAddress(imageBuffer, 0)
// Create an image object from the Quartz image
let image = UIImage(CGImage:quartzImage!);
return (image);
}
func colorForPixel(image: UIImage, x: Int, y: Int) -> UIColor {
let cgImage = image.CGImage
let imageWidth = CGImageGetWidth(cgImage)
let imageHeight = CGImageGetHeight(cgImage)
let bytesPerPixel = CGImageGetBitsPerPixel(cgImage) / 8
//print("\(imageWidth) x \(imageHeight) x \(bytesPerPixel)")
let pixelData:CFData! = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
let data:UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
// CGImage is flipped. So (imageHeight - y) is needed.
let pixelValue = data + (imageWidth * (imageHeight - y) + x) * bytesPerPixel
// kCVPixelFormatType_32BGRA
let blue = CGFloat(pixelValue[0])
let green = CGFloat(pixelValue[1])
let red = CGFloat(pixelValue[2])
let alpha = CGFloat(pixelValue[3])
return UIColor(red: red / 255, green: green / 255, blue: blue / 255, alpha: alpha / 255)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment