Address grill feedback: BT.709 tagging, per-job cancel, frameRateCap clamp
B1: Android encoder format now sets KEY_COLOR_STANDARD = BT709, KEY_COLOR_TRANSFER = SDR_VIDEO, KEY_COLOR_RANGE = LIMITED (API 24+). Previously the encoder inherited or emitted default color metadata, which meant HDR sources produced incorrectly-tagged output on Android. iOS already had AVVideoColorPropertiesKey set correctly. B2: Replace single currentCompressor reference with a per-job map keyed by jobId. The cancel function now takes a jobId and only cancels that specific job. Prevents the previous race where a second compress call overwrote the reference and made the first job uncancellable. B3: Clamp frameRateCap to >= 1 at the native module boundary. Previously a value of 0 from JS would cause divide-by-zero (Android Long division ArithmeticException, iOS CMTime Infinity / Int32(0) frameDuration trap).
This commit is contained in:
@@ -2,7 +2,8 @@ import AVFoundation
|
||||
import ExpoModulesCore
|
||||
|
||||
public class ExpoBlueskyVideoCompressModule: Module {
|
||||
private var currentCompressor: VideoCompressor?
|
||||
private var activeCompressors: [Int: VideoCompressor] = [:]
|
||||
private let activeCompressorsLock = NSLock()
|
||||
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("ExpoBlueskyVideoCompress")
|
||||
@@ -19,7 +20,7 @@ public class ExpoBlueskyVideoCompressModule: Module {
|
||||
let targetBitrate = options["targetBitrate"] as? Int ?? 0
|
||||
let maxSize = options["maxSize"] as? Int ?? 1920
|
||||
let codecPref = options["codec"] as? String ?? "auto"
|
||||
let frameRateCap = options["frameRateCap"] as? Int ?? 30
|
||||
let frameRateCap = max(1, options["frameRateCap"] as? Int ?? 30)
|
||||
let jobId = options["jobId"] as? Int ?? 0
|
||||
|
||||
let compressor = VideoCompressor(
|
||||
@@ -37,21 +38,37 @@ public class ExpoBlueskyVideoCompressModule: Module {
|
||||
}
|
||||
)
|
||||
|
||||
self.currentCompressor = compressor
|
||||
self.setCompressor(jobId, compressor)
|
||||
|
||||
do {
|
||||
let result = try await compressor.compress()
|
||||
self.currentCompressor = nil
|
||||
self.setCompressor(jobId, nil)
|
||||
return result
|
||||
} catch {
|
||||
self.currentCompressor = nil
|
||||
self.setCompressor(jobId, nil)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
Function("cancel") {
|
||||
self.currentCompressor?.cancel()
|
||||
self.currentCompressor = nil
|
||||
Function("cancel") { (jobId: Int) in
|
||||
self.cancelCompressor(jobId)
|
||||
}
|
||||
}
|
||||
|
||||
private func setCompressor(_ jobId: Int, _ compressor: VideoCompressor?) {
|
||||
activeCompressorsLock.lock()
|
||||
defer { activeCompressorsLock.unlock() }
|
||||
if let compressor = compressor {
|
||||
activeCompressors[jobId] = compressor
|
||||
} else {
|
||||
activeCompressors.removeValue(forKey: jobId)
|
||||
}
|
||||
}
|
||||
|
||||
private func cancelCompressor(_ jobId: Int) {
|
||||
activeCompressorsLock.lock()
|
||||
let compressor = activeCompressors.removeValue(forKey: jobId)
|
||||
activeCompressorsLock.unlock()
|
||||
compressor?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user