Dynamically Change RTSP URL of IP Camera in VLC Player on Android

LibVLC library allows to show RTSP stream from IP camera on Android application. There might be a case where we have multiple IP cameras and want to display RTSP stream from specific camera when user selects it from dropdown.

This tutorial provides example how dynamically change RTSP URL of IP camera in VLC player on Android application.

At first, add the LibVLC library in the module’s build.gradle file.

app/build.gradle

dependencies {
    // Other dependencies
    // ...
    implementation 'org.videolan.android:libvlc-all:3.4.4'
}

Request the INTERNET permission in the manifest file because application requires Internet access.

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.app">
 
    <uses-permission android:name="android.permission.INTERNET" />
 
    <application>
        ...
    </application>
 
</manifest>

In the layout XML file add Spinner which will used to show a dropdown list of IP cameras. You also need to add VLCVideoLayout for displaying RTSP stream from chosen camera.

app/src/main/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/cameraDropdown"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <org.videolan.libvlc.util.VLCVideoLayout
        android:id="@+id/videoLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/cameraDropdown"/>

</RelativeLayout>

We created a new VideoStreamPlayer class which responsible to display stream from IP camera by given RTSP URL.

app/src/main/java/com/example/app/VideoStreamPlayer.java

package com.example.app;

import android.content.Context;
import android.net.Uri;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
import org.videolan.libvlc.util.VLCVideoLayout;

public class VideoStreamPlayer
{
    private final LibVLC libVlc;
    private final MediaPlayer mediaPlayer;
    private final VLCVideoLayout videoLayout;

    public VideoStreamPlayer(Context context, VLCVideoLayout videoLayout)
    {
        libVlc = new LibVLC(context);
        mediaPlayer = new MediaPlayer(libVlc);
        this.videoLayout = videoLayout;
    }

    public void start(String url)
    {
        mediaPlayer.attachViews(videoLayout, null, false, false);

        Media media = new Media(libVlc, Uri.parse(url));
        media.setHWDecoderEnabled(true, false);
        media.addOption(":network-caching=600");

        mediaPlayer.setMedia(media);
        media.release();
        mediaPlayer.play();
    }

    public void stop()
    {
        mediaPlayer.stop();
        mediaPlayer.detachViews();
    }

    public void release()
    {
        mediaPlayer.release();
        libVlc.release();
    }
}

app/src/main/java/com/example/app/VideoStreamPlayer.kt

package com.example.app

import android.content.Context
import android.net.Uri
import org.videolan.libvlc.LibVLC
import org.videolan.libvlc.Media
import org.videolan.libvlc.MediaPlayer
import org.videolan.libvlc.util.VLCVideoLayout

class VideoStreamPlayer(context: Context, private var videoLayout: VLCVideoLayout)
{
    private var libVlc: LibVLC = LibVLC(context)
    private var mediaPlayer: MediaPlayer = MediaPlayer(libVlc)

    fun start(url: String)
    {
        mediaPlayer.attachViews(videoLayout, null, false, false)

        val media = Media(libVlc, Uri.parse(url))
        media.setHWDecoderEnabled(true, false)
        media.addOption(":network-caching=600")

        mediaPlayer.media = media
        media.release()
        mediaPlayer.play()
    }

    fun stop()
    {
        mediaPlayer.stop()
        mediaPlayer.detachViews()
    }

    fun release()
    {
        mediaPlayer.release()
        libVlc.release()
    }
}

In the MainActivity class we defined two arrays to store RTSP addresses and names of cameras which will used to show in dropdown. Don’t forget to adjust values depending what IP cameras you have. We used two Reolink E1 Pro cameras for testing.

We attach array adapter with names of cameras to Spinner and register a callback which invoked when user selects a camera from dropdown. When IP camera is selected, previously captured stream is stopped and new stream from selected camera is starting to show.

app/src/main/java/com/example/app/MainActivity.java

package com.example.app;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import androidx.appcompat.app.AppCompatActivity;
import org.videolan.libvlc.util.VLCVideoLayout;

public class MainActivity extends AppCompatActivity
{
    private static final String[] urlList = {
        "rtsp://user:pass@192.168.0.8:554/h264Preview_01_main",
        "rtsp://user:pass@192.168.0.9:554/h264Preview_01_main"
    };
    private static final String[] cameraList = {
        "Camera 1",
        "Camera 2"
    };

    private VideoStreamPlayer streamPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        VLCVideoLayout videoLayout = findViewById(R.id.videoLayout);
        streamPlayer = new VideoStreamPlayer(this, videoLayout);

        ArrayAdapter<String> adapter = new ArrayAdapter<>(
            this,
            android.R.layout.simple_spinner_dropdown_item,
            cameraList
        );

        Spinner dropdown = findViewById(R.id.cameraDropdown);
        dropdown.setAdapter(adapter);
        dropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View v, int pos, long id)
            {
                streamPlayer.stop();
                streamPlayer.start(urlList[pos]);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        });
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        streamPlayer.stop();
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        streamPlayer.release();
    }
}

app/src/main/java/com/example/app/MainActivity.kt

package com.example.app

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import org.videolan.libvlc.util.VLCVideoLayout

class MainActivity : AppCompatActivity()
{
    private var urlList: Array<String> = arrayOf(
        "rtsp://user:pass@192.168.0.8:554/h264Preview_01_main",
        "rtsp://user:pass@192.168.0.9:554/h264Preview_01_main"
    )
    private var cameraList: Array<String> = arrayOf(
        "Camera 1",
        "Camera 2"
    )

    private lateinit var streamPlayer: VideoStreamPlayer

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val videoLayout: VLCVideoLayout = findViewById(R.id.videoLayout)
        streamPlayer = VideoStreamPlayer(this, videoLayout)

        val adapter: ArrayAdapter<String> = ArrayAdapter<String>(
            this,
            android.R.layout.simple_spinner_dropdown_item,
            cameraList
        )

        val dropdown: Spinner = findViewById(R.id.cameraDropdown)
        dropdown.adapter = adapter
        dropdown.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>?, v: View, pos: Int, id: Long)
            {
                streamPlayer.stop()
                streamPlayer.start(urlList[pos])
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {}
        }
    }

    override fun onStop()
    {
        super.onStop()
        streamPlayer.stop()
    }

    override fun onDestroy()
    {
        super.onDestroy()
        streamPlayer.release()
    }
}

This article has 1 comment

Leave a Comment

Your email address will not be published. Required fields are marked *