David Conlisk
David Conlisk

Reputation: 3492

Can AVPlayer properly stream video files from an API endpoint?

I have a Xamarin iOS app that I want to stream videos from an API endpoint that supports HTTP range requests. I've reviewed many similar questions here on SO, but I cannot seem to get the AVPlayer to start playing the video file before it is downloaded fully no matter what I try. I've tried:

But still the file is downloaded fully before the video starts to play, which causes a delay for the user.

Is it possible to get AVPlayer to start playing a video file before it has completed downloading it, similar to how the HTML video tag does it?

Here is my current code:

    private void SetUpPlayer()
    {
        if (ViewModel.VideoStreamUrl == null)
        {
            return;
        }

        // See https://stackoverflow.com/questions/38865797/how-to-play-video-with-avplayerviewcontroller-avkit-in-xamarin-ios
        _aVPlayerItem = new AVPlayerItem(ViewModel.VideoStreamUrl)
        {
            CanUseNetworkResourcesForLiveStreamingWhilePaused = true,
            PreferredForwardBufferDuration = 1,
        };

        // See https://stackoverflow.com/questions/38867190/how-can-i-check-if-my-avplayer-is-buffering/38867386#38867386
        _playbackLikelyToKeepUpObserver?.Dispose();
        _playbackLikelyToKeepUpObserver = (NSObject)_aVPlayerItem.AddObserver("playbackLikelyToKeepUp",
            NSKeyValueObservingOptions.New,
            AVPlayerItem_BufferUpdated);

        _playbackBufferEmptyObserver?.Dispose();
        _playbackBufferEmptyObserver = (NSObject)_aVPlayerItem.AddObserver("playbackBufferEmpty",
            NSKeyValueObservingOptions.New,
            AVPlayerItem_BufferUpdated);

        _playbackBufferFullObserver?.Dispose();
        _playbackBufferFullObserver = (NSObject)_aVPlayerItem.AddObserver("playbackBufferFull",
            NSKeyValueObservingOptions.New,
            AVPlayerItem_BufferUpdated);

        _aVPlayer = new AVPlayer(_aVPlayerItem)
        {
            AutomaticallyWaitsToMinimizeStalling = false,
        };

        var playerViewController = new AVPlayerViewController
        {
            Player = _aVPlayer,
        };

        AddChildViewController(playerViewController);
        View.AddSubview(playerViewController.View);
        playerViewController.View.Frame = View.Frame;
        playerViewController.ShowsPlaybackControls = true;

        _aVPlayer.PlayImmediatelyAtRate(1);
    }

    private void AVPlayerItem_BufferUpdated(NSObservedChange obj)
    {
        ReportVideoBuffering();
    }

    private void ReportVideoBuffering()
    {
        bool isBufferEmpty = _aVPlayerItem != null && _aVPlayerItem.PlaybackBufferEmpty;
        Console.WriteLine($"Buffer empty? {isBufferEmpty}");
        Console.WriteLine($"Player status? {_aVPlayer.Status}");

        if (_aVPlayer.Status == AVPlayerStatus.ReadyToPlay)
        {
            Console.WriteLine($"Playing video.");
            _aVPlayer.Play();
        }
    }

Upvotes: 2

Views: 696

Answers (1)

David Conlisk
David Conlisk

Reputation: 3492

The simple answer to the question is no, the AVPlayer doesn't support streaming using http range requests and partial content (206) responses. In our case, we have decided to use Azure Media Services to provide a streaming endpoint which we can then use in the iPad app as well as on the web.

Upvotes: 1

Related Questions