title: LibVlcSharp: How to stream a dynamic frame sequence with RTSP (Dynamic StreamMediaInput)?
body: <p>I'm working on a project that takes individual images from an RTSP-Stream and manipulates them (drawing bounding boxes). Those images should be restreamed (h264 encoded) on a separate RTSP-stream on an other address and shouldn't be saved on the local disk.</p>
  <p>My current code so far is:</p>
  <pre><code>        {
              // OpenCV VideoCapture: Sample RTSP-Stream
              var capture = new VideoCapture(&quot;rtsp://195.200.199.8/mpeg4/media.amp&quot;);
              capture.Set(VideoCaptureProperties.FourCC, FourCC.FromFourChars('M', 'P', 'G', '4'));
              var mat = new Mat();
  
              // LibVlcSharpStreamer
              Core.Initialize();
              var libvlc = new LibVLC();
              var player = new MediaPlayer(libvlc);
              player.Play();
              while (true)
              {
                  if (capture.Grab())
                  {
                      mat = capture.RetrieveMat();
                      // Do some manipulation in here
                      var media = new Media(libvlc, new StreamMediaInput(mat.ToMemoryStream(&quot;.jpg&quot;)));
                      media.AddOption(&quot;:no-audio&quot;);
                      media.AddOption(&quot;:sout=#transcode{vcodec=h264,fps=10,vb=1024,acodec=none}:rtp{mux=ts,sdp=rtsp://192.168.xxx.xxx:554/video}&quot;);
                      media.AddOption(&quot;:sout-keep&quot;);
                      player.Media = media;
                      // Display screen
                      Cv2.ImShow(&quot;image&quot;, mat);
                      Cv2.WaitKey(1);
                  }
              }
          }
  </code></pre>
  <p>It is a little bit messy, because of testing purposes, but it works if I just use the given RTSP-Stream as the Media instead of the fetched images. I have some success with piping the images (as bytes) into the <code>cvlc</code> command line (<code>python get_images.py | cvlc -v --demux=rawvideo --rawvid-fps=25 --rawvid-chroma=RV24 --sout '#transcode{vcodec=h264,fps=25,vb=1024,acodec=none}:rtp{sdp=&quot;rtsp://:554/video&quot;}'</code>), but it should be integrated in <code>c#</code>. <code>get_images.py</code> just reads images in a <code>while</code>-loop, wirtes a text on it and forwards them into <code>std-out</code>.</p>
  <p>My thoughts on solving this problem is, to input the images via the <code>StreamMediaInput</code>-class and to dynamically change the media, if a new image has been retrieved. But it doesn't work, nothing can be seen with VLC or FFPlay.</p>
  <p>Does someone has faced a similar Problem? How can the <code>StreamMediaInput</code>-Object can be changed dynamically, such that new images are broadcastet correctly?</p>
  <p>Thank you for taking the time to read this post. Have a nice day!</p>
  <p><strong>EDIT</strong>:</p>
  <p>I tried to implement my own MediaInput class (very similar to <code>MemoryStramMediaInput</code>) with the modification of <code>UpdateMemoryStream()</code>. The MemoryStream gets updated by every new retrieved image, but the <code>read()</code> will not get called a second time (<code>read()</code> is called once per Medium). I am trying to implement the blocking <code>read()</code>, but I am struggeling to find a good way in implementing it. The code so far is:</p>
  <p><strong>EDIT 2:</strong></p>
  <p>I decided to implement the blocking with an <code>ManualResetEvent</code>, which blocks the read(), if the Position is at the end of the Stream. Futhermore the read is looped in a while to keep the data in the stream updated. It still does not work. My Code so far:</p>
  <pre><code>using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Text;
  using System.Threading;
  using LibVLCSharp.Shared;
  
  namespace LibVlcSharpStreamer
  {
      /// &lt;summary&gt;
      /// A &lt;see cref=&quot;MediaInput&quot;/&gt; implementation that reads from a .NET stream
      /// &lt;/summary&gt;
      public class MemoryStreamMediaInput : MediaInput
      {
          private Stream _stream;
  
          private ManualResetEvent manualResetEvent = new ManualResetEvent(false);
  #if NET40
          private readonly byte[] _readBuffer = new byte[0x4000];
  #endif
          /// &lt;summary&gt;
          /// Initializes a new instance of &lt;see cref=&quot;StreamMediaInput&quot;/&gt;, which reads from the given .NET stream.
          /// &lt;/summary&gt;
          /// &lt;remarks&gt;You are still responsible to dispose the stream you give as input.&lt;/remarks&gt;
          /// &lt;param name=&quot;stream&quot;&gt;The stream to be read from.&lt;/param&gt;
          public MemoryStreamMediaInput(Stream stream)
          {
              _stream = stream ?? throw new ArgumentNullException(nameof(stream));
              CanSeek = stream.CanSeek;
          }
  
          /// &lt;summary&gt;
          /// Initializes a new instance of &lt;see cref=&quot;StreamMediaInput&quot;/&gt;, which reads from the given .NET stream.
          /// &lt;/summary&gt;
          /// &lt;remarks&gt;You are still responsible to dispose the stream you give as input.&lt;/remarks&gt;
          /// &lt;param name=&quot;stream&quot;&gt;The stream to be read from.&lt;/param&gt;
          public void UpdateMemoryStream(Stream stream)
          {
              stream.CopyTo(_stream);
              _stream.Position = 0;
              manualResetEvent.Set();
              manualResetEvent.Reset();
              Console.WriteLine(&quot;released&quot;);
          }
  
          /// &lt;summary&gt;
          /// LibVLC calls this method when it wants to open the media
          /// &lt;/summary&gt;
          /// &lt;param name=&quot;size&quot;&gt;This value must be filled with the length of the media (or ulong.MaxValue if unknown)&lt;/param&gt;
          /// &lt;returns&gt;&lt;c&gt;true&lt;/c&gt; if the stream opened successfully&lt;/returns&gt;
          public override bool Open(out ulong size)
          {
              try
              {
                  try
                  {
                      size = (ulong)_stream.Length;
                  }
                  catch (Exception)
                  {
                      // byte length of the bitstream or UINT64_MAX if unknown
                      size = ulong.MaxValue;
                  }
  
                  if (_stream.CanSeek)
                  {
                      _stream.Seek(0L, SeekOrigin.Begin);
                  }
  
                  return true;
              }
              catch (Exception)
              {
                  size = 0UL;
                  return false;
              }
          }
  
          /// &lt;summary&gt;
          /// LibVLC calls this method when it wants to read the media
          /// &lt;/summary&gt;
          /// &lt;param name=&quot;buf&quot;&gt;The buffer where read data must be written&lt;/param&gt;
          /// &lt;param name=&quot;len&quot;&gt;The buffer length&lt;/param&gt;
          /// &lt;returns&gt;strictly positive number of bytes read, 0 on end-of-stream, or -1 on non-recoverable error&lt;/returns&gt;
          public unsafe override int Read(IntPtr buf, uint len)
          {
              try
              {
                  while (_stream.CanSeek)
                  {
                      if (_stream.Position &gt;= _stream.Length)
                      {
                          manualResetEvent.WaitOne();
                      }
                      var read = _stream.Read(new Span&lt;byte&gt;(buf.ToPointer(), (int)Math.Min(len, int.MaxValue)));
                      // Debug Purpose
                      Console.WriteLine(read);
                  }
                  return -1;
              }
              catch (Exception)
              {
                  return -1;
              }
          }
  
          /// &lt;summary&gt;
          /// LibVLC calls this method when it wants to seek to a specific position in the media
          /// &lt;/summary&gt;
          /// &lt;param name=&quot;offset&quot;&gt;The offset, in bytes, since the beginning of the stream&lt;/param&gt;
          /// &lt;returns&gt;&lt;c&gt;true&lt;/c&gt; if the seek succeeded, false otherwise&lt;/returns&gt;
          public override bool Seek(ulong offset)
          {
              try
              {
                  _stream.Seek((long)offset, SeekOrigin.Begin);
                  return true;
              }
              catch (Exception)
              {
                  return false;
              }
          }
  
          /// &lt;summary&gt;
          /// LibVLC calls this method when it wants to close the media.
          /// &lt;/summary&gt;
          public override void Close()
          {
              try
              {
                  if (_stream.CanSeek)
                      _stream.Seek(0, SeekOrigin.Begin);
              }
              catch (Exception)
              {
                  // ignored
              }
          }
      }
  }
  
  </code></pre>
  <p>I have marked the spot in the code, where the blocking clause would fit well, in my opinion.</p>