libvlcsharp
libvlcsharp copied to clipboard
Adding a MediaPlayerElement to Maui - Updated
Description of Change
This PR includes the implementation of a MediaPlayerElement for Maui. The changes include:
- Added new MediaPlayerElement control to LibVCLSharp.MAUI
- Added the sample LibVLCSharp.MAUI.Sample.MediaElement based on the Forms sample
- Moved the MAUI samples to a new MAUI samples folder
Issues Resolved
- fixes #637
Other Changes
None
Platforms Affected
- Core (all platforms)
- Android
Behavioral/Visual Changes
None
Before/After Screenshots
Testing Procedure
I was not able to test this on iOS
PR Checklist
- [X] Rebased on top of the target branch at time of PR
- [X] Changes adhere to coding standard
CI complaining with some weird errors, SDK related likely.. I think I had similar issues when doing the Uno part.. will investigate https://gist.github.com/mfkl/c91642258c79f752c9541da5094c6777
And as before, I cannot reproduce locally.
On your branch, CI restores only this:
2024-09-30T13:37:22.7862753Z Restore-NuGet-Packages
2024-09-30T13:37:22.7863433Z ========================================
2024-09-30T13:37:26.2608946Z D:\a\1\s\src\LibVLCSharp.Android.AWindow\LibVLCSharp.Android.AWindow.csproj : warning NU1503: Skipping restore for project 'D:\a\1\s\src\LibVLCSharp.Android.AWindow\LibVLCSharp.Android.AWindow.csproj'. The project file may be invalid or missing targets required for restore. [D:\a\1\s\src\LibVLCSharp.sln]
2024-09-30T13:37:26.2632321Z Determining projects to restore...
2024-09-30T13:38:40.4303206Z Restored D:\a\1\s\samples\MAUI\LibVLCSharp.MAUI.Sample.MediaElement\LibVLCSharp.MAUI.Sample.MediaElement.csproj (in 1.18 min).
2024-09-30T13:38:40.4305617Z Restored D:\a\1\s\samples\LibVLCSharp.MAUI.Sample\LibVLCSharp.MAUI.Sample.csproj (in 1.18 min).
2024-09-30T13:38:40.7125951Z Restored D:\a\1\s\src\LibVLCSharp.MAUI\LibVLCSharp.MAUI.csproj (in 265 ms).
2024-09-30T13:38:40.7182494Z Restored D:\a\1\s\src\LibVLCSharp.Android.AWindowModern\LibVLCSharp.Android.AWindowModern.csproj (in 1 ms).
2024-09-30T13:40:42.2630528Z Restored D:\a\1\s\src\LibVLCSharp\LibVLCSharp.csproj (in 2.03 min).
2024-09-30T13:40:42.3372853Z
On current 3.x, it restores all projects. Maybe something with the libvlcsharp.sln changes?
It's because I removed everything from build manager except what I need. Let's see what I can do.
@jonx
Hi there!
I tested your code, and overall it works pretty well. However, I encountered some issues when playing network streams, specifically with HLS (m3u8) or DASH (mpd). When I try to seek using the progress bar, it doesn’t work as expected. After dragging to a specific position, the playback either jumps back or resets to the starting point. Interestingly, if I long-press the progress bar at the desired position, it sometimes successfully seeks to that spot, but the overall seeking behavior is very inconsistent. This happens on both Android and iOS.
I'm not sure if the issue is with LibVLCSharp or MediaElement. For reference, I’ve tested the same HLS or DASH streams in the VLC apps from Google Play and App Store, and they work perfectly.
Thanks for your help!
Hi @mrsleepman,
Thank you for trying out this code and for sharing your feedback! I'm very happy to hear that it "mostly" works on both Android and iOS.
As you might know, this MediaElement control is meant to provide the best plug&play experience out of the box but will probably never support all the advanced features you would find in an advanced custom made video player.
That being said, I’ve seen similar reports regarding seeking issues with HLS and DASH streams. These types of streams handle seeking differently, often requiring the player to jump between segments, which can make precise seeking challenging.
And this code is a port from existing implementations, so it might inherit some underlying issues, I'm not sure yet, I have to investigate. Maybe one option to improve this could be using a queue to prioritize seek operations or implementing a debouncing mechanism to skip unnecessary seeks. However, this could be a lot of work and these potential solutions that would need further testing.
But I will have a look.
If you have any links to specific streams where this issue is particularly noticeable, feel free to share them. It would help me try to reproduce the issue more accurately.
Thanks again for your input!
@jonx
Hi there!
I spent some time debugging this issue today and found that it might be a logical problem. During the process of dragging the seek bar, the "SeekBar_ValueChanged" event gets triggered repeatedly. The longer the drag lasts, the more times "SeekBar_ValueChanged" is executed, which might be why the time isn’t being set correctly.
Here’s the current code where the event "SeekBar.ValueChanged" is bound:
SeekBar.ValueChanged += SeekBar_ValueChanged;
private void SeekBar_ValueChanged(object? sender, ValueChangedEventArgs e)
{
// Each drag action triggers many event calls
Console.WriteLine("SeekBar_ValueChanged");
Show();
Manager.Get<SeekBarManager>().SetSeekBarPosition(e.NewValue);
}
To resolve this, I tried testing it by using "SeekBar.DragStarted" and "SeekBar.DragCompleted", and it seems to work properly:
SeekBar.DragStarted += SeekBar_DragStarted;
SeekBar.DragCompleted += SeekBar_DragCompleted;
SeekBar.ValueChanged += SeekBar_ValueChanged;
private bool isDragging = false;
private void SeekBar_DragStarted(object? sender, EventArgs e)
{
isDragging = true;
}
private void SeekBar_DragCompleted(object? sender, EventArgs e)
{
isDragging = false;
if (SeekBar != null)
{
Show();
Manager.Get<SeekBarManager>().SetSeekBarPosition(SeekBar.Value);
}
}
private void SeekBar_ValueChanged(object? sender, ValueChangedEventArgs e)
{
if (isDragging)
{
Show();
if (SeekBar != null)
{
var position = e.NewValue / SeekBar.Maximum;
// I temporarily made Length public for testing
var estimatedTime = TimeSpan.FromMilliseconds(position * Manager.Get<SeekBarManager>().Length);
Console.WriteLine($"Dragging Time: {estimatedTime}");
}
}
}
Additionally, I made some adjustments to prevent conflicts between the player and the user while interacting with the seek bar:
seekBarManager.PositionChanged += (sender, e) =>
{
if (!isDragging)
{
UpdateTime();
}
};
Your original code was really cool and solved a lot of issues! I hope these changes from my testing can help resolve this particular problem.
I have to test it (early next week) but it looks like indeed this will solve the time bug. Thanks for looking into this further.
Does this code solve the problem you reported while seeking in video streams?
I tried to minimize changes based on your code and the time is now correctly updated after a manual seek.
A compatible .NET SDK was not found.
Requested SDK version: 8.0.300
global.json file: D:\a\1\s\src\global.json
Installed SDKs:
Install the [8.0.300] .NET SDK or update [D:\a\1\s\src\global.json] to match an installed SDK.
CI breaking again for some reason, with a stupid error message.
I tried to minimize changes based on your code and the time is now correctly updated after a manual seek.
I tested your latest code with the implementation that only adds the DragCompleted event. Unfortunately, this change alone isn’t enough to make it work correctly. The conflict between the ValueChanged event and the DragCompleted event still exists—they are both trying to control the seek bar, which leads to issues.
Here’s a DASH test stream I found on Google that I used for testing: https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd
A compatible .NET SDK was not found. Requested SDK version: 8.0.300 global.json file: D:\a\1\s\src\global.json Installed SDKs: Install the [8.0.300] .NET SDK or update [D:\a\1\s\src\global.json] to match an installed SDK.CI breaking again for some reason, with a stupid error message.
For me, the way to resolve this issue was by modifying the global.json file to match the SDK version installed on my system. Here's the SDK version I have:
dotnet --list-sdks
8.0.400 [C:\Program Files\dotnet\sdk]
{
"msbuild-sdks": {
"MSBuild.Sdk.Extras": "3.0.44",
"Uno.Sdk": "5.3.96"
},
"sdk": {
"version": "8.0.400"
}
}
This change made everything work correctly on my end. Hope this helps!
Yep, thanks, but this PR makes no changes to the CI or global.json, so I'm not sure why the pipeline suddenly fails to install the proper SDK. I also cannot reproduce when building this branch in a pipeline from my fork. It was building fine before that last commit, so my guess is Azure Pipelines is buggy for this PR specifically..
Edit: https://github.com/microsoft/azure-pipelines-tasks/issues/20508
Ok, last changes seem fine, thanks. CI is OK (besides the usual randomly crashing native test..).
Will test one last time on Android and iOS when I can, and merge.
If anyone feels like doing more testing in the meantime, be my guest!
Thanks a lot @jonx! (for your work and patience)
Aiming for a release early next week.