Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

Taking snapshot doesn't work while streaming #447

Closed
Davutcsmc opened this issue Jul 17, 2018 · 14 comments
Closed

Taking snapshot doesn't work while streaming #447

Davutcsmc opened this issue Jul 17, 2018 · 14 comments

Comments

@Davutcsmc
Copy link

Davutcsmc commented Jul 17, 2018

I have an issue / a question (pick one) about Vlc.DotNet.

Generic information

  • Vlc.DotNet version : v4.0.30319
  • Vlc.DotNet project used : Core
  • libvlc version : v2.2.8
  • .net version : VS2015
  • Project language : C#
  • Project build architecture : AnyCPU
  • Operating system : (Windows 10) (x64)

Summary

I am trying to get snapshots for "Vlc.DotNet.Core" however it s not taking snapshot when it s streaming. When i call TakeSnapshot function, it doesn't drop on "OnMediaPlayerSnapshotTaken" event.

Also, i checked the snapshot action for Vlc.DotNet.Forms and it s working.

The code i am working on is as given below :

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Vlc.DotNet.Core;

namespace SnapshotTest
{
    class Program
    {
        static void Main(string[] args)
        {
            VlcStreamerSnapshotText myObject = new VlcStreamerSnapshotText();

            myObject.streamFile();
        }
    }
    class VlcStreamerSnapshotText
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();

        static Vlc.DotNet.Core.VlcMediaPlayer mediaPlayer;
        bool IsSnapTaken = false;

        public bool streamFile(string source = "")
        {
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            aTimer.Interval = 2000;
            aTimer.Enabled = true;

            var currentDirectory = Directory.GetCurrentDirectory();
            var libDirectory = new DirectoryInfo(Path.Combine(currentDirectory, "libvlc", IntPtr.Size == 4 ? "x86" : "x64"));

            var options = new string[]
            {
                "--no-snapshot-preview",
                "--no-audio"
                //"--no-video"
                // VLC options can be given here. Please refer to the VLC command line documentation.
        };

            mediaPlayer = new Vlc.DotNet.Core.VlcMediaPlayer(new DirectoryInfo(libDirectory.FullName),options);

            string[] mediaOptions = new string[]
            {
                ":sout=#duplicate{dst=rtp{sdp=rtsp://127.0.0.1:1000/},dst=display}",
                ":sout-all",
                ":sout-keep"
            };
            
            //string[] mediaOptions = new string[] { string.Concat("--sout=#duplicate{dst=rtp{sdp=rtsp://", IpAddress, ":", "1000", "/}} --sout-all --sout-keep") };

            mediaPlayer.SetMedia(new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov"), mediaOptions);
            
            mediaPlayer.SnapshotTaken += OnMediaPlayerSnapshotTaken;

            bool playFinished = false;
            mediaPlayer.PositionChanged += (sender, e) =>
            {
                Console.Write("\r" + Math.Floor(e.NewPosition * 100) + "%");
            };

            mediaPlayer.EncounteredError += (sender, e) =>
            {
                Console.Error.Write("An error occurred");
                playFinished = true;
            };

            mediaPlayer.EndReached += (sender, e) =>
            {
                playFinished = true;
            };

            Task.Factory.StartNew(() => mediaPlayer.Play());
            //mediaPlayer.Play();

            // Ugly, sorry
            while (!playFinished)
            {
                Thread.Sleep(TimeSpan.FromMilliseconds(500));
            }
            return true;
        }

        ManualResetEvent m_mreSnapshot = new ManualResetEvent(false);
        private readonly object m_snapLock = new object();
        private static bool m_SnapshotIsTaken = false;
        public bool GetSnapshot()
        {
            m_SnapshotIsTaken = false;
            if (mediaPlayer == null)
            {
                return false;
            }

            string currentTime = DateTime.Now.ToString("yyyyMMdd_HHmmss");
            string uniqueId = generateID(string.Empty);
            string snapName = string.Format("{0}_{1}.png", currentTime, uniqueId);

            string tempFilePathCand = Path.GetTempPath();

            if (!tempFilePathCand.EndsWith("\\"))
                tempFilePathCand = tempFilePathCand + "\\" + snapName;
            else
                tempFilePathCand = tempFilePathCand + snapName;

            FileInfo snapPathInfo = new FileInfo(tempFilePathCand);
            //mediaPlayer.Manager.TakeSnapshot();
            mediaPlayer.TakeSnapshot(snapPathInfo);

            m_mreSnapshot.WaitOne(TimeSpan.FromSeconds(2));
            if (m_SnapshotIsTaken)
                return true;

            return false;
        }

        private string generateID(string tip)
        {
            return string.Format(@"{0}_{1}", tip, Guid.NewGuid().ToString("N"));
        }

        void OnMediaPlayerSnapshotTaken(object sender, VlcMediaPlayerSnapshotTakenEventArgs e)
        {
            mediaPlayer.SnapshotTaken -= OnMediaPlayerSnapshotTaken;
            m_SnapshotIsTaken = true;
            mediaPlayer.SnapshotTaken += OnMediaPlayerSnapshotTaken;
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            GetSnapshot();
        }
    }
}
@jeremyVignelles
Copy link
Collaborator

What's the result of the TakeSnapshot() call? does it return a success (true) ?

libvlc's documentation states that an error is returned by this function if the video output was not found: https://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__video.html#ga9b0a3870ce962aa0358050b2d5a59143

In other words, from my understanding, you can't take a snapshot if you don't have any video output, i.e. if you stream. I might be wrong though, because I remember having made a thumbnailer that did not have any video output..

@Davutcsmc
Copy link
Author

Davutcsmc commented Jul 17, 2018

TakeSnapshot() doesn't return any value, it defined as "public void TakeSnapshot(FileInfo file);" in "Vlc.DotNet.Core" namespace.

In fact, when I modified Media options as given below, taking snapshot is working, unfortinately, this time it is not streaming. Just changed ":" characters to "--".

string[] mediaOptions = new string[] { "--sout=#duplicate{dst=rtp{sdp=rtsp://127.0.0.1:1000/},dst=display}", "--sout-all", "--sout-keep" };

How can I test "libvlc_video_take_snapshot()"

@jeremyVignelles
Copy link
Collaborator

TakeSnaphot returns a bool in the 3.0 if I remember correctly

@Davutcsmc
Copy link
Author

Vlc.DotNet.Core nuget package doesn't support videolan vlc 3.0 ?

@jeremyVignelles
Copy link
Collaborator

I meant in Vlc.DotNet.Core 3.0 prerelease

@Davutcsmc
Copy link
Author

Unfortunately, TakeSnapshot function is also defined as void in 3.0

@jeremyVignelles
Copy link
Collaborator

Oh, I indeed forgot to change the return type of the TakeSnapshot method in the WinForms control. It however returns a boolean in the core player.

public bool TakeSnapshot(FileInfo file)

@jeremyVignelles
Copy link
Collaborator

It won't change anything to your issue however, we need to find the correct way to pass the options to the media (the correct syntax is with :, but I don't know the rest...)

@Davutcsmc
Copy link
Author

ahhh, sorry, i am also working on core player and downloaded form player accidently. As you said, it defined as a boolean function and in my situation it returns "false".

@jeremyVignelles
Copy link
Collaborator

Just fixed the return result of the TakeSnapshot of the WinForms control.
I'm currently trying to build a sample so that we can try to reproduce and fix your issue

@Davutcsmc
Copy link
Author

Is there any progress?

@jeremyVignelles
Copy link
Collaborator

Thanks for your ping (to be honest, I totally forgot). I had long days at work in the past few weeks so I didn't make any progress on that.
You can use the Thumbnailer sample and edit it if you want to reproduce on that, but the key is to find the correct options I guess

@Davutcsmc
Copy link
Author

Davutcsmc commented Aug 15, 2018

Ok, I worked on the Thumbnailer sample, however, it looks, couldn't find the correct options. Perhaps, It is not possible to take a snapshot while streaming as you defined in your first message. The code I worked on, basicly, as given below :

      using System;
      using System.Collections.Generic;
      using System.Diagnostics;
      using System.IO;
      using System.Linq;
      using System.Reflection;
      using System.Text;
      using System.Threading;
      using System.Threading.Tasks;

     namespace LibVLCSnapshotConsole
     {

     class Program
     {

        static void Main(string[] args)
        {
            bool result = Run().Result;

            Console.WriteLine("Snapshots are completed: " + result.ToString());
        }
        
        static async Task<bool> Run()
       {
            var currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
            
            var libDirectory =
                new DirectoryInfo(Path.Combine(currentDirectory, "libVLC", IntPtr.Size == 4 ? "x86" : "x64"));

            var destinationFolder = Path.Combine(currentDirectory, "thumbnails");

            if (!Directory.Exists(destinationFolder))
            {
                Directory.CreateDirectory(destinationFolder);
            }

            var options = new[]
            {
                "--intf", "dummy", /* no interface                   */
                "--vout", "dummy", /* we don't want video output     */
                "--no-audio", /* we don't want audio decoding   */
                "--no-video-title-show", /* nor the filename displayed     */
                "--no-stats", /* no stats */
                "--no-sub-autodetect-file", /* we don't want subtitles        */
                "--no-snapshot-preview", /* no blending in dummy vout      */
            };

            var mediaOptions = new[]
                {
                   ":sout=#duplicate{dst=rtp{sdp=rtsp://192.168.1.30:554/},dst=display}",
                   ":sout-all",
                   ":sout-keep"
                };

            using (var mediaPlayer = new Vlc.DotNet.Core.VlcMediaPlayer(libDirectory, options))
            {
                //mediaPlayer.SetMedia(new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov"));
                mediaPlayer.SetMedia(new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov"), mediaOptions);

                TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

                var lastSnapshot = 0L;
                mediaPlayer.TimeChanged += (sender, e) =>
                {
                    // Maps the time to a 5-seconds interval to take a snapshot every 5 seconds
                    var snapshotInterval = e.NewTime / 5000;

                    // Take a snapshot every 5 seconds
                    if (snapshotInterval > lastSnapshot)
                    {
                        lastSnapshot = snapshotInterval;
                        ThreadPool.QueueUserWorkItem(_ =>
                        {
                            bool IsSnapSuccesssfful = mediaPlayer.TakeSnapshot(new FileInfo(Path.Combine(destinationFolder, $"{snapshotInterval}.png")));
                        });
                    }
                };

                mediaPlayer.EncounteredError += (sender, e) =>
                {
                    Console.Error.Write("An error occurred");
                    tcs.TrySetCanceled();
                };

                mediaPlayer.EndReached += (sender, e) =>
                {
                    ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
                };

                mediaPlayer.Play();

                await tcs.Task;

                return tcs.Task.Result;
            }
        }


     }
    }

Kind Regards.

@jeremyVignelles
Copy link
Collaborator

After some testing, it appeared to me that what you are trying to achieve does not seem possible yet with libvlc.

I invite you to ask VideoLAN directly.

Technical details:

The only way that TakeSnapshot can return false is because this code returns no vout:

https://github.com/videolan/vlc-3.0/blob/115c4a55a728ac504f8285f70d19c56ed9d873bb/lib/video.c#L151-L153

This is confirmed by the fact that libvlc_media_player_has_vout returns 0 when setting streaming options.

This seems logical, since the streaming output (sout) overrides the default video output (vout). vout is now empty for libvlc, even if the duplicate sout tries to use display.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants