0

I'm trying to play video with AvPlayer in Xamarin.iOS. I'm working with Firebase Storage. If I upload video from android, media type is set as mp4 but from iOS, media type is set as urlencoded. I can play mp4 files with AvPlayer but urlencoded files are not playable. On the other hand, urlencoded files are playable in android VideoView. Do you have any idea about it?

Here my codes, first pick video from gallery:

    private async void PickVideoButton_TouchUpInside(object sender, EventArgs e)
    {
        await CrossMedia.Current.Initialize();

        if (!CrossMedia.Current.IsPickVideoSupported)
        {
            return;
        }
        try
        {
            file = await CrossMedia.Current.PickVideoAsync();
            if (file == null)
            {
                return;
            }

            fileStream = await ConvertMovToMp4();
            mediaType = "Video";

            avp = new AVPlayer(NSUrl.FromFilename(file.Path));
            avpvc = new AVPlayerViewController();
            avpvc.Player = avp;
            AddChildViewController(avpvc);
            GeneralPostingStoryViewBackground.AddSubview(avpvc.View);
            avpvc.View.Frame = GeneralPostingStoryImageView.Frame;
            avpvc.ShowsPlaybackControls = true;
            avp.Play();
        }
        catch (Exception ex)
        {
            alert = UIAlertController.Create("Error", "Gallery doesn't support", UIAlertControllerStyle.Alert);
            alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
            PresentViewController(alert, true, null);
        }
    }

    public async Task<Stream> ConvertMovToMp4()
    {
        string exportPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        string exportFilePath = Path.Combine(exportPath, DateTime.Now.ToString() + ".mp4");

        var asset = AVAsset.FromUrl(NSUrl.FromFilename(file.Path));
        var length = asset.Duration.Seconds;
        lengthDuration = Convert.ToInt32(length).ToString();
        AVAssetExportSession export = new AVAssetExportSession(asset, AVAssetExportSession.PresetMediumQuality);
        export.OutputUrl = NSUrl.FromFilename(exportFilePath);
        export.OutputFileType = AVFileType.Mpeg4;
        export.ShouldOptimizeForNetworkUse = true;
        await export.ExportTaskAsync();
        var stream = File.OpenRead(exportFilePath);

        return stream;
    }

Then, upload video to firebase storage:

    private async void ShareButton_TouchUpInside(object sender, EventArgs e)
    {
        try
        {
            var result = await PortableSharediOS(ID, mediaType, fileStream, commentText);
            if (result == "Success.")
            {
                CommonValues.viewControllerIndexList.RemoveAt(CommonValues.viewControllerIndexList.Count - 1);
                NavigateViewController();
            }
            else
            {
                alert = UIAlertController.Create("Error", result.ToString(), UIAlertControllerStyle.Alert);
                alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
                PresentViewController(alert, true, null);
            }
        }
        catch (Exception ex)
        {
            alert = UIAlertController.Create("Error", "Check your internet connection.", UIAlertControllerStyle.Alert);
            alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
            PresentViewController(alert, true, null);
        }
    }

Finally, I'm trying to play videos, as I said the mp4 files are playable which I've upload from android, but files which I've upload from iOS, avplayer doesn't play them..:

    public async Task GetStory(int storyIndex)
    {
        var mediaType = stories[storyIndex].StoryType;
        var story = stories[storyIndex];
        user = await firebaseHelper.GetUser(story.StoryOwner);
        if (mediaType == "Photo")
        {
            GetImage(story.MediaLink, storyViewStoryImageView);
            GetImage(user.PhotoLink, storyViewImageView);
            storyViewUserName.Text = user.UserName;
            storyViewContentView.Text = story.Content;
            time = story.MediaDuration;
            storyViewDuration.Text = time.ToString();
        }
        else
        {
            storyViewUserName.Text = user.UserName;
            storyViewContentView.Text = story.Content;
            time = story.MediaDuration;
            var asset = AVAsset.FromUrl(NSUrl.FromString(story.MediaLink));
            var item = AVPlayerItem.FromAsset(asset);
            avp = new AVPlayer(item);
            avp.Muted = false;
            avpvc = new AVPlayerViewController();
            avpvc.Player = avp;
            AddChildViewController(avpvc);
            storyViewStoryImageView.AddSubview(avpvc.View);
            avpvc.View.Hidden = false;
            avpvc.View.Frame = storyViewStoryImageView.Frame;
            avpvc.ShowsPlaybackControls = false;
            avp.Play();
            storyViewDuration.Text = time.ToString();
        }
        timer.Enabled = false;
        timer.Close();
        TimerTextVoid();
    }

I can play all files on Android. Doesn't matter where they were uploaded from.

1 Answers1

0

I figured out my problem. Download and save file to device from Firebase Storage. Then assign it to AVAsset. Codes:

    public async Task GetStory(int storyIndex)
    {
        var mediaType = stories[storyIndex].StoryType;
        var story = stories[storyIndex];
        user = await firebaseHelper.GetUser(story.StoryOwner);
        if (mediaType == "Photo")
        {
            GetImage(story.MediaLink, storyViewStoryImageView);
            GetImage(user.PhotoLink, storyViewImageView);
            storyViewUserName.Text = user.UserName;
            storyViewContentView.Text = story.Content;
            time = story.MediaDuration;
            storyViewDuration.Text = time.ToString();
        }
        else
        {
            storyViewUserName.Text = user.UserName;
            storyViewContentView.Text = story.Content;
            time = story.MediaDuration;
            var asset = await GetVideo(story.MediaLink);
            var item = new AVPlayerItem(asset);
            avp = new AVPlayer(item);
            avp.Muted = false;
            avpvc = new AVPlayerViewController();
            avpvc.Player = avp;
            AddChildViewController(avpvc);
            storyViewStoryImageView.AddSubview(avpvc.View);
            avpvc.View.Hidden = false;
            avpvc.View.Frame = storyViewStoryImageView.Frame;
            avpvc.ShowsPlaybackControls = false;
            avp.Play();
            storyViewDuration.Text = time.ToString();
        }
        timer.Enabled = false;
        timer.Close();
        TimerTextVoid();
    }

    public async Task<AVAsset> GetVideo(string url)
    {
        string videoFile;
        using (var client = new WebClient())
        {
            var content = client.DownloadData(url);
            var stream = new MemoryStream(content);

            string folder = Path.GetTempPath();
            videoFile = Path.Combine(folder, DateTime.Now.ToString() + ".mp4");

            if (!System.IO.File.Exists(videoFile))
            {
                using (FileStream outputStream = System.IO.File.Create(videoFile))
                {
                    await stream.CopyToAsync(outputStream);
                }
            }
            
        }
        var asset = AVUrlAsset.FromUrl(NSUrl.FromFilename(videoFile));
        return asset;
    }