AVMutableComposition - 只播放第一个轨道 (Swift)

3
我有一个 [AVAsset] 数组,我想将这些 Asset 合并成一个单独的 Asset,以便我可以无缝地播放视频(我尝试使用 AVQueuePlayer,但是它不能无缝地播放 assets)。
下面是我目前的代码,但当我尝试播放最终合成时,它只播放第一条轨道,即使它显示已经拥有所有轨道,总持续时间等于所有轨道的持续时间之和。
我是否缺少一步操作,即使看起来所有轨道都在合成中?也许如果 AVPlayerItem 有多个轨道,我需要以不同的方式处理 AVPlayer?
let playerLayer: AVPlayerLayer = AVPlayerLayer()
lazy var videoPlayer: AVPlayer = AVPlayer()

var videoClips = [AVAsset]()

let videoComposition = AVMutableComposition()
var playerItem: AVPlayerItem!
var lastTime: CMTime = kCMTimeZero

for clipIndex in videoClips {

    let videoCompositionTrack = videoComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))

    do {
        try videoCompositionTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, clipIndex.duration),
                                                  ofTrack: clipIndex.tracksWithMediaType(AVMediaTypeVideo)[0] ,
                                                  atTime: lastTime)
        lastTime = CMTimeAdd(lastTime, clipIndex.duration)
    } catch {
        print("Failed to insert track")
    }
}
print("VideoComposition Tracks: \(videoComposition.tracks.count)") // Shows multiple tracks

playerItem = AVPlayerItem(asset: videoComposition)
print("PlayerItem Duration: \(playerItem.duration.seconds)") // Shows the duration of all tracks together
print("PlayerItem Tracks: \(playerItem.tracks.count)") // Shows same number of tracks as the VideoComposition Track count

videoPlayer = AVPlayer(playerItem: playerItem)
playerLayer.player = videoPlayer
videoPlayer.volume = 0.0
videoPlayer.play()  // Only plays the first track
1个回答

11

我已经想出了对于最重要的问题的答案。为了同时播放所有片段,它们需要在同一个轨道上。要实现这一点,将以下代码行移到 for 循环之外:

let videoCompositionTrack = videoComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))

以下是完整的、已修正的代码:

let playerLayer: AVPlayerLayer = AVPlayerLayer()
lazy var videoPlayer: AVPlayer = AVPlayer()

var videoClips = [AVAsset]()

let videoComposition = AVMutableComposition()
var playerItem: AVPlayerItem!
var lastTime: CMTime = kCMTimeZero

let videoCompositionTrack = videoComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))

for clipIndex in videoClips {

    do {
        try videoCompositionTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, clipIndex.duration),
                                                  ofTrack: clipIndex.tracksWithMediaType(AVMediaTypeVideo)[0] ,
                                                  atTime: lastTime)
        lastTime = CMTimeAdd(lastTime, clipIndex.duration)
    } catch {
        print("Failed to insert track")
    }
}
print("VideoComposition Tracks: \(videoComposition.tracks.count)") // Shows multiple tracks

playerItem = AVPlayerItem(asset: videoComposition)
print("PlayerItem Duration: \(playerItem.duration.seconds)") // Shows the duration of all tracks together
print("PlayerItem Tracks: \(playerItem.tracks.count)") // Shows same number of tracks as the VideoComposition Track count

videoPlayer = AVPlayer(playerItem: playerItem)
playerLayer.player = videoPlayer
videoPlayer.volume = 0.0
videoPlayer.play()  // Does play all clips sequentially

编辑:我先前提到我仍然在想如何在一个媒体资源中播放多个音轨,但那不是它的工作原理,我现在明白了。一个好的资源:

https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html


2
这不正确,如果您创建一个AVMutableVideoComposition并在该轨道的layerInstruction中将轨道的不透明度设置为0(在轨道结束时),则可以播放多个轨道。 - Tiko
这里上面提到,在可能的情况下,每种媒体类型应只有一个合成轨道。统一兼容的资源轨道可以最大程度地减少资源使用量。当连续呈现媒体数据时,应将相同类型的媒体数据放置在同一合成轨道上。 - Ian Warburton
我通过这样做成功地在AVPlayer中播放了合并的视频,但是在播放时第二个视频的方向不正确,但在导出后方向是正确的。有没有解决方法? - Shivani Bajaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接