Spanish version: https://medium.com/p/55f2fb295593
This project came from the request to connect to the differents ip cameras of the market whose way of connection is based on RTSP, basically the idea behind of project was to make the connection and take screenshots from the camera.
On Windows pretty much of the work could be done using EMGUCV but on Xamarin turned out to be a bit more complicated without the use of licensed libraries.
I will not go deeper about the connection but basically RTSP use TCP communication for control messages and UDP or TCP to send the Video and Audio, the default port is the 554 and based on the camera manufacturer there is different urls to access the streaming.
I found different alternatives to use like:
- RtspClientSharp (https://github.com/BogdanovKirill/RtspClientSharp): was very convenient to make the connection and access to the frames in a very fast way but I have some issues with the decode of the frames.
- LibVLCSharp (https://github.com/videolan/libvlcsharp): was very easy and fast to implement on Xamarin but I received the frames with a small delay so I keep looking for another option.
With each alternative we found a number of problems that made us implement another libraries to supplement the deficiencies of each one until we found the following project: https://github.com/alexeyvasilyev/rtsp-client-android.
The project solves the connection RTCP/RTSPS using tcp, allows the decode of the h264 frames and audio, have support for authentication and is compatible with the most of the ip cameras of the market so I decided to test the library in a Xamarin Forms project.
The project is divided into three parts:
- The code base project
- The Android project
- The binding project to use the library
The first step was to generate an interface to encapsulate the info of the camera:
using Xamarin.Forms;
namespace Xamarin.Rtsp.Renderers
{
public class CameraView : View
{
public string Url { get; set; }
public string User { get; set; }
public string Password { get; set; }
public CameraView()
{
}
}
}After that I generated a renderer in the Android project to use the library:
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Rtsp.Droid.Renderers;
using Xamarin.Rtsp.Renderers;
[assembly: ExportRenderer(typeof(CameraView), typeof(CameraViewRenderer))]
namespace Xamarin.Rtsp.Droid.Renderers
{
public class CameraViewRenderer : ViewRenderer<CameraView, SurfaceView>, ISurfaceHolderCallback
{
SurfaceView currentView;
Surface surface;
int width;
int height;
Context _context;
RtspClient rtspClient;
public CameraViewRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<CameraView> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
currentView = new SurfaceView(_context) {
LayoutParameters =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)
};
currentView.Holder.AddCallback(this);
base.SetNativeControl(currentView);
rtspClient = new RtspClient();//DependencyService.Get<IRtspClient>();
if (e.NewElement != null)
{
rtspClient.Url = e.NewElement.Url ?? "";
rtspClient.Username = e.NewElement.User ?? "";
rtspClient.Password = e.NewElement.Password ?? "";
}
//rtspClient.StartStreaming(mSurfaceView);
}
}
public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
{
}
public void SurfaceCreated(ISurfaceHolder holder)
{
if (rtspClient != null)
{
Task.Run(async () =>
{
rtspClient.StartStreaming(currentView);
});
}
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
}
}
}And the final step was to create the RTSP client that creates the socket along the rest of the camera info and make the call to the library:
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Com.Alexvas.Rtsp;
using Java.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Rtsp.Droid.Core;
using Xamarin.Rtsp.Renderers;
[assembly: Dependency(typeof(Xamarin.Rtsp.Droid.Renderers.RtspClient))]
namespace Xamarin.Rtsp.Droid.Renderers
{
public class RtspClient : IRtspClient<SurfaceView>
{
Com.Alexvas.Rtsp.RtspClient localClient;
SurfaceView _surfaceView;
public string Url { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public async Task<bool> StartStreaming(SurfaceView surfaceView)
{
try
{
_surfaceView = surfaceView;
Uri uri = new Uri(this.Url);
var socket = await NetUtils.CreateSocketAndConnect(uri.Host, 554, 5000);
int port = uri.Port;
Java.Util.Concurrent.Atomic.AtomicBoolean rtspStopped = new Java.Util.Concurrent.Atomic.AtomicBoolean(false);
var listener = new RtspListener(surfaceView.Holder.Surface, surfaceView.Width, surfaceView.Height);
localClient = new Com.Alexvas.Rtsp.RtspClient.Builder(socket, this.Url, rtspStopped, listener)
.RequestVideo(true).RequestAudio(false).WithDebug(true).WithCredentials(this.Username, this.Password).Build();
localClient.Execute();
NetUtils.CloseSocket(socket);
}
catch (Exception ex)
{
}
//NetUtils.CloseSocket(socket);
return false;
}
}
}If you want to check the project this is the github url:
rretamal/Xamarin-RTSPExample project to show an RTSP streaming on Xamarin Forms Project based on the following repository…github.com