Microsoft Media Platform: Player Framework

This guide is provided to assist an integrator with the use of the Microsoft SDK with the various Microsoft Devices. We currently support the Window 8.1 Store and Windows Phone 8.1.

Downloads

Please contact our support for the link to download the latest version of this library.

Uplynk MMPPF Plugin for Windows Store 8.1 & Windows Phone 8.1

The Windows Store and Phone devices require version 2.0.0 of the Microsoft Media Platform Player Framework.

The Microsoft SDK provided by Uplynk comes with three plugins. UplynkMediaPlugin, UplynkClosedCaptionPlugin and UplynkCaptionSettingsPlugin. All of these can be instantiated and added to a MMPPF media player instance. Most of the APIs can be accessed directly through the MediaPlayer. However, Uplynk provides a few more API's that are available. These API's are just for the UplynkMediaPlugin.

Events

Method Description

public void SelectAudioTrack(AudioTrack track)

Sets the selected audio track

public AudioTrack SelectedAudioTrack

Gets the selected audio track

Basic Playback

Basic playback using the UplynkMediaPlugin

XAML sample code:

<mmppf:MediaPlayer
    x:Name="player"/>

C# sample code:

uplynkPlugin = new UplynkMediaPlugin();
uplynkPlugin.AssetIDChanged += uplynkPlugin_AssetIDChanged;

player.Plugins.Add(uplynkPlugin);
player.Source = new Uri("https://content.uplynk.com/52ab86c3f6c74d6abf7f162204d51609.m3u8?ad=sample_ads&ad.preroll=1");

...

void uplynkPlugin_AssetIDChanged(AssetInfo obj)
{
    Debug.WriteLine("URL: {0}, AssetInfo: {1}", player.Source, obj.Description);
}

Closed Captions

Captions can be enabled by adding the UplynkClosedCaptionPlugin and UplynkCaptionSettingsPlugin

XAML sample code:

<mmppf:MediaPlayer
    x:Name="player"
    Source="https://content.uplynk.com/52ab86c3f6c74d6abf7f162204d51609.m3u8"
    IsCaptionSelectionVisible="True"/>

C# sample code:

uplynkPlugin = new UplynkMediaPlugin();
captionsPlugin = new UplynkClosedCaptionPlugin();
captionSettingsPlugin = new UplynkCaptionSettingsPlugin();

player.Plugins.Add(uplynkPlugin);
player.Plugins.Add(captionsPlugin);
player.Plugins.Add(captionSettingsPlugin);

captionsPlugin.CaptionChannelAvailable += captionsPlugin_CaptionChannelAvailable;

player.IsCaptionSelectionVisible = true;

...

void captionsPlugin_CaptionChannelAvailable(Caption caption)
{
    if (caption.Id == "CC1")
    {
        player.SelectedCaption = caption;
    }
}

Thumbnails

Example showing how to use thumbnails for seeking. A dependency function - GetThumbnail - can be found further below in the UplynkExtensions example.

XAML sample code:

<mmppf:MediaPlayer
    x:Name="player" IsTrickPlayEnabled="False" IsFastForwardVisible="True" IsRewindVisible="True"
    SeekWhileScrubbing="False"/>

C# sample code:

using Windows.UI.Xaml.Media.Imaging;
using Uplynk.HLS.M3U8;
using Uplynk.Plugin;

...

private string currentThumbnailUrl;
private List<Segment> currentSegmentMap;

...

player.VirtualPositionChanged += player_VirtualPositionChanged;
player.RateChanged += player_RateChanged;
player.IsScrubbingChanged += player_IsScrubbingChanged;

var plugin = new UplynkMediaPlugin();
plugin.SegmentMapChanged += plugin_OnSegmentMapChanged;
player.Plugins.Add(plugin);

player.Source = new Uri("https://content.uplynk.com/52ab86c3f6c74d6abf7f162204d51609.m3u8?ad=sample_ads&ad.preroll=1");

...

private void plugin_OnSegmentMapChanged(List<Segment> segments)
{
    currentSegmentMap = segments;
}

void player_IsScrubbingChanged(object sender, RoutedEventArgs e)
{
    player.IsThumbnailVisible = (player.IsScrubbing || player.PlaybackRate < -1 || player.PlaybackRate > 1);
}

void player_RateChanged(object sender, RateChangedRoutedEventArgs e)
{
    player.IsThumbnailVisible = (player.IsScrubbing || player.PlaybackRate <= -1 || player.PlaybackRate > 1);
}

async void player_VirtualPositionChanged(object sender, RoutedPropertyChangedEventArgs<TimeSpan> e)
{
    if (player.IsThumbnailVisible && currentSegmentMap != null && currentSegmentMap.Count > 0)
    {
        string thumbnailUrl = await uplynk.UplynkExtensions.GetThumbnail(currentSegmentMap, e.NewValue.TotalSeconds);

        if (thumbnailUrl != currentThumbnailUrl && thumbnailUrl != null)
        {
            currentThumbnailUrl = thumbnailUrl;
            var thumbnailUri = new Uri(thumbnailUrl);
            player.ThumbnailImageSource = new BitmapImage(thumbnailUri);
        }
    }
}

UplynkExtensions

C# sample code:

// This is just an example. It doesn't cover every use case and isn't recommended for production use.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Uplynk.HLS.Domain;
using Uplynk.HLS.M3U8;
using Uplynk.HLS.Parsers;

namespace uplynk
{
    public static class UplynkExtensions
    {

        private static Dictionary<string,AssetInfo> _assetInfoCache;

        public static async Task<string> GetThumbnail( List<Segment> currentSegmentMap, double currentPosition )
        {
            if (_assetInfoCache == null)
            {
                _assetInfoCache = new Dictionary<string, AssetInfo>();
            }


            var currentSegment = GetCurrentAssetFromSegments(currentSegmentMap, ref currentPosition);

            if (currentSegment == null)
            {
                return null;
            }

            var url = currentSegment.GetAssetInfoUrl;
            AssetInfo currentAssetInfo = null;

            if (_assetInfoCache.ContainsKey(url))
            {
                var assetInfo = _assetInfoCache[url];
                if (assetInfo == null)
                {
                    //Still Loading....
                    return null;
                }

                currentAssetInfo = assetInfo;

            }
            else
            {
                _assetInfoCache.Add(url, null);

                var client = new HttpClient();
                HttpResponseMessage response = await client.GetAsync(new Uri(url));
                var jsonText = await response.Content.ReadAsStringAsync();
                currentAssetInfo = JsonParser.ParseAssetInfo(jsonText);

                _assetInfoCache[url] = currentAssetInfo;
            }

            AssetInfoThumb selectedThumbSize = null;

            //We want to select the biggest sized thumbnails available (based on height).

            if (currentAssetInfo.Thumbs != null && currentAssetInfo.Thumbs.Length > 0)
            {
                foreach (var thumb in currentAssetInfo.Thumbs)
                {
                    if (selectedThumbSize == null)
                    {
                        selectedThumbSize = thumb;
                    }
                    else if (thumb.Bh > selectedThumbSize.Bh)
                    {
                        selectedThumbSize = thumb;
                    }
                }
            }

            var thumbnailUrl = GetThumbUrl(currentAssetInfo, currentPosition, currentSegment.Index, selectedThumbSize);
            return thumbnailUrl;
        }

        private static Segment GetCurrentAssetFromSegments(List<Segment> segments, ref double position)
        {
            Segment segment = null;
            double offset = 0;

            foreach (var seg in segments)
            {
                double segDuration = seg.Duration.TotalSeconds;

                if (offset <= position && segDuration + offset >= position)
                {
                    segment = seg;
                    break;
                }
                else
                {
                    offset += segDuration;
                }
            }

            position -= offset;

            return segment;
        }

        private static string GetThumbUrl(AssetInfo assetInfo, double position, uint index, AssetInfoThumb thumb)
        {
            uint thumbIndex = (uint)Math.Round(position / assetInfo.SliceDuration);
            thumbIndex += index;

            if (thumb == null)
            {
                return string.Format("{0}{1:X8}.jpg", assetInfo.ThumbPrefix, thumbIndex);
            }

            return string.Format("{0}{1}{2:X8}.jpg", assetInfo.ThumbPrefix, thumb.Prefix, thumbIndex);
        }

    }
}