react-native-vision-camera/package/ios/Core/ChunkedRecorder.swift

89 lines
2.2 KiB
Swift
Raw Normal View History

//
// ChunkedRecorder.swift
// VisionCamera
//
// Created by Rafael Bastos on 12/07/2024.
// Copyright © 2024 mrousavy. All rights reserved.
//
import Foundation
import AVFoundation
class ChunkedRecorder: NSObject {
2024-07-28 16:37:20 -06:00
enum ChunkType {
case initialization
2024-07-16 03:46:24 -06:00
case data(index: UInt64, duration: CMTime?)
}
struct Chunk {
let url: URL
let type: ChunkType
}
2024-07-28 16:37:20 -06:00
let outputURL: URL
let onChunkReady: ((Chunk) -> Void)
2024-07-28 16:37:20 -06:00
private var chunkIndex: UInt64 = 0
2024-07-28 16:37:20 -06:00
init(outputURL: URL, onChunkReady: @escaping ((Chunk) -> Void)) throws {
self.outputURL = outputURL
self.onChunkReady = onChunkReady
guard FileManager.default.fileExists(atPath: outputURL.path) else {
throw CameraError.unknown(message: "output directory does not exist at: \(outputURL.path)", cause: nil)
}
}
2024-07-28 16:37:20 -06:00
}
extension ChunkedRecorder: AVAssetWriterDelegate {
2024-07-28 16:37:20 -06:00
func assetWriter(_ writer: AVAssetWriter,
didOutputSegmentData segmentData: Data,
segmentType: AVAssetSegmentType,
segmentReport: AVAssetSegmentReport?) {
2024-07-28 16:37:20 -06:00
switch segmentType {
case .initialization:
saveInitSegment(segmentData)
case .separable:
2024-07-16 03:46:24 -06:00
saveSegment(segmentData, report: segmentReport)
@unknown default:
fatalError("Unknown AVAssetSegmentType!")
}
}
2024-07-28 16:37:20 -06:00
private func saveInitSegment(_ data: Data) {
let url = outputURL.appendingPathComponent("init.mp4")
save(data: data, url: url)
onChunkReady(url: url, type: .initialization)
}
2024-07-28 16:37:20 -06:00
2024-07-16 03:46:24 -06:00
private func saveSegment(_ data: Data, report: AVAssetSegmentReport?) {
let name = "\(chunkIndex).mp4"
let url = outputURL.appendingPathComponent(name)
save(data: data, url: url)
2024-07-16 03:46:24 -06:00
let duration = report?
.trackReports
.filter { $0.mediaType == .video }
.first?
.duration
onChunkReady(url: url, type: .data(index: chunkIndex, duration: duration))
chunkIndex += 1
}
2024-07-28 16:37:20 -06:00
private func save(data: Data, url: URL) {
do {
try data.write(to: url)
} catch {
ReactLogger.log(level: .error, message: "Unable to write \(url): \(error.localizedDescription)")
}
}
2024-07-28 16:37:20 -06:00
private func onChunkReady(url: URL, type: ChunkType) {
onChunkReady(Chunk(url: url, type: type))
}
2024-07-28 16:37:20 -06:00
}