0
votes

I'm using Android's Video View to play a video in my app. It works fine when I put source as a web-link but I keep getting a "Can't play this video" message and a black screen in the Xamarin Android Player when I choose file from Local Resource. I have followed sample from Here. I have googled the issue some say the issue is may be because of

  • Unsupported file format
  • Unsupported android version

I Don't think this could be in my case as the sample project is running fine on same device .Moreover in my project video from URL are also played. I believe I might be missing a piece to fix this. Xaml :-

  <StackLayout VerticalOptions="FillAndExpand">

    <video:VideoPlayer   AutoPlay="True"  x:Name="xvideoPlayer" WidthRequest="200" HeightRequest="200"  />
    <Button Clicked="Button_Clicked" ></Button>
</StackLayout>

Cs:

 public VideoPlayerPage(string url)
    {

        InitializeComponent();
        BindingContext = videoPlayerPageViewModel = new VideoPlayerPageViewModel();
        NavigationPage.SetHasNavigationBar(this, false);

    }
private async void Button_Clicked(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        btn.IsEnabled = false;
        var FileOperations = DependencyService.Get<IFileOperations>();

        //string pLocalPath = FileOperations.GetFilePath(url, "ErpwebChat");
        string pLocalPath = "content://com.android.externalstorage.documents/document/primary%3ADocument%2FErpwebChat%2F1aecb317-8d56-46c4-b29a-182d2e61093c.mp4";
        //DownloadVideo(url, "videos");



        if (!String.IsNullOrWhiteSpace(pLocalPath))
        {
            xvideoPlayer.Source = new FileVideoSource
            {
                File = pLocalPath
            };
        }
        btn.IsEnabled = true;
    }

VideoPlayerRenderer.droid class:-

  public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
    VideoView videoView;
    MediaController mediaController;    // Used to display transport controls
    bool isPrepared;

    public VideoPlayerRenderer(Context context) : base(context)
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
    {
        base.OnElementChanged(args);

        if (args.NewElement != null)
        {
            if (Control == null)
            {
                // Save the VideoView for future reference
                videoView = new VideoView(Context);

                // Put the VideoView in a RelativeLayout
                ARelativeLayout relativeLayout = new ARelativeLayout(Context);
                relativeLayout.AddView(videoView);

                // Center the VideoView in the RelativeLayout
                ARelativeLayout.LayoutParams layoutParams =
                    new ARelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
                layoutParams.AddRule(LayoutRules.CenterInParent);
                videoView.LayoutParameters = layoutParams;

                // Handle a VideoView event
                videoView.Prepared += OnVideoViewPrepared;

                SetNativeControl(relativeLayout);
            }

            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)
    {
        if (Control != null && videoView != null)
        {
            videoView.Prepared -= OnVideoViewPrepared;
        }
        if (Element != null)
        {
            Element.UpdateStatus -= OnUpdateStatus;
        }

        base.Dispose(disposing);
    }

    void OnVideoViewPrepared(object sender, EventArgs args)
    {
        isPrepared = true;
        ((IVideoPlayerController)Element).Duration = TimeSpan.FromMilliseconds(videoView.Duration);
    }

    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)
        {
            if (Math.Abs(videoView.CurrentPosition - Element.Position.TotalMilliseconds) > 1000)
            {
                videoView.SeekTo((int)Element.Position.TotalMilliseconds);
            }
        }
    }

    void SetAreTransportControlsEnabled()
    {
        if (Element.AreTransportControlsEnabled)
        {
            mediaController = new MediaController(Context);
            mediaController.SetMediaPlayer(videoView);
            videoView.SetMediaController(mediaController);
        }
        else
        {
            videoView.SetMediaController(null);

            if (mediaController != null)
            {
                mediaController.SetMediaPlayer(null);
                mediaController = null;
            }
        }
    }

    void SetSource()
    {
        isPrepared = false;
        bool hasSetSource = false;

        if (Element.Source is UriVideoSource)
        {
            string uri = (Element.Source as UriVideoSource).Uri;

            if (!String.IsNullOrWhiteSpace(uri))
            {
                videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
                hasSetSource = true;
            }
        }
        else if (Element.Source is FileVideoSource)
        {
            string filename = (Element.Source as FileVideoSource).File;

            if (!String.IsNullOrWhiteSpace(filename))
            {
                videoView.SetVideoPath(filename);
                hasSetSource = true;
            }
        }
        else if (Element.Source is ResourceVideoSource)
        {
            string package = Context.PackageName;
            string path = (Element.Source as ResourceVideoSource).Path;

            if (!String.IsNullOrWhiteSpace(path))
            {
                string filename = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
                string uri = "android.resource://" + package + "/raw/" + filename;
                videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
                hasSetSource = true;
            }
        }

        if (hasSetSource && Element.AutoPlay)
        {
            videoView.Start();
        }
    }

    // Event handler to update status
    void OnUpdateStatus(object sender, EventArgs args)
    {
        VideoStatus status = VideoStatus.NotReady;

        if (isPrepared)
        {
            status = videoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
        }

        ((IVideoPlayerController)Element).Status = status;

        // Set Position property
        TimeSpan timeSpan = TimeSpan.FromMilliseconds(videoView.CurrentPosition);
        ((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty, timeSpan);
    }

    // Event handlers to implement methods
    void OnPlayRequested(object sender, EventArgs args)
    {
        videoView.Start();
    }

    void OnPauseRequested(object sender, EventArgs args)
    {
        videoView.Pause();
    }

    void OnStopRequested(object sender, EventArgs args)
    {
        videoView.StopPlayback();
    }
}

I am using .mp4 format Rest all classes are same as in the sample app Here Any help will be appreciated . !

Edit - Device log(From Button Click to Cant play Error) Here

2
Device logs would help!!!FreakyAli
sure I'll add itNancy Kanwar
...Unable to open content... The error is in your log, do you have permission (manifest and runtime permission to external storage) and how are you determining your :content://" path (you can not just make that up, it needs to be retrieved from the media manager).SushiHangover
Thanks for your comment @SushiHangover . But all permissions were there. Only issue was of calling method in Constructor rather than Button . Bit Strange but not its workingNancy Kanwar
try not to pass the file path with hard codingLeo Zhu - MSFT

2 Answers

0
votes

I faced the same issue with ios renderer so the way i was able to solve it was changing the condition in my SetSource function to

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);
        }
    }

for some reason passing the whole path as a string doesn't work so you can pass the file name and write the logic of creating path inside your customrenderer here is the link to my question Xamarin video player unable to play video from simulator document folder

0
votes

Try taking the video player out of the StackLayout, I've been running through Xamarins own video player sample, copied system files and class structures, nothing but blank screen.. Took it out of the stack and bingo