Какой наиболее эффективный способ объединить два или более видео в одно в приложении iOS? Я пробовал использовать AVFoundation, но он работает довольно медленно.
Я пробовал разные пресеты (даже AVAssetExportPreset1280x720), но процесс все равно очень медленный.
Есть ли какие-либо инфраструктуры или методы с ускорением на графическом процессоре, которые могут повысить производительность?
Вот моя текущая реализация.
func mergeVideos(
_ items: [VideoItem],
presetName: String,
overlay: Overlay?,
completionHandler: @escaping (Result) -> Void
) {
let fileName = "video-\(Date().description)"
let composition = AVMutableComposition()
let allItemsAreMuted = items.allSatisfy(\.isMuted)
guard
let compVideoTrack = composition.addMutableTrack(
withMediaType: .video,
preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid)
)
else {
return completionHandler(.failure(VideoEditorError.unknown))
}
var compAudioTrack: AVMutableCompositionTrack?
if !allItemsAreMuted {
compAudioTrack = composition.addMutableTrack(
withMediaType: .audio,
preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid)
)
if compAudioTrack == nil {
return completionHandler(.failure(VideoEditorError.unknown))
}
}
var currentTime = CMTime.zero
var loadedVideoTracks = [AVAsset: AVAssetTrack]()
var loadedAudioTracks = [AVAsset: AVAssetTrack]()
items.forEach { item in
do {
var audioTrack: AVAssetTrack?
let range = item.range ?? CMTimeRangeMake(start: CMTime.zero, duration: item.asset.duration)
var scaledDuration: CMTime?
if let rate = item.rate, rate != 1 {
scaledDuration = CMTime(seconds: range.duration.seconds / Double(rate), preferredTimescale: 1000)
}
if let videoTrack = loadedVideoTracks[item.asset] ?? item.asset.tracks(withMediaType: .video).first {
loadedVideoTracks[item.asset] = videoTrack
try compVideoTrack.insertTimeRange(range, of: videoTrack, at: currentTime)
}
if !item.isMuted {
audioTrack = loadedAudioTracks[item.asset] ?? item.asset.tracks(withMediaType: .audio).first
if let audioTrack = audioTrack {
loadedAudioTracks[item.asset] = audioTrack
try compAudioTrack?.insertTimeRange(range, of: audioTrack, at: currentTime)
}
}
if let scaledDuration = scaledDuration {
let currentRange = CMTimeRangeMake(start: currentTime, duration: range.duration)
compVideoTrack.scaleTimeRange(currentRange, toDuration: scaledDuration)
compAudioTrack?.scaleTimeRange(currentRange, toDuration: scaledDuration)
}
currentTime = CMTimeAdd(currentTime, scaledDuration ?? range.duration)
} catch {
completionHandler(.failure(error))
return
}
}
let exportURL = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(fileName)
.appendingPathExtension("mov")
guard let export = AVAssetExportSession(
asset: composition,
presetName: presetName
) else {
completionHandler(.failure(VideoEditorError.unknown))
return
}
if let overlay = overlay {
let videoInfo = orientation(from: loadedVideoTracks.first!.value.preferredTransform)
let videoSize: CGSize
if videoInfo.isPortrait {
videoSize = CGSize(
width: loadedVideoTracks.first!.value.naturalSize.height,
height: loadedVideoTracks.first!.value.naturalSize.width
)
} else {
videoSize = loadedVideoTracks.first!.value.naturalSize
}
let overlayLayer = CALayer()
overlayLayer.contents = overlay.image.cgImage
overlayLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
overlayLayer.opacity = 1
overlayLayer.masksToBounds = true
overlayLayer.transform = CATransform3DMakeTranslation(overlay.rotationDegrees, 0, 0)
let radians = CGFloat(overlay.rotationDegrees) * .pi / 180.0
overlayLayer.transform = CATransform3DMakeRotation(radians, 1, 0, 0)
let videoLayer = CALayer()
videoLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
let animationLayer = CALayer()
animationLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
animationLayer.addSublayer(videoLayer)
animationLayer.addSublayer(overlayLayer)
// Add the animation layer to the video composition
let videoComposition = AVMutableVideoComposition(propertiesOf: composition)
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(
postProcessingAsVideoLayers: [videoLayer],
in: animationLayer
)
export.videoComposition = videoComposition
}
export.outputURL = exportURL
export.outputFileType = .mov
export.shouldOptimizeForNetworkUse = true
export.exportAsynchronously {
DispatchQueue.main.async {
switch export.status {
case .completed:
completionHandler(.success(exportURL))
default:
completionHandler(.failure(export.error ?? VideoEditorError.unknown))
}
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/785 ... foundation
Эффективное объединение нескольких видео в iOS: альтернативы AVFoundation ⇐ IOS
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Эффективное объединение нескольких видео в iOS: альтернативы AVFoundation
Anonymous » » в форуме IOS - 0 Ответы
- 85 Просмотры
-
Последнее сообщение Anonymous
-