Platforms to show: All Mac Windows Linux Cross-Platform
/AVFoundation/Add text to video
Required plugins for this example: MBS MacBase Plugin, MBS AVFoundation Plugin, MBS MacCG Plugin, MBS MacCF Plugin, MBS Main Plugin
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /AVFoundation/Add text to video
This example is the version from Fri, 26th Jul 2018.
Project "Add text to video.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Delete"
Const kFileQuit = "&Quit"
Const kFileQuitShortcut = ""
End Class
Class Window1 Inherits Window
EventHandler Sub Open()
AVFoundation = new MyAVFoundation
dim VideoFile as FolderItem = SpecialFolder.Desktop.Child("test.mp4")
dim OutputFile as FolderItem = SpecialFolder.Desktop.Child("output.mp4")
// 1. mergeComposition adds all the AVAssets
mergeComposition = new AVMutableCompositionMBS
dim trackVideo as AVMutableCompositionTrackMBS = mergeComposition.addMutableTrackWithMediaType(AVFoundation.AVMediaTypeVideo, 0)
// 2. Add a bank for theme insertion later
//trackVideo.insertTimeRange(range, ofTrack: VideoHelper.Static.blankTrack, atTime: kCMTimeZero, error: nil)
// 3. Source tracks
dim sourceAsset as AVURLAssetMBS = AVURLAssetMBS.URLAssetWithFile(VideoFile)
// wait for duration to become available
dim e as NSErrorMBS
while sourceAsset.statusOfValueForKey("duration", e) = sourceAsset.AVKeyValueStatusLoading
// wait
app.YieldToNextThread
wend
if e <> nil then
MsgBox e.LocalizedDescription
end if
dim sourceDuration as CMTimeRangeMBS = new CMTimeRangeMBS(CMTimeMBS.kCMTimeZero, sourceAsset.duration)
dim videoTracks() as AVAssetTrackMBS = sourceAsset.tracksWithMediaType(AVFoundation.AVMediaTypeVideo)
dim audioTracks() as AVAssetTrackMBS = sourceAsset.tracksWithMediaType(AVFoundation.AVMediaTypeAudio)
dim vtrack as AVAssetTrackMBS = videoTracks(0)
dim atrack as AVAssetTrackMBS = audioTracks(0)
if (vtrack = nil) then
break
return
end if
dim renderWidth as integer = vtrack.naturalSize.width
dim renderHeight as integer = vtrack.naturalSize.height
dim insertTime as CMTimeMBS = CMTimeMBS.kCMTimeZero
dim endTime as CMTimeMBS = sourceAsset.duration
dim range as CMTimeRangeMBS = sourceDuration
// append tracks
call trackVideo.insertTimeRange(sourceDuration, vtrack, insertTime, e)
if e <> nil then
MsgBox e.LocalizedDescription
return
end if
// add video track
dim trackAudio as AVMutableCompositionTrackMBS = mergeComposition.addMutableTrackWithMediaType(AVFoundation.AVMediaTypeAudio, 0)
call trackAudio.insertTimeRange(sourceDuration, atrack, insertTime, e)
if e <> nil then
MsgBox e.LocalizedDescription
return
end if
// 4. Add subtitles (we call it theme)
dim themeVideoComposition as AVMutableVideoCompositionMBS = AVMutableVideoCompositionMBS.mutableVideoCompositionWithPropertiesOfAsset(sourceAsset)
// 4.1 - Create AVMutableVideoCompositionInstruction
dim mainInstruction as new AVMutableVideoCompositionInstructionMBS
mainInstruction.timeRange = range
// 4.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation.
dim videolayerInstruction as AVMutableVideoCompositionLayerInstructionMBS = AVMutableVideoCompositionLayerInstructionMBS.videoCompositionLayerInstructionWithAssetTrack(trackVideo)
videolayerInstruction.setTransform(trackVideo.preferredTransform, insertTime)
'videolayerInstruction.setOpacity(0.0, endTime)
videolayerInstruction.setOpacity(1.0, 1.0, range)
// 4.3 - Add instructions
mainInstruction.setLayerInstructions array(videolayerInstruction)
'themeVideoComposition.renderScale = 1.0
themeVideoComposition.renderSize = new CGSizeMBS(renderWidth, renderHeight)
themeVideoComposition.frameDuration = new CMTimeMBS(1, 30)
themeVideoComposition.setInstructions array(mainInstruction)
// add the theme
// setup variables
// add text
dim r as new CGRectMBS(0, 0, renderWidth, renderHeight)
dim title as string = "Testing this subtitle"
dim titleLayer as new CATextLayerMBS
titleLayer.string = title
titleLayer.frame = r
dim fontName as String = "Helvetica-Bold"
dim fontSize as double = 36
titleLayer.fontSize = fontSize
titleLayer.font = NSFontMBS.fontWithName(fontName, fontSize)
titleLayer.alignmentMode = CATextLayerMBS.kCAAlignmentCenter
titleLayer.foregroundColor = CGColorMBS.White
dim backgroundLayer as new CALayerMBS
backgroundLayer.frame = r
backgroundLayer.masksToBounds = true
// 2. set parent layer and video layer
dim parentLayer as new CALayerMBS
dim videoLayer as new CALayerMBS
parentLayer.frame = r
videoLayer.frame = r
videoLayer.Hidden = false
parentLayer.Hidden = false
parentLayer.addSublayer(backgroundLayer)
parentLayer.addSublayer(videoLayer)
parentLayer.addSublayer(titleLayer)
// 3. make animation
dim tool as AVVideoCompositionCoreAnimationToolMBS = AVVideoCompositionCoreAnimationToolMBS.videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer(videoLayer, parentLayer)
themeVideoComposition.animationTool = tool
// Remove the file if it already exists (merger does not overwrite)
OutputFile.Delete
// export to output url
dim PresetName as string = AVAssetExportSessionMBS.AVAssetExportPresetAppleM4V1080pHD
exporter = new AVAssetExportSessionMBS(mergeComposition, PresetName)
exporter.outputFile = OutputFile
exporter.videoComposition = themeVideoComposition
exporter.outputFileType = AVFoundation.AVFileTypeAppleM4V 'AVFileTypeQuickTimeMovie
exporter.shouldOptimizeForNetworkUse = true
exporter.exportAsynchronously
End EventHandler
Property AVFoundation As MyAVFoundation
Property exporter As AVAssetExportSessionMBS
Property mergeComposition As AVMutableCompositionMBS
End Class
MenuBar MainMenuBar
MenuItem FileMenu = "&File"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem EditSeparator1 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "#App.kEditClear"
MenuItem EditSeparator2 = "-"
MenuItem EditSelectAll = "Select &All"
End MenuBar
Class MyAVFoundation Inherits AVFoundationMBS
EventHandler Sub exportAsynchronouslyCompleted(ExportSession as AVAssetExportSessionMBS, tag as variant)
dim e as NSErrorMBS = ExportSession.error
if e <> nil then
MsgBox e.LocalizedDescription+EndOfLine+e.LocalizedFailureReason+EndOfLine+e.LocalizedRecoverySuggestion
else
MsgBox "export done."
end if
End EventHandler
End Class
End Project
The items on this page are in the following plugins: MBS AVFoundation Plugin.