Customer Sign In

upLynk

Microsoft Universal SDK

Overview

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 upLynk 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
  • UplynkMediaPlugin.AssetIDChanged
    • OnAssetIDChanged(AssetInfo assetInfo)
  • UplynkMediaPlugin.SegmentMapChanged
    • OnSegmentMapChanged(List<Segment> segments)
  • UplynkMediaPlugin.AudioTracksLoaded
    • OnAudioTracksLoaded(List<AudioTrack> audioTracks)
  • UplynkMediaPlugin.AudioTrackSelected
    • OnAudioTrackSelected()
  • UplynkMediaPlugin.PlaybackBitrateChanged
    • OnPlaybackBitrateChanged(long bitrate)
  • UplynkMediaPlugin.ID3Data
    • OnID3Data(ID3Frame obj)
Methods
public void SelectAudioTrack(AudioTrack track)Sets the selected audio track
public AudioTrack SelectedAudioTrackGets the selected audio track

Basic Playback

Basic playback using the UplynkMediaPlugin

Example:

XAML Code
1
2
<mmppf:MediaPlayer
    x:Name="player"/>
C# Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
uplynkPlugin = new UplynkMediaPlugin();
uplynkPlugin.AssetIDChanged += uplynkPlugin_AssetIDChanged;

player.Plugins.Add(uplynkPlugin);
player.Source = new Uri("http://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

Example:

XAML Code
1
2
3
4
<mmppf:MediaPlayer
    x:Name="player"
    Source="http://content.uplynk.com/52ab86c3f6c74d6abf7f162204d51609.m3u8"
    IsCaptionSelectionVisible="True"/>
C# Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
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.

Example:

XAML Code
1
2
3
<mmppf:MediaPlayer
    x:Name="player" IsTrickPlayEnabled="False" IsFastForwardVisible="True" IsRewindVisible="True"
    SeekWhileScrubbing="False"/>
C# Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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("http://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# Code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 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);
        }

    }
}