5

I have an ipfs encrypted video URL.
I am not able to play video in avplayer but URL plays well in webview.
here is URL: https://ipfs.moralis.io:2053/ipfs/QmUjWnQZVVNmTSVak2QDhTxMkn3dPQozxawa1sm3jE5bLr

let currentURL = URL(string: "https://ipfs.moralis.io:2053/ipfs/QmUjWnQZVVNmTSVak2QDhTxMkn3dPQozxawa1sm3jE5bLr")!
let playerItem = AVPlayerItem(url: currentURL)
playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions(), context: nil)
player = AVPlayer(playerItem: playerItem)let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.avplayerUIView.bounds
self.avplayerUIView.layer.addSublayer(playerLayer)
player.play()

Also, I have used AVUrlAssets with video extension and video codecs but still, video is not playing

let mimeType = "video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\""
let asset: AVURLAsset = AVURLAsset(url: videoURL!, options: ["AVURLAssetOutOfBandMIMETypeKey" : mimeType])
NickCoder
  • 1,504
  • 2
  • 23
  • 35

2 Answers2

2

It's a good practice to handle errors from your code to get info about the problem so lets make next error handler:

class ErrorObserver: NSObject {
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
        guard let player = object as? AVPlayer, let error = player.currentItem?.error, let keyPath = keyPath else {
            return
        }
        print("Key:", keyPath)
        print("Error:", error)
    }
}

let errorObserver = ErrorObserver()

...

// Add observer AVPlayerItem status
player.addObserver(errorObserver, forKeyPath: #keyPath(AVPlayer.currentItem.status), options:[.new], context: nil)

If you run your code it produces next error:

Key: currentItem.status
Error: Error Domain=AVFoundationErrorDomain Code=-11850 "Operation Stopped" UserInfo={NSLocalizedFailureReason=The server is not correctly configured., NSLocalizedDescription=Operation Stopped, NSUnderlyingError=0x600003bbc060 {Error Domain=NSOSStatusErrorDomain Code=-12939 "(null)"}}

"The server is not correctly configured." is often related to the HTTP range requests issue on a server side because supporting downloading by ranges is required to play media from the Internet.

Lets check this with curl:

$ curl -I https://ipfs.moralis.io:2053/ipfs/QmUjWnQZVVNmTSVak2QDhTxMkn3dPQozxawa1sm3jE5bLr
HTTP/2 200 
date: Fri, 05 Aug 2022 09:48:23 GMT
content-type: video/mp4
content-length: 4835525
cf-ray: 735e9de8d95c9290-FRA
accept-ranges: bytes
...

As you can see from the response the server supports ranges - "accept-ranges: bytes".

Lets check the partial request:

$ curl https://ipfs.moralis.io:2053/ipfs/QmUjWnQZVVNmTSVak2QDhTxMkn3dPQozxawa1sm3jE5bLr -i -H "Range: bytes=0-1023"
HTTP/2 200 
date: Fri, 05 Aug 2022 09:50:05 GMT
content-type: video/mp4
content-length: 4835525
cf-ray: 735ea066cfd61649-MUC
accept-ranges: bytes
...

The server responds with HTTP/2 200 and the full content length but the response must be like this:

HTTP/2 206 Partial Content
Accept-Ranges: bytes
Server: UploadServer
Aka-c-hit: cache-hit
Content-Range: bytes 0-1023/253755577
Content-Length: 1024
Connection: keep-alive
Content-Type: video/mp4
...

So that your server doesn't support HTTP ranges requests and AVPlayer can't play your mp4 video.

You can resolve the issue with two ways:

  1. Change the servers's settings to support HTTP range requests.
  2. Programmatically download video and save it to a local file and after you can play it from file URL.
iUrii
  • 11,742
  • 1
  • 33
  • 48
  • i cannot download video and save it and then play from local file URL because videos will be multiple So if I ask to change server settings will I be able to play video directly from URL? just to confirm last part of your answer after I change server settings, still i have to download video and play it from local? – NickCoder Aug 05 '22 at 12:21
  • 1
    @NickCoder I mean two ways to resolve the issue (I've made a correction about). The best solution is making changes on the server side and then the player can play your video by URL. – iUrii Aug 05 '22 at 14:47
  • Thank you so much i will tell them to make changes as you told and test in app – NickCoder Aug 05 '22 at 16:08
0

Strange. It seems AVPlayerLayer can not resolve video. If you remove playerLayer, you will hear audio is playing fine.

My solution is using AVPlayerViewController.

let vc = AVPlayerViewController()
vc.view.frame = view.bounds
vc.player = player
player.play()
present(vc, animated: true) // or use as a child view controller by embedding in a container view 
ugur
  • 3,604
  • 3
  • 26
  • 57