Skip to content

Instantly share code, notes, and snippets.

@standinga
Created November 18, 2018 00:16
Show Gist options
  • Save standinga/08cc70fb40fe0d99b765869c80a90e2b to your computer and use it in GitHub Desktop.
Save standinga/08cc70fb40fe0d99b765869c80a90e2b to your computer and use it in GitHub Desktop.
Read MJPEG int CGImage using Swift4, URLSession, OSX
//
// main.swift
// MJPEGreader
//
// Created by michal on 17/11/2017.
// Copyright © 2018 michal. All rights reserved.
//
import Foundation
let configuration = URLSessionConfiguration.ephemeral
var urlComponents = URLComponents(string: "http://192.168.0.27:8080")!
urlComponents.query = "action=stream"
let url = urlComponents.url!
enum MjpegReadError: Error {
case badResponse, parseImage
}
class MjpegRead: NSObject, URLSessionDelegate, URLSessionDataDelegate {
let startMarker: Data = Data(bytes: [0xFF, 0xD8])
let endMarker: Data = Data(bytes: [0xFF, 0xD9])
var buffer: Data = Data()
let configuration = URLSessionConfiguration.ephemeral
var session: URLSession?
var task: URLSessionDataTask?
var handler: ((CGImage?, MjpegReadError?)->())?
func readStream(_ url: URL, handler: @escaping (CGImage?, MjpegReadError?)->()) {
self.handler = handler
session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: nil)
task = session?.dataTask(with: url)
task?.resume()
}
func stopStream() {
task?.cancel()
task = nil
}
// MARK: Session Delegates
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
guard let response = dataTask.response as? HTTPURLResponse, response.statusCode == 200 else {
handler?(nil, .badResponse)
return
}
if data.range(of: startMarker) != nil {
print("started new frame")
buffer = Data() // clean up buffer
}
buffer.append(data)
// frame has ended if not nil
if data.range(of: endMarker) != nil {
print ("finished frame")
let frame = parseFrame(buffer)
handler?(frame, nil)
}
}
private func parseFrame(_ data: Data) -> CGImage? {
guard let imgProvider = CGDataProvider.init(data: data as CFData) else {
handler?(nil, .parseImage)
return nil
}
guard let image = CGImage.init(jpegDataProviderSource: imgProvider, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) else {
handler?(nil, .parseImage)
return nil
}
return image
}
}
let mjpegRead = MjpegRead()
mjpegRead.readStream(url) { image, error in
if let error = error {
print(error.localizedDescription)
}
if let image = image {
print("image:", image.width, image.height)
}
}
dispatchMain()
@sbhmajd
Copy link

sbhmajd commented Feb 21, 2021

Thanks for this, you saved my life. Worked perfectly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment