Platforms to show: All Mac Windows Linux Cross-Platform

/AVFoundation/Merge and Crop Videos


Required plugins for this example: MBS AVFoundation Plugin, MBS MacCG Plugin, MBS MacCF Plugin, MBS Main Plugin, MBS MacBase Plugin

You find this example project in your Plugins Download as a Xojo project file within the examples folder: /AVFoundation/Merge and Crop Videos

This example is the version from Tue, 24th Sep 2018.

Project "Merge and Crop Videos.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Löschen"
Const kFileQuit = "Beenden"
Const kFileQuitShortcut = ""
EventHandler Sub NewDocument() // select work folder dim x as FolderItem = SelectFolder if x <> nil then Work x end if End EventHandler
EventHandler Sub Open() 'Register Plugins f = new MyAVFoudationMBS End EventHandler
Function ParseTime(t as string) As CMTimeMBS if instr(t, ":") > 0 then dim m as string = NthField(t, ":", 1) dim s as string = NthField(t, ":", 2) dim z as Double = val(s) + val(m) * 60 Return CMTimeMBS.MakeWithSeconds(z) end if End Function
Sub Work(Folder as FolderItem) // we read a list.txt in folder with file names and times // Name tab StartTime tab EndTime // we merge all videos by adding the video together // than we crop videos //Create AVMutableComposition Object which will hold our multiple AVMutableCompositionTrack or we can say it will hold our video and audio files. dim f as FolderItem = folder.Child("list.txt") dim tis as TextInputStream = TextInputStream.Open(f) dim error as NSErrorMBS dim tab as string = encodings.UTF8.Chr(9) dim m as AVMutableCompositionMBS = AVMutableCompositionMBS.composition while not tis.EOF dim line as string = tis.ReadLine(encodings.UTF8) dim name as string = NthField(line, tab, 1) dim abZeit as string = NthField(line, tab, 2) dim bisZeit as string = NthField(line, tab, 3) dim file as FolderItem = folder.Child(name) dim asset as AVAssetMBS = AVAssetMBS.assetWithFile(file) log "Add "+file.DisplayName dim len as CMTimeMBS = asset.duration log "Duration "+str(len.Seconds) dim sourceTimeRange as CMTimeRangeMBS = CMTimeRangeMBS.Make(CMTimeMBS.kCMTimeZero, len) if abZeit <> "" then dim t as CMTimeMBS = ParseTime(abZeit) if t <> nil then sourceTimeRange = CMTimeRangeMBS.Make(t, len.Subtract(t)) log "Start at "+str(t.Seconds) end if end if if bisZeit <> "" then dim t as CMTimeMBS = ParseTime(bisZeit) if t <> nil then sourceTimeRange = CMTimeRangeMBS.Make(CMTimeMBS.kCMTimeZero, t) log "End at "+str(t.Seconds) end if end if call m.insertTimeRange(sourceTimeRange, asset, m.duration, error) if error <> nil then dim e as string = error.LocalizedDescription break MsgBox e quit end if wend log "Total duration: "+str(m.duration.Seconds)+" seconds" dim timeRange as CMTimeRangeMBS = CMTimeRangeMBS.Make(CMTimeMBS.kCMTimeZero, m.duration) log "timeRange: "+timeRange.Description // now crop to 1440x600 pixel videoComposition = AVMutableVideoCompositionMBS.mutableVideoComposition videoComposition.frameDuration = CMTimeMBS.Make(1, 30) videoComposition.renderSize = CGMakeSizeMBS(1440, 600) dim Instructions() as AVMutableVideoCompositionInstructionMBS dim mvideotracks() as AVAssetTrackMBS = m.tracksWithMediaType(AVFoundationMBS.AVMediaTypeVideo) log "videotracks count: "+str(mvideotracks.Ubound+1) dim instruction as AVMutableVideoCompositionInstructionMBS = AVMutableVideoCompositionInstructionMBS.videoCompositionInstruction instruction.timeRange = CMTimeRangeMBS.AllTimeRange dim transformers() as AVMutableVideoCompositionLayerInstructionMBS for each videoTrack as AVAssetTrackMBS in mvideotracks dim transformer as AVMutableVideoCompositionLayerInstructionMBS = AVMutableVideoCompositionLayerInstructionMBS.videoCompositionLayerInstructionWithAssetTrack(videoTrack) log "Video track time range: "+videoTrack.timeRange.Description // here we define area of interest dim r as CGRectMBS = CGMakeRectMBS(15, 450, 1440, 600) transformer.setCropRectangle(r, CMTimeMBS.kCMTimeZero) // and use a transform to move pixels into visible area of render size above dim trans as CGAffineTransformMBS = CGAffineTransformMBS.MakeTranslation(-r.Origin.x, -r.Origin.y) transformer.setTransform(trans, CMTimeMBS.kCMTimeZero) transformers.append transformer next instruction.setLayerInstructions transformers Instructions.Append instruction //add the transformer layer instructions, then add to video composition videoComposition.setInstructions instructions // start export e = new AVAssetExportSessionMBS(m, AVAssetExportSessionMBS.AVAssetExportPresetAppleM4VAppleTV) e.timeRange = timeRange e.shouldOptimizeForNetworkUse = true e.videoComposition = videoComposition dim filetypes() as string = e.supportedFileTypes e.outputFileType = FileTypes(0) e.OutputFile = SpecialFolder.Desktop.Child(folder.name+"."+e.outputFileExtension) ProgressWindow.e = e ProgressWindow.show e.exportAsynchronously(nil) End Sub
Property e As AVAssetExportSessionMBS
Property f As MyAVFoudationMBS
Property videoComposition As AVMutableVideoCompositionMBS
End Class
Class ProgressWindow Inherits Window
Control bar Inherits ProgressBar
ControlInstance bar Inherits ProgressBar
End Control
Control Timer1 Inherits Timer
ControlInstance Timer1 Inherits Timer
EventHandler Sub Action() bar.Value = e.progress * bar.Maximum End EventHandler
End Control
EventHandler Function CancelClose(appQuitting as Boolean) As Boolean if e<>Nil then e.cancelExport end if End EventHandler
Property e As AVAssetExportSessionMBS
End Class
MenuBar MenuBar1
MenuItem FileMenu = "&Ablage"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Bearbeiten"
MenuItem EditUndo = "&Rückgängig"
MenuItem UntitledMenu1 = "-"
MenuItem EditCut = "&Ausschneiden"
MenuItem EditCopy = "&Kopieren"
MenuItem EditPaste = "&Einfügen"
MenuItem EditClear = "#App.kEditClear"
MenuItem UntitledMenu0 = "-"
MenuItem EditSelectAll = "&Alles auswählen"
End MenuBar
Class MyAVFoudationMBS Inherits AVFoundationMBS
EventHandler Sub exportAsynchronouslyCompleted(ExportSession as AVAssetExportSessionMBS, tag as variant) ProgressWindow.close Select case ExportSession.status case ExportSession.AVAssetExportSessionStatusUnknown break case ExportSession.AVAssetExportSessionStatusWaiting break // should never happen case ExportSession.AVAssetExportSessionStatusExporting break // should never happen case ExportSession.AVAssetExportSessionStatusCompleted MsgBox "Export done." case ExportSession.AVAssetExportSessionStatusFailed MsgBox "Export failed." case ExportSession.AVAssetExportSessionStatusCancelled MsgBox "Export cancelled." end Select if ExportSession.error <>Nil then MsgBox "Error: "+ExportSession.error.localizedDescription end if quit End EventHandler
End Class
Class LogWindow Inherits Window
Control List Inherits Listbox
ControlInstance List Inherits Listbox
End Control
End Class
Module Module1
Sub Log(s as string) LogWindow.List.AddRow s End Sub
End Module
End Project

See also:

The items on this page are in the following plugins: MBS AVFoundation Plugin.


The biggest plugin in space...