Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@budidino
Forked from acj/TrimVideo.swift
Created April 28, 2017 04:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save budidino/ffefdbd1a8a33607c54d495b6120850e to your computer and use it in GitHub Desktop.
Save budidino/ffefdbd1a8a33607c54d495b6120850e to your computer and use it in GitHub Desktop.
Trim video using AVFoundation in Swift
//
// TrimVideo.swift
// VideoLab
//
// Created by Adam Jensen on 3/28/15.
// Copyright (c) 2015 Adam Jensen. All rights reserved.
//
import AVFoundation
import Foundation
typealias TrimCompletion = (NSError?) -> ()
typealias TrimPoints = [(CMTime, CMTime)]
func verifyPresetForAsset(preset: String, asset: AVAsset) -> Bool {
let compatiblePresets = AVAssetExportSession.exportPresetsCompatibleWithAsset(asset) as! [String]
let filteredPresets = compatiblePresets.filter { $0 == preset }
return filteredPresets.count > 0 || preset == AVAssetExportPresetPassthrough
}
func removeFileAtURLIfExists(url: NSURL) {
if let filePath = url.path {
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(filePath) {
var error: NSError?
if !fileManager.removeItemAtPath(filePath, error: &error) {
NSLog("Couldn't remove existing destination file: \(error)")
}
}
}
}
func trimVideo(sourceURL: NSURL, destinationURL: NSURL, trimPoints: TrimPoints, completion: TrimCompletion?) {
assert(sourceURL.fileURL)
assert(destinationURL.fileURL)
let options = [ AVURLAssetPreferPreciseDurationAndTimingKey: true ]
let asset = AVURLAsset(URL: sourceURL, options: options)
let preferredPreset = AVAssetExportPresetPassthrough
if verifyPresetForAsset(preferredPreset, asset) {
let composition = AVMutableComposition()
let videoCompTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
let audioCompTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
let assetVideoTrack: AVAssetTrack = asset.tracksWithMediaType(AVMediaTypeVideo).first as! AVAssetTrack
let assetAudioTrack: AVAssetTrack = asset.tracksWithMediaType(AVMediaTypeAudio).first as! AVAssetTrack
var compError: NSError?
var accumulatedTime = kCMTimeZero
for (startTimeForCurrentSlice, endTimeForCurrentSlice) in trimPoints {
let durationOfCurrentSlice = CMTimeSubtract(endTimeForCurrentSlice, startTimeForCurrentSlice)
let timeRangeForCurrentSlice = CMTimeRangeMake(startTimeForCurrentSlice, durationOfCurrentSlice)
videoCompTrack.insertTimeRange(timeRangeForCurrentSlice, ofTrack: assetVideoTrack, atTime: accumulatedTime, error: &compError)
audioCompTrack.insertTimeRange(timeRangeForCurrentSlice, ofTrack: assetAudioTrack, atTime: accumulatedTime, error: &compError)
if compError != nil {
NSLog("error during composition: \(compError)")
if let completion = completion {
completion(compError)
}
}
accumulatedTime = CMTimeAdd(accumulatedTime, durationOfCurrentSlice)
}
let exportSession = AVAssetExportSession(asset: composition, presetName: preferredPreset)
exportSession.outputURL = destinationURL
exportSession.outputFileType = AVFileTypeAppleM4V
exportSession.shouldOptimizeForNetworkUse = true
removeFileAtURLIfExists(destinationURL)
exportSession.exportAsynchronouslyWithCompletionHandler({ () -> Void in
if let completion = completion {
completion(exportSession.error)
}
})
} else {
NSLog("Could not find a suitable export preset for the input video")
let error = NSError(domain: "org.linuxguy.VideoLab", code: -1, userInfo: nil)
if let completion = completion {
completion(error)
}
}
}
let sourceURL = NSURL(fileURLWithPath: "/Users/acj/scratch/TestVideo.mp4")
let destinationURL = NSURL(fileURLWithPath: "/Users/acj/scratch/TrimmedVideo.mp4")
let sem = dispatch_semaphore_create(0)
if let sourceURL = sourceURL, destinationURL = destinationURL {
let timeScale: Int32 = 1000
let trimPoints = [(CMTimeMake(2000, timeScale), CMTimeMake(5000, timeScale)),
(CMTimeMake(20500, timeScale), CMTimeMake(23000, timeScale)),
(CMTimeMake(60000, timeScale), CMTimeMake(65000, timeScale))]
trimVideo(sourceURL, destinationURL, trimPoints) { error in
if let error = error {
NSLog("Failure: \(error)")
} else {
NSLog("Success")
}
dispatch_semaphore_signal(sem)
}
} else {
NSLog("error: Please check the source and destination paths.")
}
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment