Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
24 changes: 19 additions & 5 deletions mediaplayer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ kotlin {

jvmMain.dependencies {
implementation(libs.kotlinx.coroutines.swing)
implementation(libs.gst1.java.core)
implementation(libs.jna.jpms)
implementation(libs.jna.platform.jpms)
implementation(libs.slf4j.simple)
}

Expand Down Expand Up @@ -197,13 +194,30 @@ val buildNativeWindows by tasks.registering(Exec::class) {
commandLine("cmd", "/c", nativeDir.file("build.bat").asFile.absolutePath)
}

val buildNativeLinux by tasks.registering(Exec::class) {
description = "Compiles the C native library into Linux .so (GStreamer + JNI)"
group = "build"
val hasPrebuilt = nativeResourceDir
.dir("linux-x86-64")
.file("libNativeVideoPlayer.so")
.asFile
.exists()
enabled = Os.isFamily(Os.FAMILY_UNIX) && !Os.isFamily(Os.FAMILY_MAC) && !hasPrebuilt

val nativeDir = layout.projectDirectory.dir("src/jvmMain/native/linux")
inputs.dir(nativeDir)
outputs.dir(nativeResourceDir)
workingDir(nativeDir)
commandLine("bash", "build.sh")
}

tasks.named("jvmProcessResources") {
dependsOn(buildNativeMacOs, buildNativeWindows)
dependsOn(buildNativeMacOs, buildNativeWindows, buildNativeLinux)
}

tasks.configureEach {
if (name == "sourcesJar") {
dependsOn(buildNativeMacOs, buildNativeWindows)
dependsOn(buildNativeMacOs, buildNativeWindows, buildNativeLinux)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package io.github.kdroidfilter.composemediaplayer
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import com.sun.jna.Platform
import io.github.kdroidfilter.composemediaplayer.linux.LinuxVideoPlayerState
import io.github.kdroidfilter.composemediaplayer.mac.MacVideoPlayerState
import io.github.kdroidfilter.composemediaplayer.util.CurrentPlatform
import io.github.kdroidfilter.composemediaplayer.windows.WindowsVideoPlayerState
import io.github.vinceglb.filekit.PlatformFile

Expand Down Expand Up @@ -37,11 +37,10 @@ actual fun createVideoPlayerState(): VideoPlayerState = DefaultVideoPlayerState(
*/
@Stable
open class DefaultVideoPlayerState: VideoPlayerState {
val delegate: VideoPlayerState = when {
Platform.isWindows() -> WindowsVideoPlayerState()
Platform.isMac() -> MacVideoPlayerState()
Platform.isLinux() -> LinuxVideoPlayerState()
else -> throw UnsupportedOperationException("Unsupported platform")
val delegate: VideoPlayerState = when (CurrentPlatform.os) {
CurrentPlatform.OS.WINDOWS -> WindowsVideoPlayerState()
CurrentPlatform.OS.MAC -> MacVideoPlayerState()
CurrentPlatform.OS.LINUX -> LinuxVideoPlayerState()
}

override val hasMedia: Boolean get() = delegate.hasMedia
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,7 @@ package io.github.kdroidfilter.composemediaplayer.linux

import java.nio.ByteBuffer

/**
* Calculates a fast hash of the frame buffer to detect frame changes.
* Samples approximately 200 pixels evenly distributed across the frame.
*
* @param buffer The source buffer containing RGBA pixel data
* @param pixelCount Total number of pixels in the frame
* @return A hash value representing the frame content
*/
internal fun calculateFrameHash(buffer: ByteBuffer, pixelCount: Int): Int {
if (pixelCount <= 0) return 0

var hash = 1
val step = if (pixelCount <= 200) 1 else pixelCount / 200
for (i in 0 until pixelCount step step) {
hash = 31 * hash + buffer.getInt(i * 4)
}
return hash
}

/**
* Copies RGBA frame data from source to destination buffer with minimal overhead.
* Handles row padding when destination stride differs from source.
*
* This function performs a single memory copy operation when strides match,
* achieving zero-copy performance (beyond the necessary single copy from
* GStreamer buffer to Skia bitmap).
*
* @param src Source buffer containing RGBA pixel data from GStreamer
* @param dst Destination buffer (Skia bitmap pixels via peekPixels)
* @param width Frame width in pixels
* @param height Frame height in pixels
* @param dstRowBytes Destination row stride (may include padding)
*/
internal fun copyRgbaFrame(
internal fun copyBgraFrame(
src: ByteBuffer,
dst: ByteBuffer,
width: Int,
Expand Down Expand Up @@ -63,15 +30,13 @@ internal fun copyRgbaFrame(
srcBuf.rewind()
dstBuf.rewind()

// Fast path: when strides match, do a single bulk copy
if (dstRowBytes == srcRowBytes) {
srcBuf.limit(requiredSrcBytes.toInt())
dstBuf.limit(requiredSrcBytes.toInt())
dstBuf.put(srcBuf)
return
}

// Slow path: copy row by row when there's padding
val srcCapacity = srcBuf.capacity()
val dstCapacity = dstBuf.capacity()
for (row in 0 until height) {
Expand Down
Loading
Loading