Skip to content

Commit

Permalink
- javafx video player finally working
Browse files Browse the repository at this point in the history
  • Loading branch information
FaroukAbichou committed Jan 3, 2024
1 parent ef6cacd commit d2dcbb0
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 279 deletions.
12 changes: 3 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ version = "1.0-SNAPSHOT"

javafx {
version = "17"
modules("javafx.controls", "javafx.fxml")
modules("javafx.controls", "javafx.fxml" , "javafx.media" , "javafx.swing" , "javafx.web")
}

repositories {
Expand Down Expand Up @@ -42,14 +42,6 @@ dependencies {
implementation(libs.kotlinx.coroutinesSwing)

implementation(libs.kotlinx.dateTime)
// implementation("org.openjfx:javafx-plugin:0.0.10")
implementation("org.openjfx:javafx-graphics:19.0.2.1")
implementation("org.openjfx:javafx-base:19.0.2.1")
implementation("org.openjfx:javafx-controls:19.0.2.1")
implementation("org.openjfx:javafx-fxml:19.0.2.1")
implementation("org.openjfx:javafx-media:19.0.2.1")
implementation("org.openjfx:javafx-swing:19.0.2.1")
implementation("org.openjfx:javafx-web:19.0.2.1")
}

val os: OperatingSystem = OperatingSystem.current()
Expand Down Expand Up @@ -83,6 +75,8 @@ compose.desktop {
jvmArgs(
"-Xdock:name=Kapture",
"-Dapple.awt.application.appearance=system",
// "--module-path", "<path_to_javafx_libs>", // Replace with the actual path
// "--add-modules", "javafx.controls,javafx.fxml,javafx.media,javafx.swing,javafx.web"
)
}
linux {
Expand Down
75 changes: 13 additions & 62 deletions src/main/kotlin/core/components/ComposeJFXPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,97 +7,48 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.round
import core.util.FilePaths
import javafx.application.Platform
import javafx.embed.swing.JFXPanel
import javafx.scene.Scene
import javafx.scene.control.Menu
import javafx.scene.control.MenuBar
import javafx.scene.control.MenuItem
import javafx.scene.media.Media
import javafx.stage.FileChooser
import record.video.presentation.component.player.Player
import java.awt.BorderLayout
import java.io.File
import javax.swing.JPanel

@Composable
fun ComposeJFXPanel(
composeWindow: ComposeWindow,
jfxPanel: JFXPanel,
size: Size,
onCreate: () -> Unit,
onDestroy: () -> Unit = {}
) {
val jPanel = remember { JPanel() }
val density = LocalDensity.current.density

val mediaPath = File(
FilePaths.VideosPath + "/ScreenRec.mp4"
).toURI().toString()
val media = Media(mediaPath)
Box(
modifier = Modifier
.onGloballyPositioned { childCoordinates ->
val coordinates = childCoordinates.parentCoordinates!!
val location = coordinates.localToWindow(Offset.Zero).round()
jPanel.setBounds(
(location.x / density).toInt(),
(location.y / density).toInt(),
(size.width / density).toInt(),
(size.height / density).toInt()
)
jPanel.validate()
jPanel.repaint()
},
content = {}
modifier = Modifier.onGloballyPositioned { childCoordinates ->
val coordinates = childCoordinates.parentCoordinates!!
val location = coordinates.localToWindow(Offset.Zero).round()
jPanel.setBounds(
(location.x / density).toInt(),
(location.y / density).toInt(),
(coordinates.size.width / density).toInt(),
(coordinates.size.height / density).toInt()
)
}
)

DisposableEffect(jPanel) {
composeWindow.add(jPanel)
jPanel.layout = BorderLayout(0, 0)
jPanel.layout = BorderLayout()
jPanel.add(jfxPanel)

// Setup JavaFX Scene
Platform.runLater {
val menuBar = MenuBar()
val menu = Menu("File")
val openItem = MenuItem("Open").apply {
setOnAction {
val fileChooser = FileChooser()
val file = fileChooser.showOpenDialog(null)
if (file != null) {
// Here, you create and play a new video based on the selected file
val newPlayer = Player(file.toURI().toURL().toExternalForm())
// Set any additional properties of the player here
// For example, newPlayer.setTop(menuBar)
}
}
}
menu.items.add(openItem)
menuBar.menus.add(menu)

// Now create the player
val player = Player(
mediaPath
).apply {
top = menuBar
}

// Create the scene and set it to the JFXPanel
val scene = Scene(player, size.width.toDouble(), size.height.toDouble())
jfxPanel.scene = scene
player.player.play()
onCreate()
}

onCreate()
onDispose {
onDestroy()
composeWindow.remove(jPanel)
}
}
}
}
4 changes: 1 addition & 3 deletions src/main/kotlin/core/components/KpSideNavigationBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ fun KpIconButton(
enabled: Boolean = true,
) {
Button(
onClick = {
onClick()
},
onClick = onClick,
enabled = enabled,
colors = ButtonDefaults.buttonColors(
contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/core/components/helper/rememberMediaPlayer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package core.components.helper

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import record.video.presentation.component.player.Player

@Composable
fun rememberMediaPlayer(file: String): Player {
val mediaPlayer = remember { Player(file) }

DisposableEffect(mediaPlayer) {
onDispose {
mediaPlayer.stop() // Stop the player to release resources
mediaPlayer.player.dispose() // Dispose the underlying MediaPlayer object
}
}

return mediaPlayer
}
98 changes: 27 additions & 71 deletions src/main/kotlin/record/video/presentation/component/VideoPlayer.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
package record.video.presentation.component

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Slider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.sun.javafx.application.PlatformImpl
import core.ImageResource
import core.components.ComposeJFXPanel
import core.components.KpIconButton
import core.components.helper.rememberMediaPlayer
import core.util.FilePaths
import javafx.embed.swing.JFXPanel
import javafx.scene.text.Text
import record.video.presentation.component.player.VideoPlayer
import record.video.presentation.component.player.rememberVideoPlayerState
import javafx.scene.Scene
import java.io.File

@Composable
fun VideoPlayer(composeWindow: ComposeWindow) {
Expand All @@ -32,80 +29,39 @@ fun VideoPlayer(composeWindow: ComposeWindow) {
DisposableEffect(Unit) {
PlatformImpl.addListener(finishListener)

onDispose {
PlatformImpl.removeListener(finishListener)
}
onDispose { PlatformImpl.removeListener(finishListener) }
}

val jfxPanel = remember { JFXPanel() }
val videoPath = remember { FilePaths.VideosPath + "/ScreenRec.mp4" }

val videoPlayerState = rememberVideoPlayerState()
val isPlaying = videoPlayerState.isPlaying
val timeMillis = videoPlayerState.timeMillis
val lengthMillis = videoPlayerState.lengthMillis
val mediaPath = File(FilePaths.VideosPath + "/Screen.mp4").toURI().toString()
val player = rememberMediaPlayer(mediaPath)

Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
) {
Box(
modifier = Modifier
.size(400.dp, 400.dp)
.background(Color.Green),
contentAlignment = Alignment.Center
.size(500.dp, 500.dp),
contentAlignment = Alignment.Center,
){
ComposeJFXPanel(
jfxPanel = remember { JFXPanel() },
composeWindow = composeWindow,
size = Size(200f, 200f),
onCreate = {
val videoPlayer = VideoPlayer(
jfxPanel = jfxPanel,
videoPath = videoPath
)
videoPlayer.play()
},
jfxPanel = jfxPanel,
onCreate = { jfxPanel.scene = Scene(player) },
onDestroy = {}
)
}

Column(
modifier = Modifier
.size(800.dp, 800.dp)
.background(Color.Red)
.padding(32.dp),
) {
Row(
modifier = Modifier.align(Alignment.CenterHorizontally),
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
Button(
onClick = {

}
) {
Text("Backward")
}
Button(
onClick = {
// show = !show
}) {

Text(if(isPlaying) "Pause" else "Play")
}
Button(
onClick = {

}) {

Text("Forward")
}
}

if(lengthMillis != -1L) {
Slider(
value = timeMillis.toFloat(),
onValueChange = {

},
modifier= Modifier.fillMaxWidth()
)
}
}
KpIconButton(
onClick = {
player.play()
},
imageResource = ImageResource.image,
enabled = true,
)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,34 @@ package record.video.presentation.component.player

import javafx.scene.layout.BorderPane
import javafx.scene.layout.Pane
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.media.Media
import javafx.scene.media.MediaPlayer
import javafx.scene.media.MediaView

class Player(file: String?) : BorderPane() {
var media: Media
var player: MediaPlayer
var view: MediaView
var mpane: Pane
var bar: MediaBar

var media = Media(file)
var player = MediaPlayer(media)
var view = MediaView(player)
var mpane = Pane()
init {
media = Media(file)
player = MediaPlayer(media)
view = MediaView(player)
mpane = Pane()
mpane.children.add(view) // Calling the function getChildren

// inorder to add the view
player.isAutoPlay = false
mpane.children.add(view)
center = mpane
bar = MediaBar(player) // Passing the player to MediaBar
bottom = bar // Setting the MediaBar at bottom
style = "-fx-background-color:#bfc2c7" // Adding color to the mediabar
player.play() // Making the video play
}

fun play() {
player.play()
}

fun pause() {
player.pause()
}

fun stop() {
player.stop()
}

fun setRate(rate: Double) {
player.rate = rate
}
}
Loading

0 comments on commit d2dcbb0

Please sign in to comment.