ios - 在我的 iOS 应用程序中与我的外部附件通信以播放流中的视频
问题描述
在我的 iOS 应用程序中,我需要使用外部附件框架播放视频。该框架将通过委托方法提供流。但我找不到从字节流播放的播放器。请推荐解决此问题的最佳方法
- (void)stream:(NSStream*)theStream 句柄事件:(NSStreamEvent)streamEvent { }
解决方案
有两种方法,第一种是将字节流保存在本地临时文件中,然后用 AVAsset 播放。
let url = URL(fileURLWithPath: filePath)
let asset = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: ["playable"])
player = AVPlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
playerLayer.videoGravity = .resizeAspect
view.layer.addSublayer(playerLayer)
如果您不想将视频保存在设备中,您可以在您的应用程序中创建一个 HTTPServer 并使用 AVURLAsset 与 AVPlayer 一起播放它。这是一个使用 GCD Web 服务器的示例,请注意服务器需要接受范围请求才能与 AVPlayer 和 .
self.webServer = GCDWebServer()
self.webServer!.addDefaultHandler(forMethod: "GET", request: GCDWebServerRequest.self, asyncProcessBlock: {(request,completionBlock) in
let path = Bundle.main.path(forResource: "sample", ofType: "mp4")
var attr:[FileAttributeKey : Any]
do {
attr = try FileManager.default.attributesOfItem(atPath: path!)
}
catch{
completionBlock(GCDWebServerResponse(statusCode: 500))
return
}
let fileSize = attr[FileAttributeKey.size] as! UInt64
if (request.hasByteRange()){
let handler = FileHandle.init(forReadingAtPath: path!)
handler?.seek(toFileOffset: UInt64(request.byteRange.lowerBound))
var response:GCDWebServerDataResponse
if(request.byteRange.upperBound <= -1){
response = GCDWebServerDataResponse(data: (handler?.readDataToEndOfFile())!, contentType: "video/mp4")
}
else{
response = GCDWebServerDataResponse(data: (handler?.readData(ofLength: request.byteRange.length))!, contentType: "video/mp4")
}
response.statusCode = 206
response.setValue("bytes \(request.byteRange.lowerBound)-\(request.byteRange.upperBound-1)/\(fileSize)", forAdditionalHeader: "Content-Range")
response.setValue("bytes", forAdditionalHeader: "Accept-Ranges")
response.setValue("\(request.byteRange.length)", forAdditionalHeader: "Content-Length")
response.setValue("video/mp4", forAdditionalHeader: "Content-Type")
response.setValue("keep-alive", forAdditionalHeader: "Connection")
completionBlock(response)
return
}
else {
let handler = FileHandle.init(forReadingAtPath: path!)
let response = GCDWebServerDataResponse(data: (handler?.readDataToEndOfFile())!, contentType: "video/mp4")
response.setValue("bytes", forAdditionalHeader: "Accept-Ranges")
response.setValue("keep-alive", forAdditionalHeader: "Connection")
completionBlock(response)
return
}
})
self.webServer!.start(withPort: 8080, bonjourName: "")
GCDWebServer.setLogLevel(0)
然后您可以将您的 AVPlayer 设置为使用本地 Web 服务器来播放视频。
let asset = AVURLAsset(url: URL(string: "http://localhost:8080/")!)
let playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: ["playable"])
player = AVPlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x: 0, y: 0, width: viewPlayer.frame.width, height: viewPlayer.frame.height)
playerLayer.videoGravity = .resizeAspect
viewPlayer.layer.addSublayer(playerLayer)
self.view.layoutIfNeeded()
player!.play()
推荐阅读
- java - Jmeter - 将文件从一台主机复制到另一台主机
- c# - c#中字符串的奇怪IndexOf返回-1
- azure - 在 Linux 上使用 blob fuse 挂载 Azure blob 存储时,挂载大小为 7.8GB,如何将初始挂载大小增加到 2 TB
- r - 在两个日期之间的 R 数据框中生成记录
- python - Python sklearn ValueError:数组太大
- javascript - 无法为莫里斯图绘制垂直事件线
- java - 如何分隔二维数组中的不同值
- xpath - 来自网站的 Google 表格 IMPORTXML 文本字段
- postgresql - 如何使用 postgres 11 从函数中的迭代中返回表
- bluetooth - 树莓派零,蓝牙通过 ttyS0 或 Serial0