Видеоплеер Xamarin не может воспроизвести видео из папки документов симулятора - PullRequest
0 голосов
/ 11 июля 2019

Привет, я реализовал видеоплеер xamarin, который описан по следующей ссылке https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/video-player/

Я загружаю видео через код в папку с документами приложения, путь к которому такой [/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 ]

1 голос
/ 12 июля 2019

Я не вижу ваш код и не могу понять, в чем ваша проблема. Я бы показал вам, как заставить его воспроизводить локальное видео, хранящееся в папке с документами:

В 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);
0 голосов
/ 15 июля 2019

Я публикую окончательный ответ, потому что в итоге я использовал ответ Джека, чтобы изменить свой customRenderer.поэтому я изменил это условие в функции SetSource () в настраиваемом Renderer

 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.ранее это был полный путь, например

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...