|
1 | 1 | package io.github.kdroidfilter.composemediaplayer.mac |
2 | 2 |
|
3 | | -import com.sun.jna.Native |
4 | | -import com.sun.jna.Pointer |
| 3 | +import java.io.File |
| 4 | +import java.nio.ByteBuffer |
| 5 | +import java.nio.file.Files |
5 | 6 |
|
6 | 7 | /** |
7 | | - * JNA direct mapping to the native library. |
8 | | - * Includes methods to retrieve frame rate and metadata information. |
| 8 | + * JNI direct mapping to the native macOS video player library. |
| 9 | + * Handles are opaque Long values (native pointer cast to jlong, 0 = null). |
9 | 10 | */ |
10 | 11 | internal object SharedVideoPlayer { |
11 | 12 | init { |
12 | | - // Register the native library for direct mapping |
13 | | - Native.register("NativeVideoPlayer") |
| 13 | + loadNativeLibrary() |
14 | 14 | } |
15 | 15 |
|
16 | | - @JvmStatic external fun createVideoPlayer(): Pointer? |
17 | | - @JvmStatic external fun openUri(context: Pointer?, uri: String?) |
18 | | - @JvmStatic external fun playVideo(context: Pointer?) |
19 | | - @JvmStatic external fun pauseVideo(context: Pointer?) |
20 | | - @JvmStatic external fun setVolume(context: Pointer?, volume: Float) |
21 | | - @JvmStatic external fun getVolume(context: Pointer?): Float |
22 | | - @JvmStatic external fun getLatestFrame(context: Pointer?): Pointer? |
23 | | - @JvmStatic external fun getFrameWidth(context: Pointer?): Int |
24 | | - @JvmStatic external fun getFrameHeight(context: Pointer?): Int |
25 | | - @JvmStatic external fun getVideoFrameRate(context: Pointer?): Float |
26 | | - @JvmStatic external fun getScreenRefreshRate(context: Pointer?): Float |
27 | | - @JvmStatic external fun getCaptureFrameRate(context: Pointer?): Float |
28 | | - @JvmStatic external fun getVideoDuration(context: Pointer?): Double |
29 | | - @JvmStatic external fun getCurrentTime(context: Pointer?): Double |
30 | | - @JvmStatic external fun seekTo(context: Pointer?, time: Double) |
31 | | - @JvmStatic external fun disposeVideoPlayer(context: Pointer?) |
32 | | - @JvmStatic external fun getLeftAudioLevel(context: Pointer?): Float |
33 | | - @JvmStatic external fun getRightAudioLevel(context: Pointer?): Float |
34 | | - @JvmStatic external fun setPlaybackSpeed(context: Pointer?, speed: Float) |
35 | | - @JvmStatic external fun getPlaybackSpeed(context: Pointer?): Float |
36 | | - |
37 | | - // Metadata retrieval functions |
38 | | - @JvmStatic external fun getVideoTitle(context: Pointer?): String? |
39 | | - @JvmStatic external fun getVideoBitrate(context: Pointer?): Long |
40 | | - @JvmStatic external fun getVideoMimeType(context: Pointer?): String? |
41 | | - @JvmStatic external fun getAudioChannels(context: Pointer?): Int |
42 | | - @JvmStatic external fun getAudioSampleRate(context: Pointer?): Int |
| 16 | + private fun loadNativeLibrary() { |
| 17 | + val osArch = System.getProperty("os.arch", "").lowercase() |
| 18 | + val resourceDir = |
| 19 | + if (osArch == "aarch64" || osArch == "arm64") "darwin-aarch64" else "darwin-x86-64" |
| 20 | + val libName = "libNativeVideoPlayer.dylib" |
| 21 | + |
| 22 | + val stream = SharedVideoPlayer::class.java.getResourceAsStream("/$resourceDir/$libName") |
| 23 | + ?: throw UnsatisfiedLinkError( |
| 24 | + "Native library not found in resources: /$resourceDir/$libName" |
| 25 | + ) |
| 26 | + |
| 27 | + val tempDir = Files.createTempDirectory("nativevideoplayer").toFile() |
| 28 | + val tempFile = File(tempDir, libName) |
| 29 | + stream.use { input -> tempFile.outputStream().use { input.copyTo(it) } } |
| 30 | + System.load(tempFile.absolutePath) |
| 31 | + tempFile.deleteOnExit() |
| 32 | + tempDir.deleteOnExit() |
| 33 | + } |
| 34 | + |
| 35 | + // Playback control |
| 36 | + @JvmStatic external fun nCreatePlayer(): Long |
| 37 | + @JvmStatic external fun nOpenUri(handle: Long, uri: String) |
| 38 | + @JvmStatic external fun nPlay(handle: Long) |
| 39 | + @JvmStatic external fun nPause(handle: Long) |
| 40 | + @JvmStatic external fun nSetVolume(handle: Long, volume: Float) |
| 41 | + @JvmStatic external fun nGetVolume(handle: Long): Float |
| 42 | + @JvmStatic external fun nSeekTo(handle: Long, time: Double) |
| 43 | + @JvmStatic external fun nDisposePlayer(handle: Long) |
| 44 | + @JvmStatic external fun nSetPlaybackSpeed(handle: Long, speed: Float) |
| 45 | + @JvmStatic external fun nGetPlaybackSpeed(handle: Long): Float |
| 46 | + |
| 47 | + // Frame access — lock/unlock CVPixelBuffer directly (zero intermediate copy) |
| 48 | + // outInfo must be IntArray(3); filled with [width, height, bytesPerRow] on success. |
| 49 | + // Returns the native base address of the locked buffer, or 0 on failure. |
| 50 | + // MUST call nUnlockFrame after reading. |
| 51 | + @JvmStatic external fun nLockFrame(handle: Long, outInfo: IntArray): Long |
| 52 | + @JvmStatic external fun nUnlockFrame(handle: Long) |
| 53 | + @JvmStatic external fun nWrapPointer(address: Long, size: Long): ByteBuffer? |
| 54 | + @JvmStatic external fun nGetFrameWidth(handle: Long): Int |
| 55 | + @JvmStatic external fun nGetFrameHeight(handle: Long): Int |
| 56 | + @JvmStatic external fun nSetOutputSize(handle: Long, width: Int, height: Int): Int |
| 57 | + |
| 58 | + // Timing / rate info |
| 59 | + @JvmStatic external fun nGetVideoFrameRate(handle: Long): Float |
| 60 | + @JvmStatic external fun nGetScreenRefreshRate(handle: Long): Float |
| 61 | + @JvmStatic external fun nGetCaptureFrameRate(handle: Long): Float |
| 62 | + @JvmStatic external fun nGetVideoDuration(handle: Long): Double |
| 63 | + @JvmStatic external fun nGetCurrentTime(handle: Long): Double |
| 64 | + |
| 65 | + // Audio levels |
| 66 | + @JvmStatic external fun nGetLeftAudioLevel(handle: Long): Float |
| 67 | + @JvmStatic external fun nGetRightAudioLevel(handle: Long): Float |
| 68 | + |
| 69 | + // Metadata |
| 70 | + @JvmStatic external fun nGetVideoTitle(handle: Long): String? |
| 71 | + @JvmStatic external fun nGetVideoBitrate(handle: Long): Long |
| 72 | + @JvmStatic external fun nGetVideoMimeType(handle: Long): String? |
| 73 | + @JvmStatic external fun nGetAudioChannels(handle: Long): Int |
| 74 | + @JvmStatic external fun nGetAudioSampleRate(handle: Long): Int |
| 75 | + |
| 76 | + // Playback completion |
| 77 | + @JvmStatic external fun nConsumeDidPlayToEnd(handle: Long): Boolean |
43 | 78 | } |
0 commit comments