如何在Swift中使用AVPlayer播放IPFS URL的视频

5

我有一个IPFS加密视频的URL。
我无法在AVPlayer中播放视频,但URL在WebView中可以播放得很好。
这是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()

我曾经使用过带有视频扩展名和视频编解码器的AVUrlAssets,但仍然无法播放视频。

let mimeType = "video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\""
let asset: AVURLAsset = AVURLAsset(url: videoURL!, options: ["AVURLAssetOutOfBandMIMETypeKey" : mimeType])
2个回答

2

在处理代码中的错误时,及时获取有关问题的信息是一种好的实践,因此让我们制作下一个错误处理程序:

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)

如果您运行代码,它会产生以下错误:
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)"}}

"服务器配置不正确"通常与服务器端支持范围下载有关,因为播放来自互联网的媒体需要支持按范围下载。请使用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
...

从响应中可以看出,服务器支持范围——“accept-ranges: bytes”。

让我们检查部分请求:

$ 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
...

服务器的响应包括HTTP/2 200 和全部内容长度,但是响应应该像这样:
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
...

如果您的服务器不支持HTTP范围请求,AVPlayer将无法播放您的mp4视频。

您可以通过以下两种方式解决此问题:

  1. 更改服务器设置以支持HTTP范围请求。
  2. 编程下载视频并将其保存到本地文件中,然后可以从文件URL播放它。

我无法下载视频并将其保存,然后从本地文件URL播放,因为视频将是多个。所以,如果我要求更改服务器设置,我是否能够直接从URL播放视频? 只是确认您回答的最后一部分 在我更改服务器设置之后,我仍然需要下载视频并从本地播放吗? - NickCoder
1
@NickCoder 我的意思是有两种解决问题的方法(我已经做了更正)。最好的解决方案是在服务器端进行更改,然后播放器可以通过URL播放您的视频。 - iUrii
非常感谢,我会告诉他们按照您的要求进行更改并在应用程序中进行测试。 - NickCoder

0
奇怪,看起来AVPlayerLayer无法解析视频。如果您删除playerLayer,您会听到音频正常播放。
我的解决方案是使用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 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接