を凍結する原因となる問題のGIFへのリンクです:はAVPlayerLayerここ
https://gifyu.com/images/ScreenRecording2017-01-25at02.20PM.gif
私は、カメラロールからPHAsset
を取って変更可能な組成物にそれを追加して、追加しています追加したトラックを操作してAVAssetExportSession
にエクスポートします。結果はNSTemporaryDirectory()
に保存された.movファイル拡張子を持つQuickTimeファイルです:
guard let exporter = AVAssetExportSession(asset: mergedComposition, presetName: AVAssetExportPresetHighestQuality) else {
fatalError()
}
exporter.outputURL = temporaryUrl
exporter.outputFileType = AVFileTypeQuickTimeMovie
exporter.shouldOptimizeForNetworkUse = true
exporter.videoComposition = videoContainer
// Export the new video
delegate?.mergeDidStartExport(session: exporter)
exporter.exportAsynchronously() { [weak self] in
DispatchQueue.main.async {
self?.exportDidFinish(session: exporter)
}
}
私は、このエクスポートしたファイルを取り、いくつかの時間のマッピングに基づいて、クリップに「スローモーション」を適用するマッパーオブジェクトにロードそれに与えられた。ここでの結果はAVCompositionです:
func compose() -> AVComposition {
let composition = AVMutableComposition(urlAssetInitializationOptions: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
let emptyTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
let audioTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
let asset = AVAsset(url: url)
guard let videoAssetTrack = asset.tracks(withMediaType: AVMediaTypeVideo).first else { return composition }
var segments: [AVCompositionTrackSegment] = []
for map in timeMappings {
let segment = AVCompositionTrackSegment(url: url, trackID: kCMPersistentTrackID_Invalid, sourceTimeRange: map.source, targetTimeRange: map.target)
segments.append(segment)
}
emptyTrack.preferredTransform = videoAssetTrack.preferredTransform
emptyTrack.segments = segments
if let _ = asset.tracks(withMediaType: AVMediaTypeVideo).first {
audioTrack.segments = segments
}
return composition.copy() as! AVComposition
}
そこで私は、このファイルだけでなく、また私の中AVPlayerLayer
Sに接続されているAVPlayer
の中でプレーするAVPlayerItem
秒にslowmoにマッピングされている元のファイルを読み込みますアプリ:
let firstItem = AVPlayerItem(asset: originalAsset)
let player1 = AVPlayer(playerItem: firstItem)
firstItem.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithmVarispeed
player1.actionAtItemEnd = .none
firstPlayer.player = player1
// set up player 2
let secondItem = AVPlayerItem(asset: renderedVideo)
secondItem.seekingWaitsForVideoCompositionRendering = true //tried false as well
secondItem.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithmVarispeed
secondItem.videoComposition = nil // tried AVComposition(propertiesOf: renderedVideo) as well
let player2 = AVPlayer(playerItem: secondItem)
player2.actionAtItemEnd = .none
secondPlayer.player = player2
これらの動画を何度も繰り返し再生するための開始時刻と終了時刻があります。私は最後に興味がないので、PlayerItemDidReachEnd
を使用しないで、私はユーザーが入力した時間に興味があります。私もビデオを再生しようとする前に、両方のプレイヤーが求めて終了したことを確保にdispatchGroup使用:
func playAllPlayersFromStart() {
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
firstPlayer.player?.currentItem?.seek(to: startTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero, completionHandler: { _ in
dispatchGroup.leave()
})
DispatchQueue.global().async { [weak self] in
guard let startTime = self?.startTime else { return }
dispatchGroup.wait()
dispatchGroup.enter()
self?.secondPlayer.player?.currentItem?.seek(to: startTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero, completionHandler: { _ in
dispatchGroup.leave()
})
dispatchGroup.wait()
DispatchQueue.main.async { [weak self] in
self?.firstPlayer.player?.play()
self?.secondPlayer.player?.play()
}
}
}
ここで奇妙な部分があることも、私のCOMPOSE()関数のループを経由してマップされた元のアセット、完璧に良い。しかしながら、CMTimeMapping
セグメントのうちの1つの間にシークすると、compose()関数によっても実行されたrenderedVideoがフリーズすることがあります。フリーズするファイルとフリーズしないファイルの唯一の違いは、AVAssetExportSessionを介してNSTemporaryDirectoryにエクスポートされ、2つのビデオトラックを1つにまとめることだけです。どちらも同じ期間です。またフリーズしているプレイヤーにBoundaryTimeObservers
を追加すると、まだフリーズしていてループしてしまうので、フリーズしているのはオーディオレイヤーではないことだけです。また、オーディオも適切にループします。
私にとっては、ビデオが「フリーズ」後にシークを開始するために一時停止した場所を過ぎた場合、ビデオが「再開する」ということです。私は数日間このことに固執していて、本当にいくつかの指導を愛するでしょう。注意すべき
その他の奇妙なもの: - エクスポートされた資産に対して、元のCMTimeMappingがまったく同じ期間であっても、あなたは、レンダリングされた資産のスローモーションランプはオリジナルよりもより「途切れ」であることがわかります。 - ビデオがフリーズするとオーディオが続きます。 - スローモーションセクションの間にビデオがほとんど凍結しない(セグメントに基づくCMTimeMappingオブジェクトに起因する) - レンダリングされたビデオは、最初に "キャッチアップ"しなければならないように見える。奇妙な部分はセグメントがまったく同じで、2つの別々のソースファイルを参照することです.1つは資産ライブラリにあり、もう1つはNSTemporaryDirectoryにあります - それはそうだと私には思われます私がプレイする前にAVPlayerとAVPlayerItemStatusが 'readyToPlay'であることを確認してください。 - プレイヤーがロックアップしたポイントをPASTに進めると、 'アンフリーズ'するように見えます - 'AVPlayerItemPlaybackDidStall'のオブザーバーを追加しようとしましたと呼ばれる。
乾杯!
本当に感謝します。残念なことに、第2のプレイヤーがまだフリーズするので、ダイスはありません。境界時間オブザーバがプレイヤー1に再始動を知らせる適切な場所に当たったので、プレイヤー自身がまだ遊んでいると私は言うことができます。また、オーディオは最初から適切に再開し、ビデオは「フリーズ」フレームを通過するまでロックアップします。 –