I'm new to Swift. I'm trying to combine several mp4 files into a single movie, but my code ends up writing an empty video file.
This is the code I wrote:
import Foundation
import AVFoundation
var folderURL = URL(fileURLWithPath: "/")
var outputMovieURL = URL(fileURLWithPath:"/test.mov")
var mp4URLs = try! FileManager
.default
.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles])
.filter { forMP4(url:$0) }
func forMP4(url: URL) -> Bool {
return url.pathExtension == "mp4"
}
let movie = AVMutableComposition()
let videoTrack = movie.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
for url in mp4URLs {
if #available(macOS 12.0, *) {
do {
let videoAsset = AVAsset(url: url)
let firstVideoTrack = try await videoAsset.loadTracks(withMediaType: .video).first
let range = CMTimeRangeMake(start: CMTime.zero, duration: videoAsset.duration)
try videoTrack?.insertTimeRange(range, of: firstVideoTrack!, at: CMTime.zero)
} catch {
print("Failed to insert video data from URL: \(url)")
print("Error: \(error.localizedDescription)")
}
print(movie.duration)
} else {
// Fallback on earlier versions
}
}
let exporter = AVAssetExportSession(asset: movie,
presetName: AVAssetExportPresetHighestQuality)
exporter?.outputURL = outputMovieURL
exporter?.outputFileType = .mov
//export!
exporter?.exportAsynchronously(completionHandler: { [weak exporter] in
DispatchQueue.main.async {
if let error = exporter?.error {
print("failed \(error.localizedDescription)")
} else {
print("movie has been exported to \(outputMovieURL)")
}
}
})
What is odd is that the duration of it increments as I include videos. This is the output of the code's print(movie.duration)
command.
CMTime(value: 1135671, timescale: 1000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0)
CMTime(value: 1153202, timescale: 1000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0)
CMTime(value: 1801843, timescale: 1000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0)
CMTime(value: 1944314, timescale: 1000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0)