在 swift 3 中播放部分下载的视频

Play partially downloaded video in swift 3

我需要播放视频的特定部分(例如,从 10 秒到 20 秒)。 所以我使用 Alamofire 和自定义 header 范围来下载这部分视频:

Alamofire.download(videoUrl,
                           method: .get,
                           headers: ["Range":String(format: "bytes=%d-%d", startByte, endByte)],
                           to: destination).response { (response) in

                                completionHandler(response.destinationURL)
        }

到目前为止一切顺利,我可以看到下载的文件。

但是当我尝试播放它时,avplayer 会失败,我正在使用

videoAsset.loadValuesAsynchronously(forKeys: [ObserverContexts.urlAssetDurationKey, ObserverContexts.urlAssetPlayableKey])

异步加载特定键但无法加载持续时间状态:

let durationStatus = self.videoAsset.statusOfValue(forKey: ObserverContexts.urlAssetDurationKey, error: &durationError)
                guard durationStatus == .loaded else {
                    Logger.log.error("durationStatus not loaded: \(self.videoId)")
                    self.delegate?.onLoadError(error: . durationStatusNotLoaded)
                    return
                }

所以触发了这个错误,我无法播放视频。

我不是视频文件的高手,但我认为视频文件有一个 header,部分下载会破坏这个 header 并且播放器无法播放它。

因此,我们将不胜感激任何建议或想法(即使是最简单的)。

提前tnx。

编辑: 视频肯定有问题 header,如果我从视频开始 10 秒开始下载,视频会播放 10 秒, 但是视频结束时间或持续时间错误,我该如何解决?

这不是原始问题的答案,但我通过使用 AVFoundation 成功实现了我的目标,现在我可以下载我想要的确切部分并且可以播放了:

let downloadUrl = URL(string: videoUrl)!
let asset = AVURLAsset(url: downloadUrl)
let composition = AVMutableComposition()
let videoTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID:Int32(kCMPersistentTrackID_Invalid))
let audioTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
let tracks = asset.tracks(withMediaType: AVMediaTypeVideo)

guard let assetVideoTrack = tracks.first else {
    Logger.log.debug("video track is not available: \(videoId)")
    completionHandler(nil)
    return
}

let startCM = CMTime(seconds: startSecond, preferredTimescale: 1)
//let endCM = CMTime(seconds: startSecond  + duration, preferredTimescale: 1)
//EDITED
let endCM = CMTime(seconds: duration, preferredTimescale: 1)
let timeRange = CMTimeRangeMake(startCM, endCM)

do {
    try videoTrack.insertTimeRange(timeRange, of: assetVideoTrack, at: CMTimeMake(0, 1))
} catch let errorInsertingVideo {
    Logger.log.debug("can not get video time range: \(videoId) -- \(errorInsertingVideo.localizedDescription)")
    completionHandler(nil)
    return
}

videoTrack.preferredTransform = assetVideoTrack.preferredTransform

guard let assetAudioTrack : AVAssetTrack = asset.tracks(withMediaType: AVMediaTypeAudio).first else {
    Logger.log.debug("audio track is not available: \(videoId)")
    completionHandler(nil)
    return
}

do {
    try audioTrack.insertTimeRange(timeRange, of: assetAudioTrack, at: CMTimeMake(0, 1))
}catch let errorInsertingAudio {
    Logger.log.debug("can not get audio time range: \(videoId) -- \(errorInsertingAudio.localizedDescription)")
    completionHandler(nil)
    return
}

guard let destinationUrl = self.getDestinationUrl(videoId) else {
    // can not access video cache dir
    Logger.log.error("can not access video cache dir")
    completionHandler(nil)
    return
}

let exportSession : AVAssetExportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough)!

exportSession.outputURL = destinationUrl
exportSession.timeRange = timeRange
exportSession.outputFileType = AVFileTypeQuickTimeMovie

exportSession.exportAsynchronously(completionHandler: { 
    switch exportSession.status {
    case .completed:
        let output = exportSession.outputURL!
        completionHandler(output)
    case .failed:
        completionHandler(nil)
        break
    default :
        completionHandler(nil)
        break
    }
})

通过这个技巧,我可以从视频中间(或开始)的任何一秒开始下载恰好 10 秒(可选)的视频。

编辑:好吧这段代码可以不能下载中间部分,它只适用于你从视频的开头开始。

编辑 2:已添加修复程序。

我不认为 IOS 或 Swift 提供从中间下载图像然后播放的功能。您可以以位的形式下载视频文件内容,然后可以将它们保存为任何文件名的任何扩展名。 但是视频文件除了您下载的这些字节之外还包含大量数据,例如 header、类型、持续时间等。如果您下载的文件不包含这些数据,您的视频将无法播放。

在这种情况下,我认为(99% 确定)您将不得不使用 native 代码,而不仅仅是 Swift 将视频从特定时间解码到您想要的时间.

有很多免费的图书馆,试试吧。 ffmpeg. Check this也是一种这样的库。

祝一切顺利。