3

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
sean
  • 3,484
  • 5
  • 27
  • 45

1 Answers1

11

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

sean
  • 3,484
  • 5
  • 27
  • 45
  • 2
    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. – Tiko Jul 05 '17 at 06:07
  • [Here](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/03_Editing.html#//apple_ref/doc/uid/TP40010188-CH8-SW5), 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._ – Ian Warburton Jun 08 '20 at 20:44
  • 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? – Shivani Bajaj Jul 28 '20 at 08:28