1

I'm trying to create an application aggravating multiple RTSP's for use in a mobile app. The idea is that i run a simple WPF app on Windows PC connected to IP cameras at home and a xamarin app connects to it. I want the WPF program to relay needed RTSP to an app on request, but to do this i'm at a loss. I learned how to receive streams both on windows and the android app, but i'm looking for a way to forward a stream received by windows app into the android one.

From what I've found out lurking on the internet, there is a way to stream using VLC library: How to streaming video via VLC api in C#

But I have no idea on how to stream from another stream instead of a file.

This is what I've got - simple display of RTSP on an app:

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Serwer"
        xmlns:wpf="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="650" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition  Width="*"/>
            <ColumnDefinition  Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0">Placeholder for settings</Label>
        <Label Grid.Row="0" Grid.Column="1">Placeholder for more streams</Label>
        <Label Grid.Row="1" Grid.Column="1"></Label>
        <wpf:VideoView x:Name="VideoView" Grid.Row="1" Grid.Column="0"/>
    </Grid>
</Window>

This is the code behind XAML:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Serwer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        const string VIDEO_URL = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov";
        readonly LibVLC _libvlc;

        public MainWindow()
        {
            InitializeComponent();
            // this will load the native libvlc library (if needed, depending on the platform). 
            Core.Initialize();

            // instantiate the main libvlc object
            _libvlc = new LibVLC();
            VideoView.MediaPlayer = new LibVLCSharp.Shared.MediaPlayer(_libvlc);
            VideoView.MediaPlayer.Play(new Media(_libvlc, VIDEO_URL, FromType.FromLocation));
        }
    }
}
Ahacz
  • 33
  • 1
  • 4
  • I would try using VLC to read the stream, and streaming it to the network again. I'm not sure libvlc/LibVLCSharp would help there, it would add an overhead without any benefit since the streaming would be mostly a black box. – cube45 Nov 18 '19 at 17:41
  • my idea is that if you need to start/stop from C#, you can use Process.Start to launch VLC – cube45 Nov 18 '19 at 17:42
  • I want to make it as simple for the user as possible. That's why I'm using VLCSharp. I know that there are vlc commands that would help me duplicate the stream - display it once and then forward the duplicate either via http or RTSP. The problem is that I cannot find the syntax and command list for VLC in C#. For now I have found this: rtsp1.AddOption(":sout=#duplicate{dst=display,dst=std {access=udp,mux=ts,dst=http://localhost:8080/go.mpg}"); The thing is that it still doesn't load because this option above was written without any knowledge on how to properly string it together. – Ahacz Nov 18 '19 at 18:18
  • Oh, I didn't understand that your app would need a display as well. that might be tedious with VLC to combine live display and on-demand streaming. however, the syntax you are using seems about right, but I don't know the details. If you want rtsp, you will likely need a sdp somewhere in the string. – cube45 Nov 18 '19 at 22:08
  • another option would be udp multicast. that way, you could always be streaming on the network and seeing the stream, and you can just play the stream on the receiving end. On the plus side, it should be easy for VLC to handle, and multiple clients could be connected at once without overhead (scalability), on the downside, you are always streaming something, and multicast must be supported on every router of your network – cube45 Nov 18 '19 at 22:12
  • That is a good idea if it wasnt for the constant streaming. Later on in the project I will integrate security into the app itself so that I can stream safely. Always broadcasting would not be optimal in that case. I will try reading about this sdp flag and will update if something works. :) – Ahacz Nov 19 '19 at 13:13
  • See also https://wiki.videolan.org/Documentation:Streaming_HowTo/Command_Line_Examples/#RTSP_live_streaming . The on-demand part will not work since VLM is deprecated as far as I know. I wouldn't say that VLC would be a good fit for your project. Maybe have a look at gstreamer ? I'm not sure that they are able to show a stream in a WPF app, but their streaming API seems definitely powerful. – cube45 Nov 19 '19 at 13:22

1 Answers1

2

Okay, I managed to finally find the list of commands and use them properly. Turns out I fell in love with LibVLC. :D
Here's the link descripting various commands : https://wiki.videolan.org/Documentation:Streaming_HowTo/Advanced_Streaming_Using_the_Command_Line/#rtp

And here is how I've done the code:

using LibVLCSharp.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Serwer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        const string VIDEO_URL = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov";
        readonly LibVLC _libvlc;

        public MainWindow()
        {
            InitializeComponent();            // this will load the native libvlc library (if needed, depending on the platform). 
            Core.Initialize();                // instantiate the main libvlc object
            _libvlc = new LibVLC();
            VideoView.MediaPlayer = new LibVLCSharp.Shared.MediaPlayer(_libvlc);
            var rtsp1 = new Media(_libvlc, VIDEO_URL, FromType.FromLocation);       //Create a media object and then set its options to duplicate streams - 1 on display 2 as RTSP
            rtsp1.AddOption(":sout=#duplicate" +
                "{dst=display{noaudio}," +
                "dst=rtp{mux=ts,dst=192.168.0.110,port=8080,sdp=rtsp://192.168.0.110:8080/go.sdp}");  //The address has to be your local network adapters addres not localhost
            VideoView.MediaPlayer.Play(rtsp1);
            VideoView1.MediaPlayer = new LibVLCSharp.Shared.MediaPlayer(_libvlc);
            VideoView1.MediaPlayer.Mute=true;
            VideoView1.MediaPlayer.Play(new Media(_libvlc, "rtsp://192.168.0.110:8080/go.sdp", FromType.FromLocation));
        }
    }
}

Thanks cube for pointing me in the right direction!

Ahacz
  • 33
  • 1
  • 4