首页 > 解决方案 > 在我的 iOS 应用程序中与我的外部附件通信以播放流中的视频

问题描述

在我的 iOS 应用程序中,我需要使用外部附件框架播放视频。该框架将通过委托方法提供流。但我找不到从字节流播放的播放器。请推荐解决此问题的最佳方法

标签: iosswiftusbvideo-streamingexternal-accessory

解决方案


有两种方法,第一种是将字节流保存在本地临时文件中,然后用 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()

推荐阅读