LibVLC for Android is a library that allows to embed VLC engine on Android application. This tutorial provides example how to display RTSP stream from IP camera using LibVLC on Android application.
First, we need to add LibVLC dependency in the module's build.gradle file.
app/build.gradle
dependencies {
implementation 'org.videolan.android:libvlc-all:3.4.2'
}
Request the INTERNET permission in the manifest file because application should have 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>
Open the layout XML file and add a RecyclerView Design code that will be used to display RTSP stream from IP camera.
app/src/main/res/layout/recyclerview_live_video_play.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/camera_name"/>
<SurfaceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/camera_surface_view"/>
</LinearLayout>
Open the layout XML file and add a RecyclerView that will be used to display RTSP stream from IP camera.
app/src/main/res/layout/MainActivity21.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity21">
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/streams_recycler_view21"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Add a Model Class LiveCamera that will be used to display RTSP stream from IP camera.
app/src/main/java/com/example/app/LiveCamera.class
<?xml version="1.0" encoding="utf-8"?>
public class LiveCamera {
private String name;
private String url;
public LiveCamera(String name, String url) {
this.name = name;
this.url = url;
}
public String getName() {
return name;
}
public String getUrl() {
return url;
}
}
Add a Model Class LiveCameraPlayer that will be used to display RTSP stream from IP camera.
app/src/main/java/com/example/app/LiveCameraPlayer.class
package com.example.camera3.adapter;
import android.net.Uri;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
public class LiveCameraPlayer implements MediaPlayer.EventListener, SurfaceHolder.Callback {
private LibVLC libVLC;
private SurfaceView surfaceView;
private String mediaUrl;
private MediaPlayer mediaPlayer;
public LiveCameraPlayer(LibVLC libVLC, SurfaceView surfaceView, String mediaUrl) {
this.libVLC = libVLC;
this.surfaceView = surfaceView;
this.mediaUrl = mediaUrl;
this.mediaPlayer = new MediaPlayer(libVLC);
}
public void start() {
SurfaceHolder surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
Media media = new Media(libVLC, Uri.parse(mediaUrl));
mediaPlayer.setMedia(media);
mediaPlayer.setEventListener(this);
mediaPlayer.setAspectRatio(null);
mediaPlayer.setScale(0);
media.release();
}
public void stop() {
mediaPlayer.stop();
mediaPlayer.getVLCVout().detachViews();
mediaPlayer.release();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mediaPlayer.getVLCVout().setVideoSurface(holder.getSurface(), holder);
mediaPlayer.getVLCVout().attachViews();
mediaPlayer.play();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Do nothing
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mediaPlayer.getVLCVout().detachViews();
}
@Override
public void onEvent(MediaPlayer.Event event) {
switch (event.type) {
case MediaPlayer.Event.EndReached:
case MediaPlayer.Event.EncounteredError:
mediaPlayer.stop();
mediaPlayer.getVLCVout().detachViews();
break;
default:
break;
}
}
}
Add a Recyclerview Adapter Class LiveCameraAdapter that will be used to display RTSP stream from IP camera.
app/src/main/java/com/example/app/LiveCameraAdapter.class
package com.example.camera3.adapter;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.example.camera3.R;
import org.videolan.libvlc.LibVLC;
import java.util.List;
public class LiveCameraAdapter extends RecyclerView.Adapter<LiveCameraAdapter.ViewHolder> {
private Context context;
private List<LiveCamera> cameras;
private LibVLC libVLC;
private Fragment fragment;
public LiveCameraAdapter(Context context, LibVLC libVLC, List<LiveCamera> cameras) {
this.context = context;
this.cameras = cameras;
this.libVLC = libVLC;
}
public LiveCameraAdapter(Context context, LibVLC libVLC, List<LiveCamera> cameras, Fragment fragment) {
this.context = context;
this.cameras = cameras;
this.libVLC = libVLC;
this.fragment = fragment;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_layout_cell, parent, false);
return new ViewHolder(view);
}
@Override
public void onViewRecycled(ViewHolder holder) {
// Stop the camera player
LiveCameraPlayer cameraPlayer = (LiveCameraPlayer) holder.cameraSurfaceView.getTag();
if (cameraPlayer != null) {
cameraPlayer.stop();
}
}
@Override
public int getItemCount() {
return cameras.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView cameraName;
public SurfaceView cameraSurfaceView;
public ViewHolder(View view) {
super(view);
cameraName = view.findViewById(R.id.camera_name);
cameraSurfaceView = view.findViewById(R.id.camera_surface_view);
}
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
LiveCamera camera = cameras.get(position);
if (holder != null && holder.itemView != null) {
String url = String.valueOf(cameras.get(position));
holder.cameraName.setText(camera.getName());
// Initialize the camera player
LiveCameraPlayer cameraPlayer = new LiveCameraPlayer(libVLC, holder.cameraSurfaceView, camera.getUrl());
holder.cameraSurfaceView.setTag(cameraPlayer);
cameraPlayer.start();
}
}
}
When the activity starts, the RTSP stream from the IP camera is captured and displayed using media player. Make sure you have changed RTSP URL of your IP camera. Manufacturers might use different RTSP URLs. We used Reolink E1 Pro camera for testing. The network-caching option can be minimized to reduce the delay of RTSP stream coming from an IP camera. If you're set network-caching to low, then stream capture can freeze. So try to use various values and adjust this option to your mobile device.
When the activity enters a stopped state, the media player is stopped too and a video layout is detached from the player. Resources are released when the activity is destroyed.
app/src/main/java/com/example/app/MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.camera3;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.example.camera3.Socket.VideoRecyclerViewAdapter;
import com.example.camera3.adapter.LiveCamera;
import com.example.camera3.adapter.LiveCameraAdapter;
import org.videolan.libvlc.LibVLC;
import java.util.ArrayList;
import java.util.List;
public class MainActivity21 extends AppCompatActivity {
private RecyclerView recyclerView;
private LiveCameraAdapter cameraAdapter;
private LibVLC libVLC;
private VideoRecyclerViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main21);
// Initialize the libvlc library
ArrayList<String> options = new ArrayList<>();
options.add("--no-drop-late-frames");
options.add("--no-skip-frames");
libVLC = new LibVLC(this, options);
// Initialize the RecyclerView
recyclerView = findViewById(R.id.streams_recycler_view21);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Initialize the camera adapter
List<LiveCamera> cameras = new ArrayList<>();
cameras.add(new LiveCamera("Camera 1", "http://192.168.100.19:8080/video"));
cameras.add(new LiveCamera("Camera 2", "http://192.168.100.19:8080/video"));
cameras.add(new LiveCamera("Camera 3", "http://192.168.100.19:8080/video"));
cameraAdapter = new LiveCameraAdapter(getApplicationContext(),libVLC,cameras);
recyclerView.setAdapter(cameraAdapter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Release the libvlc library
libVLC.release();
}
}