Browse Source
With this approach the Video can be properly displayed within your Compose UI and removes the need for a SwingPanel.pull/3336/head
Drew Carlson
1 year ago
3 changed files with 179 additions and 103 deletions
@ -0,0 +1,78 @@
|
||||
package org.jetbrains.compose.videoplayer |
||||
|
||||
import androidx.compose.runtime.State |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.ui.graphics.ImageBitmap |
||||
import androidx.compose.ui.graphics.asComposeImageBitmap |
||||
import org.jetbrains.skia.Bitmap |
||||
import org.jetbrains.skia.ColorAlphaType |
||||
import org.jetbrains.skia.ColorType |
||||
import org.jetbrains.skia.ImageInfo |
||||
import uk.co.caprica.vlcj.player.base.MediaPlayer |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.CallbackVideoSurface |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.VideoSurface |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.VideoSurfaceAdapters |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormat |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormatCallback |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.RenderCallback |
||||
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.format.RV32BufferFormat |
||||
import java.nio.ByteBuffer |
||||
import javax.swing.SwingUtilities |
||||
|
||||
internal class SkiaBitmapVideoSurface : VideoSurface(VideoSurfaceAdapters.getVideoSurfaceAdapter()) { |
||||
|
||||
private val videoSurface = SkiaBitmapVideoSurface() |
||||
private lateinit var imageInfo: ImageInfo |
||||
private lateinit var frameBytes: ByteArray |
||||
private val skiaBitmap: Bitmap = Bitmap() |
||||
private val composeBitmap = mutableStateOf<ImageBitmap?>(null) |
||||
|
||||
val bitmap: State<ImageBitmap?> = composeBitmap |
||||
|
||||
override fun attach(mediaPlayer: MediaPlayer) { |
||||
videoSurface.attach(mediaPlayer) |
||||
} |
||||
|
||||
private inner class SkiaBitmapBufferFormatCallback : BufferFormatCallback { |
||||
private var sourceWidth: Int = 0 |
||||
private var sourceHeight: Int = 0 |
||||
|
||||
override fun getBufferFormat(sourceWidth: Int, sourceHeight: Int): BufferFormat { |
||||
this.sourceWidth = sourceWidth |
||||
this.sourceHeight = sourceHeight |
||||
return RV32BufferFormat(sourceWidth, sourceHeight) |
||||
} |
||||
|
||||
override fun allocatedBuffers(buffers: Array<ByteBuffer>) { |
||||
frameBytes = buffers[0].run { ByteArray(remaining()).also(::get) } |
||||
imageInfo = ImageInfo( |
||||
sourceWidth, |
||||
sourceHeight, |
||||
ColorType.BGRA_8888, |
||||
ColorAlphaType.PREMUL, |
||||
) |
||||
} |
||||
} |
||||
|
||||
private inner class SkiaBitmapRenderCallback : RenderCallback { |
||||
override fun display( |
||||
mediaPlayer: MediaPlayer, |
||||
nativeBuffers: Array<ByteBuffer>, |
||||
bufferFormat: BufferFormat, |
||||
) { |
||||
SwingUtilities.invokeLater { |
||||
nativeBuffers[0].rewind() |
||||
nativeBuffers[0].get(frameBytes) |
||||
skiaBitmap.installPixels(imageInfo, frameBytes, bufferFormat.width * 4) |
||||
composeBitmap.value = skiaBitmap.asComposeImageBitmap() |
||||
} |
||||
} |
||||
} |
||||
|
||||
private inner class SkiaBitmapVideoSurface : CallbackVideoSurface( |
||||
SkiaBitmapBufferFormatCallback(), |
||||
SkiaBitmapRenderCallback(), |
||||
true, |
||||
videoSurfaceAdapter, |
||||
) |
||||
} |
Loading…
Reference in new issue