0

I am trimming an existing (stored in the gallery) video into smaller chunks; but I find the resulting video quality to be too degraded:

var chunkNumber = 1
let startTime = CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(600.0))
let theDuration = CMTime(seconds: 10.0, preferredTimescale: CMTimeScale(600.0))

// the AVMutableComposition holds the track instances
let mixCompostion = AVMutableComposition()

// video
let videoTrack = mixCompostion.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
    try videoTrack?.insertTimeRange(CMTimeRangeMake(startTime, theDuration),
            of: (asset?.tracks(withMediaType: AVMediaType.video)[0])!, at: kCMTimeZero)
} catch {
    print ("failed to load the video track")
}

// audio
if ((asset?.tracks(withMediaType: AVMediaType.audio).count)! > 0) {
    let audioTrack = mixCompostion.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: 0)
    do {
        try audioTrack?.insertTimeRange(CMTimeRangeMake(startTime, theDuration),
                of: (asset?.tracks(withMediaType: AVMediaType.audio)[0])!, at: kCMTimeZero)
    } catch {
        print ("failed to load the audio track")
    }
}

// layers
let parentLayer = CALayer()
let videoLayer = CALayer()
let layerFrame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
parentLayer.frame = layerFrame
videoLayer.frame = layerFrame
parentLayer.addSublayer(videoLayer)

// master instruction wraps entire set of instructions
let masterInstruction = AVMutableVideoCompositionInstruction()
masterInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, theDuration)
let videoLayerInstruction = videoCompositionInstructionForTrack(track: videoTrack!, asset: asset!)

// add instructions to master, prepare composition
masterInstruction.layerInstructions = [videoLayerInstruction]
let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [masterInstruction]
mainComposition.frameDuration = CMTimeMake(1, 30)
mainComposition.renderSize = CGSize(width: mainCompositionWidth, height: mainCompositionHeight)
mainComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)

// get path
let date = Date()
let savePath = (documentDirectory as NSString).appendingPathComponent("\(date)-\(chunkNumber).mov")
let url = URL(fileURLWithPath: savePath)
chunkNumber += 1

// create exporter
guard let exporter = AVAssetExportSession(asset: mixCompostion, presetName: AVAssetExportPresetHighestQuality) else { return }
exporter.outputURL = url
exporter.outputFileType = AVFileType.mov
exporter.shouldOptimizeForNetworkUse = true
exporter.videoComposition = mainComposition

// export
exporter.exportAsynchronously(completionHandler: { () -> Void in
    DispatchQueue.global().async {
        self.exportDidFinish(session: exporter)
    }
})

func exportDidFinish(session: AVAssetExportSession) {
    if session.status == AVAssetExportSessionStatus.completed {
        PHPhotoLibrary.shared().performChanges({
            _ = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: session.outputURL!)
        }, completionHandler: { (success, error) in
            let completionString = success ? "Success." : error?.localizedDescription
            print ("Finished updating asset: \(String(describing: completionString))")
        })
    }
    else if session.status == AVAssetExportSessionStatus.failed {
        print ("Export failed -> Reason: \(String(describing: session.error))")
        delegate?.exportFailed()
    }
}

Is there anything different I could be doing, to keep the quality of the video as equal, or at least closer to the original?

coco
  • 2,998
  • 1
  • 35
  • 58

1 Answers1

-1

For better control over video manipulation you could use ffmpeg via one of the wrapper libraries - see these links for example:

I have not used one of the iOS ones, but I have done the same thing on Android and it works well, with the usual caveat that video processing on mobile devices is slow.

Mick
  • 24,231
  • 1
  • 54
  • 120