您好,我实现了xamarin视频播放器,下面的链接https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/video-player/
我正在通过代码将视频下载到应用程序的document文件夹中,该文件夹具有这样的路径 [/Users/vaibhavjain/Library/Developer/CoreSimulator/Devices/{GUID}/data/Containers/Data/Application/{GUID}/Documents/MediaDocuments/Nature1.mp4] 现在,我检查了视频是否已正确下载到该路径,但是当我将此路径作为源传递给上方的视频播放器时,它无法播放
我的猜测是玩家无法到达路径,或者正在期待相对路径,但是我找不到我应该提供的路径类型的任何示例。
这是ios上自定义渲染器的代码
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
AVPlayerItem playerItem;
AVPlayerViewController _playerViewController; // solely for ViewController property
public override UIViewController ViewController => _playerViewController;
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);
if (args.NewElement != null)
{
if (Control == null)
{
// Create AVPlayerViewController
_playerViewController = new AVPlayerViewController();
// Set Player property to AVPlayer
player = new AVPlayer();
_playerViewController.Player = player;
var x = _playerViewController.View;
// Use the View from the controller as the native control
SetNativeControl(_playerViewController.View);
}
SetAreTransportControlsEnabled();
SetSource();
args.NewElement.UpdateStatus += OnUpdateStatus;
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}
if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (player != null)
{
player.ReplaceCurrentItemWithPlayerItem(null);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(sender, args);
if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
TimeSpan controlPosition = ConvertTime(player.CurrentTime);
if (Math.Abs((controlPosition - Element.Position).TotalSeconds) > 1)
{
player.Seek(CMTime.FromSeconds(Element.Position.TotalSeconds, 1));
}
}
}
void SetAreTransportControlsEnabled()
{
((AVPlayerViewController)ViewController).ShowsPlaybackControls = Element.AreTransportControlsEnabled;
}
void SetSource()
{
AVAsset asset = null;
if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;
if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(new NSUrl(uri));
}
}
else if (Element.Source is FileVideoSource)
{
string uri = (Element.Source as FileVideoSource).File;
if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(NSUrl.CreateFileUrl(uri, null));
}
}
else if (Element.Source is ResourceVideoSource)
{
string path = (Element.Source as ResourceVideoSource).Path;
if (!String.IsNullOrWhiteSpace(path))
{
string directory = Path.GetDirectoryName(path);
string filename = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path).Substring(1);
NSUrl url = NSBundle.MainBundle.GetUrlForResource(filename, extension, directory);
asset = AVAsset.FromUrl(url);
}
}
if (asset != null)
{
playerItem = new AVPlayerItem(asset);
}
else
{
playerItem = null;
}
player.ReplaceCurrentItemWithPlayerItem(playerItem);
if (playerItem != null && Element.AutoPlay)
{
player.Play();
}
}
// Event handler to update status
void OnUpdateStatus(object sender, EventArgs args)
{
VideoStatus videoStatus = VideoStatus.NotReady;
switch (player.Status)
{
case AVPlayerStatus.ReadyToPlay:
switch (player.TimeControlStatus)
{
case AVPlayerTimeControlStatus.Playing:
videoStatus = VideoStatus.Playing;
break;
case AVPlayerTimeControlStatus.Paused:
videoStatus = VideoStatus.Paused;
break;
}
break;
}
((IVideoPlayerController)Element).Status = videoStatus;
if (playerItem != null)
{
((IVideoPlayerController)Element).Duration = ConvertTime(playerItem.Duration);
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty, ConvertTime(playerItem.CurrentTime));
}
}
TimeSpan ConvertTime(CMTime cmTime)
{
return TimeSpan.FromSeconds(Double.IsNaN(cmTime.Seconds) ? 0 : cmTime.Seconds);
}
// Event handlers to implement methods
void OnPlayRequested(object sender, EventArgs args)
{
player.Play();
}
void OnPauseRequested(object sender, EventArgs args)
{
player.Pause();
}
void OnStopRequested(object sender, EventArgs args)
{
player.Pause();
player.Seek(new CMTime(0, 1));
}
}
答案 0 :(得分:1)
我看不到您的代码,也不知道您的问题是什么。我将向您展示如何使其发挥作用,以播放存储在文档文件夹中的本地视频:
在xamarin.forms
中:
public class MyVideoView : View
{
}
在xaml
中,只需使用此MyVideoView
即可:
<StackLayout>
<!-- Place new controls here -->
<local:MyVideoView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</StackLayout>
在iOS项目中,自定义渲染器应为:
public class VideoPlayerRenderer : ViewRenderer
{
AVPlayer player;
AVPlayerItem playerItem;
AVPlayerViewController _playerViewController; // solely for ViewController property
public override UIViewController ViewController => _playerViewController;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
if (Control == null)
{
// Create AVPlayerViewController
_playerViewController = new AVPlayerViewController();
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var path = Path.Combine(documents, "iOSApiVideo.mp4");
NSUrl url = NSUrl.CreateFileUrl(path, null);
//if you put your video in the project directly use below code
//NSUrl url = NSBundle.MainBundle.GetUrlForResource("iOSApiVideo", "mp4");
// Set Player property to AVPlayer
player = new AVPlayer(url);
_playerViewController.Player = player;
// Use the View from the controller as the native control
SetNativeControl(_playerViewController.View);
player.Play();
}
}
}
}
将path
替换为your own path
,它将起作用。
注意:
不起作用
NSUrl url = new NSUrl(path);
工作
NSUrl url = NSUrl.CreateFileUrl(path, null);
答案 1 :(得分:0)
我要发布最终答案,因为我最终使用了杰克的答案来修改我的customRenderer。 所以我在自定义渲染器的SetSource()函数中更改了此条件
else if (Element.Source is FileVideoSource)
{
string uri = (Element.Source as FileVideoSource).File;
if (!String.IsNullOrWhiteSpace(uri))
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var path = Path.Combine(documents, uri);
NSUrl url = NSUrl.CreateFileUrl(path, null);
asset = AVAsset.FromUrl(url);
}
}
唯一的变化是现在我正在customRenderer中获取路径,并且仅将FileName作为参数从ViewModel传递。之前它是完整路径,例如[/Users/vaibhavjain/Library/Developer/CoreSimulator/Devices/{GUID}/data/Containers/Data/Application/{GUID}/Documents/MediaDocuments/Nature1.mp4]