Skip to content

Commit

Permalink
fix: Fix measuring MPE
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Nov 21, 2023
1 parent e7ae842 commit 67e21c1
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 60 deletions.
26 changes: 8 additions & 18 deletions src/AddIns/Uno.UI.MediaPlayer.Skia.Gtk/GtkMediaPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public partial class GtkMediaPlayer : FrameworkElement
private double _playbackRate;
private Rect _transportControlsBounds;
private Windows.UI.Xaml.Media.Stretch _stretch = Windows.UI.Xaml.Media.Stretch.Uniform;
private double _videoRatio;
private readonly MediaPlayerPresenter _owner;
private (double playerHeight, double playerWidth, uint videoHeight, uint videoWidth) _lastSetDimensions;

Expand Down Expand Up @@ -61,6 +60,9 @@ public GtkMediaPlayer(MediaPlayerPresenter owner)
//_libvlc?.Dispose();
}

internal uint NaturalVideoHeight => _lastSetDimensions.videoHeight;
internal uint NaturalVideoWidth => _lastSetDimensions.videoWidth;

public string Source
{
get => (string)GetValue(SourceProperty);
Expand All @@ -73,19 +75,7 @@ public string Source

public double Duration { get; set; }

public double VideoRatio
{
get => _videoRatio;
set
{
if (_videoRatio != value)
{
_videoRatio = value;

OnVideoRatioChanged?.Invoke(this, EventArgs.Empty);
}
}
}
public double VideoRatio { get; set; }

public bool IsVideo
=> _mediaPlayer?.Media?.Tracks?.Any(x => x.TrackType == TrackType.Video) == true;
Expand Down Expand Up @@ -357,6 +347,10 @@ private void UpdateVideoStretch(bool forceVideoViewVisibility = false)
}
VideoRatio = (double)videoHeight / (double)videoWidth;
if (videoHeight != _lastSetDimensions.videoHeight || videoWidth != _lastSetDimensions.videoWidth)
{
OnNaturalVideoDimensionChanged?.Invoke();
}
var currentSize = new Size(ActualWidth, ActualHeight);
Expand Down Expand Up @@ -468,10 +462,6 @@ private void UpdateVideoSizeAllocate(double playerHeight, double playerWidth, ui
var topInsetFill = (playerHeight - newHeight) / 2;
var leftInsetFill = 0;

var newHeightFill = (int)(videoHeight * playerRatio);
var newWidthFill = (int)(videoWidth * playerRatio);
double correctVideoRate = (VideoRatio / playerRatio);

if (_videoView is not null)
{
Point pagePositionFill = this.TransformToVisual(root).TransformPoint(new Point(leftInsetFill, topInsetFill));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public partial class GtkMediaPlayer
public event EventHandler<object>? OnMetadataLoaded;
public event EventHandler<object>? OnTimeUpdate;
public event EventHandler<object>? OnSourceLoaded;
public event EventHandler<object?>? OnVideoRatioChanged;
public event Action? OnNaturalVideoDimensionChanged;

private bool _updateVideoSizeOnFirstTimeStamp = true;
private bool _isParsedLocalFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void InitializePlayer()
_player.OnSourceLoaded += OnPrepared;
_player.OnSourceEnded += OnCompletion;
_player.OnTimeUpdate += OnTimeUpdate;
_player.OnVideoRatioChanged += OnVideoRatioChanged;
_player.OnNaturalVideoDimensionChanged += OnNaturalVideoDimensionChanged;

_owner.PlaybackSession.PlaybackStateChanged -= OnStatusChanged;
_owner.PlaybackSession.PlaybackStateChanged += OnStatusChanged;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ public void OnVolumeChanged()
_player?.SetVolume(volume);
}

private void OnVideoRatioChanged(object? sender, object? e)
private void OnNaturalVideoDimensionChanged()
{
if (_player is not null
&& _player.IsVideo
&& Events is not null)
{
IsVideo = _player.IsVideo;
Events?.RaiseVideoRatioChanged(Math.Max(1, (double)_player.VideoRatio));
Events?.RaiseNaturalVideoDimensionChanged();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public class MediaPlayerPresenterExtension : IMediaPlayerPresenterExtension
{
private MediaPlayerPresenter? _owner;
private GtkMediaPlayer _player;

public uint NaturalVideoHeight => _player.NaturalVideoHeight;
public uint NaturalVideoWidth => _player.NaturalVideoWidth;

public MediaPlayerPresenterExtension(object owner)
{
if (owner is not MediaPlayerPresenter presenter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ public void OnPrepared(object? sender, object what)
this.Log().Debug($"OnPrepared: {mp.VideoWidth}x{mp.VideoHeight}");
}

Events.RaiseVideoRatioChanged((double)mp.VideoWidth / global::System.Math.Max(mp.VideoHeight, 1));
Events.RaiseNaturalVideoDimensionChanged();
}
catch { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ public interface IMediaPlayerPresenterExtension
void RequestCompactOverlay();

void ExitCompactOverlay();

uint NaturalVideoHeight { get; }

uint NaturalVideoWidth { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private static void OnMediaPlayerChanged(DependencyObject sender, DependencyProp
{
oldMediaPlayer.MediaFailed -= mpe.OnMediaFailed;
oldMediaPlayer.MediaOpened -= mpe.OnMediaOpened;
oldMediaPlayer.VideoRatioChanged -= mpe.OnVideoRatioChanged;
oldMediaPlayer.NaturalVideoDimensionChanged -= mpe.OnNaturalVideoDimensionChanged;
oldMediaPlayer.Dispose();
}

Expand All @@ -229,14 +229,14 @@ private static void OnMediaPlayerChanged(DependencyObject sender, DependencyProp
newMediaPlayer.Source = mpe.Source;
newMediaPlayer.MediaFailed += mpe.OnMediaFailed;
newMediaPlayer.MediaOpened += mpe.OnMediaOpened;
newMediaPlayer.VideoRatioChanged -= mpe.OnVideoRatioChanged;
newMediaPlayer.NaturalVideoDimensionChanged -= mpe.OnNaturalVideoDimensionChanged;
mpe.TransportControls?.SetMediaPlayer(newMediaPlayer);
mpe._isTransportControlsBound = true;
}
};
}

private void OnVideoRatioChanged(Windows.Media.Playback.MediaPlayer sender, double args)
private void OnNaturalVideoDimensionChanged(MediaPlayer sender, object args)
{
_ = Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
Expand Down Expand Up @@ -362,6 +362,7 @@ protected override void OnApplyTemplate()
_layoutRoot = this.GetTemplateChild(LayoutRootName) as Grid;
_posterImage = this.GetTemplateChild(PosterImageName) as Image;
_mediaPlayerPresenter = this.GetTemplateChild(MediaPlayerPresenterName) as MediaPlayerPresenter;
_mediaPlayerPresenter?.SetOwner(this);

_transportControlsPresenter = this.GetTemplateChild(TransportControlsPresenterName) as ContentPresenter;
_transportControlsPresenter.Content = TransportControls;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ partial void InitializePartial()
}
}

internal uint NaturalVideoHeight => _extension?.NaturalVideoHeight ?? 0;
internal uint NaturalVideoWidth => _extension?.NaturalVideoWidth ?? 0;

partial void OnMediaPlayerChangedPartial(MediaPlayer mediaPlayer)
=> _extension?.MediaPlayerChanged();

Expand Down
134 changes: 109 additions & 25 deletions src/Uno.UI/UI/Xaml/Controls/MediaPlayerElement/MediaPlayerPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,36 @@ namespace Windows.UI.Xaml.Controls
{
public partial class MediaPlayerPresenter : Border
{
private double _currentRatio = 1;
private WeakReference<MediaPlayerElement> wrOwner;

internal void SetOwner(MediaPlayerElement owner)
{
wrOwner = new WeakReference<MediaPlayerElement>(owner);
}

private float GetScaledOtherDimension(
float scaledOneDimension,
uint naturalOneDimension,
uint naturalOtherDimension)
{
//
// naturalOneDimension is mapped to scaledOneDimension. Map naturalOtherDimension to scaledOtherDimension using the
// same scale factor.
//
// scaledOther / naturalOther = scaledOne / naturalOne
// scaledOther = naturalOther * scaledOne / naturalOne
//

if (naturalOneDimension == 0)
{
return 0.0f;
}
else
{
return (float)naturalOtherDimension * scaledOneDimension / (float)naturalOneDimension;
}
}


#region MediaPlayer Property

Expand All @@ -36,14 +65,14 @@ private static void OnMediaPlayerChanged(DependencyObject sender, DependencyProp
}
if (args.OldValue is Windows.Media.Playback.MediaPlayer oldPlayer)
{
oldPlayer.VideoRatioChanged -= presenter.OnVideoRatioChanged;
oldPlayer.NaturalVideoDimensionChanged -= presenter.OnNaturalVideoDimensionChanged;
oldPlayer.MediaFailed -= presenter.OnMediaFailed;
oldPlayer.SourceChanged -= presenter.OnSourceChanged;
}

if (args.NewValue is Windows.Media.Playback.MediaPlayer newPlayer)
{
newPlayer.VideoRatioChanged += presenter.OnVideoRatioChanged;
newPlayer.NaturalVideoDimensionChanged += presenter.OnNaturalVideoDimensionChanged;
newPlayer.MediaFailed += presenter.OnMediaFailed;
newPlayer.SourceChanged += presenter.OnSourceChanged;

Expand Down Expand Up @@ -118,19 +147,14 @@ private protected override void OnUnloaded()
base.OnUnloaded();
}

private void OnVideoRatioChanged(Windows.Media.Playback.MediaPlayer sender, double args)
private void OnNaturalVideoDimensionChanged(MediaPlayer sender, object args)
{
if (args > 0) // The VideoRect may initially be empty, ignore because a 0 ratio will lead to infinite dims being returned on measure, resulting in an exception
{
_currentRatio = args;
}

_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Visibility = Visibility.Visible;
});

InvalidateArrange();
InvalidateMeasure();
}

private void OnMediaFailed(Windows.Media.Playback.MediaPlayer sender, MediaPlayerFailedEventArgs args)
Expand All @@ -148,30 +172,90 @@ private void OnSourceChanged(Windows.Media.Playback.MediaPlayer sender, object a
});
}

private FrameworkElement GetLayoutOwner()
{
if (wrOwner?.TryGetTarget(out var owner) == true && owner is not null && !IsFullWindow)
{
return owner;
}

return this;
}

protected override Size MeasureOverride(Size availableSize)
{
if (double.IsNaN(Width) && double.IsNaN(Height))
var layoutOwner = GetLayoutOwner();
var explicitWidth = layoutOwner.Width;
var explicitHeight = layoutOwner.Height;
if (!double.IsNaN(explicitWidth) && !double.IsNaN(explicitHeight))
{
availableSize.Width = availableSize.Width;
if (_currentRatio != 0)
{
availableSize.Height = availableSize.Width / _currentRatio;
}
return new Size(explicitWidth, explicitHeight);
}
else if (double.IsNaN(Width))

//
// When determining the layout size:
//
// 1. If the explicit size is provided, then use that.
//
// 2. If the explicit size is only provided in one dimension, then use the explicit size in that dimension
// and infer the other from the natural size of the media.
//
// Note that if the media is not ready yet, then we use 0x0.
//
// 3. If neither dimension is provided and the stretch is None, then use the natural size of the media.
//
// 4. If neither dimension is provided, the stretch isn't None, and the available size is finite, then use
// the available size.
//
// 5. If neither dimension is provided, the stretch isn't None, and the available size is infinite in one
// dimension, then fill the available area in one dimension and infer the other from the natural size
// of the media.
//
// 6. If neither dimension is provided, the stretch isn't None, and the available size is infinite in both
// dimensions, use the natural size of the media.
//
if (!double.IsNaN(explicitWidth))
{
availableSize.Width = Height * _currentRatio;
availableSize.Height = Height;
return new Size(
explicitWidth,
GetScaledOtherDimension((float)explicitWidth, NaturalVideoWidth, NaturalVideoHeight));
}
else if (double.IsNaN(Height))
else if (!double.IsNaN(explicitHeight))
{
availableSize.Width = Width;
availableSize.Height = Width / _currentRatio;
return new Size(
GetScaledOtherDimension((float)explicitHeight, NaturalVideoHeight, NaturalVideoWidth),
explicitHeight);
}
else if (Stretch == Stretch.None)
{
return new Size(NaturalVideoWidth, NaturalVideoHeight);
}
else
{
bool isFiniteWidth = !double.IsInfinity(availableSize.Width);
bool isFiniteHeight = !double.IsInfinity(availableSize.Height);

base.MeasureOverride(availableSize);

return availableSize;
if (isFiniteWidth && isFiniteHeight)
{
return availableSize;
}
else if (isFiniteWidth)
{
return new Size(
availableSize.Width,
GetScaledOtherDimension((float)availableSize.Width, NaturalVideoWidth, NaturalVideoHeight));
}
else if (isFiniteHeight)
{
return new Size(
GetScaledOtherDimension((float)availableSize.Height, NaturalVideoHeight, NaturalVideoWidth),
availableSize.Height);
}
else
{
return new Size(NaturalVideoWidth, NaturalVideoHeight);
}
}
}
}
}
4 changes: 2 additions & 2 deletions src/Uno.UWP/Media/Playback/IMediaPlayerEventsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ public interface IMediaPlayerEventsExtension
void RaiseSeekCompleted();

/// <summary>
/// Raises the <see cref="MediaPlayer.VideoRatioChanged"/> event
/// Raises the <see cref="MediaPlayer.NaturalVideoDimensionChanged"/> event
/// </summary>
void RaiseVideoRatioChanged(double videoRatio);
void RaiseNaturalVideoDimensionChanged();

/// <summary>
/// Raises the <see cref="MediaPlayer.BufferingEnded"/> event
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UWP/Media/Playback/MediaPlayer.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public void OnPrepared(AndroidMediaPlayer mp)
{
PlaybackSession.NaturalDuration = TimeSpan.FromMilliseconds(_player.Duration);

VideoRatioChanged?.Invoke(this, (double)mp.VideoWidth / global::System.Math.Max(mp.VideoHeight, 1));
NaturalVideoDimensionChanged?.Invoke(this, null);

IsVideo = mp.GetTrackInfo()?.Any(x => x.TrackType == MediaTrackType.Video) == true;

Expand Down
9 changes: 5 additions & 4 deletions src/Uno.UWP/Media/Playback/MediaPlayer.Events.others.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ void RaiseSubtitleFrameChanged()
void RaiseVideoFrameAvailable()
=> VideoFrameAvailable?.Invoke(this, new object());

void RaiseVideoRatioChanged(double videoRatio)
=> VideoRatioChanged?.Invoke(this, videoRatio);
void RaiseNaturalVideoDimensionChanged()
=> NaturalVideoDimensionChanged?.Invoke(this, null);

void RaiseVolumeChanged()
=> VolumeChanged?.Invoke(this, null);
Expand Down Expand Up @@ -112,8 +112,9 @@ void IMediaPlayerEventsExtension.RaiseSubtitleFrameChanged()
void IMediaPlayerEventsExtension.RaiseVideoFrameAvailable()
=> _owner.RaiseVideoFrameAvailable();

void IMediaPlayerEventsExtension.RaiseVideoRatioChanged(double videoRatio)
=> _owner.RaiseVideoRatioChanged(videoRatio);
void IMediaPlayerEventsExtension.RaiseNaturalVideoDimensionChanged()
=> _owner.RaiseNaturalVideoDimensionChanged();

void IMediaPlayerEventsExtension.RaiseVolumeChanged()
=> _owner.RaiseVolumeChanged();

Expand Down
Loading

0 comments on commit 67e21c1

Please sign in to comment.