Playing Subtitles with Videos in Silverlight

Introduction:

This article is about playing subtitles in a video in Silverlight. It is really very easy to implement this functionality.

Background:

I had a requirement for playing titles with videos in Silverlight.

I started implementing this feature by using a timer. We can set the timer interval to 500 ms and the timer will trigger the event every 500 ms. We can put our logic to show/hide the title bar and achieve our goal, but this approach has an issue. There will be buffering in the video and that will make the timer out of sync with the position of the video, so this approach can't handle the media buffering scenario.

I found another way to implement the same. MediaElement has a collection of timeline markers associated with the currently loaded media element. The collection is cleared and repopulated each time the MediaElement opens a new media file, and is only considered valid after the MediaOpened event has occurred. For more information on markers, follow this link:

https://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement.markers(VS.95).aspx.

The reader should be aware of Silverlight basics and the MediaElement control to follow this article.

Using the Code:

I didn't add the media file with the Zip file, so before running the solution, you have to add a WMV file with the name "SUP015.wmv" in the ClientBin folder of the web project.

Define the title class which should have the start time of the title, the end time of the title, and the message of the title.

public class Title
{
    public string Id { get; set; }
    public double InTime { get; set; }
    public double OutTime { get; set; }
    public string Message { get; set; }
}

We can use the MarkerReached event to get a notification whenever the video reaches the title start or end time. The MarkerReached event is not raised when the MediaElement seeks past a timeline marker. This event is raised whenever a marker associated with the media is reached. The marker might come from one of three locations: stored in the metadata of the currently opened media, associated with the currently opened media, or coming from a separate stream, explicitly added to the Markers collection for the currently opened media, using script. We can subscribe to the above event in the MediaElement loaded event.

this.MediaEl.MarkerReached +=
  new TimelineMarkerRoutedEventHandler(MediaEl_MarkerReached);

Before playing the media, we have to add markers for all the titles. We can use the two properties of the markers for this: Time and Type. Time is the time span at which the MediaElement will raise the MarkerReached event, and Type is a string which can be used to identify the title when the MarkerReached event occurs. We can use the following code to add all the titles to the Markers collection:

private void AddMarker()
{
    foreach(Title comment in list)
    {
        this.MediaEl.Markers.Add(new TimelineMarker(){
            Time = TimeSpan.FromSeconds(comment.InTime),
            Type = comment.Id.ToString() + ":Start", Text = "Test"});
        this.MediaEl.Markers.Add(new TimelineMarker() {
            Time = TimeSpan.FromSeconds(comment.OutTime),
            Type = comment.Id.ToString() + ":End", Text = "Test" });
    }
}

Here, we are using Type to identify the title as well as if it's the start or the end of the title. We are adding every title twice to the Markers collection, once for the start of the title and once for the end of the title.

Following is the code for the MarkerReached event:

private void MediaEl_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
{
    string[] array = e.Marker.Type.Split(':');
    if(array != null && array.Length == 2)
    {
        if(array[1] == "Start")
        {
            Title comment = list.SingleOrDefault(x => x.Id == array[0]);
            if(comment != null)
            {
                this.CommentCanas.Visibility = System.Windows.Visibility.Visible;
                CommentText.Text = comment.Message + " TimeSpan:" +
                                   this.MediaEl.Position.ToString();
            }
        }
        else if(array[1] == "End")
        {
            this.CommentCanas.Visibility = System.Windows.Visibility.Collapsed;
            CommentText.Text = string.Empty;
        }
    }
}

We can get the Type value of the marker from the event arguments. The Type contains the unique ID of the title to identify the title, and Start or End to identify the start or end of the title. If it is Start, then we can set the Visibility of the Canvas to Visible and set the text. If it is End, then we can set the Visibility of the Canvas to Collapsed.

TitlesInVideoPlayer_src.zip