[Core,iOS,Droid,UWP,Tizen] Remove MediaElement (#12007)

* [Core,UWP,iOS,Android] Remove MediaElement

* [Tizen] Remove MediaElement

* [WPF] Remove reference to MediaElement

* [Tests] Remove MediaSourceTests

* [Core] Remove MediaSource

* [Tizen] Remove extra files related with MediaElement

* Update ExperimentalFlags.cs

* [Controls] Removing References to MedialElement strings

* [Controls] Remove  reference to MediaElement flag
This commit is contained in:
Rui Marinho 2020-09-10 10:22:37 +01:00 коммит произвёл GitHub
Родитель c05e04d1cb
Коммит 6b816f7148
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
42 изменённых файлов: 6 добавлений и 4238 удалений

Просмотреть файл

@ -166,9 +166,6 @@ namespace Xamarin.Forms.Platform
#endif
internal class _MasterDetailPageRenderer { }
[RenderWith (typeof(MediaElementRenderer))]
internal class _MediaElementRenderer { }
[RenderWith(typeof(RefreshViewRenderer))]
internal class _RefreshViewRenderer { }

Просмотреть файл

@ -45,7 +45,7 @@ namespace Xamarin.Forms.ControlGallery.Android
#if TEST_EXPERIMENTAL_RENDERERS
#else
Forms.SetFlags("UseLegacyRenderers", "SwipeView_Experimental", "MediaElement_Experimental");
Forms.SetFlags("UseLegacyRenderers", "SwipeView_Experimental");
#endif
Forms.Init(this, bundle);

Просмотреть файл

@ -22,7 +22,7 @@ namespace Xamarin.Forms.ControlGallery.Tizen
{
var app = new MainApplication();
FormsMaps.Init("HERE", "write-your-API-key-here");
Forms.SetFlags("CollectionView_Experimental", "Shell_Experimental", "MediaElement_Experimental");
Forms.SetFlags("CollectionView_Experimental", "Shell_Experimental");
Forms.Init(app);
FormsMaterial.Init();
app.Run(args);

Просмотреть файл

@ -10,7 +10,7 @@ namespace Xamarin.Forms.ControlGallery.WPF
public MainWindow()
{
InitializeComponent();
Forms.SetFlags("CarouselView_Experimental", "MediaElement_Experimental", "RadioButton_Experimental");
Forms.SetFlags("CarouselView_Experimental", "RadioButton_Experimental");
Xamarin.Forms.Forms.Init();
FormsMaps.Init("");
LoadApplication(new Controls.App());

Просмотреть файл

@ -71,7 +71,7 @@ namespace Xamarin.Forms.ControlGallery.WindowsUniversal
rootFrame.NavigationFailed += OnNavigationFailed;
Forms.SetFlags("Shell_UWP_Experimental", "SwipeView_Experimental", "MediaElement_Experimental");
Forms.SetFlags("Shell_UWP_Experimental", "SwipeView_Experimental");
Forms.Init (e);
//FormsMaps.Init (Controls.App.Config["UWPMapsAuthKey"]);

Просмотреть файл

@ -151,7 +151,7 @@ namespace Xamarin.Forms.ControlGallery.iOS
App.IOSVersion = int.Parse(versionPart[0]);
Xamarin.Calabash.Start();
Forms.SetFlags("SwipeView_Experimental", "MediaElement_Experimental");
Forms.SetFlags("SwipeView_Experimental");
Forms.Init();
FormsMaps.Init();
FormsMaterial.Init();

Просмотреть файл

@ -415,7 +415,6 @@ namespace Xamarin.Forms.Controls
new GalleryPageFactory(() => new ListViewDemoPage(), "ListView Demo Gallery - Legacy"),
new GalleryPageFactory(() => new MapGallery(), "Map Gallery - Legacy"),
new GalleryPageFactory(() => new MapWithItemsSourceGallery(), "Map With ItemsSource Gallery - Legacy"),
new GalleryPageFactory(() => new MediaElementDemoPage(), "MediaElement"),
new GalleryPageFactory(() => new MapElementsGallery(), "Map Elements Gallery - Legacy"),
new GalleryPageFactory(() => new MinimumSizeGallery(), "MinimumSize Gallery - Legacy"),
new GalleryPageFactory(() => new MultiGallery(), "Multi Gallery - Legacy"),

Просмотреть файл

@ -1,190 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Forms.Controls
{
internal class MediaElementDemoPage : ContentPage
{
MediaElement element;
Label positionLabel;
Label consoleLabel;
public MediaElementDemoPage()
{
element = new MediaElement();
element.HorizontalOptions = new LayoutOptions(LayoutAlignment.Fill,true);
element.VerticalOptions = new LayoutOptions(LayoutAlignment.Fill,true);
element.MinimumWidthRequest = 320;
element.MinimumHeightRequest = 240;
element.AutoPlay = false;
element.Aspect = Aspect.AspectFill;
element.ShowsPlaybackControls = true;
element.BackgroundColor = Color.Red;
element.MediaEnded += Element_MediaEnded;
element.MediaFailed += Element_MediaFailed;
element.MediaOpened += Element_MediaOpened;
consoleLabel = new Label();
var infoStack = new StackLayout { Orientation = StackOrientation.Horizontal };
var stateLabel = new Label();
stateLabel.SetBinding(Label.TextProperty, new Binding("CurrentState", BindingMode.OneWay, null, null, "s:{0}", element));
var bufferingLabel = new Label();
bufferingLabel.SetBinding(Label.TextProperty, new Binding("BufferingProgress", BindingMode.OneWay, null, null, "b:{0:f2}", element));
var heightLabel = new Label();
heightLabel.SetBinding(Label.TextProperty, new Binding("VideoHeight", BindingMode.OneWay, null, null, "h:{0}", element));
var widthLabel = new Label();
widthLabel.SetBinding(Label.TextProperty, new Binding("VideoWidth", BindingMode.OneWay, null, null, "w:{0}", element));
var durationLabel = new Label();
durationLabel.SetBinding(Label.TextProperty, new Binding("Duration", BindingMode.OneWay, null, null, "d:{0:g}", element));
var volumeLabel = new Label();
volumeLabel.SetBinding(Label.TextProperty, new Binding("Volume", BindingMode.OneWay, null, null, "v:{0}", element));
infoStack.Children.Add(stateLabel);
infoStack.Children.Add(bufferingLabel);
infoStack.Children.Add(heightLabel);
infoStack.Children.Add(widthLabel);
infoStack.Children.Add(durationLabel);
infoStack.Children.Add(volumeLabel);
positionLabel = new Label();
positionLabel.TextColor = Color.Black;
//positionLabel.SetBinding(Label.TextProperty, new Binding("Position", BindingMode.OneWay, null, null, "{0:g}", element));
var playButton = new Button();
playButton.Text = "\u25b6\uFE0F";
playButton.FontSize = 48;
playButton.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, true);
playButton.Clicked += PlayButton_Clicked;
var pauseButton = new Button();
pauseButton.Text = "\u23f8\uFE0F";
pauseButton.FontSize = 48;
pauseButton.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, true);
pauseButton.Clicked += PauseButton_Clicked;
var stopButton = new Button();
stopButton.Text = "\u23f9\uFE0F";
stopButton.FontSize = 48;
stopButton.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, true);
stopButton.Clicked += StopButton_Clicked;
var showControlsSwitch = new Switch();
showControlsSwitch.SetBinding(Switch.IsToggledProperty, new Binding("ShowsPlaybackControls", BindingMode.TwoWay, source: element));
var mediaControlStack = new StackLayout();
mediaControlStack.Orientation = StackOrientation.Horizontal;
mediaControlStack.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, false);
mediaControlStack.Children.Add(playButton);
mediaControlStack.Children.Add(pauseButton);
mediaControlStack.Children.Add(stopButton);
mediaControlStack.Children.Add(showControlsSwitch);
var aspectFitButton = new Button() { Text = "Aspect Fit" };
aspectFitButton.Clicked += (s, e) => { element.Aspect = Aspect.AspectFit; };
var aspectFillButton = new Button() { Text = "Aspect Fill" };
aspectFillButton.Clicked += (s, e) => { element.Aspect = Aspect.AspectFill; };
var fillButton = new Button() { Text = "Fill" };
fillButton.Clicked += (s, e) => { element.Aspect = Aspect.Fill; };
var aspectStack = new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, false) };
aspectStack.Children.Add(aspectFitButton);
aspectStack.Children.Add(aspectFillButton);
aspectStack.Children.Add(fillButton);
var volumeSlider = new Slider()
{
Minimum = 0,
Maximum = 1
};
volumeSlider.Value = 0.1;
volumeSlider.ValueChanged += VolumeSlider_ValueChanged;
var stack = new StackLayout();
stack.Padding = new Thickness(10);
stack.Spacing = 10;
stack.HorizontalOptions = new LayoutOptions(LayoutAlignment.Fill, false);
stack.VerticalOptions = new LayoutOptions(LayoutAlignment.Fill, false);
stack.Children.Add(element);
stack.Children.Add(infoStack);
stack.Children.Add(positionLabel);
stack.Children.Add(mediaControlStack);
stack.Children.Add(aspectStack);
stack.Children.Add(consoleLabel);
stack.Children.Add(new Label() { Text = "Volume:" });
stack.Children.Add(volumeSlider);
element.Volume = 0.1;
Content = stack;
}
private void VolumeSlider_ValueChanged(object sender, ValueChangedEventArgs e)
{
element.Volume = (sender as Slider).Value;
}
void Element_MediaOpened(object sender, EventArgs e)
{
consoleLabel.Text += "Media opened" + Environment.NewLine;
}
void Element_MediaFailed(object sender, EventArgs e)
{
consoleLabel.Text += "Media failed" + Environment.NewLine;
}
void Element_MediaEnded(object sender, EventArgs e)
{
consoleLabel.Text += "Media ended" + Environment.NewLine;
}
void PlayButton_Clicked(object sender, EventArgs e)
{
element.Play();
}
void PauseButton_Clicked(object sender, EventArgs e)
{
element.Pause();
}
void StopButton_Clicked(object sender, EventArgs e)
{
element.Stop();
}
protected override void OnAppearing()
{
base.OnAppearing();
if(Device.RuntimePlatform == Device.WPF)
{
// workaround for lack of https support on WPF
element.Source = new Uri("http://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4");
}
else
{
element.Source = new Uri("https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4");
}
Device.StartTimer(TimeSpan.FromMilliseconds(100), ()=>{
Device.BeginInvokeOnMainThread(() =>
{
positionLabel.Text = element.Position.ToString("mm\\:ss\\.ff");
});
return polling;
});
}
bool polling = true;
protected override void OnDisappearing()
{
base.OnDisappearing();
polling = false;
}
}
}

Просмотреть файл

@ -48,7 +48,6 @@ namespace Xamarin.Forms.Markup.UnitTests
{ typeof(InputView), na },
{ typeof(ItemsLayout), na },
{ typeof(LinearItemsLayout), na },
{ typeof(MediaSource), na },
{ typeof(Menu), na },
{ typeof(MultiTrigger), na },
{ typeof(NavigableElement), na },

Просмотреть файл

@ -1,92 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class MediaElementTests : BaseTestFixture
{
[SetUp]
public override void Setup()
{
base.Setup();
}
[TearDown]
public override void TearDown()
{
base.TearDown();
}
[Test]
public void TestSource()
{
var mediaElement = new MediaElement();
Assert.IsNull(mediaElement.Source);
bool signaled = false;
mediaElement.PropertyChanged += (sender, e) => {
if (e.PropertyName == "Source")
signaled = true;
};
var source = MediaSource.FromFile("Video.mp4");
mediaElement.Source = source;
Assert.AreEqual(source, mediaElement.Source);
Assert.True(signaled);
}
[Test]
public void TestSourceDoubleSet()
{
var mediaElement = new MediaElement { Source = MediaSource.FromFile("Video.mp4") };
bool signaled = false;
mediaElement.PropertyChanged += (sender, e) => {
if (e.PropertyName == "Source")
signaled = true;
};
mediaElement.Source = mediaElement.Source;
Assert.False(signaled);
}
[Test]
public void TestFileMediaSourceChanged()
{
var source = (FileMediaSource)MediaSource.FromFile("Video.mp4");
bool signaled = false;
source.SourceChanged += (sender, e) => {
signaled = true;
};
source.File = "Other.mp4";
Assert.AreEqual("Other.mp4", source.File);
Assert.True(signaled);
}
[Test]
public void TestSourceRoundTrip()
{
var uri = new Uri("https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4");
var media = new MediaElement();
Assert.Null(media.Source);
media.Source = uri;
Assert.NotNull(media.Source);
Assert.IsInstanceOf(typeof(UriMediaSource), media.Source, "Not expected mediasource type");
Assert.AreEqual(uri, ((UriMediaSource)media.Source).Uri);
}
}
}

Просмотреть файл

@ -1,165 +0,0 @@
using NUnit.Framework;
using System;
namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class MediaSourceTests : BaseTestFixture
{
[SetUp]
public override void Setup()
{
base.Setup();
Device.PlatformServices = new MockPlatformServices();
}
[Test]
public void TestConstructors()
{
var filesource = new FileMediaSource { File = "File.mp4" };
Assert.AreEqual("File.mp4", filesource.File);
var urisource = new UriMediaSource { Uri = new Uri("http://xamarin.com/media.mp4") };
Assert.AreEqual("http://xamarin.com/media.mp4", urisource.Uri.AbsoluteUri);
}
[Test]
public void TestHelpers()
{
var mediasource = MediaSource.FromFile("File.mp4");
Assert.That(mediasource, Is.TypeOf<FileMediaSource>());
Assert.AreEqual("File.mp4", ((FileMediaSource)mediasource).File);
var urisource = MediaSource.FromUri(new Uri("http://xamarin.com/media.mp4"));
Assert.That(urisource, Is.TypeOf<UriMediaSource>());
Assert.AreEqual("http://xamarin.com/media.mp4", ((UriMediaSource)(urisource)).Uri.AbsoluteUri);
}
[Test]
public void TestImplicitFileConversion()
{
var mediaElement = new MediaElement { Source = "File.mp4" };
Assert.IsTrue(mediaElement.Source != null);
Assert.That(mediaElement.Source, Is.InstanceOf<FileMediaSource>());
Assert.AreEqual("File.mp4", ((FileMediaSource)(mediaElement.Source)).File);
}
[Test]
public void TestImplicitStringConversionWhenNull()
{
string s = null;
var sut = (MediaSource)s;
Assert.That(sut, Is.InstanceOf<FileMediaSource>());
Assert.IsNull(((FileMediaSource)sut).File);
}
[Test]
public void TestImplicitUriConversion()
{
var mediaElement = new MediaElement { Source = new Uri("http://xamarin.com/media.mp4") };
Assert.IsTrue(mediaElement.Source != null);
Assert.That(mediaElement.Source, Is.InstanceOf<UriMediaSource>());
Assert.AreEqual("http://xamarin.com/media.mp4", ((UriMediaSource)(mediaElement.Source)).Uri.AbsoluteUri);
}
[Test]
public void TestImplicitStringUriConversion()
{
var mediaElement = new MediaElement { Source = "http://xamarin.com/media.mp4" };
Assert.IsTrue(mediaElement.Source != null);
Assert.That(mediaElement.Source, Is.InstanceOf<UriMediaSource>());
Assert.AreEqual("http://xamarin.com/media.mp4", ((UriMediaSource)(mediaElement.Source)).Uri.AbsoluteUri);
}
[Test]
public void TestImplicitUriConversionWhenNull()
{
Uri u = null;
var sut = (MediaSource)u;
Assert.IsNull(sut);
}
[Test]
public void TestSetStringValue()
{
var mediaElement = new MediaElement();
mediaElement.SetValue(MediaElement.SourceProperty, "media.mp4");
Assert.IsNotNull(mediaElement.Source);
Assert.That(mediaElement.Source, Is.InstanceOf<FileMediaSource>());
Assert.AreEqual("media.mp4", ((FileMediaSource)(mediaElement.Source)).File);
}
[Test]
public void TextBindToStringValue()
{
var mediaElement = new MediaElement();
mediaElement.SetBinding(MediaElement.SourceProperty, ".");
Assert.IsNull(mediaElement.Source);
mediaElement.BindingContext = "media.mp4";
Assert.IsNotNull(mediaElement.Source);
Assert.That(mediaElement.Source, Is.InstanceOf<FileMediaSource>());
Assert.AreEqual("media.mp4", ((FileMediaSource)(mediaElement.Source)).File);
}
[Test]
public void TextBindToStringUriValue()
{
var mediaElement = new MediaElement();
mediaElement.SetBinding(MediaElement.SourceProperty, ".");
Assert.IsNull(mediaElement.Source);
mediaElement.BindingContext = "http://xamarin.com/media.mp4";
Assert.IsNotNull(mediaElement.Source);
Assert.That(mediaElement.Source, Is.InstanceOf<UriMediaSource>());
Assert.AreEqual("http://xamarin.com/media.mp4", ((UriMediaSource)(mediaElement.Source)).Uri.AbsoluteUri);
}
[Test]
public void TextBindToUriValue()
{
var mediaElement = new MediaElement();
mediaElement.SetBinding(MediaElement.SourceProperty, ".");
Assert.IsNull(mediaElement.Source);
mediaElement.BindingContext = new Uri("http://xamarin.com/media.mp4");
Assert.IsNotNull(mediaElement.Source);
Assert.That(mediaElement.Source, Is.InstanceOf<UriMediaSource>());
Assert.AreEqual("http://xamarin.com/media.mp4", ((UriMediaSource)(mediaElement.Source)).Uri.AbsoluteUri);
}
class MockMediaSource : MediaSource
{
}
[Test]
public void TestBindingContextPropagation()
{
var context = new object();
var mediaElement = new MediaElement();
mediaElement.BindingContext = context;
var source = new MockMediaSource();
mediaElement.Source = source;
Assert.AreSame(context, source.BindingContext);
mediaElement = new MediaElement();
source = new MockMediaSource();
mediaElement.Source = source;
mediaElement.BindingContext = context;
Assert.AreSame(context, source.BindingContext);
}
[Test]
public void ImplicitCastOnAbsolutePathsShouldCreateAFileMediaSource()
{
var path = "/private/var/mobile/Containers/Data/Application/B1E5AB19-F815-4B4A-AB97-BD4571D53743/Documents/temp/video.mp4";
var mediaElement = new MediaElement { Source = path };
Assert.That(mediaElement.Source, Is.TypeOf<FileMediaSource>());
}
[Test]
public void ImplicitCastOnWindowsAbsolutePathsShouldCreateAFileMediaSource()
{
var path = "C:\\Users\\Username\\Videos\\video.mp4";
var mediaElement = new MediaElement { Source = path };
Assert.That(mediaElement.Source, Is.TypeOf<FileMediaSource>());
}
}
}

Просмотреть файл

@ -119,8 +119,6 @@
<Compile Include="ImageButtonUnitTest.cs" />
<Compile Include="ItemsViewTests.cs" />
<Compile Include="LayoutChildIntoBoundingRegionTests.cs" />
<Compile Include="MediaElementTests.cs" />
<Compile Include="MediaSourceTests.cs" />
<Compile Include="MenuUnitTests.cs" />
<Compile Include="PreviewerReflectionTests.cs" />
<Compile Include="RegionTests.cs" />

Просмотреть файл

@ -12,7 +12,6 @@ namespace Xamarin.Forms
internal const string ShellUWPExperimental = "Shell_UWP_Experimental";
internal const string CarouselViewExperimental = "CarouselView_Experimental";
internal const string SwipeViewExperimental = "SwipeView_Experimental";
internal const string MediaElementExperimental = "MediaElement_Experimental";
internal const string MarkupExperimental = "Markup_Experimental";
internal const string RadioButtonExperimental = "RadioButton_Experimental";
internal const string ShapesExperimental = "Shapes_Experimental";

Просмотреть файл

@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Forms
{
[TypeConverter(typeof(FileMediaSourceConverter))]
public sealed class FileMediaSource : MediaSource
{
public static readonly BindableProperty FileProperty = BindableProperty.Create(nameof(File), typeof(string), typeof(FileMediaSource), default(string));
public string File
{
get { return (string)GetValue(FileProperty); }
set { SetValue(FileProperty, value); }
}
public override string ToString()
{
return $"File: {File}";
}
public static implicit operator FileMediaSource(string file)
{
return (FileMediaSource)FromFile(file);
}
public static implicit operator string(FileMediaSource file)
{
return file != null ? file.File : null;
}
protected override void OnPropertyChanged(string propertyName = null)
{
if (propertyName == FileProperty.PropertyName)
OnSourceChanged();
base.OnPropertyChanged(propertyName);
}
}
}

Просмотреть файл

@ -1,16 +0,0 @@
using System;
namespace Xamarin.Forms
{
[Xaml.TypeConversion(typeof(FileMediaSource))]
public sealed class FileMediaSourceConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (value != null)
return (FileMediaSource)MediaSource.FromFile(value);
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(FileMediaSource)));
}
}
}

Просмотреть файл

@ -24,7 +24,6 @@ namespace Xamarin.Forms.Markup
{ "Xamarin.Forms.Entry", Entry.TextProperty },
{ "Xamarin.Forms.EntryCell", EntryCell.TextProperty },
{ "Xamarin.Forms.FileImageSource", FileImageSource.FileProperty },
{ "Xamarin.Forms.FileMediaSource", FileMediaSource.FileProperty },
{ "Xamarin.Forms.HtmlWebViewSource", HtmlWebViewSource.HtmlProperty },
{ "Xamarin.Forms.Image", Image.SourceProperty },
{ "Xamarin.Forms.ImageButton", ImageButton.CommandProperty },
@ -33,7 +32,6 @@ namespace Xamarin.Forms.Markup
{ "Xamarin.Forms.Label", Label.TextProperty },
{ "Xamarin.Forms.ListView", ListView.ItemsSourceProperty },
{ "Xamarin.Forms.MasterDetailPage", Page.TitleProperty },
{ "Xamarin.Forms.MediaElement", MediaElement.SourceProperty },
{ "Xamarin.Forms.MenuItem", MenuItem.CommandProperty },
{ "Xamarin.Forms.MultiPage", Page.TitleProperty },
{ "Xamarin.Forms.NavigationPage", Page.TitleProperty },
@ -62,7 +60,6 @@ namespace Xamarin.Forms.Markup
{ "Xamarin.Forms.TimePicker", TimePicker.TimeProperty },
{ "Xamarin.Forms.ToolbarItem", ToolbarItem.CommandProperty },
{ "Xamarin.Forms.UriImageSource", UriImageSource.UriProperty },
{ "Xamarin.Forms.UriMediaSource", UriMediaSource.UriProperty },
{ "Xamarin.Forms.UrlWebViewSource", UrlWebViewSource.UrlProperty },
{ "Xamarin.Forms.WebView", WebView.SourceProperty }
};

Просмотреть файл

@ -1,309 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform;
namespace Xamarin.Forms
{
[RenderWith(typeof(_MediaElementRenderer))]
public sealed class MediaElement : View, IMediaElementController
{
[EditorBrowsable(EditorBrowsableState.Never)]
public static void VerifyMediaElementFlagEnabled(
string constructorHint = null,
[CallerMemberName] string memberName = "")
{
ExperimentalFlags.VerifyFlagEnabled(nameof(MediaElement), ExperimentalFlags.MediaElementExperimental, memberName: memberName);
}
public static readonly BindableProperty AspectProperty =
BindableProperty.Create(nameof(Aspect), typeof(Aspect), typeof(MediaElement), Aspect.AspectFit);
public static readonly BindableProperty AutoPlayProperty =
BindableProperty.Create(nameof(AutoPlay), typeof(bool), typeof(MediaElement), true);
public static readonly BindableProperty BufferingProgressProperty =
BindableProperty.Create(nameof(BufferingProgress), typeof(double), typeof(MediaElement), 0.0);
public static readonly BindableProperty CurrentStateProperty =
BindableProperty.Create(nameof(CurrentState), typeof(MediaElementState), typeof(MediaElement), MediaElementState.Closed);
public static readonly BindableProperty DurationProperty =
BindableProperty.Create(nameof(Duration), typeof(TimeSpan?), typeof(MediaElement), null);
public static readonly BindableProperty IsLoopingProperty =
BindableProperty.Create(nameof(IsLooping), typeof(bool), typeof(MediaElement), false);
public static readonly BindableProperty KeepScreenOnProperty =
BindableProperty.Create(nameof(KeepScreenOn), typeof(bool), typeof(MediaElement), false);
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(MediaElement), TimeSpan.Zero);
public static readonly BindableProperty ShowsPlaybackControlsProperty =
BindableProperty.Create(nameof(ShowsPlaybackControls), typeof(bool), typeof(MediaElement), false);
public static readonly BindableProperty SourceProperty =
BindableProperty.Create(nameof(Source), typeof(MediaSource), typeof(MediaElement),
propertyChanging: OnSourcePropertyChanging, propertyChanged: OnSourcePropertyChanged);
public static readonly BindableProperty VideoHeightProperty =
BindableProperty.Create(nameof(VideoHeight), typeof(int), typeof(MediaElement));
public static readonly BindableProperty VideoWidthProperty =
BindableProperty.Create(nameof(VideoWidth), typeof(int), typeof(MediaElement));
public static readonly BindableProperty VolumeProperty =
BindableProperty.Create(nameof(Volume), typeof(double), typeof(MediaElement), 1.0, BindingMode.TwoWay, new BindableProperty.ValidateValueDelegate(ValidateVolume));
private static bool ValidateVolume(BindableObject o, object newValue)
{
double d = (double)newValue;
return d >= 0.0 && d <= 1.0;
}
public Aspect Aspect
{
get => (Aspect)GetValue(AspectProperty);
set => SetValue(AspectProperty, value);
}
public bool AutoPlay
{
get { return (bool)GetValue(AutoPlayProperty); }
set { SetValue(AutoPlayProperty, value); }
}
public double BufferingProgress
{
get { return (double)GetValue(BufferingProgressProperty); }
}
public bool CanSeek
{
get { return Source != null && Duration.HasValue; }
}
public MediaElementState CurrentState
{
get { return (MediaElementState)GetValue(CurrentStateProperty); }
}
public TimeSpan? Duration
{
get { return (TimeSpan?)GetValue(DurationProperty); }
}
public bool IsLooping
{
get { return (bool)GetValue(IsLoopingProperty); }
set { SetValue(IsLoopingProperty, value); }
}
public bool KeepScreenOn
{
get { return (bool)GetValue(KeepScreenOnProperty); }
set { SetValue(KeepScreenOnProperty, value); }
}
public bool ShowsPlaybackControls
{
get { return (bool)GetValue(ShowsPlaybackControlsProperty); }
set { SetValue(ShowsPlaybackControlsProperty, value); }
}
public TimeSpan Position
{
get
{
PositionRequested?.Invoke(this, EventArgs.Empty);
return (TimeSpan)GetValue(PositionProperty);
}
set
{
SeekRequested?.Invoke(this, new SeekRequested(value));
}
}
[TypeConverter(typeof(MediaSourceConverter))]
public MediaSource Source
{
get { return (MediaSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public int VideoHeight
{
get { return (int)GetValue(VideoHeightProperty); }
}
public int VideoWidth
{
get { return (int)GetValue(VideoWidthProperty); }
}
public double Volume
{
get
{
VolumeRequested?.Invoke(this, EventArgs.Empty);
return (double)GetValue(VolumeProperty);
}
set
{
SetValue(VolumeProperty, value);
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<SeekRequested> SeekRequested;
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<StateRequested> StateRequested;
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler PositionRequested;
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler VolumeRequested;
public void Play()
{
StateRequested?.Invoke(this, new StateRequested(MediaElementState.Playing));
}
public void Pause()
{
StateRequested?.Invoke(this, new StateRequested(MediaElementState.Paused));
}
public void Stop()
{
StateRequested?.Invoke(this, new StateRequested(MediaElementState.Stopped));
}
double IMediaElementController.BufferingProgress { get => (double)GetValue(BufferingProgressProperty); set => SetValue(BufferingProgressProperty, value); }
MediaElementState IMediaElementController.CurrentState { get => (MediaElementState)GetValue(CurrentStateProperty); set => SetValue(CurrentStateProperty, value); }
TimeSpan? IMediaElementController.Duration { get => (TimeSpan?)GetValue(DurationProperty); set => SetValue(DurationProperty, value); }
TimeSpan IMediaElementController.Position { get => (TimeSpan)GetValue(PositionProperty); set => SetValue(PositionProperty, value); }
int IMediaElementController.VideoHeight { get => (int)GetValue(VideoHeightProperty); set => SetValue(VideoHeightProperty, value); }
int IMediaElementController.VideoWidth { get => (int)GetValue(VideoWidthProperty); set => SetValue(VideoWidthProperty, value); }
double IMediaElementController.Volume { get => (double)GetValue(VolumeProperty); set => SetValue(VolumeProperty, value);
}
void IMediaElementController.OnMediaEnded()
{
SetValue(CurrentStateProperty, MediaElementState.Stopped);
MediaEnded?.Invoke(this, EventArgs.Empty);
}
public event EventHandler MediaEnded;
void IMediaElementController.OnMediaFailed()
{
MediaFailed?.Invoke(this, EventArgs.Empty);
}
public event EventHandler MediaFailed;
void IMediaElementController.OnMediaOpened()
{
MediaOpened?.Invoke(this, EventArgs.Empty);
}
public event EventHandler MediaOpened;
void IMediaElementController.OnSeekCompleted()
{
SeekCompleted?.Invoke(this, EventArgs.Empty);
}
public event EventHandler SeekCompleted;
protected override void OnBindingContextChanged()
{
if (Source != null)
SetInheritedBindingContext(Source, BindingContext);
base.OnBindingContextChanged();
}
void OnSourceChanged(object sender, EventArgs eventArgs)
{
OnPropertyChanged(SourceProperty.PropertyName);
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
static void OnSourcePropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
{
((MediaElement)bindable).OnSourcePropertyChanged((MediaSource)oldvalue, (MediaSource)newvalue);
}
void OnSourcePropertyChanged(MediaSource oldvalue, MediaSource newvalue)
{
if (newvalue != null)
{
newvalue.SourceChanged += OnSourceChanged;
SetInheritedBindingContext(newvalue, BindingContext);
}
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
static void OnSourcePropertyChanging(BindableObject bindable, object oldvalue, object newvalue)
{
((MediaElement)bindable).OnSourcePropertyChanging((MediaSource)oldvalue, (MediaSource)newvalue);
}
void OnSourcePropertyChanging(MediaSource oldvalue, MediaSource newvalue)
{
if (oldvalue == null)
return;
oldvalue.SourceChanged -= OnSourceChanged;
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public class SeekRequested : EventArgs
{
public TimeSpan Position { get; }
public SeekRequested(TimeSpan position)
{
Position = position;
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public class StateRequested : EventArgs
{
public MediaElementState State { get; }
public StateRequested(MediaElementState state)
{
State = state;
}
}
public interface IMediaElementController
{
double BufferingProgress { get; set; }
MediaElementState CurrentState { get; set; }
TimeSpan? Duration { get; set; }
TimeSpan Position { get; set; }
int VideoHeight { get; set; }
int VideoWidth { get; set; }
double Volume { get; set; }
void OnMediaEnded();
void OnMediaFailed();
void OnMediaOpened();
void OnSeekCompleted();
}
}

Просмотреть файл

@ -1,12 +0,0 @@
namespace Xamarin.Forms
{
public enum MediaElementState
{
Closed,
Opening,
Buffering,
Playing,
Paused,
Stopped,
}
}

Просмотреть файл

@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Forms
{
[TypeConverter(typeof(MediaSourceConverter))]
public abstract class MediaSource : Element
{
readonly WeakEventManager _weakEventManager = new WeakEventManager();
public static MediaSource FromFile(string file)
{
return new FileMediaSource { File = file };
}
public static MediaSource FromUri(Uri uri)
{
if (!uri.IsAbsoluteUri)
throw new ArgumentException("uri is relative");
return new UriMediaSource { Uri = uri };
}
public static implicit operator MediaSource(string source)
{
Uri uri;
return Uri.TryCreate(source, UriKind.Absolute, out uri) && uri.Scheme != "file" ? FromUri(uri) : FromFile(source);
}
public static implicit operator MediaSource(Uri uri)
{
if (uri is null)
return null;
if (!uri.IsAbsoluteUri)
throw new ArgumentException("uri is relative");
return FromUri(uri);
}
protected void OnSourceChanged()
{
_weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(SourceChanged));
}
internal event EventHandler SourceChanged
{
add { _weakEventManager.AddEventHandler(value); }
remove { _weakEventManager.RemoveEventHandler(value); }
}
}
}

Просмотреть файл

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Forms
{
[Xaml.TypeConversion(typeof(MediaSource))]
public sealed class MediaSourceConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (value != null)
{
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri) && uri.Scheme != "file" ? MediaSource.FromUri(uri) : MediaSource.FromFile(value);
}
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(MediaSource)));
}
}
}

Просмотреть файл

@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using XVisualElement = Xamarin.Forms.VisualElement;
namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
{
public interface IVideoOutput
{
XVisualElement MediaView { get; }
View Controller { get; set; }
VideoOuputType OuputType { get; }
}
public enum VideoOuputType
{
Overlay,
Buffer,
}
public enum DisplayAspectMode
{
Fill,
AspectFit,
AspectFill,
OrignalSize
}
public enum PlaybackState
{
Stopped,
Playing,
Paused
}
public interface IMediaPlayer
{
PlaybackState State { get; }
event EventHandler PlaybackPaused;
event EventHandler PlaybackStarted;
event EventHandler PlaybackStopped;
Task<bool> Start();
void Stop();
void Pause();
}
public interface IPlatformMediaPlayer : IDisposable
{
bool UsesEmbeddingControls { get; set; }
bool AutoPlay { get; set; }
bool AutoStop { get; set; }
double Volume { get; set; }
bool IsMuted { get; set; }
bool IsLooping { get; set; }
int Position { get; }
int Duration { get; }
DisplayAspectMode AspectMode { get; set; }
event EventHandler PlaybackCompleted;
event EventHandler PlaybackStarted;
event EventHandler PlaybackPaused;
event EventHandler PlaybackStopped;
event EventHandler UpdateStreamInfo;
event EventHandler<BufferingProgressUpdatedEventArgs> BufferingProgressUpdated;
event EventHandler ErrorOccurred;
void SetDisplay(IVideoOutput output);
void SetSource(MediaSource source);
Task<bool> Start();
void Stop();
void Pause();
Task<int> Seek(int ms);
Task<Stream> GetAlbumArts();
Task<IDictionary<string, string>> GetMetadata();
Task<Size> GetVideoSize();
View GetEmbeddingControlView(IMediaPlayer player);
}
public class BufferingProgressUpdatedEventArgs : EventArgs
{
public double Progress { get; set; }
}
}

Просмотреть файл

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
public sealed class UriMediaSource : MediaSource
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(nameof(Uri), typeof(Uri), typeof(UriMediaSource), default(Uri),
propertyChanged: (bindable, oldvalue, newvalue) => ((UriMediaSource)bindable).OnSourceChanged(), validateValue: (bindable, value) => value == null || ((Uri)value).IsAbsoluteUri);
[TypeConverter(typeof(UriTypeConverter))]
public Uri Uri
{
get { return (Uri)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public override string ToString()
{
return $"Uri: {Uri}";
}
}
}

Просмотреть файл

@ -1,537 +0,0 @@
using Android.Content;
using Android.Media;
using Android.Views;
using Android.Widget;
using System;
using System.ComponentModel;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.Android.FastRenderers;
using AView = Android.Views.View;
namespace Xamarin.Forms.Platform.Android
{
public sealed class MediaElementRenderer : FrameLayout, IVisualElementRenderer, IViewRenderer, IEffectControlProvider, MediaPlayer.IOnCompletionListener, MediaPlayer.IOnInfoListener, MediaPlayer.IOnPreparedListener, MediaPlayer.IOnErrorListener
{
bool _isDisposed;
int? _defaultLabelFor;
MediaElement MediaElement { get; set; }
IMediaElementController Controller => MediaElement as IMediaElementController;
readonly AutomationPropertiesProvider _automationPropertiesProvider;
readonly EffectControlProvider _effectControlProvider;
VisualElementTracker _tracker;
MediaController _controller;
MediaPlayer _mediaPlayer;
FormsVideoView _view;
public MediaElementRenderer(Context context) : base(context)
{
Xamarin.Forms.MediaElement.VerifyMediaElementFlagEnabled(nameof(MediaElementRenderer));
_automationPropertiesProvider = new AutomationPropertiesProvider(this);
_effectControlProvider = new EffectControlProvider(this);
_view = new FormsVideoView(Context);
_view.SetZOrderMediaOverlay(true);
_view.SetOnCompletionListener(this);
_view.SetOnInfoListener(this);
_view.SetOnPreparedListener(this);
_view.SetOnErrorListener(this);
_view.MetadataRetrieved += MetadataRetrieved;
AddView(_view, -1, -1);
_controller = new MediaController(Context);
_controller.SetAnchorView(this);
_view.SetMediaController(_controller);
}
public VisualElement Element => MediaElement;
VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
ViewGroup IVisualElementRenderer.ViewGroup => null;
AView IVisualElementRenderer.View => this;
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
AView view = this;
view.Measure(widthConstraint, heightConstraint);
return new SizeRequest(new Size(MeasuredWidth, MeasuredHeight), new Size());
}
void IViewRenderer.MeasureExactly()
{
ViewRenderer.MeasureExactly(this, Element, Context);
}
void UnsubscribeFromEvents(MediaElement element)
{
if (element == null)
return;
element.PropertyChanged -= OnElementPropertyChanged;
element.SeekRequested -= SeekRequested;
element.StateRequested -= StateRequested;
element.PositionRequested -= OnPositionRequested;
}
void IVisualElementRenderer.SetElement(VisualElement element)
{
if (element is null)
throw new ArgumentNullException(nameof(element));
if (!(element is MediaElement))
throw new ArgumentException($"{nameof(element)} must be of type {nameof(MediaElement)}");
MediaElement oldElement = MediaElement;
MediaElement = (MediaElement)element;
Performance.Start(out string reference);
if (oldElement != null)
{
UnsubscribeFromEvents(oldElement);
}
Color currentColor = oldElement?.BackgroundColor ?? Color.Default;
if (element.BackgroundColor != currentColor)
{
UpdateBackgroundColor();
}
if (MediaElement != null)
{
MediaElement.PropertyChanged += OnElementPropertyChanged;
MediaElement.SeekRequested += SeekRequested;
MediaElement.StateRequested += StateRequested;
MediaElement.PositionRequested += OnPositionRequested;
}
if (_tracker is null)
{
// Can't set up the tracker in the constructor because it access the Element (for now)
SetTracker(new VisualElementTracker(this));
}
OnElementChanged(new ElementChangedEventArgs<MediaElement>(oldElement as MediaElement, MediaElement));
EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
Performance.Stop(reference);
}
void StateRequested(object sender, StateRequested e)
{
if (_view == null)
return;
switch (e.State)
{
case MediaElementState.Playing:
_view.Start();
Controller.CurrentState = _view.IsPlaying ? MediaElementState.Playing : MediaElementState.Stopped;
break;
case MediaElementState.Paused:
if (_view.CanPause())
{
_view.Pause();
Controller.CurrentState = MediaElementState.Paused;
}
break;
case MediaElementState.Stopped:
_view.Pause();
_view.SeekTo(0);
Controller.CurrentState = _view.IsPlaying ? MediaElementState.Playing : MediaElementState.Stopped;
break;
}
UpdateLayoutParameters();
Controller.Position = _view.Position;
}
void OnPositionRequested(object sender, EventArgs e)
{
if (_view == null)
return;
Controller.Position = _view.Position;
}
void SeekRequested(object sender, SeekRequested e)
{
if (_view == null)
return;
Controller.Position = _view.Position;
}
void IVisualElementRenderer.SetLabelFor(int? id)
{
if (_defaultLabelFor is null)
{
_defaultLabelFor = LabelFor;
}
LabelFor = (int)(id ?? _defaultLabelFor);
}
void SetTracker(VisualElementTracker tracker)
{
_tracker = tracker;
}
void UpdateBackgroundColor()
{
SetBackgroundColor(Element.BackgroundColor.ToAndroid());
}
void IVisualElementRenderer.UpdateLayout() => _tracker?.UpdateLayout();
protected override void Dispose(bool disposing)
{
if (_isDisposed)
{
return;
}
_isDisposed = true;
ReleaseControl();
if (disposing)
{
SetOnClickListener(null);
SetOnTouchListener(null);
_automationPropertiesProvider?.Dispose();
_tracker?.Dispose();
if (Element != null)
{
UnsubscribeFromEvents(Element as MediaElement);
if (Platform.GetRenderer(Element) == this)
Element.ClearValue(Platform.RendererProperty);
}
}
base.Dispose(disposing);
}
//todo: make virtual when unsealed
void OnElementChanged(ElementChangedEventArgs<MediaElement> e)
{
if (e.OldElement != null)
{
}
if (e.NewElement != null)
{
this.EnsureId();
UpdateKeepScreenOn();
UpdateLayoutParameters();
UpdateShowPlaybackControls();
UpdateSource();
UpdateBackgroundColor();
ElevationHelper.SetElevation(this, e.NewElement);
}
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
}
void MetadataRetrieved(object sender, EventArgs e)
{
if (_view == null)
return;
Controller.Duration = _view.DurationTimeSpan;
Controller.VideoHeight = _view.VideoHeight;
Controller.VideoWidth = _view.VideoWidth;
Device.BeginInvokeOnMainThread(UpdateLayoutParameters);
}
//todo: make virtual when unsealed
void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch(e.PropertyName)
{
case nameof(MediaElement.Aspect):
UpdateLayoutParameters();
break;
case nameof(MediaElement.IsLooping):
if (_mediaPlayer != null)
{
_mediaPlayer.Looping = MediaElement.IsLooping;
}
break;
case nameof(MediaElement.KeepScreenOn):
UpdateKeepScreenOn();
break;
case nameof(MediaElement.ShowsPlaybackControls):
UpdateShowPlaybackControls();
break;
case nameof(MediaElement.Source):
UpdateSource();
break;
case nameof(MediaElement.Volume):
_mediaPlayer?.SetVolume((float)MediaElement.Volume, (float)MediaElement.Volume);
break;
}
ElementPropertyChanged?.Invoke(this, e);
}
public void RegisterEffect(Effect effect)
{
_effectControlProvider.RegisterEffect(effect);
}
void UpdateKeepScreenOn()
{
if (_view == null)
return;
_view.KeepScreenOn = MediaElement.KeepScreenOn;
}
void UpdateShowPlaybackControls()
{
if (_controller == null)
return;
_controller.Visibility = MediaElement.ShowsPlaybackControls ? ViewStates.Visible : ViewStates.Gone;
}
void UpdateSource()
{
if (_view == null)
return;
if (MediaElement.Source != null)
{
if (MediaElement.Source is UriMediaSource uriSource)
{
if (uriSource.Uri.Scheme == "ms-appx")
{
if (uriSource.Uri.LocalPath.Length <= 1)
return;
// video resources should be in the raw folder with Build Action set to AndroidResource
string uri = "android.resource://" + Context.PackageName + "/raw/" + uriSource.Uri.LocalPath.Substring(1, uriSource.Uri.LocalPath.LastIndexOf('.') - 1).ToLower();
_view.SetVideoURI(global::Android.Net.Uri.Parse(uri));
}
else if (uriSource.Uri.Scheme == "ms-appdata")
{
string filePath = Platform.ResolveMsAppDataUri(uriSource.Uri);
if (string.IsNullOrEmpty(filePath))
throw new ArgumentException("Invalid Uri", "Source");
_view.SetVideoPath(filePath);
}
else
{
if (uriSource.Uri.IsFile)
{
_view.SetVideoPath(uriSource.Uri.AbsolutePath);
}
else
{
_view.SetVideoURI(global::Android.Net.Uri.Parse(uriSource.Uri.AbsoluteUri));
}
}
}
else if (MediaElement.Source is FileMediaSource fileSource)
{
_view.SetVideoPath(fileSource.File);
}
if (MediaElement.AutoPlay)
{
_view.Start();
Controller.CurrentState = _view.IsPlaying ? MediaElementState.Playing : MediaElementState.Stopped;
}
}
else if (_view.IsPlaying)
{
_view.StopPlayback();
Controller.CurrentState = MediaElementState.Stopped;
}
}
void MediaPlayer.IOnCompletionListener.OnCompletion(MediaPlayer mp)
{
if (Controller == null)
return;
Controller.Position = TimeSpan.FromMilliseconds(_mediaPlayer.CurrentPosition);
Controller.OnMediaEnded();
}
void MediaPlayer.IOnPreparedListener.OnPrepared(MediaPlayer mp)
{
if (Controller == null)
return;
Controller.OnMediaOpened();
UpdateLayoutParameters();
_mediaPlayer = mp;
mp.Looping = MediaElement.IsLooping;
mp.SeekTo(0);
if (MediaElement.AutoPlay)
{
_mediaPlayer.Start();
Controller.CurrentState = MediaElementState.Playing;
}
else
{
Controller.CurrentState = MediaElementState.Paused;
}
}
void UpdateLayoutParameters()
{
if (_view == null)
return;
if (_view.VideoWidth == 0 || _view.VideoHeight == 0)
{
_view.LayoutParameters = new FrameLayout.LayoutParams(Width, Height, GravityFlags.Fill);
return;
}
float ratio = (float)_view.VideoWidth / (float)_view.VideoHeight;
float controlRatio = (float)Width / Height;
switch (MediaElement.Aspect)
{
case Aspect.Fill:
// TODO: this doesn't stretch like other platforms...
_view.LayoutParameters = new FrameLayout.LayoutParams(Width, Height, GravityFlags.Fill) { LeftMargin = 0, RightMargin = 0, TopMargin = 0, BottomMargin = 0 };
break;
case Aspect.AspectFit:
if (ratio > controlRatio)
{
int requiredHeight = (int)(Width / ratio);
int vertMargin = (Height - requiredHeight) / 2;
_view.LayoutParameters = new FrameLayout.LayoutParams(Width, requiredHeight, GravityFlags.FillHorizontal | GravityFlags.CenterVertical) { LeftMargin = 0, RightMargin = 0, TopMargin = vertMargin, BottomMargin = vertMargin };
}
else
{
int requiredWidth = (int)(Height * ratio);
int horizMargin = (Width - requiredWidth) / 2;
_view.LayoutParameters = new FrameLayout.LayoutParams(requiredWidth, Height, GravityFlags.CenterHorizontal | GravityFlags.FillVertical) { LeftMargin = horizMargin, RightMargin = horizMargin, TopMargin = 0, BottomMargin = 0 };
}
break;
case Aspect.AspectFill:
if (ratio > controlRatio)
{
int requiredWidth = (int)(Height * ratio);
int horizMargin = (Width - requiredWidth) / 2;
_view.LayoutParameters = new FrameLayout.LayoutParams((int)(Height * ratio), Height, GravityFlags.CenterHorizontal | GravityFlags.FillVertical) { TopMargin = 0, BottomMargin = 0, LeftMargin = horizMargin, RightMargin = horizMargin };
}
else
{
int requiredHeight = (int)(Width / ratio);
int vertMargin = (Height - requiredHeight) / 2;
_view.LayoutParameters = new FrameLayout.LayoutParams(Width, requiredHeight, GravityFlags.FillHorizontal | GravityFlags.CenterVertical) { LeftMargin = 0, RightMargin = 0, TopMargin = vertMargin, BottomMargin = vertMargin };
}
break;
}
}
void ReleaseControl()
{
if (_view != null)
{
_view.MetadataRetrieved -= MetadataRetrieved;
RemoveView(_view);
_view.SetOnPreparedListener(null);
_view.SetOnCompletionListener(null);
_view.Dispose();
_view = null;
}
if (_controller != null)
{
_controller.Dispose();
_controller = null;
}
if (_mediaPlayer != null)
{
_mediaPlayer.Dispose();
_mediaPlayer = null;
}
}
bool MediaPlayer.IOnErrorListener.OnError(MediaPlayer mp, MediaError what, int extra)
{
if (Controller == null)
return false;
Controller.OnMediaFailed();
return false;
}
bool MediaPlayer.IOnInfoListener.OnInfo(MediaPlayer mp, MediaInfo what, int extra)
{
if (_view == null)
return false;
switch (what)
{
case MediaInfo.BufferingStart:
Controller.CurrentState = MediaElementState.Buffering;
mp.BufferingUpdate += Mp_BufferingUpdate;
break;
case MediaInfo.BufferingEnd:
mp.BufferingUpdate -= Mp_BufferingUpdate;
Controller.CurrentState = MediaElementState.Paused;
break;
case MediaInfo.VideoRenderingStart:
_view.SetBackground(null);
Controller.CurrentState = MediaElementState.Playing;
break;
}
_mediaPlayer = mp;
return true;
}
void Mp_BufferingUpdate(object sender, MediaPlayer.BufferingUpdateEventArgs e)
{
Controller.BufferingProgress = e.Percent / 100f;
}
}
}

Просмотреть файл

@ -38,7 +38,6 @@ using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer (typeof (CarouselPage), typeof (CarouselPageRenderer))]
[assembly: ExportRenderer (typeof (Page), typeof (PageRenderer))]
[assembly: ExportRenderer (typeof (MasterDetailPage), typeof (MasterDetailRenderer))]
[assembly: ExportRenderer (typeof (MediaElement), typeof(MediaElementRenderer))]
[assembly: ExportRenderer (typeof (RefreshView), typeof (RefreshViewRenderer))]
[assembly: ExportRenderer(typeof(Path), typeof(PathRenderer))]
#endif

Просмотреть файл

@ -1,72 +0,0 @@
using Tizen.Multimedia;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
using ERect = ElmSharp.Rect;
using MRect = Tizen.Multimedia.Rectangle;
namespace Xamarin.Forms.Platform.Tizen
{
public static class MediaElementExtension
{
public static MRect ToMultimediaRectangle(this ERect rect)
{
return new MRect(rect.X, rect.Y, rect.Width, rect.Height);
}
public static PlayerDisplayMode ToNative(this Aspect aspect)
{
PlayerDisplayMode ret = PlayerDisplayMode.LetterBox;
switch (aspect)
{
case Aspect.AspectFill:
ret = PlayerDisplayMode.CroppedFull;
break;
case Aspect.AspectFit:
ret = PlayerDisplayMode.LetterBox;
break;
case Aspect.Fill:
ret = PlayerDisplayMode.FullScreen;
break;
}
return ret;
}
public static PlayerDisplayMode ToNative(this DisplayAspectMode mode)
{
PlayerDisplayMode ret = PlayerDisplayMode.LetterBox;
switch (mode)
{
case DisplayAspectMode.AspectFill:
ret = PlayerDisplayMode.CroppedFull;
break;
case DisplayAspectMode.AspectFit:
ret = PlayerDisplayMode.LetterBox;
break;
case DisplayAspectMode.Fill:
ret = PlayerDisplayMode.FullScreen;
break;
case DisplayAspectMode.OrignalSize:
ret = PlayerDisplayMode.OriginalOrFull;
break;
}
return ret;
}
public static DisplayAspectMode ToDisplayAspectMode(this Aspect aspect)
{
DisplayAspectMode ret = DisplayAspectMode.AspectFit;
switch (aspect)
{
case Aspect.AspectFill:
ret = DisplayAspectMode.AspectFill;
break;
case Aspect.AspectFit:
ret = DisplayAspectMode.AspectFit;
break;
case Aspect.Fill:
ret = DisplayAspectMode.Fill;
break;
}
return ret;
}
}
}

Просмотреть файл

@ -1,233 +0,0 @@
using System;
using System.Globalization;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
using XLabel = Xamarin.Forms.Label;
using XTextAlignment = Xamarin.Forms.TextAlignment;
using PlayerState = Xamarin.Forms.PlatformConfiguration.TizenSpecific.PlaybackState;
namespace Xamarin.Forms.Platform.Tizen.Native
{
public class EmbeddingControls : ContentView
{
public ImageButton PlayImage { get; private set; }
public ImageButton PauseImage { get; private set; }
public EmbeddingControls()
{
PlayImage = new ImageButton
{
Source = ImageSource.FromResource(ThemeConstants.MediaPlayer.Resources.PlayImagePath, typeof(EmbeddingControls).Assembly),
IsVisible = false
};
PlayImage.Clicked += OnImageButtonClicked;
AbsoluteLayout.SetLayoutFlags(PlayImage, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(PlayImage, new Rectangle(0.5, 0.5, 0.25, 0.25));
PauseImage = new ImageButton
{
Source = ImageSource.FromResource(ThemeConstants.MediaPlayer.Resources.PauseImagePath, typeof(EmbeddingControls).Assembly),
IsVisible = false
};
PauseImage.Clicked += OnImageButtonClicked;
AbsoluteLayout.SetLayoutFlags(PauseImage, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(PauseImage, new Rectangle(0.5, 0.5, 0.25, 0.25));
var bufferingLabel = new XLabel
{
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label), false),
HorizontalTextAlignment = XTextAlignment.Center,
TextColor = ThemeConstants.MediaPlayer.ColorClass.DefaultProgressLabelColor
};
bufferingLabel.SetBinding(XLabel.TextProperty, new Binding
{
Path = "BufferingProgress",
StringFormat = "{0:0%}"
});
bufferingLabel.SetBinding(IsVisibleProperty, new Binding
{
Path = "IsBuffering",
});
AbsoluteLayout.SetLayoutFlags(bufferingLabel, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(bufferingLabel, new Rectangle(0.5, 0.5, 0.25, 0.25));
var progressBoxView = new BoxView
{
Color = ThemeConstants.MediaPlayer.ColorClass.DefaultProgressBarColor
};
progressBoxView.SetBinding(AbsoluteLayout.LayoutBoundsProperty, new Binding
{
Path = "Progress",
Converter = new ProgressToBoundTextConverter()
});
AbsoluteLayout.SetLayoutFlags(progressBoxView, AbsoluteLayoutFlags.All);
var posLabel = new XLabel
{
Margin = new Thickness(10, 0, 0, 0),
FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(XLabel)),
HorizontalTextAlignment = XTextAlignment.Start
};
posLabel.SetBinding(XLabel.TextProperty, new Binding
{
Path = "Position",
Converter = new MillisecondToTextConverter()
});
AbsoluteLayout.SetLayoutFlags(posLabel, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(posLabel, new Rectangle(0,0,1,1));
var durationLabel = new XLabel
{
Margin = new Thickness(0, 0, 10, 0),
FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(XLabel)),
HorizontalTextAlignment = XTextAlignment.End
};
durationLabel.SetBinding(XLabel.TextProperty, new Binding
{
Path = "Duration",
Converter = new MillisecondToTextConverter()
});
AbsoluteLayout.SetLayoutFlags(durationLabel, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(durationLabel, new Rectangle(0, 0, 1, 1));
var progressInnerLayout = new AbsoluteLayout
{
HorizontalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 23,
BackgroundColor = ThemeConstants.MediaPlayer.ColorClass.DefaultProgressAreaColor,
Children =
{
progressBoxView,
posLabel,
durationLabel
}
};
var progressLayout = new StackLayout
{
Children =
{
new StackLayout { VerticalOptions = LayoutOptions.FillAndExpand },
new StackLayout
{
Margin = Device.Idiom == TargetIdiom.Watch ? new Thickness(80, 0, 80, 0) : 20,
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = ThemeConstants.MediaPlayer.ColorClass.DefaultProgressAreaBackgroundColor,
Children = { progressInnerLayout }
}
}
};
AbsoluteLayout.SetLayoutFlags(progressLayout, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(progressLayout, new Rectangle(0, 0, 1, 1));
Content = new AbsoluteLayout
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Children = {
progressLayout,
PlayImage,
PauseImage,
bufferingLabel
}
};
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (BindingContext is IMediaPlayer player)
{
player.PlaybackPaused += OnPlaybackStateChanged;
player.PlaybackStarted += OnPlaybackStateChanged;
player.PlaybackStopped += OnPlaybackStateChanged;
}
}
async void OnPlaybackStateChanged(object sender, EventArgs e)
{
if (BindingContext is IMediaPlayer player)
{
if (player.State == PlayerState.Playing)
{
var unused = PlayImage.FadeTo(0, 100);
await PlayImage.ScaleTo(3.0, 300);
PlayImage.IsVisible = false;
PlayImage.Scale = 1.0;
PauseImage.IsVisible = true;
unused = PauseImage.FadeTo(1, 50);
}
else
{
var unused = PauseImage.FadeTo(0, 100);
await PauseImage.ScaleTo(3.0, 300);
PauseImage.IsVisible = false;
PauseImage.Scale = 1.0;
PlayImage.IsVisible = true;
unused = PlayImage.FadeTo(1, 50);
}
}
}
async void OnImageButtonClicked(object sender, EventArgs e)
{
if (BindingContext is IMediaPlayer player)
{
if (player.State == PlayerState.Playing)
{
player.Pause();
}
else
{
await player.Start();
}
}
}
}
public class ProgressToBoundTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double progress = (double)value;
if (Double.IsNaN(progress))
{
progress = 0d;
}
return new Rectangle(0, 0, progress, 1);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Rectangle rect = (Rectangle)value;
return rect.Width;
}
}
public class MillisecondToTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int millisecond = (int)value;
int second = (millisecond / 1000) % 60;
int min = (millisecond / 1000 / 60) % 60;
int hour = (millisecond / 1000 / 60 / 60);
if (hour > 0)
{
return string.Format("{0:d2}:{1:d2}:{2:d2}", hour, min, second);
}
else
{
return string.Format("{0:d2}:{1:d2}", min, second);
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -1,87 +0,0 @@
using System;
using ElmSharp;
using System.Collections.Generic;
using System.Collections.Specialized;
namespace Xamarin.Forms.Platform.Tizen.Native
{
public class LayoutCanvas : WidgetLayout, IContainable<EvasObject>
{
readonly ObservableCollection<EvasObject> _children = new ObservableCollection<EvasObject>();
Box _box;
public LayoutCanvas(EvasObject parent) : base(parent)
{
_box = new Box(parent);
SetContent(_box);
_children.CollectionChanged += (o, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var v in e.NewItems)
{
var view = v as EvasObject;
if (null != view)
{
OnAdd(view);
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var v in e.OldItems)
{
if (v is EvasObject view)
{
OnRemove(view);
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
OnRemoveAll();
}
};
}
public event EventHandler<LayoutEventArgs> LayoutUpdated
{
add { _box.LayoutUpdated += value; }
remove { _box.LayoutUpdated -= value; }
}
public new IList<EvasObject> Children
{
get
{
return _children;
}
}
protected override void OnUnrealize()
{
foreach (var child in _children)
{
child.Unrealize();
}
base.OnUnrealize();
}
void OnAdd(EvasObject view)
{
_box.PackEnd(view);
}
void OnRemove(EvasObject view)
{
_box.UnPack(view);
}
void OnRemoveAll()
{
_box.UnPackAll();
}
}
}

Просмотреть файл

@ -1,545 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
namespace Xamarin.Forms.Platform.Tizen.Native
{
public class MediaPlayer : Element, IMediaPlayer, IDisposable
{
public static readonly BindableProperty SourceProperty = BindableProperty.Create(nameof(Source), typeof(MediaSource), typeof(MediaPlayer), default(MediaSource), propertyChanged: OnSourceChanged);
public static readonly BindableProperty VideoOutputProperty = BindableProperty.Create(nameof(VideoOutput), typeof(IVideoOutput), typeof(MediaPlayer), null, propertyChanging: null, propertyChanged: (b, o, n) => ((MediaPlayer)b).OnVideoOutputChanged());
public static readonly BindableProperty UsesEmbeddingControlsProperty = BindableProperty.Create(nameof(UsesEmbeddingControls), typeof(bool), typeof(MediaPlayer), true, propertyChanged: (b, o, n) => ((MediaPlayer)b).OnUsesEmbeddingControlsChanged());
public static readonly BindableProperty VolumeProperty = BindableProperty.Create(nameof(Volume), typeof(double), typeof(MediaPlayer), 1d, coerceValue: (bindable, value) => ((double)value).Clamp(0, 1), propertyChanged: (b, o, n) => ((MediaPlayer)b).OnVolumeChanged());
public static readonly BindableProperty IsMutedProperty = BindableProperty.Create(nameof(IsMuted), typeof(bool), typeof(MediaPlayer), false, propertyChanged: (b, o, n) => ((MediaPlayer)b).UpdateIsMuted());
public static readonly BindableProperty AspectModeProperty = BindableProperty.Create(nameof(AspectMode), typeof(DisplayAspectMode), typeof(MediaPlayer), DisplayAspectMode.AspectFit, propertyChanged: (b, o, n) => ((MediaPlayer)b).OnAspectModeChanged());
public static readonly BindableProperty AutoPlayProperty = BindableProperty.Create(nameof(AutoPlay), typeof(bool), typeof(MediaPlayer), false, propertyChanged: (b, o, n) => ((MediaPlayer)b).UpdateAutoPlay());
public static readonly BindableProperty AutoStopProperty = BindableProperty.Create(nameof(AutoStop), typeof(bool), typeof(MediaPlayer), true, propertyChanged: (b, o, n) => ((MediaPlayer)b).UpdateAutoStop());
public static readonly BindableProperty IsLoopingProperty = BindableProperty.Create(nameof(IsLooping), typeof(bool), typeof(MediaPlayer), false, propertyChanged: (b, o, n) => ((MediaPlayer)b).UpdateIsLooping());
static readonly BindablePropertyKey DurationPropertyKey = BindableProperty.CreateReadOnly(nameof(Duration), typeof(int), typeof(MediaPlayer), 0);
public static readonly BindableProperty DurationProperty = DurationPropertyKey.BindableProperty;
static readonly BindablePropertyKey BufferingProgressPropertyKey = BindableProperty.CreateReadOnly(nameof(BufferingProgress), typeof(double), typeof(MediaPlayer), 0d);
public static readonly BindableProperty BufferingProgressProperty = BufferingProgressPropertyKey.BindableProperty;
static readonly BindablePropertyKey PositionPropertyKey = BindableProperty.CreateReadOnly(nameof(Position), typeof(int), typeof(MediaPlayer), 0);
public static readonly BindableProperty PositionProperty = PositionPropertyKey.BindableProperty;
static readonly BindablePropertyKey StatePropertyKey = BindableProperty.CreateReadOnly(nameof(State), typeof(PlaybackState), typeof(MediaPlayer), PlaybackState.Stopped);
public static readonly BindableProperty StateProperty = StatePropertyKey.BindableProperty;
public static readonly BindableProperty PositionUpdateIntervalProperty = BindableProperty.Create(nameof(PositionUpdateInterval), typeof(int), typeof(MediaPlayer), 500);
static readonly BindablePropertyKey IsBufferingPropertyKey = BindableProperty.CreateReadOnly(nameof(IsBuffering), typeof(bool), typeof(MediaPlayer), false);
public static readonly BindableProperty IsBufferingProperty = IsBufferingPropertyKey.BindableProperty;
bool _disposed = false;
bool _isPlaying;
bool _controlsAlwaysVisible;
IPlatformMediaPlayer _impl;
CancellationTokenSource _hideTimerCTS = new CancellationTokenSource();
Lazy<View> _controls;
public MediaPlayer()
{
_impl = new MediaPlayerImpl();
_impl.UpdateStreamInfo += OnUpdateStreamInfo;
_impl.PlaybackCompleted += SendPlaybackCompleted;
_impl.PlaybackStarted += SendPlaybackStarted;
_impl.PlaybackPaused += SendPlaybackPaused;
_impl.PlaybackStopped += SendPlaybackStopped;
_impl.BufferingProgressUpdated += OnUpdateBufferingProgress;
_impl.ErrorOccurred += OnErrorOccurred;
_impl.UsesEmbeddingControls = true;
_impl.Volume = 1d;
_impl.AspectMode = DisplayAspectMode.AspectFit;
_impl.AutoPlay = false;
_impl.AutoStop = true;
_controlsAlwaysVisible = false;
_controls = new Lazy<View>(() =>
{
return _impl.GetEmbeddingControlView(this);
});
}
~MediaPlayer()
{
Dispose(false);
}
public DisplayAspectMode AspectMode
{
get { return (DisplayAspectMode)GetValue(AspectModeProperty); }
set { SetValue(AspectModeProperty, value); }
}
public bool AutoPlay
{
get
{
return (bool)GetValue(AutoPlayProperty);
}
set
{
SetValue(AutoPlayProperty, value);
}
}
public bool AutoStop
{
get
{
return (bool)GetValue(AutoStopProperty);
}
set
{
SetValue(AutoStopProperty, value);
}
}
public bool IsLooping
{
get
{
return (bool)GetValue(IsLoopingProperty);
}
set
{
SetValue(IsLoopingProperty, value);
}
}
public double BufferingProgress
{
get
{
return (double)GetValue(BufferingProgressProperty);
}
private set
{
SetValue(BufferingProgressPropertyKey, value);
}
}
public int Duration
{
get
{
return (int)GetValue(DurationProperty);
}
private set
{
SetValue(DurationPropertyKey, value);
}
}
[Xamarin.Forms.TypeConverter(typeof(MediaSourceConverter))]
public MediaSource Source
{
get { return (MediaSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public IVideoOutput VideoOutput
{
get { return (IVideoOutput)GetValue(VideoOutputProperty); }
set { SetValue(VideoOutputProperty, value); }
}
public double Volume
{
get { return (double)GetValue(VolumeProperty); }
set { SetValue(VolumeProperty, value); }
}
public bool IsMuted
{
get { return (bool)GetValue(IsMutedProperty); }
set { SetValue(IsMutedProperty, value); }
}
public int PositionUpdateInterval
{
get { return (int)GetValue(PositionUpdateIntervalProperty); }
set { SetValue(PositionUpdateIntervalProperty, value); }
}
public bool UsesEmbeddingControls
{
get
{
return (bool)GetValue(UsesEmbeddingControlsProperty);
}
set
{
SetValue(UsesEmbeddingControlsProperty, value);
_impl.UsesEmbeddingControls = value;
}
}
public int Position
{
get
{
return _impl.Position;
}
private set
{
SetValue(PositionPropertyKey, value);
OnPropertyChanged(nameof(Progress));
}
}
public PlaybackState State
{
get
{
return (PlaybackState)GetValue(StateProperty);
}
private set
{
SetValue(StatePropertyKey, value);
}
}
public bool IsBuffering
{
get
{
return (bool)GetValue(IsBufferingProperty);
}
private set
{
SetValue(IsBufferingPropertyKey, value);
}
}
public double Progress
{
get
{
return Position / (double)Math.Max(Position, Duration);
}
}
public Command StartCommand => new Command(() =>
{
if (State == PlaybackState.Playing)
{
Pause();
}
else
{
Start();
}
});
public Command FastForwardCommand => new Command(() =>
{
if (State != PlaybackState.Stopped)
{
Seek(Math.Min(Position + 5000, Duration));
}
}, () => State != PlaybackState.Stopped);
public Command RewindCommand => new Command(() =>
{
if (State != PlaybackState.Stopped)
{
Seek(Math.Max(Position - 5000, 0));
}
}, () => State != PlaybackState.Stopped);
public event EventHandler PlaybackCompleted;
public event EventHandler PlaybackStarted;
public event EventHandler PlaybackPaused;
public event EventHandler PlaybackStopped;
public event EventHandler<BufferingProgressUpdatedEventArgs> BufferingProgressUpdated;
public event EventHandler BufferingStarted;
public event EventHandler BufferingCompleted;
public event EventHandler ErrorOccurred;
public event EventHandler MediaPrepared;
public void Pause()
{
_impl.Pause();
}
public Task<int> Seek(int ms)
{
ShowController();
return _impl.Seek(ms).ContinueWith((t) => Position = _impl.Position);
}
public Task<bool> Start()
{
return _impl.Start();
}
public void Stop()
{
_impl.Stop();
}
public Task<Stream> GetAlbumArts()
{
return _impl.GetAlbumArts();
}
public Task<IDictionary<string, string>> GetMetadata()
{
return _impl.GetMetadata();
}
public Task<Size> GetVideoSize()
{
return _impl.GetVideoSize();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_impl.UpdateStreamInfo -= OnUpdateStreamInfo;
_impl.PlaybackCompleted -= SendPlaybackCompleted;
_impl.PlaybackStarted -= SendPlaybackStarted;
_impl.PlaybackPaused -= SendPlaybackPaused;
_impl.PlaybackStopped -= SendPlaybackStopped;
_impl.BufferingProgressUpdated -= OnUpdateBufferingProgress;
_impl.ErrorOccurred -= OnErrorOccurred;
_impl.Dispose();
}
_disposed = true;
}
void UpdateAutoPlay()
{
_impl.AutoPlay = AutoPlay;
}
void UpdateAutoStop()
{
_impl.AutoStop = AutoStop;
}
void UpdateIsMuted()
{
_impl.IsMuted = IsMuted;
}
void UpdateIsLooping()
{
_impl.IsLooping = IsLooping;
}
void OnUpdateStreamInfo(object sender, EventArgs e)
{
Duration = _impl.Duration;
MediaPrepared?.Invoke(this, EventArgs.Empty);
}
void SendPlaybackCompleted(object sender, EventArgs e)
{
PlaybackCompleted?.Invoke(this, EventArgs.Empty);
}
void SendPlaybackStarted(object sender, EventArgs e)
{
_isPlaying = true;
State = PlaybackState.Playing;
StartPostionPollingTimer();
PlaybackStarted?.Invoke(this, EventArgs.Empty);
_controlsAlwaysVisible = false;
ShowController();
}
void SendPlaybackPaused(object sender, EventArgs e)
{
_isPlaying = false;
State = PlaybackState.Paused;
PlaybackPaused?.Invoke(this, EventArgs.Empty);
_controlsAlwaysVisible = true;
ShowController();
}
void SendPlaybackStopped(object sender, EventArgs e)
{
_isPlaying = false;
State = PlaybackState.Stopped;
Position = 0;
PlaybackStopped?.Invoke(this, EventArgs.Empty);
_controlsAlwaysVisible = true;
ShowController();
}
void StartPostionPollingTimer()
{
Device.StartTimer(TimeSpan.FromMilliseconds(PositionUpdateInterval), () =>
{
Position = _impl.Position;
return _isPlaying;
});
}
void OnSourceChanged(object sender, EventArgs e)
{
_impl.SetSource(Source);
}
void OnVideoOutputChanged()
{
if (VideoOutput != null)
{
if (UsesEmbeddingControls)
{
VideoOutput.Controller = _controls.Value;
}
VideoOutput.MediaView.Focused += OnVideoOutputFocused;
if (VideoOutput.MediaView is View outputView)
{
TapGestureRecognizer tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += OnOutputTapped;
outputView.GestureRecognizers.Add(tapGesture);
}
}
_impl.SetDisplay(VideoOutput);
}
void OnOutputTapped(object sender, EventArgs e)
{
if (!UsesEmbeddingControls)
return;
if (!_controls.Value.IsVisible)
{
ShowController();
}
}
async void OnUsesEmbeddingControlsChanged()
{
if (UsesEmbeddingControls)
{
if (VideoOutput != null)
{
VideoOutput.Controller = _controls.Value;
ShowController();
}
}
else
{
if (VideoOutput != null)
{
HideController(0);
await Task.Delay(200);
VideoOutput.Controller = null;
}
}
}
void OnVideoOutputFocused(object sender, FocusEventArgs e)
{
if (UsesEmbeddingControls)
{
ShowController();
}
}
void OnVolumeChanged()
{
_impl.Volume = Volume;
}
void OnAspectModeChanged()
{
_impl.AspectMode = AspectMode;
}
void OnUpdateBufferingProgress(object sender, BufferingProgressUpdatedEventArgs e)
{
if (!IsBuffering && e.Progress >= 0)
{
IsBuffering = true;
BufferingStarted?.Invoke(this, EventArgs.Empty);
}
else if (IsBuffering && e.Progress == 1.0)
{
IsBuffering = false;
BufferingCompleted?.Invoke(this, EventArgs.Empty);
}
BufferingProgress = e.Progress;
BufferingProgressUpdated?.Invoke(this, new BufferingProgressUpdatedEventArgs { Progress = BufferingProgress });
}
void OnErrorOccurred(object sender, EventArgs e)
{
ErrorOccurred?.Invoke(this, EventArgs.Empty);
}
async void HideController(int after)
{
if (!_controls.IsValueCreated)
return;
_hideTimerCTS?.Cancel();
_hideTimerCTS?.Dispose();
_hideTimerCTS = new CancellationTokenSource();
try
{
await Task.Delay(after, _hideTimerCTS.Token);
if (!_controlsAlwaysVisible)
{
await _controls.Value.FadeTo(0, 200);
_controls.Value.IsVisible = false;
}
}
catch (Exception)
{
//Exception when canceled
}
}
void ShowController()
{
if (_controls.IsValueCreated)
{
_controls.Value.IsVisible = true;
_controls.Value.FadeTo(1.0, 200);
HideController(5000);
}
}
static void OnSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as MediaPlayer)?.OnSourceChanged(bindable, EventArgs.Empty);
}
}
}

Просмотреть файл

@ -1,406 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using Tizen.Multimedia;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
namespace Xamarin.Forms.Platform.Tizen.Native
{
public class MediaPlayerImpl : IPlatformMediaPlayer
{
bool _disposed = false;
bool _cancelToStart;
DisplayAspectMode _aspectMode = DisplayAspectMode.AspectFit;
Player _player;
Task _taskPrepare;
TaskCompletionSource<bool> _tcsForStreamInfo;
IVideoOutput _videoOutput;
MediaSource _source;
public MediaPlayerImpl()
{
_player = new Player();
_player.PlaybackCompleted += OnPlaybackCompleted;
_player.BufferingProgressChanged += OnBufferingProgressChanged;
_player.ErrorOccurred += OnErrorOccurred;
}
~MediaPlayerImpl()
{
Dispose(false);
}
public bool UsesEmbeddingControls { get; set; }
public bool AutoPlay { get; set; }
public bool AutoStop { get; set; }
public double Volume
{
get => _player.Volume;
set => _player.Volume = (float)value;
}
public bool IsMuted
{
get => _player.Muted;
set => _player.Muted = value;
}
public bool IsLooping
{
get => _player.IsLooping;
set => _player.IsLooping = value;
}
public int Duration => _player.StreamInfo.GetDuration();
public int Position
{
get
{
if (_player.State == PlayerState.Idle || _player.State == PlayerState.Preparing)
return 0;
return _player.GetPlayPosition();
}
}
public DisplayAspectMode AspectMode
{
get { return _aspectMode; }
set
{
_aspectMode = value;
ApplyAspectMode();
}
}
bool HasSource => _source != null;
IVideoOutput VideoOutput
{
get { return _videoOutput; }
set
{
if (TargetView != null)
TargetView.PropertyChanged -= OnTargetViewPropertyChanged;
_videoOutput = value;
if (TargetView != null)
{
TargetView.PropertyChanged += OnTargetViewPropertyChanged;
}
}
}
VisualElement TargetView => VideoOutput?.MediaView;
Task TaskPrepare
{
get => _taskPrepare ?? Task.CompletedTask;
set => _taskPrepare = value;
}
public event EventHandler UpdateStreamInfo;
public event EventHandler PlaybackCompleted;
public event EventHandler PlaybackStarted;
public event EventHandler<BufferingProgressUpdatedEventArgs> BufferingProgressUpdated;
public event EventHandler PlaybackStopped;
public event EventHandler PlaybackPaused;
public event EventHandler ErrorOccurred;
public async Task<bool> Start()
{
_cancelToStart = false;
if (!HasSource)
return false;
if (_player.State == PlayerState.Idle)
{
await Prepare();
}
if (_cancelToStart)
return false;
try
{
_player.Start();
}
catch (Exception e)
{
Log.Error($"Error On Start : {e.Message}");
return false;
}
PlaybackStarted?.Invoke(this, EventArgs.Empty);
return true;
}
public void Pause()
{
try
{
_player.Pause();
PlaybackPaused?.Invoke(this, EventArgs.Empty);
}
catch (Exception e)
{
Log.Error($"Error on Pause : {e.Message}");
}
}
public void Stop()
{
_cancelToStart = true;
var unusedTask = ChangeToIdleState();
PlaybackStopped?.Invoke(this, EventArgs.Empty);
}
public void SetDisplay(IVideoOutput output)
{
VideoOutput = output;
}
public async Task<int> Seek(int ms)
{
try
{
await _player.SetPlayPositionAsync(ms, false);
}
catch (Exception e)
{
Log.Error($"Fail to seek : {e.Message}");
}
return Position;
}
public void SetSource(MediaSource source)
{
_source = source;
if (HasSource && AutoPlay)
{
var unusedTask = Start();
}
}
public async Task<Stream> GetAlbumArts()
{
if (_player.State == PlayerState.Idle)
{
if (_tcsForStreamInfo == null || _tcsForStreamInfo.Task.IsCompleted)
{
_tcsForStreamInfo = new TaskCompletionSource<bool>();
}
await _tcsForStreamInfo.Task;
}
await TaskPrepare;
var imageData = _player.StreamInfo.GetAlbumArt();
if (imageData == null)
return null;
return new MemoryStream(imageData);
}
public async Task<IDictionary<string, string>> GetMetadata()
{
if (_player.State == PlayerState.Idle)
{
if (_tcsForStreamInfo == null || _tcsForStreamInfo.Task.IsCompleted)
{
_tcsForStreamInfo = new TaskCompletionSource<bool>();
}
await _tcsForStreamInfo.Task;
}
await TaskPrepare;
Dictionary<string, string> metadata = new Dictionary<string, string>
{
[nameof(StreamMetadataKey.Album)] = _player.StreamInfo.GetMetadata(StreamMetadataKey.Album),
[nameof(StreamMetadataKey.Artist)] = _player.StreamInfo.GetMetadata(StreamMetadataKey.Artist),
[nameof(StreamMetadataKey.Author)] = _player.StreamInfo.GetMetadata(StreamMetadataKey.Author),
[nameof(StreamMetadataKey.Genre)] = _player.StreamInfo.GetMetadata(StreamMetadataKey.Genre),
[nameof(StreamMetadataKey.Title)] = _player.StreamInfo.GetMetadata(StreamMetadataKey.Title),
[nameof(StreamMetadataKey.Year)] = _player.StreamInfo.GetMetadata(StreamMetadataKey.Year)
};
return metadata;
}
public async Task<Size> GetVideoSize()
{
if (_player.State == PlayerState.Idle)
{
if (_tcsForStreamInfo == null || _tcsForStreamInfo.Task.IsCompleted)
{
_tcsForStreamInfo = new TaskCompletionSource<bool>();
}
await _tcsForStreamInfo.Task;
}
await TaskPrepare;
var videoSize = _player.StreamInfo.GetVideoProperties().Size;
return new Size(videoSize.Width, videoSize.Height);
}
public View GetEmbeddingControlView(IMediaPlayer player)
{
return new EmbeddingControls
{
BindingContext = player
};
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_player.PlaybackCompleted -= OnPlaybackCompleted;
_player.BufferingProgressChanged -= OnBufferingProgressChanged;
_player.ErrorOccurred -= OnErrorOccurred;
_player.Dispose();
}
_disposed = true;
}
void ApplyDisplay()
{
if (VideoOutput == null)
{
_player.Display = null;
}
else
{
var renderer = Platform.GetRenderer(TargetView);
if (renderer is IMediaViewProvider provider && provider.GetMediaView() != null)
{
try
{
Display display = new Display(provider.GetMediaView());
_player.Display = display;
_player.DisplaySettings.Mode = _aspectMode.ToNative();
}
catch
{
Log.Error("Error on MediaView");
}
}
}
}
void ApplySource()
{
if (_source == null)
{
return;
}
if (_source is UriMediaSource uriSource)
{
var uri = uriSource.Uri;
_player.SetSource(new MediaUriSource(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri));
}
else if (_source is FileMediaSource fileSource)
{
_player.SetSource(new MediaUriSource(ResourcePath.GetPath(fileSource.File)));
}
}
async void OnTargetViewPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Renderer")
{
if (Platform.GetRenderer(sender as BindableObject) != null && HasSource && AutoPlay)
{
await Start();
}
else if (Platform.GetRenderer(sender as BindableObject) == null && AutoStop)
{
Stop();
}
}
}
async Task Prepare()
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
var prevTask = TaskPrepare;
TaskPrepare = tcs.Task;
await prevTask;
if (_player.State == PlayerState.Ready)
return;
ApplyDisplay();
ApplySource();
try
{
await _player.PrepareAsync();
UpdateStreamInfo?.Invoke(this, EventArgs.Empty);
_tcsForStreamInfo?.TrySetResult(true);
}
catch (Exception e)
{
Log.Error($"Error on prepare : {e.Message}");
}
tcs.SetResult(true);
}
async void ApplyAspectMode()
{
if (_player.State == PlayerState.Preparing)
{
await TaskPrepare;
}
_player.DisplaySettings.Mode = AspectMode.ToNative();
}
void OnBufferingProgressChanged(object sender, BufferingProgressChangedEventArgs e)
{
BufferingProgressUpdated?.Invoke(this, new BufferingProgressUpdatedEventArgs { Progress = e.Percent / 100.0 });
}
void OnPlaybackCompleted(object sender, EventArgs e)
{
PlaybackCompleted?.Invoke(this, EventArgs.Empty);
}
void OnErrorOccurred(object sender, PlayerErrorOccurredEventArgs e)
{
Log.Error($"Playback Error Occurred (code:{e.Error})-{e.ToString()}");
ErrorOccurred?.Invoke(this, EventArgs.Empty);
}
async Task ChangeToIdleState()
{
switch (_player.State)
{
case PlayerState.Playing:
case PlayerState.Paused:
_player.Stop();
_player.Unprepare();
break;
case PlayerState.Ready:
_player.Unprepare();
break;
case PlayerState.Preparing:
await TaskPrepare;
_player.Unprepare();
break;
}
}
}
}

Просмотреть файл

@ -1,12 +1,10 @@
using Xamarin.Forms;
using Xamarin.Forms.Platform.Tizen;
using MediaPlayerImpl = Xamarin.Forms.Platform.Tizen.Native.MediaPlayerImpl;
[assembly: Dependency(typeof(ResourcesProvider))]
[assembly: Dependency(typeof(Deserializer))]
[assembly: Dependency(typeof(NativeBindingService))]
[assembly: Dependency(typeof(NativeValueConverterService))]
[assembly: Dependency(typeof(MediaPlayerImpl))]
[assembly: ExportRenderer(typeof(Layout), typeof(LayoutRenderer))]
[assembly: ExportRenderer(typeof(ScrollView), typeof(ScrollViewRenderer))]
@ -44,7 +42,6 @@ using MediaPlayerImpl = Xamarin.Forms.Platform.Tizen.Native.MediaPlayerImpl;
[assembly: ExportRenderer(typeof(CarouselView), typeof(CarouselViewRenderer))]
[assembly: ExportRenderer(typeof(SwipeView), typeof(SwipeViewRenderer))]
[assembly: ExportRenderer(typeof(RefreshView), typeof(RefreshViewRenderer))]
[assembly: ExportRenderer(typeof(MediaElement), typeof(MediaElementRenderer))]
[assembly: ExportRenderer(typeof(IndicatorView), typeof(IndicatorViewRenderer))]
[assembly: ExportRenderer(typeof(RadioButton), typeof(RadioButtonRenderer))]

Просмотреть файл

@ -1,248 +0,0 @@
using System;
using System.Globalization;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
using Xamarin.Forms.Platform.Tizen.Native;
using ElmSharp;
using Tizen.Multimedia;
using XForms = Xamarin.Forms.Forms;
namespace Xamarin.Forms.Platform.Tizen
{
public class MediaElementRenderer : ViewRenderer<MediaElement, LayoutCanvas>, IMediaViewProvider, IVideoOutput
{
MediaPlayer _player;
MediaView _mediaView;
View _controller;
EvasObject _nativeController;
IMediaElementController Controller => Element as IMediaElementController;
VisualElement IVideoOutput.MediaView => Element;
View IVideoOutput.Controller
{
get
{
return _controller;
}
set
{
if (_controller != null)
{
_controller.Parent = null;
Control.Children.Remove(_nativeController);
_nativeController.Unrealize();
}
_controller = value;
if (_controller != null)
{
_controller.Parent = Element;
_nativeController = Platform.GetOrCreateRenderer(_controller).NativeView;
Control.Children.Add(_nativeController);
}
}
}
VideoOuputType IVideoOutput.OuputType => VideoOuputType.Buffer;
MediaView IMediaViewProvider.GetMediaView()
{
return _mediaView;
}
public MediaElementRenderer()
{
MediaElement.VerifyMediaElementFlagEnabled(nameof(MediaElementRenderer));
}
protected override void OnElementChanged(ElementChangedEventArgs<MediaElement> e)
{
if (e.OldElement != null)
{
e.OldElement.SeekRequested -= OnSeekRequested;
e.OldElement.StateRequested -= OnStateRequested;
e.OldElement.PositionRequested -= OnPositionRequested;
}
if (Control == null)
{
SetNativeControl(new LayoutCanvas(XForms.NativeParent));
_mediaView = new MediaView(XForms.NativeParent);
Control.LayoutUpdated += (s, evt) => OnLayout();
Control.Children.Add(_mediaView);
Control.AllowFocus(true);
_player = new MediaPlayer()
{
VideoOutput = this
};
_player.PlaybackStarted += OnPlaybackStarted;
_player.PlaybackPaused += OnPlaybackPaused;
_player.PlaybackStopped += OnPlaybackStopped;
_player.PlaybackCompleted += OnPlaybackCompleted;
_player.BufferingProgressUpdated += OnBufferingProgressUpdated;
_player.ErrorOccurred += OnErrorOccurred;
_player.MediaPrepared += OnMediaPrepared;
_player.BindingContext = Element;
_player.SetBinding(MediaPlayer.SourceProperty, "Source");
_player.SetBinding(MediaPlayer.UsesEmbeddingControlsProperty, "ShowsPlaybackControls");
_player.SetBinding(MediaPlayer.AutoPlayProperty, "AutoPlay");
_player.SetBinding(MediaPlayer.VolumeProperty, "Volume");
_player.SetBinding(MediaPlayer.IsLoopingProperty, "IsLooping");
_player.SetBinding(MediaPlayer.AspectModeProperty, new Binding
{
Path = "Aspect",
Converter = new AspectToDisplayAspectModeConverter()
});
BindableObject.SetInheritedBindingContext(_player, Element.BindingContext);
Element.SeekRequested += OnSeekRequested;
Element.StateRequested += OnStateRequested;
Element.PositionRequested += OnPositionRequested;
}
base.OnElementChanged(e);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Element.SeekRequested -= OnSeekRequested;
Element.StateRequested -= OnStateRequested;
Element.PositionRequested -= OnPositionRequested;
_mediaView?.Unrealize();
if (_player != null)
{
_player.PlaybackStarted -= OnPlaybackStarted;
_player.PlaybackPaused -= OnPlaybackPaused;
_player.PlaybackStopped -= OnPlaybackStopped;
_player.PlaybackCompleted -= OnPlaybackCompleted;
_player.BufferingProgressUpdated -= OnBufferingProgressUpdated;
_player.ErrorOccurred -= OnErrorOccurred;
_player.MediaPrepared -= OnMediaPrepared;
_player.Dispose();
}
if (_controller != null )
{
_controller.Parent = null;
Platform.SetRenderer(_controller, null);
}
_nativeController?.Unrealize();
Control?.Unrealize();
}
base.Dispose(disposing);
}
protected void OnLayout()
{
_mediaView.Geometry = Control.Geometry;
_controller?.Layout(Element.Bounds);
if (_nativeController != null)
_nativeController.Geometry = Control.Geometry;
}
protected void OnSeekRequested(object sender, SeekRequested e)
{
_player.Seek((int)e.Position.TotalMilliseconds);
}
protected void OnStateRequested(object sender, StateRequested e)
{
switch (e.State)
{
case MediaElementState.Playing:
_player.Start();
break;
case MediaElementState.Paused:
_player.Pause();
break;
case MediaElementState.Stopped:
_player.Stop();
break;
}
}
protected void OnPositionRequested(object sender, EventArgs e)
{
Controller.Position = TimeSpan.FromMilliseconds(_player.Position);
}
protected void OnPlaybackStarted(object sender, EventArgs e)
{
Controller.CurrentState = MediaElementState.Playing;
}
protected void OnPlaybackPaused(object sender, EventArgs e)
{
Controller.CurrentState = MediaElementState.Paused;
}
protected void OnPlaybackStopped(object sender, EventArgs e)
{
Controller.CurrentState = MediaElementState.Stopped;
}
protected void OnPlaybackCompleted(object sender, EventArgs e)
{
Controller.OnMediaEnded();
}
protected void OnBufferingProgressUpdated(object sender, BufferingProgressUpdatedEventArgs e)
{
if (e.Progress == 1.0)
{
switch (_player.State)
{
case PlaybackState.Paused:
Controller.CurrentState = MediaElementState.Paused;
break;
case PlaybackState.Playing:
Controller.CurrentState = MediaElementState.Playing;
break;
case PlaybackState.Stopped:
Controller.CurrentState = MediaElementState.Stopped;
break;
}
}
else if (Controller.CurrentState != MediaElementState.Buffering && e.Progress >= 0)
{
Controller.CurrentState = MediaElementState.Buffering;
}
Controller.BufferingProgress = e.Progress;
}
protected void OnErrorOccurred(object sender, EventArgs e)
{
Controller.OnMediaFailed();
}
protected async void OnMediaPrepared(object sender, EventArgs e)
{
Controller.OnMediaOpened();
Controller.Duration = TimeSpan.FromMilliseconds(_player.Duration);
var videoSize = await _player.GetVideoSize();
Controller.VideoWidth = (int)videoSize.Width;
Controller.VideoHeight = (int)videoSize.Height;
}
}
public interface IMediaViewProvider
{
MediaView GetMediaView();
}
public class AspectToDisplayAspectModeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((Aspect)value).ToDisplayAspectMode();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Просмотреть файл

@ -102,7 +102,6 @@ namespace Xamarin.Forms.Platform.Tizen
Registered.Register(typeof(CarouselView), () => new CarouselViewRenderer());
Registered.Register(typeof(SwipeView), () => new SwipeViewRenderer());
Registered.Register(typeof(RefreshView), () => new RefreshViewRenderer());
Registered.Register(typeof(MediaElement), () => new MediaElementRenderer());
Registered.Register(typeof(IndicatorView), () => new IndicatorViewRenderer());
Registered.Register(typeof(RadioButton), () => new RadioButtonRenderer());
@ -135,7 +134,6 @@ namespace Xamarin.Forms.Platform.Tizen
DependencyService.Register<IDeserializer, Deserializer>();
DependencyService.Register<INativeBindingService, NativeBindingService>();
DependencyService.Register<INativeValueConverterService, NativeValueConverterService>();
DependencyService.Register<IPlatformMediaPlayer, MediaPlayerImpl>();
//Custom Handlers
if (customHandlers != null)

Просмотреть файл

@ -10,8 +10,6 @@
<ItemGroup>
<None Remove="Resource\arrow_left.png" />
<None Remove="Resource\dots_horizontal.png" />
<None Remove="Resource\img_button_pause.png" />
<None Remove="Resource\img_button_play.png" />
<None Remove="Resource\menu.png" />
<None Remove="Resource\wc_visual_cue.png" />
</ItemGroup>
@ -21,8 +19,6 @@
<ItemGroup>
<EmbeddedResource Include="Resource\arrow_left.png" />
<EmbeddedResource Include="Resource\dots_horizontal.png" />
<EmbeddedResource Include="Resource\img_button_pause.png" />
<EmbeddedResource Include="Resource\img_button_play.png" />
<EmbeddedResource Include="Resource\menu.png" />
<EmbeddedResource Include="Resource\refresh_48dp.png" />
<EmbeddedResource Include="Resource\wc_visual_cue.png" />

Просмотреть файл

@ -1,305 +0,0 @@
using System;
using Windows.System.Display;
using Windows.UI.Xaml;
using Controls = Windows.UI.Xaml.Controls;
namespace Xamarin.Forms.Platform.UWP
{
public sealed class MediaElementRenderer : ViewRenderer<MediaElement, Controls.MediaElement>
{
long _bufferingProgressChangedToken;
long _positionChangedToken;
DisplayRequest _request = new DisplayRequest();
public MediaElementRenderer()
{
Xamarin.Forms.MediaElement.VerifyMediaElementFlagEnabled(nameof(MediaElementRenderer));
}
void ReleaseControl()
{
if (Control is null)
return;
if (_bufferingProgressChangedToken != 0)
{
Control.UnregisterPropertyChangedCallback(Controls.MediaElement.BufferingProgressProperty, _bufferingProgressChangedToken);
_bufferingProgressChangedToken = 0;
}
if (_positionChangedToken != 0)
{
Control.UnregisterPropertyChangedCallback(Controls.MediaElement.PositionProperty, _positionChangedToken);
_positionChangedToken = 0;
}
Element.SeekRequested -= SeekRequested;
Element.StateRequested -= StateRequested;
Element.PositionRequested -= PositionRequested;
Control.CurrentStateChanged -= ControlCurrentStateChanged;
Control.SeekCompleted -= ControlSeekCompleted;
Control.MediaOpened -= ControlMediaOpened;
Control.MediaEnded -= ControlMediaEnded;
Control.MediaFailed -= ControlMediaFailed;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
ReleaseControl();
}
protected override void OnElementChanged(ElementChangedEventArgs<MediaElement> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
ReleaseControl();
}
if (e.NewElement != null)
{
SetNativeControl(new Controls.MediaElement());
Control.HorizontalAlignment = HorizontalAlignment.Stretch;
Control.VerticalAlignment = VerticalAlignment.Stretch;
Control.AreTransportControlsEnabled = Element.ShowsPlaybackControls;
Control.AutoPlay = Element.AutoPlay;
Control.IsLooping = Element.IsLooping;
Control.Stretch = Element.Aspect.ToStretch();
_bufferingProgressChangedToken = Control.RegisterPropertyChangedCallback(Controls.MediaElement.BufferingProgressProperty, BufferingProgressChanged);
_positionChangedToken = Control.RegisterPropertyChangedCallback(Controls.MediaElement.PositionProperty, PositionChanged);
Element.SeekRequested += SeekRequested;
Element.StateRequested += StateRequested;
Element.PositionRequested += PositionRequested;
Control.SeekCompleted += ControlSeekCompleted;
Control.CurrentStateChanged += ControlCurrentStateChanged;
Control.MediaOpened += ControlMediaOpened;
Control.MediaEnded += ControlMediaEnded;
Control.MediaFailed += ControlMediaFailed;
UpdateSource();
}
}
void PositionRequested(object sender, EventArgs e)
{
if (!(Control is null))
{
Controller.Position = Control.Position;
}
}
IMediaElementController Controller => Element as IMediaElementController;
void StateRequested(object sender, StateRequested e)
{
if (!(Control is null))
{
switch (e.State)
{
case MediaElementState.Playing:
Control.Play();
break;
case MediaElementState.Paused:
if (Control.CanPause)
{
Control.Pause();
}
break;
case MediaElementState.Stopped:
Control.Stop();
break;
}
Controller.Position = Control.Position;
}
}
void SeekRequested(object sender, SeekRequested e)
{
if (!(Control is null) && Control.CanSeek)
{
Control.Position = e.Position;
Controller.Position = Control.Position;
}
}
void ControlMediaFailed(object sender, ExceptionRoutedEventArgs e)
{
Controller?.OnMediaFailed();
}
void ControlMediaEnded(object sender, RoutedEventArgs e)
{
if (!(Control is null))
{
Controller.Position = Control.Position;
}
Controller.CurrentState = MediaElementState.Stopped;
Controller.OnMediaEnded();
}
void ControlMediaOpened(object sender, RoutedEventArgs e)
{
Controller.Duration = Control.NaturalDuration.HasTimeSpan ? Control.NaturalDuration.TimeSpan : (TimeSpan?)null;
Controller.VideoHeight = Control.NaturalVideoHeight;
Controller.VideoWidth = Control.NaturalVideoWidth;
Control.Volume = Element.Volume;
Control.Stretch = Element.Aspect.ToStretch();
Controller.OnMediaOpened();
}
void ControlCurrentStateChanged(object sender, RoutedEventArgs e)
{
if (Element is null || Control is null)
return;
switch (Control.CurrentState)
{
case Windows.UI.Xaml.Media.MediaElementState.Playing:
if (Element.KeepScreenOn)
{
_request.RequestActive();
}
break;
case Windows.UI.Xaml.Media.MediaElementState.Paused:
case Windows.UI.Xaml.Media.MediaElementState.Stopped:
case Windows.UI.Xaml.Media.MediaElementState.Closed:
if (Element.KeepScreenOn)
{
_request.RequestRelease();
}
break;
}
Controller.CurrentState = FromWindowsMediaElementState(Control.CurrentState);
}
static MediaElementState FromWindowsMediaElementState(Windows.UI.Xaml.Media.MediaElementState state)
{
switch(state)
{
case Windows.UI.Xaml.Media.MediaElementState.Buffering:
return MediaElementState.Buffering;
case Windows.UI.Xaml.Media.MediaElementState.Closed:
return MediaElementState.Closed;
case Windows.UI.Xaml.Media.MediaElementState.Opening:
return MediaElementState.Opening;
case Windows.UI.Xaml.Media.MediaElementState.Paused:
return MediaElementState.Paused;
case Windows.UI.Xaml.Media.MediaElementState.Playing:
return MediaElementState.Playing;
case Windows.UI.Xaml.Media.MediaElementState.Stopped:
return MediaElementState.Stopped;
}
throw new ArgumentOutOfRangeException();
}
void BufferingProgressChanged(DependencyObject sender, DependencyProperty dp)
{
if (!(Control is null))
{
Controller.BufferingProgress = Control.BufferingProgress;
}
}
void PositionChanged(DependencyObject sender, DependencyProperty dp)
{
if (!(Control is null))
{
Controller.Position = Control.Position;
}
}
void ControlSeekCompleted(object sender, RoutedEventArgs e)
{
if (!(Control is null))
{
Controller.Position = Control.Position;
Controller.OnSeekCompleted();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(MediaElement.Aspect):
Control.Stretch = Element.Aspect.ToStretch();
break;
case nameof(MediaElement.AutoPlay):
Control.AutoPlay = Element.AutoPlay;
break;
case nameof(MediaElement.IsLooping):
Control.IsLooping = Element.IsLooping;
break;
case nameof(MediaElement.KeepScreenOn):
if (Element.KeepScreenOn)
{
if (Control.CurrentState == Windows.UI.Xaml.Media.MediaElementState.Playing)
{
_request.RequestActive();
}
}
else
{
_request.RequestRelease();
}
break;
case nameof(MediaElement.ShowsPlaybackControls):
Control.AreTransportControlsEnabled = Element.ShowsPlaybackControls;
break;
case nameof(MediaElement.Source):
UpdateSource();
break;
case nameof(MediaElement.Width):
Width = Math.Max(0, Element.Width);
break;
case nameof(MediaElement.Height):
Height = Math.Max(0, Element.Height);
break;
case nameof(MediaElement.Volume):
Control.Volume = Element.Volume;
break;
}
base.OnElementPropertyChanged(sender, e);
}
void UpdateSource()
{
if (Element.Source is null)
return;
if (Element.Source is UriMediaSource uriSource)
Control.Source = uriSource.Uri;
else if (Element.Source is FileMediaSource fileSource)
Control.Source = new Uri(fileSource.File);
}
}
}

Просмотреть файл

@ -35,7 +35,6 @@ using Rectangle = Xamarin.Forms.Shapes.Rectangle;
[assembly: ExportRenderer(typeof(CheckBox), typeof(CheckBoxRenderer))]
[assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))]
[assembly: ExportRenderer(typeof(NativeViewWrapper), typeof(NativeViewWrapperRenderer))]
[assembly: ExportRenderer(typeof(MediaElement), typeof(MediaElementRenderer))]
[assembly: ExportRenderer(typeof(RefreshView), typeof(RefreshViewRenderer))]
[assembly: ExportRenderer(typeof(Shell), typeof(ShellRenderer))]
[assembly: ExportRenderer(typeof(Path), typeof(PathRenderer))]

Просмотреть файл

@ -33,7 +33,6 @@ using Rectangle = Xamarin.Forms.Shapes.Rectangle;
[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
[assembly: ExportRenderer(typeof(ListView), typeof(ListViewRenderer))]
[assembly: ExportRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer))]
[assembly: ExportRenderer(typeof(MediaElement), typeof(MediaElementRenderer))]
[assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))]
[assembly: ExportRenderer(typeof(EmbeddedFont), typeof(EmbeddedFontLoader))]
[assembly: ExportRenderer(typeof(Path), typeof(PathRenderer))]

Просмотреть файл

@ -1,308 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
namespace Xamarin.Forms.Platform.WPF
{
public sealed class MediaElementRenderer : ViewRenderer<MediaElement, System.Windows.Controls.MediaElement>
{
IMediaElementController Controller => Element as IMediaElementController;
MediaElementState _requestedState;
public MediaElementRenderer()
{
Xamarin.Forms.MediaElement.VerifyMediaElementFlagEnabled(nameof(MediaElementRenderer));
}
protected override void OnElementChanged(ElementChangedEventArgs<MediaElement> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
Element.SeekRequested -= ElementSeekRequested;
Element.StateRequested -= ElementStateRequested;
Element.PositionRequested -= ElementPositionRequested;
if (Control != null)
{
Control.BufferingStarted -= ControlBufferingStarted;
Control.BufferingEnded -= ControlBufferingEnded;
Control.MediaOpened -= ControlMediaOpened;
Control.MediaEnded -= ControlMediaEnded;
Control.MediaFailed -= ControlMediaFailed;
}
}
if (e.NewElement != null)
{
SetNativeControl(new System.Windows.Controls.MediaElement());
Control.HorizontalAlignment = HorizontalAlignment.Stretch;
Control.VerticalAlignment = VerticalAlignment.Stretch;
Control.LoadedBehavior = MediaState.Manual;
Control.UnloadedBehavior = MediaState.Close;
Control.Stretch = Element.Aspect.ToStretch();
Control.BufferingStarted += ControlBufferingStarted;
Control.BufferingEnded += ControlBufferingEnded;
Control.MediaOpened += ControlMediaOpened;
Control.MediaEnded += ControlMediaEnded;
Control.MediaFailed += ControlMediaFailed;
Element.SeekRequested += ElementSeekRequested;
Element.StateRequested += ElementStateRequested;
Element.PositionRequested += ElementPositionRequested;
UpdateSource();
}
}
void ElementPositionRequested(object sender, EventArgs e)
{
if (!(Control is null))
{
Controller.Position = Control.Position;
}
}
void ElementStateRequested(object sender, StateRequested e)
{
_requestedState = e.State;
switch (e.State)
{
case MediaElementState.Playing:
if (Element.KeepScreenOn)
{
DisplayRequestActive();
}
Control.Play();
Controller.CurrentState = _requestedState;
break;
case MediaElementState.Paused:
if (Control.CanPause)
{
if (Element.KeepScreenOn)
{
DisplayRequestRelease();
}
Control.Pause();
Controller.CurrentState = _requestedState;
}
break;
case MediaElementState.Stopped:
if (Element.KeepScreenOn)
{
DisplayRequestRelease();
}
Control.Stop();
Controller.CurrentState = _requestedState;
break;
}
Controller.Position = Control.Position;
}
void ElementSeekRequested(object sender, SeekRequested e)
{
Control.Position = e.Position;
Controller.Position = Control.Position;
}
void UpdateSource()
{
if (Element.Source is null)
return;
if (Control.Clock != null)
Control.Clock = null;
if (Element.Source is UriMediaSource uriSource)
{
if (uriSource.Uri.Scheme == "ms-appx")
{
Control.Source = new Uri(Element.Source.ToString().Replace("ms-appx:///", ""), UriKind.Relative);
}
else if (uriSource.Uri.Scheme == "ms-appdata")
{
string filePath = string.Empty;
if (uriSource.Uri.LocalPath.StartsWith("/local"))
{
// WPF doesn't have the concept of an app package local folder so using My Documents as a placeholder
filePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), uriSource.Uri.LocalPath.Substring(7));
}
else if (uriSource.Uri.LocalPath.StartsWith("/temp"))
{
filePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), uriSource.Uri.LocalPath.Substring(6));
}
else
{
throw new ArgumentException("Invalid Uri", "Source");
}
Control.Source = new Uri(filePath);
}
else if (uriSource.Uri.Scheme == "https")
{
throw new ArgumentException("WPF supports only HTTP remote sources and not the HTTPS URI scheme.", "Source");
}
else
{
Control.Source = uriSource.Uri;
}
}
else if (Element.Source is FileMediaSource fileSource)
{
Control.Source = new Uri(fileSource.File);
}
Controller.CurrentState = MediaElementState.Opening;
}
void ControlBufferingEnded(object sender, RoutedEventArgs e)
{
Controller.BufferingProgress = 1.0;
if (Element.AutoPlay)
{
Controller.CurrentState = MediaElementState.Playing;
}
else
{
Controller.CurrentState = _requestedState; ;
}
}
void ControlBufferingStarted(object sender, RoutedEventArgs e)
{
Controller.BufferingProgress = 0.0;
Controller.CurrentState = MediaElementState.Buffering;
}
void ControlMediaFailed(object sender, ExceptionRoutedEventArgs e)
{
Controller.OnMediaFailed();
}
void ControlMediaEnded(object sender, RoutedEventArgs e)
{
if (Element.IsLooping)
{
Control.Position = TimeSpan.Zero;
Control.Play();
}
else
{
_requestedState = MediaElementState.Stopped;
Controller.CurrentState = MediaElementState.Stopped;
Controller.OnMediaEnded();
}
Controller.Position = Control.Position;
}
void ControlMediaOpened(object sender, RoutedEventArgs e)
{
Controller.Duration = Control.NaturalDuration.HasTimeSpan ? Control.NaturalDuration.TimeSpan : (TimeSpan?)null;
Controller.VideoHeight = Control.NaturalVideoHeight;
Controller.VideoWidth = Control.NaturalVideoWidth;
Controller.OnMediaOpened();
if (Element.AutoPlay)
{
Control.Play();
_requestedState = MediaElementState.Playing;
Controller.CurrentState = MediaElementState.Playing;
}
else
{
Controller.CurrentState = _requestedState;
}
}
void ControlSeekCompleted(object sender, RoutedEventArgs e)
{
Controller.Position = Control.Position;
Controller.OnSeekCompleted();
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(MediaElement.Aspect):
Control.Stretch = Element.Aspect.ToStretch();
break;
case nameof(MediaElement.KeepScreenOn):
if (Element.KeepScreenOn)
{
if (Element.CurrentState == MediaElementState.Playing)
{
DisplayRequestActive();
}
}
else
{
DisplayRequestRelease();
}
break;
case nameof(MediaElement.Source):
UpdateSource();
break;
case nameof(MediaElement.Volume):
Control.Volume = Element.Volume;
break;
}
base.OnElementPropertyChanged(sender, e);
}
protected override void UpdateWidth()
{
Control.Width = Math.Max(0, Element.Width);
}
protected override void UpdateHeight()
{
Control.Height = Math.Max(0, Element.Height);
}
void DisplayRequestActive()
{
NativeMethods.SetThreadExecutionState(NativeMethods.EXECUTION_STATE.DISPLAY_REQUIRED | NativeMethods.EXECUTION_STATE.CONTINUOUS);
}
void DisplayRequestRelease()
{
NativeMethods.SetThreadExecutionState(NativeMethods.EXECUTION_STATE.CONTINUOUS);
}
static class NativeMethods
{
[DllImport("Kernel32", SetLastError = true)]
internal static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
internal enum EXECUTION_STATE : uint
{
/// <summary>
/// Informs the system that the state being set should remain in effect until the next call that uses ES_CONTINUOUS and one of the other state flags is cleared.
/// </summary>
CONTINUOUS = 0x80000000,
/// <summary>
/// Forces the display to be on by resetting the display idle timer.
/// </summary>
DISPLAY_REQUIRED = 0x00000002,
}
}
}
}

Просмотреть файл

@ -1,451 +0,0 @@
using AVFoundation;
using AVKit;
using CoreGraphics;
using CoreMedia;
using Foundation;
using System;
using System.IO;
using UIKit;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Platform.iOS
{
public sealed class MediaElementRenderer : ViewRenderer<MediaElement, UIView>
{
IMediaElementController Controller => Element as IMediaElementController;
AVPlayerViewController _avPlayerViewController = new AVPlayerViewController();
NSObject _playedToEndObserver;
NSObject _statusObserver;
NSObject _rateObserver;
bool _idleTimerDisabled = false;
[Internals.Preserve(Conditional = true)]
public MediaElementRenderer()
{
MediaElement.VerifyMediaElementFlagEnabled(nameof(MediaElementRenderer));
}
void SetKeepScreenOn(bool value)
{
if (value)
{
if (!UIApplication.SharedApplication.IdleTimerDisabled)
{
_idleTimerDisabled = true;
UIApplication.SharedApplication.IdleTimerDisabled = true;
}
}
else if (_idleTimerDisabled)
{
_idleTimerDisabled = false;
UIApplication.SharedApplication.IdleTimerDisabled = false;
}
}
void UpdateSource()
{
if (Element.Source != null)
{
AVAsset asset = null;
var uriSource = Element.Source as UriMediaSource;
if (uriSource != null)
{
if (uriSource.Uri.Scheme == "ms-appx")
{
if (uriSource.Uri.LocalPath.Length <= 1)
return;
// used for a file embedded in the application package
asset = AVAsset.FromUrl(NSUrl.FromFilename(uriSource.Uri.LocalPath.Substring(1)));
}
else if (uriSource.Uri.Scheme == "ms-appdata")
{
string filePath = Platform.ResolveMsAppDataUri(uriSource.Uri);
if (string.IsNullOrEmpty(filePath))
throw new ArgumentException("Invalid Uri", "Source");
asset = AVAsset.FromUrl(NSUrl.FromFilename(filePath));
}
else
{
asset = AVUrlAsset.Create(NSUrl.FromString(uriSource.Uri.AbsoluteUri));
}
}
else
{
var fileSource = Element.Source as FileMediaSource;
if (fileSource != null)
{
asset = AVAsset.FromUrl(NSUrl.FromFilename(fileSource.File));
}
}
var item = new AVPlayerItem(asset);
RemoveStatusObserver();
_statusObserver = (NSObject)item.AddObserver("status", NSKeyValueObservingOptions.New, ObserveStatus);
if (_avPlayerViewController.Player != null)
{
_avPlayerViewController.Player.ReplaceCurrentItemWithPlayerItem(item);
}
else
{
_avPlayerViewController.Player = new AVPlayer(item);
_rateObserver = (NSObject)_avPlayerViewController.Player.AddObserver("rate", NSKeyValueObservingOptions.New, ObserveRate);
}
if (Element.AutoPlay)
Play();
}
else
{
if (Element.CurrentState == MediaElementState.Playing || Element.CurrentState == MediaElementState.Buffering)
{
_avPlayerViewController.Player.Pause();
Controller.CurrentState = MediaElementState.Stopped;
}
}
}
protected override void Dispose(bool disposing)
{
if(_playedToEndObserver != null)
{
NSNotificationCenter.DefaultCenter.RemoveObserver(_playedToEndObserver);
_playedToEndObserver = null;
}
if(_rateObserver != null)
{
_rateObserver.Dispose();
_rateObserver = null;
}
RemoveStatusObserver();
_avPlayerViewController?.Player?.Pause();
_avPlayerViewController?.Player?.ReplaceCurrentItemWithPlayerItem(null);
base.Dispose(disposing);
}
void RemoveStatusObserver()
{
if (_statusObserver != null)
{
try
{
_avPlayerViewController?.Player?.CurrentItem?.RemoveObserver(_statusObserver, "status");
}
finally
{
_statusObserver = null;
}
}
}
void ObserveRate(NSObservedChange e)
{
if (Controller is object)
{
switch (_avPlayerViewController.Player.Rate)
{
case 0.0f:
Controller.CurrentState = MediaElementState.Paused;
break;
case 1.0f:
Controller.CurrentState = MediaElementState.Playing;
break;
}
Controller.Position = Position;
}
}
void ObserveStatus(NSObservedChange e)
{
Controller.Volume = _avPlayerViewController.Player.Volume;
switch (_avPlayerViewController.Player.Status)
{
case AVPlayerStatus.Failed:
Controller.OnMediaFailed();
break;
case AVPlayerStatus.ReadyToPlay:
var duration = _avPlayerViewController.Player.CurrentItem.Duration;
if (duration.IsIndefinite)
Controller.Duration = TimeSpan.Zero;
else
Controller.Duration = TimeSpan.FromSeconds(duration.Seconds);
Controller.VideoHeight = (int)_avPlayerViewController.Player.CurrentItem.Asset.NaturalSize.Height;
Controller.VideoWidth = (int)_avPlayerViewController.Player.CurrentItem.Asset.NaturalSize.Width;
Controller.OnMediaOpened();
Controller.Position = Position;
break;
}
}
TimeSpan Position
{
get
{
if (_avPlayerViewController.Player.CurrentTime.IsInvalid)
return TimeSpan.Zero;
return TimeSpan.FromSeconds(_avPlayerViewController.Player.CurrentTime.Seconds);
}
}
void PlayedToEnd(NSNotification notification)
{
if (Element == null)
{
return;
}
if (Element.IsLooping)
{
_avPlayerViewController.Player.Seek(CMTime.Zero);
Controller.Position = Position;
_avPlayerViewController.Player.Play();
}
else
{
SetKeepScreenOn(false);
Controller.Position = Position;
try
{
Device.BeginInvokeOnMainThread(Controller.OnMediaEnded);
}
catch (Exception e)
{
Log.Warning("MediaElement", $"Failed to play media to end: {e}");
}
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(MediaElement.Aspect):
_avPlayerViewController.VideoGravity = AspectToGravity(Element.Aspect);
break;
case nameof(MediaElement.KeepScreenOn):
if (!Element.KeepScreenOn)
{
SetKeepScreenOn(false);
}
else if(Element.CurrentState == MediaElementState.Playing)
{
// only toggle this on if property is set while video is already running
SetKeepScreenOn(true);
}
break;
case nameof(MediaElement.ShowsPlaybackControls):
_avPlayerViewController.ShowsPlaybackControls = Element.ShowsPlaybackControls;
break;
case nameof(MediaElement.Source):
UpdateSource();
break;
case nameof(MediaElement.Volume):
_avPlayerViewController.Player.Volume = (float)Element.Volume;
break;
}
}
void MediaElementSeekRequested(object sender, SeekRequested e)
{
if (_avPlayerViewController.Player.Status != AVPlayerStatus.ReadyToPlay || _avPlayerViewController.Player.CurrentItem == null)
return;
NSValue[] ranges = _avPlayerViewController.Player.CurrentItem.SeekableTimeRanges;
CMTime seekTo = new CMTime(Convert.ToInt64(e.Position.TotalMilliseconds), 1000);
foreach (NSValue v in ranges)
{
if (seekTo >= v.CMTimeRangeValue.Start && seekTo < (v.CMTimeRangeValue.Start + v.CMTimeRangeValue.Duration))
{
_avPlayerViewController.Player.Seek(seekTo, SeekComplete);
break;
}
}
}
void Play()
{
var audioSession = AVAudioSession.SharedInstance();
NSError err = audioSession.SetCategory(AVAudioSession.CategoryPlayback);
if (!(err is null))
Log.Warning("MediaElement", "Failed to set AVAudioSession Category {0}", err.Code);
audioSession.SetMode(AVAudioSession.ModeMoviePlayback, out err);
if (!(err is null))
Log.Warning("MediaElement", "Failed to set AVAudioSession Mode {0}", err.Code);
err = audioSession.SetActive(true);
if (!(err is null))
Log.Warning("MediaElement", "Failed to set AVAudioSession Active {0}", err.Code);
if (_avPlayerViewController.Player != null)
{
_avPlayerViewController.Player.Play();
Controller.CurrentState = MediaElementState.Playing;
}
if (Element.KeepScreenOn)
{
SetKeepScreenOn(true);
}
}
void MediaElementStateRequested(object sender, StateRequested e)
{
MediaElementVolumeRequested(this, EventArgs.Empty);
switch (e.State)
{
case MediaElementState.Playing:
Play();
break;
case MediaElementState.Paused:
if (Element.KeepScreenOn)
{
SetKeepScreenOn(false);
}
if (_avPlayerViewController.Player != null)
{
_avPlayerViewController.Player.Pause();
Controller.CurrentState = MediaElementState.Paused;
}
break;
case MediaElementState.Stopped:
if (Element.KeepScreenOn)
{
SetKeepScreenOn(false);
}
//ios has no stop...
_avPlayerViewController?.Player.Pause();
_avPlayerViewController?.Player.Seek(CMTime.Zero);
Controller.CurrentState = MediaElementState.Stopped;
NSError err = AVAudioSession.SharedInstance().SetActive(false);
if (!(err is null))
Log.Warning("MediaElement", "Failed to set AVAudioSession Inactive {0}", err.Code);
break;
}
Controller.Position = Position;
}
static AVLayerVideoGravity AspectToGravity(Aspect aspect)
{
switch (aspect)
{
case Aspect.Fill:
return AVLayerVideoGravity.Resize;
case Aspect.AspectFill:
return AVLayerVideoGravity.ResizeAspectFill;
default:
return AVLayerVideoGravity.ResizeAspect;
}
}
void SeekComplete(bool finished)
{
if (finished)
{
Controller.OnSeekCompleted();
}
}
private void MediaElementVolumeRequested(object sender, EventArgs e)
{
Controller.Volume = _avPlayerViewController.Player.Volume;
}
void MediaElementPositionRequested(object sender, EventArgs e)
{
Controller.Position = Position;
}
protected override void OnElementChanged(ElementChangedEventArgs<MediaElement> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
e.OldElement.SeekRequested -= MediaElementSeekRequested;
e.OldElement.StateRequested -= MediaElementStateRequested;
e.OldElement.PositionRequested -= MediaElementPositionRequested;
e.OldElement.VolumeRequested -= MediaElementVolumeRequested;
if (_playedToEndObserver != null)
{
NSNotificationCenter.DefaultCenter.RemoveObserver(_playedToEndObserver);
_playedToEndObserver = null;
}
// stop video if playing
if (_avPlayerViewController?.Player?.CurrentItem != null)
{
RemoveStatusObserver();
_avPlayerViewController.Player.Pause();
_avPlayerViewController.Player.Seek(CMTime.Zero);
_avPlayerViewController.Player.ReplaceCurrentItemWithPlayerItem(null);
AVAudioSession.SharedInstance().SetActive(false);
}
}
if (e.NewElement != null)
{
SetNativeControl(_avPlayerViewController.View);
Element.PropertyChanged += OnElementPropertyChanged;
Element.SeekRequested += MediaElementSeekRequested;
Element.StateRequested += MediaElementStateRequested;
Element.PositionRequested += MediaElementPositionRequested;
Element.VolumeRequested += MediaElementVolumeRequested;
_avPlayerViewController.ShowsPlaybackControls = Element.ShowsPlaybackControls;
_avPlayerViewController.VideoGravity = AspectToGravity(Element.Aspect);
if (Element.KeepScreenOn)
{
SetKeepScreenOn(true);
}
_playedToEndObserver = NSNotificationCenter.DefaultCenter.AddObserver(AVPlayerItem.DidPlayToEndTimeNotification, PlayedToEnd);
UpdateBackgroundColor();
UpdateSource();
}
}
void UpdateBackgroundColor()
{
BackgroundColor = Element.BackgroundColor.ToUIColor();
}
}
}

Просмотреть файл

@ -233,7 +233,6 @@
<Compile Include="Renderers\ButtonElementManager.cs" />
<Compile Include="Renderers\IImageVisualElementRenderer.cs" />
<Compile Include="Renderers\ImageButtonRenderer.cs" />
<Compile Include="Renderers\MediaElementRenderer.cs" />
<Compile Include="Resources\StringResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>

Просмотреть файл

@ -139,11 +139,7 @@
{
}
internal class _MediaElementRenderer
{
}
internal class _SwipeViewRenderer
internal class _SwipeViewRenderer
{
}