Over a million developers have joined DZone.

Displaying Subtitles using Timeline Markers in Windows Phone 7 media applications

· Mobile Zone

Learn how to Deliver Better Mobile Apps Faster with Continuous Quality by managing the complexities of testing multiple devices and scenarios with this whitepaper from Perfecto Mobile.

In this tutorial I will show my custom implementation of subtitles using Timeline Markers. Timeline Markers are usually used with SmoothStreamingMediaElement, but in my tutorial I am going to use TimelineMarker and TimelineMarkerCollection classes for my custom Media Player control.

eugenedotnet subtitles for media element using timeline markers

Creating XAML

First step is to create a XAML for our custom Player user control. I have used a very simple version of it that contains only a textbox for displaying subtitle and a MediaElement.

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <MediaElement Grid.Row="0" Height="350" x:Name="meElement" />
    <TextBlock Grid.Row="0" x:Name="tbMarker" Margin="10,0,10,35"
                VerticalAlignment="Bottom" TextWrapping="Wrap" />
</Grid>

Adding properties to codebehind

Next we need to add properties to hold a current timeline marker and a collection of timeline markers for a video. Each timeline marker represents a single subtitle.

private TimelineMarkerCollection Markers { get; set; }
 
private TimelineMarker _currentMarker;
public TimelineMarker CurrentMarker
{
    get
    {
        return _currentMarker;
    }
    set
    {
        _currentMarker = value;
        tbMarker.Text = _currentMarker != null ?
            _currentMarker.Text : string.Empty;
        tbMarker.Visibility = _currentMarker != null ?
            Visibility.Visible : Visibility.Collapsed;
    }
}

Creating Mock Subtitles (Timeline Markers)

During the next step I have created a mock TimelineMarkerCollection representing subtitles for a video content. TimelineMarker is generated every 400 milliseconds and not generated during 5000-10000 millisecond time span.

public static TimelineMarkerCollection CreateMockMarkers(TimeSpan duration)
{
    TimelineMarkerCollection tmc = new TimelineMarkerCollection();
    for (double i = 400; i < duration.TotalMilliseconds; i = i + 400)
    {
        if (i < 5000 || i > 10000)
        {
            tmc.Add(new TimelineMarker()
            {
                Text = string.Format("Some Text at {0}", i),
                Time = TimeSpan.FromMilliseconds(i)
            });
        }
    }
    return tmc;
}

Searching for current marker

Most important step is to find current marker. I want each of my markers to display not longer than 3000 milliseconds (MAXIMUM_MARKER_DURATION variable). Search for a current marker should be accomplished within MediaElement position change event(this event is implemented using DispatcherTimer, also check the next section “Full version of codebehind” to understand the event logic here). Bellow is a code I’ve used for searching.

private void CheckMarkers(double position)
{
    if (Markers != null && Markers.Any())
    {
        CurrentMarker = (from item in Markers
            where item.Time != null
            && item.Time.TotalMilliseconds <= (position + MAXIMUM_MARKER_DURATION)
            && item.Time.TotalMilliseconds >= position
            orderby item.Time descending
            select item).FirstOrDefault();
    }
}

Full version of codebehind

Bellow is a full version of codebehind I’ve used for Player control:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Data;
using System.Globalization;
using System.ComponentModel;
 
namespace EugeneDotnetWPSamples.MediaPlayer
{
    public partial class MediaPlayer : UserControl
    {
 
        DispatcherTimer currentPosition = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(200) };
 
        private double MAXIMUM_MARKER_DURATION = 3000;
 
        private TimelineMarkerCollection Markers { get; set; }
 
        private TimelineMarker _currentMarker;
 
        public TimelineMarker CurrentMarker
        {
            get
            {
                return _currentMarker;
            }
            set
            {
                _currentMarker = value;
                tbMarker.Text = _currentMarker != null ?
                    _currentMarker.Text : string.Empty;
                tbMarker.Visibility = _currentMarker != null ?
                    Visibility.Visible : Visibility.Collapsed;
            }
        }
 
        public MediaPlayer()
        {
            InitializeComponent();
 
            meElement.Source = new Uri(@"http://vnfiles.ign.com/nwvault.ign.com/fms/files/movies/53/CEP1080028433040trailer_low.wmv");
 
            meElement.MediaOpened += (s, e) =>
            {
                Markers = CreateMockMarkers(meElement.NaturalDuration.TimeSpan);
            };
 
            currentPosition.Tick += (s, e) =>
                {
                    CheckMarkers(meElement.Position.TotalMilliseconds);
                };
 
            meElement.CurrentStateChanged += (s, e) =>
            {
                if (meElement.CurrentState == MediaElementState.Playing)
                    currentPosition.Start();
                else
                    currentPosition.Stop();
            };
        }
 
        private void CheckMarkers(double position)
        {
            if (Markers != null && Markers.Any())
            {
                CurrentMarker = (from item in Markers
                                 where item.Time != null
                                 && item.Time.TotalMilliseconds <= (position + MAXIMUM_MARKER_DURATION)
                                 && item.Time.TotalMilliseconds >= position
                                 orderby item.Time descending
                                 select item).FirstOrDefault();
            }
        }
 
        public static TimelineMarkerCollection CreateMockMarkers(TimeSpan duration)
        {
            TimelineMarkerCollection tmc = new TimelineMarkerCollection();
            for (double i = 400; i < duration.TotalMilliseconds; i = i + 400)
            {
                if (i < 5000 || i > 10000)
                {
                    tmc.Add(new TimelineMarker()
                    {
                        Text = string.Format("Some Text at {0}", i),
                        Time = TimeSpan.FromMilliseconds(i)
                    });
                }
            }
            return tmc;
        }
    }
}

Source: http://www.eugenedotnet.com/2011/01/w15-displaying-subtitles-using-timeline-markers/

Do you know Why Apps Succeed? Perfecto Mobile analyzed over 1,000 responses to their Digial Quality Strategies survey and aim to answer the question, "Why do apps succeed?" in this exclusive report.

Topics:

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}