AVMutableComposition - Only Playing First Track (Swift)
Asked Answered
S

1

4

I have an array of [AVAsset], and I am trying to combine all of those Assets into a single Asset so that I can play back the video seamlessly (I tried using an AVQueuePlayer, but that does not play back the assets seamlessly).

Below is what I have so far, but when I try to play the final composition, it only plays the first track, even though it shows that it has all tracks and the total duration equals all of the tracks together.

Am I missing a step, even though it appears that all the tracks are in the composition? Perhaps I need to handle the AVPlayer differently if the AVPlayerItem has multiple tracks?

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
Sphygmomanometer answered 16/5, 2016 at 13:31 Comment(0)
S
12

I was able to figure out an answer the most important question. In order to play all of the clips together, they need to be in the same track. To do this, move the following line outside (before) the for loop:

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

Here is the full, corrected code:

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

EDIT: I mentioned earlier that I was still wondering how to play multiple tracks in one asset. That's not how it works, I understand now. A good resource:

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

Sphygmomanometer answered 17/5, 2016 at 1:57 Comment(3)
Thats not correct, You can play multiple tracks if You create a AVMutableVideoComposition, and set opacity of track to 0 (on track end) in layerInstruction of that track.Rhaetian
Here, it says, Where possible, you should have only one composition track for each media type. This unification of compatible asset tracks leads to a minimal amount of resource usage. When presenting media data serially, you should place any media data of the same type on the same composition track.Grower
I was able to play my merged video in AVPlayer by doing this, but I am getting wrong orientation for 2nd video while playing, but am getting the correct orientation after exporting. Any solution for the same?Unprejudiced

© 2022 - 2024 — McMap. All rights reserved.