diff --git a/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/ExpoBlueskyVideoCompressModule.kt b/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/ExpoBlueskyVideoCompressModule.kt index 345deedd66..30b1def7c6 100644 --- a/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/ExpoBlueskyVideoCompressModule.kt +++ b/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/ExpoBlueskyVideoCompressModule.kt @@ -2,9 +2,10 @@ package expo.modules.blueskyvideocompress import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition +import java.util.concurrent.ConcurrentHashMap class ExpoBlueskyVideoCompressModule : Module() { - private var currentCompressor: VideoCompressor? = null + private val activeCompressors = ConcurrentHashMap() override fun definition() = ModuleDefinition { Name("ExpoBlueskyVideoCompress") @@ -23,7 +24,7 @@ class ExpoBlueskyVideoCompressModule : Module() { val targetBitrate = (options["targetBitrate"] as? Number)?.toInt() ?: 0 val maxSize = (options["maxSize"] as? Number)?.toInt() ?: 1920 val codecPref = (options["codec"] as? String) ?: "auto" - val frameRateCap = (options["frameRateCap"] as? Number)?.toInt() ?: 30 + val frameRateCap = ((options["frameRateCap"] as? Number)?.toInt() ?: 30).coerceAtLeast(1) val jobId = (options["jobId"] as? Number)?.toInt() ?: 0 val compressor = VideoCompressor( @@ -42,21 +43,20 @@ class ExpoBlueskyVideoCompressModule : Module() { } ) - currentCompressor = compressor + activeCompressors[jobId] = compressor try { val result = compressor.compress() - currentCompressor = null + activeCompressors.remove(jobId) return@AsyncFunction result } catch (e: Exception) { - currentCompressor = null + activeCompressors.remove(jobId) throw e } } - Function("cancel") { - currentCompressor?.cancel() - currentCompressor = null + Function("cancel") { jobId: Int -> + activeCompressors.remove(jobId)?.cancel() } } } diff --git a/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/VideoCompressor.kt b/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/VideoCompressor.kt index dc5ee5a41c..a4727c3600 100644 --- a/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/VideoCompressor.kt +++ b/modules/expo-bluesky-video-compress/android/src/main/java/expo/modules/blueskyvideocompress/VideoCompressor.kt @@ -148,6 +148,11 @@ class VideoCompressor( ) setInteger(MediaFormat.KEY_FRAME_RATE, frameRateCap) setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT709) + setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_SDR_VIDEO) + setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED) + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { setInteger(MediaFormat.KEY_PRIORITY, 0) setInteger(MediaFormat.KEY_OPERATING_RATE, frameRateCap) diff --git a/modules/expo-bluesky-video-compress/index.ts b/modules/expo-bluesky-video-compress/index.ts index 2dae0b4cfc..423d7f3ac2 100644 --- a/modules/expo-bluesky-video-compress/index.ts +++ b/modules/expo-bluesky-video-compress/index.ts @@ -63,7 +63,7 @@ export function compress( } const abortHandler = () => { - NativeModule.cancel() + NativeModule.cancel(jobId) subscription?.remove() reject(new AbortError()) } diff --git a/modules/expo-bluesky-video-compress/ios/ExpoBlueskyVideoCompressModule.swift b/modules/expo-bluesky-video-compress/ios/ExpoBlueskyVideoCompressModule.swift index d23dabb001..3bcea3c9f4 100644 --- a/modules/expo-bluesky-video-compress/ios/ExpoBlueskyVideoCompressModule.swift +++ b/modules/expo-bluesky-video-compress/ios/ExpoBlueskyVideoCompressModule.swift @@ -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() + } } diff --git a/modules/expo-bluesky-video-compress/src/ExpoBlueskyVideoCompressModule.ts b/modules/expo-bluesky-video-compress/src/ExpoBlueskyVideoCompressModule.ts index cd3648735a..dcf63c729f 100644 --- a/modules/expo-bluesky-video-compress/src/ExpoBlueskyVideoCompressModule.ts +++ b/modules/expo-bluesky-video-compress/src/ExpoBlueskyVideoCompressModule.ts @@ -11,7 +11,7 @@ type ProgressEvent = {id: number; progress: number} interface ExpoBlueskyVideoCompressModule { probe(uri: string): Promise compress(uri: string, options: NativeCompressOptions): Promise - cancel(): void + cancel(jobId: number): void addListener( eventName: 'onProgress', listener: (event: ProgressEvent) => void,