I'm having trouble making a simple stream from my camera on my Raspberry Pi Zero 2W to my Android app.
With PiCamera2, I managed to create an HLS or DASH stream and connect to it from VLC but unfortunately I can't connect to it from my custom app on Android with ExoPlayer.
The app crashes as soon as I open it.
I tried the following Kotlin + Jetpack Compose code:
const val EXAMPLE_VIDEO_URI = "http://192.168.1.18:8000/stream.m3u8"
// Get the current context
val context = LocalContext.current
// Initialize ExoPlayer
val exoPlayer = ExoPlayer.Builder(context).build()
// Create a MediaSource
exoPlayer.setMediaItem(MediaItem.fromUri(EXAMPLE_VIDEO_URI))
exoPlayer.prepare()
// Manage lifecycle events
DisposableEffect(Unit) {
onDispose {
exoPlayer.release()
}
}
// Use AndroidView to embed an Android View (PlayerView) into Compose
AndroidView(
factory = { ctx ->
PlayerView(ctx).apply {
player = exoPlayer
}
},
modifier = Modifier
.fillMaxWidth()
.height(200.dp) // Set your desired height
)
My python code just in case
from picamera2.outputs import FfmpegOutput
from picamera2.encoders import H264Encoder
from picamera2 import Picamera2
import time
import libcamera
picam2 = Picamera2()
config = picam2.create_video_configuration()
config["transform"] = libcamera.Transform(hflip=1, vflip=1)
picam2.configure(config)
encoder = H264Encoder(bitrate=1000000, repeat=True, iperiod=15)
output = FfmpegOutput("-f hls -hls_time 4 -hls_list_size 5 -hls_flags delete_segments -hls_allow_cache 0 stream.m3u8")
picam2.start_recording(encoder, output)
while True:
pass
And when I connect, I have those errors
23:43:40.444 E FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 10069
java.lang.IllegalStateException: java.lang.ClassNotFoundException: androidx.media3.exoplayer.hls.HlsMediaSource$Factory
at androidx.media3.exoplayer.source.DefaultMediaSourceFactory.createMediaSource(DefaultMediaSourceFactory.java:481)
at androidx.media3.exoplayer.ExoPlayerImpl.createMediaSources(ExoPlayerImpl.java:1971)
at androidx.media3.exoplayer.ExoPlayerImpl.setMediaItems(ExoPlayerImpl.java:596)
at androidx.media3.common.BasePlayer.setMediaItems(BasePlayer.java:56)
at androidx.media3.common.BasePlayer.setMediaItem(BasePlayer.java:41)
at com.example.myapplication.MainActivityKt.Greeting(MainActivity.kt:58)
at com.example.myapplication.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:38)
at com.example.myapplication.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:37)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:303)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:285)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(SubcomposeLayout.kt:991)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(SubcomposeLayout.kt:477)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:90)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3302)
at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3235)
at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:725)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1071)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3599)
at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:633)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:619)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto(SubcomposeLayout.kt:500)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:472)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:463)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:447)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:872)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1.invoke-0kLqBqw(Scaffold.kt:285)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1.invoke(Scaffold.kt:179)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
23:43:40.446 E at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
at androidx.compose.ui.layout.RootMeasurePolicy.measure-3p2s80s(RootMeasurePolicy.kt:38)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
23:43:40.449 E at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1145)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:354)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureOnly(MeasureAndLayoutDelegate.kt:562)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureOnly(MeasureAndLayoutDelegate.kt:407)
at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:1058)
at android.view.View.measure(View.java:28143)
at androidx.compose.ui.platform.AbstractComposeView.internalOnMeasure$ui_release(ComposeView.android.kt:302)
at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:289)
at android.view.View.measure(View.java:28143)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7035)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:28143)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7035)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:28143)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7035)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:745)
at android.view.View.measure(View.java:28143)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:4685)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:3150)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3455)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2847)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:10190)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1406)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1415)
at android.view.Choreographer.doCallbacks(Choreographer.java:1015)
at android.view.Choreographer.doFrame(Choreographer.java:945)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1389)
at android.os.Handler.handleCallback(Handler.java:959)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8699)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
Caused by: java.lang.ClassNotFoundException: androidx.media3.exoplayer.hls.HlsMediaSource$Factory
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:607)
at java.lang.Class.forName(Class.java:512)
at androidx.media3.exoplayer.source.DefaultMediaSourceFactory$DelegateFactoryLoader.loadSupplier(DefaultMediaSourceFactory.java:757)
at androidx.media3.exoplayer.source.DefaultMediaSourceFactory$DelegateFactoryLoader.getMediaSourceFactory(DefaultMediaSourceFactory.java:640)
at androidx.media3.exoplayer.source.DefaultMediaSourceFactory.createMediaSource(DefaultMediaSourceFactory.java:479)
... 115 more
23:43:40.449 E Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.media3.exoplayer.hls.HlsMediaSource$Factory" on path: DexPathList[[dex file "/data/data/com.example.myapplication/code_cache/.overlay/base.apk/classes4.dex", zip file "/data/app/~~-RzgklG-NtzSIfb80fqCPg==/com.example.myapplication-lRiVhEm2XNqxSO08sFvoMw==/base.apk"],nativeLibraryDirectories=[/data/app/~~-RzgklG-NtzSIfb80fqCPg==/com.example.myapplication-lRiVhEm2XNqxSO08sFvoMw==/lib/x86_64, /system/lib64, /system_ext/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
at java.lang.ClassLoader.loadClass(ClassLoader.java:637)
at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
... 121 more
Can you help me understand what does that mean ? Where is the issue ?
You are trying to set live stream url directly in media source:
const val EXAMPLE_VIDEO_URI = "http://192.168.1.18:8000/stream.m3u8"
...
exoPlayer.setMediaItem(MediaItem.fromUri(EXAMPLE_VIDEO_URI))
Instead, you first need to create media source from HlsMediaSource
. Sample implementation:
const val EXAMPLE_VIDEO = "http://192.168.1.18:8000/stream.m3u8"
// Get the current context
val context = LocalContext.current
// Initialize ExoPlayer
val exoPlayer = ExoPlayer.Builder(context).build()
val hlsDataSourceFactory = DefaultHttpDataSource.Factory()
val uri = Uri.Builder().encodedPath(EXAMPLE_VIDEO).build()
val hlsMediaItem = MediaItem.Builder().setUri(uri).build()
val mediaSource =
HlsMediaSource.Factory(hlsDataSourceFactory).createMediaSource(hlsMediaItem)
exoPlayer?.setMediaSource(mediaSource)
exoPlayer?.prepare()
You will have to add dependency for hls:
implementation("androidx.media3:media3-exoplayer-hls:x.x.x")