Search code examples
c#wpfmediaelement

WPF MediaElement briefly stutters when trying to buffer/preload next video


Am trying to write a program that can play a series of video files in a smooth manner as if it were just one long video. Previous questions on the topic I found online recommended preloading/buffering next video and then switching over only once the new video is ready. I've written a test program doing just that.

The switching between current player / next player with the buffered video works fine, but there is a brief stutter in the playback (only a fraction of a second, but very noticeable) when I assign the new MediaElement.Source / open the next file.

Any idea on how to solve this? do I need to split off a thread with Task.Run()? (but am afraid that will create ownership conflicts with the UI thread...). Is this just a performance limitation with MediaElement and are there workarounds / alternatives? would this https://github.com/unosquare/ffmediaelement work better for instance?

the really crazy thing btw. is that i even tried to open 2 different windows, with second window on its own thread, but the first video still stutters when the second window is loading its file.

thanks!

I have written the simple test program below.

Window has 3 superimposed MediaElements, Player1/Player2/Player3. Player1 is always playing even when hidden (i need that for other reasons that are not relevant to current problem). Two of the players are hidden at all times (opacity = 0) and I preload the next video into a hidden player while another one is visible and playing.

As said above, the problem is that the playback in the visible player stutters briefly when the hidden player loads the next file.

MainWindow.xaml:

<Window x:Class="Test_App.MainWindow"
        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:Test_App"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
        <Grid>
            <MediaElement x:Name="Player1" MediaOpened="P1MediaOpened" Stretch="UniformToFill" LoadedBehavior="Manual" UnloadedBehavior="Stop" />
            <MediaElement x:Name="Player2" Stretch="UniformToFill" LoadedBehavior="Manual" UnloadedBehavior="Stop" />
            <MediaElement x:Name="Player3" Stretch="UniformToFill" LoadedBehavior="Manual" UnloadedBehavior="Stop" />
        </Grid>
</Window>type here

cs file:

namespace Test_App
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Player2.Opacity = 0.0;
            Player3.Opacity = 0.0;
            Player2.Volume = 0.0;
            Player3.Volume = 0.0;
            Player1.Source = new Uri("I:BaseVideo.mp4");
            Player1.Play();

            Loaded += LoadNextVideos;
        }

        private async void LoadNextVideos(object sender, RoutedEventArgs e)
        {
            Player2.Source = new Uri("002.mp4");
            await Task.Delay(3000);
            
            Player2.Play();
            Player2.Opacity = 1.0;
            Player1.Opacity = 0.0;
            await Task.Delay(2000);
            Player3.Source = new Uri("003.mp4");
            await Task.Delay(2000);
            Player3.Play();
            Player3.Opacity = 1.0;
            Player2.Opacity = 0.0;
            Player2.Pause();
            await Task.Delay(2000);
            Player2.Source = new Uri("004.mp4");
            await Task.Delay(2000);

            Player2.Play();
            Player2.Opacity = 1.0;
            Player3.Opacity = 0.0;
            Player3.Pause();
            await Task.Delay(2000);
            Player3.Source = new Uri("005.mp4");
            await Task.Delay(2000);
            Player3.Play();
            Player3.Opacity = 1.0;
            Player2.Opacity = 0.0;
            Player2.Pause();
            await Task.Delay(2000);
            Player2.Source = new Uri("006.mp4");
            await Task.Delay(2000);
        }

Solution

  • Ok in the end I gave up on trying to solve this with wpf mediaelement and switched to using FMME, which turns out to not have the stuttering issue. I'll close this question.