我需要播放视频的特定部分(例如,形式为10秒到20秒)。
所以我使用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
}
加载特定键异步,但无法加载持续时间状态:
In [5]: from psycopg2.extras import NumericRange
In [6]: a = NumericRange(2, 8, '[)')
In [7]: a.lower
Out[7]: 2
In [8]: a.upper
Out[8]: 8
所以此错误会被触发,我无法播放视频。
我不是视频文件中的主人,但我认为视频文件有标题,部分下载会破坏此标题,播放器无法播放。
所以任何建议或想法(即使是最简单的)都会受到赞赏。
提前tnx。编辑:视频标题肯定有问题,如果我从视频开始下载10秒后,视频播放10秒,但是结束视频时间或持续时间错误,我该如何解决?
答案 0 :(得分:-1)
这不是原始问题的答案,但我设法通过使用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 :修复已添加。
答案 1 :(得分:-1)