Click here to Skip to main content
15,891,136 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am working on a video project. In that project there will be a video playing for the user, and if the user clicks a button- that video is changed to the next one. Point is, the next video will play from the point the previous one stopped in (So if the user presses the NEXT button at 00:00:30 the next video will play from that point).

The problem I am facing is that there are always a few moments of black screen until the next video will play, and I want the change to be smooth without the user watching a black screen for a second or two. In one of my tries I have managed to get rid of the black screen but then a new problem appears - the timing of the switch is not 100% perfect.
So far, I've tried to solve it with different approaches :

Approach one: (For some reason still shows a black screen while having time delay)
C#
<Window x:Class="Media.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <Storyboard x:Key="ShowSecond">
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="firstMediaElement">
            <DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static Visibility.Collapsed}"/>
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="secondMediaElement">
            <DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static Visibility.Visible}"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Window.Triggers>
    <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="btnlaunchNext">
        <BeginStoryboard Storyboard="{StaticResource ShowSecond}"/>
    </EventTrigger>
</Window.Triggers>
<Grid>
    <StackPanel removed="Black">

        <MediaElement Name="firstMediaElement" LoadedBehavior="Manual" Source="firstFile.mp4" Width="260" Height="150" Stretch="Fill" />
        <MediaElement Name="secondMediaElement" Volume="0" LoadedBehavior="Manual" Source="secondFile.mp4" Visibility="Collapsed" Width="260" Height="150" Stretch="Fill" />

        <!-- Buttons to launch videos. -->
        <Button x:Name="btnlaunch" Content="PLAY FIRST" Click="OnLaunchFirstButtonClick"/>
        <Button x:Name="btnlaunchNext" Content="PLAY NEXT" Click="OnLaunchNextButtonClick"/>

    </StackPanel>
</Grid>
 </Window>


and the .cs :
C#
    using System;
using System.Timers;
using System.Windows;

namespace Media
{
    /// <summary>
    /// Interaction logic for pour MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public TimeSpan Position { get; set; }

    Timer _updateTimer;

    public MainWindow()
    {
        InitializeComponent();

        //Timer interval fixed to 1 second to read the actual position of the first media element
        this._updateTimer = new Timer(1000);
        this._updateTimer.Elapsed += this.UpdateTimerElapsed;
    }

    //The callback of your update timer
    private void UpdateTimerElapsed(object sender, ElapsedEventArgs e)
    {
        //I use the dispatcher because you call the Position from another thread so it has to be synchronized
        Dispatcher.Invoke(new Action(() => this.Position = firstMediaElement.Position));
    }

    //When stopping the first, you start the second and set its Position
    private void OnLaunchNextButtonClick(object sender, RoutedEventArgs e)
    {
        this.firstMediaElement.Stop();

        this.secondMediaElement.Volume = 10;
        this.secondMediaElement.Play();
        this.secondMediaElement.Position = this.Position;
    }

    //When you start the first, you have to start the update timer
    private void OnLaunchFirstButtonClick(object sender, RoutedEventArgs e)
    {
        this.firstMediaElement.Play();
        this._updateTimer.Start();
    }
}


The second approach(Perfect timing + Black screen):
C#
TimeSpan Time = mediaElement1.Position;
mediaElement1.Source = new Uri(NEW PATH);
mediaElement1.Position = Time;
mediaElement1.Play();


Third approach(Using two mediaElements and a timer to smooth the change up[There's no black screen!], still the timing is not perfect - obviously.. and it is a hard time for the machine to play 2 videos at the same time):
C#
mediaElement2.Source = new Uri(VideoArr[Index].FullName);
mediaElement2.Position = mediaElement1.Position + new TimeSpan(0, 0, 1); ;
mediaElement2.Play();
mediaElement2.Volume = 0;
mediaElement2.Visibility = Visibility.Visible;
Stopwatch st = new Stopwatch();
st.Start();
while (st.ElapsedMilliseconds < 1000) { }
mediaElement1.Visibility = Visibility.Collapsed;
mediaElement2.Volume = 0.5;
mediaElement1.Source = null;
mediaElement1.Position = new TimeSpan();


Thanks in advance for any light on that matter, couldn't find a way to succeed in both preventing the black screen while keeping a perfect timing while transfering the videos.
EDIT : Using MediaKit can not help because it does not support .MP4's.
Posted
Updated 19-Jan-14 1:36am
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900