androidkotlinstreamandroid-jetpack-composeexoplayer

Crash when using ExoPlayer (Jetpack)


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 ?


Solution

  • 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")