C#: is it possible to generate or fake a visual tree in a service?

113 Views Asked by At

I have a windowsservice that is supposed to generate thumbprints of videos. To achieve this i am trying to use the MediaElement-class (https://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement(v=vs.110).aspx). To fire events when opening medias this element has to be in a visualtree. Is it possible to simulate or fake a visual tree ?

Edit: I now use MediaPlayer instead of MediaElements but can't rely on the events because they are not thrown.

Updated code

        public class Mp4ThumbnailExtractor : IDisposable
{
    private ManualResetEvent waitHandle;
    private TimeSpan mediaOpenTimeout;

    public TimeSpan Time { get; set; }
        = TimeSpan.Parse("00:00:30");

    public TimeSpan FallbackTime { get; set; }
        = TimeSpan.Parse("00:00:10");

    public int Height { get; set; }
        = 400;

    public int Width { get; set; }
        = 400;

    public int Dpi { get; set; }
        = 96;

    public Mp4ThumbnailExtractor()
    {
        waitHandle = new ManualResetEvent(false);
        mediaOpenTimeout = TimeSpan.Parse("00:00:15");
    }

    public MemoryStream CreateThumbnail(string videoPath)
    {
        MemoryStream memory = new MemoryStream();
        Uri sourceUri = new Uri(videoPath);

        MediaPlayer media = new MediaPlayer();
        media.MediaOpened += Media_MediaOpened;
        media.ScrubbingEnabled = true;

        try
        {
            media.Open(new Uri(videoPath));

            //TODO: media.opened event will not get fired
            Thread.Sleep(mediaOpenTimeout);
            waitHandle.Set();

            //15sec timeout for loading the media
            if (waitHandle.WaitOne(mediaOpenTimeout))
            {
                SetPosition(media);

                //TODO: this is bad...
                Thread.Sleep(2000);

                DrawingVisual dv = new DrawingVisual();
                DrawingContext dc = dv.RenderOpen();
                dc.DrawVideo(media, new Rect(0, 0, Width, Height));
                dc.Close();
                RenderTargetBitmap bmp = new RenderTargetBitmap(Width, Height, Dpi, Dpi, PixelFormats.Pbgra32);
                bmp.Render(dv);

                JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(bmp));
                encoder.Save(memory);

                memory.Seek(0, SeekOrigin.Begin);
            }
            else
            {
                throw new Exception($"Unable to open media '{videoPath}' in '{mediaOpenTimeout}'");
            }
        }
        finally
        {
            media.Close();
        }
        return memory;
    }

    private void SetPosition(MediaPlayer player)
    {
        if (player.NaturalDuration.HasTimeSpan)
        {
            TimeSpan naturalTime = player.NaturalDuration.TimeSpan;
            if (naturalTime < Time)
            {
                if (naturalTime > FallbackTime)
                {
                    player.Position = FallbackTime;
                }
            }
            else
            {
                player.Position = Time;
            }
        }
    }

    private void Media_MediaOpened(object sender, EventArgs e)
    {
        waitHandle.Set();
    }

    public void Dispose()
    {
        waitHandle.Dispose();
    }
}
1

There are 1 best solutions below

1
On BEST ANSWER

MediaElement is basically a visual control for hosting media content:

Represents a control that contains audio and/or video

You need a UI-less MediaPlayer. Just don't forget to call Open method or MediaOpened won't fire.