Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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