Skip to content

Commit bfc342e

Browse files
committed
Added Subtitle Track selector
Implemented the ability to select a subtitle track on the video player page. Added a SubtitleAudioTrackSelector UserControl. This UserControl hosts the subtitle tracks and will also host the audio tracks from which a user can select a track. Introduced a MediaTrackService which can be injected to provider some methods. Methods it provide are at this moment the retrieval of subtitle tracks and the preferred subtitle track. Due to LibVLC not being able to be injected by a dependency injector due to several reasons, this service needs to be initialized by calling the initialize method and providing it with a reference to a (initialized!) MediaPlayer instance. This service can be expanded to perform more general MediaPlayer tasks as well in the future if need be. Added a ValueConverterGroup enabling the chaining of value converters. Added a custom exception which gets thrown when one of the the MediaTrackService methods get called without the service being initialized. Added MediaTrackService to the dependency Injector container in App.xaml.cs. Replaced public mediaplayer property calls with private.
1 parent c8f4558 commit bfc342e

11 files changed

Lines changed: 479 additions & 43 deletions

OneDrive-Cloud-Player/App.xaml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Microsoft.Extensions.DependencyInjection;
55
using Microsoft.Identity.Client;
66
using OneDrive_Cloud_Player.Models.GraphData;
7+
using OneDrive_Cloud_Player.Models.Interfaces;
78
using OneDrive_Cloud_Player.Services;
89
using OneDrive_Cloud_Player.Views;
910
using System;
@@ -83,6 +84,7 @@ IServiceProvider ConfigureDependencyInjection()
8384
var serviceCollection = new ServiceCollection();
8485

8586
// Add services for dependency injection here.
87+
serviceCollection.AddTransient<IMediaTrackService, MediaTrackService>();
8688

8789
return serviceCollection.BuildServiceProvider();
8890
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using LibVLCSharp.Shared;
2+
using LibVLCSharp.Shared.Structures;
3+
4+
namespace OneDrive_Cloud_Player.Models.Interfaces
5+
{
6+
public interface IMediaTrackService
7+
{
8+
/// <summary>
9+
/// Needs to be called before using the service.<br />
10+
/// Due to LibVLCSharp's inability for the MediaPlayer to be put into a service, we need to get a reference to the MediaPlayer ourselves instead.<br />
11+
/// Initialize this service by parsing the MediaPlayer object reference for its media tracks.
12+
/// </summary>
13+
/// <param name="mediaPlayer"></param>
14+
/// <returns></returns>
15+
IMediaTrackService Initialize(ref MediaPlayer mediaPlayer);
16+
17+
/// <summary>
18+
/// Get the preferred subtitle track. When no preferred subtitle track is found, a default will be returned.
19+
/// <br />
20+
/// <i>Note: This method should not be called on a LibVLC thread.
21+
/// <see href="https://code.videolan.org/videolan/LibVLCSharp/-/blob/3.x/docs/best_practices.md#do-not-call-libvlc-from-a-libvlc-event-without-switching-thread-first">Here</see> is more info on why.</i>
22+
/// </summary>
23+
/// <returns><see cref="TrackDescription"/> Preferred subtitle track or default</returns>
24+
/// <exception cref="ServiceNotInitializedException"></exception>
25+
TrackDescription GetPreferredSubtitleTrack();
26+
27+
/// <summary>
28+
/// Get the embedded subtitle tracks in the media file.
29+
/// <br />
30+
/// <i>Note: This method should not be called on a LibVLC thread.
31+
/// <see href="https://code.videolan.org/videolan/LibVLCSharp/-/blob/3.x/docs/best_practices.md#do-not-call-libvlc-from-a-libvlc-event-without-switching-thread-first">Here</see> is more info on why.</i>
32+
/// </summary>
33+
/// <returns>Array containing <see cref="TrackDescription"/>'s or empty when no tracks are available</returns>
34+
TrackDescription[] GetEmbeddedSubtitleTracks();
35+
}
36+
}

OneDrive-Cloud-Player/OneDrive-Cloud-Player.csproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,18 @@
130130
<Compile Include="Models\GraphData\CachedDrive.cs" />
131131
<Compile Include="Models\GraphData\CachedDriveItem.cs" />
132132
<Compile Include="Models\GraphData\OneDriveCache.cs" />
133+
<Compile Include="Models\Interfaces\IMediaTrackService.cs" />
133134
<Compile Include="Models\Interfaces\INavigable.cs" />
134135
<Compile Include="Models\MediaWrapper.cs" />
135136
<Compile Include="Properties\AssemblyInfo.cs" />
136137
<Compile Include="Services\Converters\MainPageExplorerConverter.cs" />
137138
<Compile Include="Services\Converters\MediaTimeConverter.cs" />
139+
<Compile Include="Services\Converters\ValueConverterGroup.cs" />
138140
<Compile Include="Services\Helpers\CacheHelper.cs" />
139141
<Compile Include="Services\Helpers\GraphHelper.cs" />
140142
<Compile Include="Services\Helpers\GraphAuthHelper.cs" />
141143
<Compile Include="Services\NavigationService.cs" />
144+
<Compile Include="Services\MediaTrackService.cs" />
142145
<Compile Include="Services\Utilities\JsonHandler.cs" />
143146
<Compile Include="ViewModels\LoginPageViewModel.cs" />
144147
<Compile Include="ViewModels\MainPageViewModel.cs" />
@@ -154,6 +157,9 @@
154157
<Compile Include="Views\SettingsPage.xaml.cs">
155158
<DependentUpon>SettingsPage.xaml</DependentUpon>
156159
</Compile>
160+
<Compile Include="Views\SubtitleAudioTrackSelector.xaml.cs">
161+
<DependentUpon>SubtitleAudioTrackSelector.xaml</DependentUpon>
162+
</Compile>
157163
<Compile Include="Views\VideoPlayerPage.xaml.cs">
158164
<DependentUpon>VideoPlayerPage.xaml</DependentUpon>
159165
</Compile>
@@ -250,6 +256,10 @@
250256
<Generator>MSBuild:Compile</Generator>
251257
<SubType>Designer</SubType>
252258
</Page>
259+
<Page Include="Views\SubtitleAudioTrackSelector.xaml">
260+
<SubType>Designer</SubType>
261+
<Generator>MSBuild:Compile</Generator>
262+
</Page>
253263
<Page Include="Views\VideoPlayerPage.xaml">
254264
<SubType>Designer</SubType>
255265
<Generator>MSBuild:Compile</Generator>
@@ -277,6 +287,12 @@
277287
<PackageReference Include="Microsoft.Toolkit.Mvvm">
278288
<Version>7.1.2</Version>
279289
</PackageReference>
290+
<PackageReference Include="Microsoft.Toolkit.Uwp.UI">
291+
<Version>7.1.3</Version>
292+
</PackageReference>
293+
<PackageReference Include="Microsoft.UI.Xaml">
294+
<Version>2.8.2</Version>
295+
</PackageReference>
280296
<PackageReference Include="Microsoft.Xaml.Behaviors.Uwp.Managed">
281297
<Version>2.0.1</Version>
282298
</PackageReference>

OneDrive-Cloud-Player/Services/Converters/MediaTimeConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace OneDrive_Cloud_Player.Services.Converters
66
class MediaTimeConverter : IValueConverter
77
{
88
object IValueConverter.Convert(object timeMs, Type targetType, object parameter, string language)
9-
{
9+
{
1010
TimeSpan timeSpan = TimeSpan.FromMilliseconds(Convert.ToDouble(timeMs));
1111
return timeSpan.ToString(@"hh\:mm\:ss");
1212
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Windows.UI.Xaml.Data;
5+
6+
namespace OneDrive_Cloud_Player.Services.Converters
7+
{
8+
public class ValueConverterGroup : List<IValueConverter>, IValueConverter
9+
{
10+
public object Convert(object value, Type targetType, object parameter, string language)
11+
{
12+
return this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, language));
13+
}
14+
15+
public object ConvertBack(object value, Type targetType, object parameter, string language)
16+
{
17+
throw new NotImplementedException();
18+
}
19+
}
20+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using LibVLCSharp.Shared;
2+
using LibVLCSharp.Shared.Structures;
3+
using OneDrive_Cloud_Player.Models.Interfaces;
4+
using System;
5+
using System.Diagnostics;
6+
using System.Linq;
7+
using Windows.Storage;
8+
9+
namespace OneDrive_Cloud_Player.Services
10+
{
11+
/// <summary>
12+
/// Manage the media tracks of the libvlcsharp media player instance.
13+
/// </summary>
14+
public class MediaTrackService : IMediaTrackService
15+
{
16+
private MediaPlayer _mediaPlayer;
17+
private bool _isInitialized = false;
18+
private readonly ApplicationDataContainer _userSettings;
19+
20+
public MediaTrackService()
21+
{
22+
_userSettings = ApplicationData.Current.LocalSettings;
23+
}
24+
25+
/// <summary>
26+
/// Due to LibVLCSharp's inability for the MediaPlayer to be put into a service, we need to get a reference to the MediaPlayer ourselves instead.
27+
/// Initialize this service by parsing the MediaPlayer object reference for its media tracks.
28+
/// </summary>
29+
public IMediaTrackService Initialize(ref MediaPlayer mediaPlayer)
30+
{
31+
if (_isInitialized)
32+
{
33+
throw new InvalidOperationException("Service already initialized!");
34+
}
35+
36+
Debug.WriteLine("initializing {0}", this.GetType().Name);
37+
_mediaPlayer = mediaPlayer;
38+
_isInitialized = true;
39+
return this;
40+
}
41+
42+
/// <summary>
43+
/// <inheritdoc/>
44+
/// </summary>
45+
/// <exception cref="InvalidOperationException"></exception>
46+
private void CheckInitializationState()
47+
{
48+
if (!_isInitialized)
49+
{
50+
throw new InvalidOperationException("Service not initialized!");
51+
}
52+
}
53+
54+
/// <summary>
55+
/// <inheritdoc/>
56+
/// </summary>
57+
/// <returns> <inheritdoc/></returns>
58+
public TrackDescription GetPreferredSubtitleTrack()
59+
{
60+
CheckInitializationState();
61+
62+
//Enable or disable default subtitle based on user setting.
63+
if (!(bool)_userSettings.Values["ShowDefaultSubtitles"])
64+
{
65+
return default;
66+
}
67+
68+
return _mediaPlayer.SpuDescription.ElementAtOrDefault(1); ;
69+
}
70+
71+
/// <summary>
72+
/// <inheritdoc/>
73+
/// </summary>
74+
/// <returns><inheritdoc/></returns>
75+
public TrackDescription[] GetEmbeddedSubtitleTracks()
76+
{
77+
CheckInitializationState();
78+
return _mediaPlayer.SpuDescription;
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)