Xamarin视频播放器无法播放模拟器文档文件夹中的视频

时间:2019-07-11 18:39:41

标签: xamarin video xamarin.forms xamarin.ios

您好,我实现了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));
    }
}

2 个答案:

答案 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]