From 759442cc83566998b0dfe6ba9e9f62f9818d2b45 Mon Sep 17 00:00:00 2001
From: Smeulf <smeulf@team-mediaportal.com>
Date: Sun, 19 Feb 2012 16:14:50 +0100
Subject: [PATCH] Added Title support to VideoPlayer for MKV Editions

---
 MediaPortal/Incubator/BDHandler/BDPlayer.cs        |    6 +-
 .../Source/UI/Players/VideoPlayer/DvdPlayer.cs     |    6 +-
 .../Source/UI/Players/VideoPlayer/VideoPlayer.cs   |   63 ++++++++++++++++++-
 .../UI/UiComponents/Media/Language/strings_en.xml  |    3 +-
 .../Models/DefaultVideoPlayerUIContributor.cs      |   66 ++++++++++++++++++++
 .../Skin/default/screens/DialogChooseTitle.xaml    |   23 +++++++
 .../default/themes/default/styles/MediaStyles.xaml |    3 +
 7 files changed, 160 insertions(+), 10 deletions(-)
 create mode 100644 MediaPortal/Source/UI/UiComponents/Media/Skin/default/screens/DialogChooseTitle.xaml

diff --git a/MediaPortal/Incubator/BDHandler/BDPlayer.cs b/MediaPortal/Incubator/BDHandler/BDPlayer.cs
index 2605ad9..6b30836 100644
--- a/MediaPortal/Incubator/BDHandler/BDPlayer.cs
+++ b/MediaPortal/Incubator/BDHandler/BDPlayer.cs
@@ -251,15 +251,15 @@ namespace MediaPortal.UI.Players.Video
 
     private readonly string[] _emptyStringArray = new string[0];
 
-    public string[] Titles
+    public override string[] Titles
     {
       get { return _emptyStringArray; }
     }
 
-    public void SetTitle(string title)
+    public override void SetTitle(string title)
     { }
 
-    public string CurrentTitle
+    public override string CurrentTitle
     {
       get { return null; }
     }
diff --git a/MediaPortal/Source/UI/Players/VideoPlayer/DvdPlayer.cs b/MediaPortal/Source/UI/Players/VideoPlayer/DvdPlayer.cs
index 622d7ff..0abf25d 100644
--- a/MediaPortal/Source/UI/Players/VideoPlayer/DvdPlayer.cs
+++ b/MediaPortal/Source/UI/Players/VideoPlayer/DvdPlayer.cs
@@ -892,7 +892,7 @@ namespace MediaPortal.UI.Players.Video
     /// <summary>
     /// Gets the available DVD titles.
     /// </summary>
-    public string[] Titles
+    public override string[] Titles
     {
       get
       {
@@ -914,7 +914,7 @@ namespace MediaPortal.UI.Players.Video
     /// Sets the DVD title to play.
     /// </summary>
     /// <param name="title">DVD title</param>
-    public void SetTitle(string title)
+    public override void SetTitle(string title)
     {
       string[] titles = Titles;
       for (int i = 0; i < titles.Length; ++i)
@@ -930,7 +930,7 @@ namespace MediaPortal.UI.Players.Video
     /// <summary>
     /// Gets the current DVD title.
     /// </summary>
-    public string CurrentTitle
+    public override string CurrentTitle
     {
       get
       {
diff --git a/MediaPortal/Source/UI/Players/VideoPlayer/VideoPlayer.cs b/MediaPortal/Source/UI/Players/VideoPlayer/VideoPlayer.cs
index a56fbfd..9450c43 100644
--- a/MediaPortal/Source/UI/Players/VideoPlayer/VideoPlayer.cs
+++ b/MediaPortal/Source/UI/Players/VideoPlayer/VideoPlayer.cs
@@ -49,7 +49,7 @@ using System.Globalization;
 
 namespace MediaPortal.UI.Players.Video
 {
-  public class VideoPlayer : ISlimDXVideoPlayer, IDisposable, IPlayerEvents, IInitializablePlayer, IMediaPlaybackControl, ISubtitlePlayer, IChapterPlayer
+  public class VideoPlayer : ISlimDXVideoPlayer, IDisposable, IPlayerEvents, IInitializablePlayer, IMediaPlaybackControl, ISubtitlePlayer, IChapterPlayer, ITitlePlayer
   {
     #region Classes & interfaces
 
@@ -149,6 +149,7 @@ namespace MediaPortal.UI.Players.Video
 
     protected StreamInfoHandler _streamInfoAudio = null;
     protected StreamInfoHandler _streamInfoSubtitles = null;
+    protected StreamInfoHandler _streamInfoTitles = null; //Used mostly for MKV Editions
     private readonly object _syncObj = new object();
 
     /// <summary>
@@ -1014,12 +1015,14 @@ namespace MediaPortal.UI.Players.Video
       if (_graphBuilder == null || !_initialized)
         return false;
 
-      if (_streamInfoAudio == null || _streamInfoSubtitles == null)
+      if (_streamInfoAudio == null || _streamInfoSubtitles == null || _streamInfoTitles == null)
       {
         FilterGraphTools.TryDispose(ref _streamInfoAudio);
         FilterGraphTools.TryDispose(ref _streamInfoSubtitles);
+        FilterGraphTools.TryDispose(ref _streamInfoTitles);
         _streamInfoAudio = new StreamInfoHandler();
         _streamInfoSubtitles = new StreamInfoHandler();
+        _streamInfoTitles = new StreamInfoHandler();
 
         foreach (
           IAMStreamSelect streamSelector in FilterGraphTools.FindFiltersByInterface<IAMStreamSelect>(_graphBuilder))
@@ -1073,6 +1076,11 @@ namespace MediaPortal.UI.Players.Video
               _streamInfoSubtitles.AddUnique(currentStream, true);
             }
 
+            if (groupNumber == 18) //This is a MKV Edition handeled by Haali splitter
+            {
+              _streamInfoTitles.AddUnique(currentStream, true);
+            }
+
             // free MediaType and references
             FilterGraphTools.FreeAMMediaType(mediaType);
           }
@@ -1374,6 +1382,7 @@ namespace MediaPortal.UI.Players.Video
       get 
       {
         lock (SyncObj)
+          EnumerateStreams();
           return _chapterNames ?? EMPTY_STRING_ARRAY; 
       }
     }
@@ -1502,6 +1511,55 @@ namespace MediaPortal.UI.Players.Video
 
     #endregion
 
+    #region ITitlePlayer implementation
+
+    public virtual string[] Titles
+    {
+      get
+      {
+        lock (SyncObj)
+        {
+          EnumerateStreams();
+
+          if (_streamInfoTitles == null)
+            return EMPTY_STRING_ARRAY;
+
+          // Check if there are real title streams available.
+          string[] titleStreamNames = _streamInfoTitles.GetStreamNames();
+          if (titleStreamNames.Length == 0)
+            return EMPTY_STRING_ARRAY;
+          return titleStreamNames;
+        }
+      }
+    }
+
+    /// <summary>
+    /// Sets the current subtitle stream.
+    /// </summary>
+    /// <param name="subtitle">subtitle stream</param>
+    public virtual void SetTitle(string title)
+    {
+      lock (SyncObj)
+      {
+        _streamInfoTitles.EnableStream(title);
+        _streamInfoTitles = null; //Will force a stream enumeration by setting _chapterNames to null
+        EnumerateStreams();
+      }
+    }
+
+    public virtual string CurrentTitle
+    {
+      get
+      {
+        lock (SyncObj)
+        {
+          return _streamInfoTitles != null ? _streamInfoTitles.CurrentStreamName : String.Empty;
+        }
+      }
+    }
+
+    #endregion
+
     #region Base overrides
 
     public override string ToString()
@@ -1511,6 +1569,5 @@ namespace MediaPortal.UI.Players.Video
 
     #endregion
 
-
   }
 }
diff --git a/MediaPortal/Source/UI/UiComponents/Media/Language/strings_en.xml b/MediaPortal/Source/UI/UiComponents/Media/Language/strings_en.xml
index 39c730c..2a27370 100644
--- a/MediaPortal/Source/UI/UiComponents/Media/Language/strings_en.xml
+++ b/MediaPortal/Source/UI/UiComponents/Media/Language/strings_en.xml
@@ -231,10 +231,11 @@
     <String Name="PlaylistLoadSomeItemsMissingText" Text="Not all items of the playlist could be loaded. Some items are missing."/>
     <String Name="PlaylistLoadAllItemsMissingText" Text="The playlist could not be loaded, all items of the playlist are missing."/>
 
-    <!-- DVDPlayerUIContributor -->
+    <!-- VideoPlayerUIContributor -->
     <String Name="SubtitleOff" Text="Disable Subtitles"/>
     <String Name="ChooseChapterDialogHeader" Text="Choose chapter"/>
     <String Name="ChooseSubtitleDialogHeader" Text="Choose subtitle"/>
+    <String Name="ChooseTitleDialogHeader" Text="Choose title"/>
 
     <!-- Video Player time units -->
     <String Name="Seconds" Text="sec"/>
diff --git a/MediaPortal/Source/UI/UiComponents/Media/Models/DefaultVideoPlayerUIContributor.cs b/MediaPortal/Source/UI/UiComponents/Media/Models/DefaultVideoPlayerUIContributor.cs
index ea89548..e93c08a 100644
--- a/MediaPortal/Source/UI/UiComponents/Media/Models/DefaultVideoPlayerUIContributor.cs
+++ b/MediaPortal/Source/UI/UiComponents/Media/Models/DefaultVideoPlayerUIContributor.cs
@@ -46,6 +46,7 @@ namespace MediaPortal.UiComponents.Media.Models
     {
       _subtitlesAvailableProperty = new WProperty(typeof(bool), false);
       _chaptersAvailableProperty = new WProperty(typeof(bool), false);
+      _titlesAvailableProperty = new WProperty(typeof(bool), false);
       StartTimer();
     }
 
@@ -63,6 +64,11 @@ namespace MediaPortal.UiComponents.Media.Models
     protected string[] _chapters = EMPTY_STRING_ARRAY;
     protected ItemsList _chapterMenuItems;
 
+    protected ITitlePlayer _titlePlayer;
+    protected AbstractProperty _titlesAvailableProperty;
+    protected string[] _titles = EMPTY_STRING_ARRAY;
+    protected ItemsList _titleMenuItems;
+
     protected bool _updating;
 
     #endregion
@@ -89,6 +95,17 @@ namespace MediaPortal.UiComponents.Media.Models
       set { _chaptersAvailableProperty.SetValue(value); }
     }
 
+    public AbstractProperty TitlesAvailableProperty
+    {
+      get { return _titlesAvailableProperty; }
+    }
+
+    public bool TitlesAvailable
+    {
+      get { return (bool)_titlesAvailableProperty.GetValue(); }
+      set { _titlesAvailableProperty.SetValue(value); }
+    }
+
     /// <summary>
     /// Provides a list of items to be shown in the subtitle selection menu.
     /// </summary>
@@ -151,6 +168,37 @@ namespace MediaPortal.UiComponents.Media.Models
       }
     }
 
+    /// <summary>
+    /// Provides a list of items to be shown in the title selection menu.
+    /// </summary>
+    public ItemsList TitleMenuItems
+    {
+      get
+      {
+        _titleMenuItems.Clear();
+        ITitlePlayer titlePlayer = _titlePlayer;
+        if (titlePlayer != null && _titles.Length > 0)
+        {
+          string currentTitle = titlePlayer.CurrentTitle;
+
+          foreach (string title in _titles)
+          {
+            // Use local variable, otherwise delegate argument is not fixed
+            string localTitle = title;
+
+            ListItem item = new ListItem(Consts.KEY_NAME, localTitle)
+            {
+              Command = new MethodDelegateCommand(() => titlePlayer.SetTitle(localTitle)),
+              // Check if it is the selected subtitle, then mark it
+              Selected = localTitle == currentTitle
+            };
+
+            _titleMenuItems.Add(item);
+          }
+        }
+        return _titleMenuItems;
+      }
+    }
 
     public bool BackgroundDisabled
     {
@@ -179,8 +227,10 @@ namespace MediaPortal.UiComponents.Media.Models
       _mediaWorkflowStateType = stateType;
       _subtitlePlayer = player as ISubtitlePlayer;
       _chapterPlayer = player as IChapterPlayer;
+      _titlePlayer = player as ITitlePlayer;
       _subtitleMenuItems = new ItemsList();
       _chapterMenuItems = new ItemsList();
+      _titleMenuItems = new ItemsList();
     }
 
     // Update GUI properties
@@ -205,6 +255,14 @@ namespace MediaPortal.UiComponents.Media.Models
           }
           else
             _chapters = EMPTY_STRING_ARRAY;
+
+          if (_titlePlayer != null)
+          {
+            _titles = _titlePlayer.Titles;
+            TitlesAvailable = _titles.Length > 0;
+          }
+          else
+            _titles = EMPTY_STRING_ARRAY;
         }
         finally
         {
@@ -230,6 +288,14 @@ namespace MediaPortal.UiComponents.Media.Models
     }
 
     /// <summary>
+    /// Opens the title selection dialog.
+    /// </summary>
+    public void OpenChooseTitleDialog()
+    {
+      ServiceRegistration.Get<IScreenManager>().ShowDialog("DialogChooseTitle");
+    }
+
+    /// <summary>
     /// Execute selected menu item for subtitle and chapter selection.
     /// </summary>
     /// <param name="item">One of the items of <see cref="SubtitleMenuItems"/>.</param>
diff --git a/MediaPortal/Source/UI/UiComponents/Media/Skin/default/screens/DialogChooseTitle.xaml b/MediaPortal/Source/UI/UiComponents/Media/Skin/default/screens/DialogChooseTitle.xaml
new file mode 100644
index 0000000..c9cf874
--- /dev/null
+++ b/MediaPortal/Source/UI/UiComponents/Media/Skin/default/screens/DialogChooseTitle.xaml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Include
+    xmlns="www.team-mediaportal.com/2008/mpf/directx"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    Source="screens\simple_dialog_menu.xaml"
+    >
+  <Include.Resources>
+    <Service x:Key="ScreenManager" InterfaceName="ScreenManager"/>
+
+    <!-- Dialog title -->
+    <ResourceWrapper x:Key="Dialog_Header_Text" Resource="[Media.ChooseTitleDialogHeader]"/>
+
+    <Model x:Key="VideoPlayerModel" Id="4E2301B4-3C17-4a1d-8DE5-2CEA169A0256"/>
+
+    <ResourceWrapper x:Key="Menu_Items" EnableBindings="True"
+        Resource="{Binding Source={StaticResource VideoPlayerModel},Path=PlayerUIContributor.TitleMenuItems,Mode=OneTime}"/>
+
+    <!-- Command -->
+    <CommandStencil x:Key="Execute_Command_Stencil"
+        Source="{StaticResource VideoPlayerModel}" Path="PlayerUIContributor.Select"/>
+  </Include.Resources>
+</Include>
diff --git a/MediaPortal/Source/UI/UiComponents/Media/Skin/default/themes/default/styles/MediaStyles.xaml b/MediaPortal/Source/UI/UiComponents/Media/Skin/default/themes/default/styles/MediaStyles.xaml
index 7de3d8d..f5b0f97 100644
--- a/MediaPortal/Source/UI/UiComponents/Media/Skin/default/themes/default/styles/MediaStyles.xaml
+++ b/MediaPortal/Source/UI/UiComponents/Media/Skin/default/themes/default/styles/MediaStyles.xaml
@@ -137,6 +137,9 @@
                     Command="{Command SeekForward}"/>
                 <Button x:Name="SkipForwardButton" Style="{ThemeResource SkipForwardButtonStyle}" Margin="5,0,5,0" IsVisible="{Binding CanSkipForward}"
                     Command="{Command Next}"/>
+                <Button x:Name="SelectTitleButton" Style="{ThemeResource ShowDvdMenuButtonStyle}" Margin="5,0,5,0"
+                  IsVisible="{Binding Source={StaticResource VideoPlayerModel},Path=PlayerUIContributor.TitlesAvailable}"
+                  Command="{Command Source={StaticResource VideoPlayerModel},Path=PlayerUIContributor.OpenChooseTitleDialog}"/>
                 <Button x:Name="PreviousChapterButton" Style="{ThemeResource PreviousChapterButtonStyle}" Margin="5,0,5,0"
                     IsVisible="{Binding Source={StaticResource VideoPlayerModel},Path=PlayerUIContributor.ChaptersAvailable}"
                     Command="{Command Source={StaticResource VideoPlayerModel},Path=PlayerUIContributor.PrevChapter}"/>
-- 
1.7.6.msysgit.0

