Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Extract sample buffer streaming logic
  • Loading branch information
RobertOdrowaz committed Aug 10, 2025
commit 59d347999b401b58efc47c2053c7b78c86d7319a
Original file line number Diff line number Diff line change
Expand Up @@ -758,74 +758,7 @@ final class DefaultCamera: FLTCam, Camera {
return
}

if isStreamingImages {
if let eventSink = imageStreamHandler?.eventSink,
streamingPendingFramesCount < maxStreamingPendingFramesCount
{
if let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
streamingPendingFramesCount += 1

// Must lock base address before accessing the pixel data
CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)

let imageWidth = CVPixelBufferGetWidth(pixelBuffer)
let imageHeight = CVPixelBufferGetHeight(pixelBuffer)

var planes: [[String: Any]] = []

let isPlanar = CVPixelBufferIsPlanar(pixelBuffer)
let planeCount = isPlanar ? CVPixelBufferGetPlaneCount(pixelBuffer) : 1

for i in 0..<planeCount {
let planeAddress: UnsafeMutableRawPointer?
let bytesPerRow: Int
let height: Int
let width: Int

if isPlanar {
planeAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, i)
bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, i)
height = CVPixelBufferGetHeightOfPlane(pixelBuffer, i)
width = CVPixelBufferGetWidthOfPlane(pixelBuffer, i)
} else {
planeAddress = CVPixelBufferGetBaseAddress(pixelBuffer)
bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
height = CVPixelBufferGetHeight(pixelBuffer)
width = CVPixelBufferGetWidth(pixelBuffer)
}

let length = bytesPerRow * height
let bytes = Data(bytes: planeAddress!, count: length)

let planeBuffer: [String: Any] = [
"bytesPerRow": bytesPerRow,
"width": width,
"height": height,
"bytes": FlutterStandardTypedData(bytes: bytes),
]
planes.append(planeBuffer)
}

// Lock the base address before accessing pixel data, and unlock it afterwards.
// Done accessing the `pixelBuffer` at this point.
CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)

let imageBuffer: [String: Any] = [
"width": imageWidth,
"height": imageHeight,
"format": videoFormat,
"planes": planes,
"lensAperture": Double(captureDevice.lensAperture()),
"sensorExposureTime": Int(captureDevice.exposureDuration().seconds * 1_000_000_000),
"sensorSensitivity": Double(captureDevice.iso()),
]

DispatchQueue.main.async {
eventSink(imageBuffer)
}
}
}
}
handleSampleBufferStreaming(sampleBuffer)

if isRecording && !isRecordingPaused {
if videoWriter?.status == .failed, let error = videoWriter?.error {
Expand Down Expand Up @@ -906,6 +839,81 @@ final class DefaultCamera: FLTCam, Camera {
}
}

private func handleSampleBufferStreaming(_ sampleBuffer: CMSampleBuffer) {
guard isStreamingImages,
let eventSink = imageStreamHandler?.eventSink,
streamingPendingFramesCount < maxStreamingPendingFramesCount
else {
return
}

// Non-pixel buffer samples, such as audio samples, are ignored for streaming
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}

streamingPendingFramesCount += 1

// Must lock base address before accessing the pixel data
CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)

let imageWidth = CVPixelBufferGetWidth(pixelBuffer)
let imageHeight = CVPixelBufferGetHeight(pixelBuffer)

var planes: [[String: Any]] = []

let isPlanar = CVPixelBufferIsPlanar(pixelBuffer)
let planeCount = isPlanar ? CVPixelBufferGetPlaneCount(pixelBuffer) : 1

for i in 0..<planeCount {
let planeAddress: UnsafeMutableRawPointer?
let bytesPerRow: Int
let height: Int
let width: Int

if isPlanar {
planeAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, i)
bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, i)
height = CVPixelBufferGetHeightOfPlane(pixelBuffer, i)
width = CVPixelBufferGetWidthOfPlane(pixelBuffer, i)
} else {
planeAddress = CVPixelBufferGetBaseAddress(pixelBuffer)
bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
height = CVPixelBufferGetHeight(pixelBuffer)
width = CVPixelBufferGetWidth(pixelBuffer)
}

let length = bytesPerRow * height
let bytes = Data(bytes: planeAddress!, count: length)

let planeBuffer: [String: Any] = [
"bytesPerRow": bytesPerRow,
"width": width,
"height": height,
"bytes": FlutterStandardTypedData(bytes: bytes),
]
planes.append(planeBuffer)
}

// Lock the base address before accessing pixel data, and unlock it afterwards.
// Done accessing the `pixelBuffer` at this point.
CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)

let imageBuffer: [String: Any] = [
"width": imageWidth,
"height": imageHeight,
"format": videoFormat,
"planes": planes,
"lensAperture": Double(captureDevice.lensAperture()),
"sensorExposureTime": Int(captureDevice.exposureDuration().seconds * 1_000_000_000),
"sensorSensitivity": Double(captureDevice.iso()),
]

DispatchQueue.main.async {
eventSink(imageBuffer)
}
}

private func copySampleBufferWithAdjustedTime(_ sample: CMSampleBuffer, by offset: CMTime)
-> CMSampleBuffer?
{
Expand Down