I am already including a CATextLayer in an existing video on an iPhone and save it into another mp4 file (as suggested here: How can I add a watermark in a captured video on iOS).
AVAsset videoAsset = AVAsset.FromUrl(NSUrl.CreateFileUrl(urlpath, false, null));
AVMutableComposition mixComposition = AVMutableComposition.Create();
AVMutableCompositionTrack compositionVideoTrack = mixComposition.AddMutableTrack(AVMediaType.Video, 0);
AVAssetTrack clipVideoTrack = videoAsset.TracksWithMediaType(AVMediaType.Video).First();
CMTimeRange timeRange = new CMTimeRange(){
Start = CMTime.Zero,
Duration = videoAsset.Duration
};
NSError error;
compositionVideoTrack.InsertTimeRange(timeRange, clipVideoTrack, CMTime.Zero, out error);
compositionVideoTrack.PreferredTransform = videoAsset.TracksWithMediaType(AVMediaType.Video).First().PreferredTransform;
// Create overlay layer
CGSize naturalSize = videoAsset.NaturalSize;
CATextLayer overLayer = new CATextLayer(){
Frame = new CGRect(new CGPoint(0, 0), naturalSize),
String = "text layer on my video",
ForegroundColor = UIColor.White.CGColor
};
// Sort the layers
CALayer parentLayer = new CALayer() {
Frame = new CGRect(new CGPoint(0, 0), naturalSize)
};
CALayer videoLayer = new CALayer(){
Frame = new CGRect(new CGPoint(0,0), naturalSize)
};
parentLayer.AddSublayer(videoLayer);
parentLayer.AddSublayer(overLayer);
// Create composition
AVMutableVideoComposition videoComposition = AVMutableVideoComposition.Create();
videoComposition.RenderSize = naturalSize;
videoComposition.FrameDuration = new CMTime(1, 30);
videoComposition.AnimationTool = AVVideoCompositionCoreAnimationTool.FromLayer(videoLayer, parentLayer);
// Instruction
AVMutableVideoCompositionInstruction instruction = new AVMutableVideoCompositionInstruction();
CMTimeRange timeRangeMixComposition = new CMTimeRange(){
Start = CMTime.Zero,
Duration = mixComposition.Duration
};
instruction.TimeRange = timeRangeMixComposition;
AVAssetTrack videoTrack = mixComposition.TracksWithMediaType(AVMediaType.Video).First();
AVMutableVideoCompositionLayerInstruction layerInstruction = AVMutableVideoCompositionLayerInstruction.FromAssetTrack(videoTrack);
instruction.LayerInstructions = new AVVideoCompositionLayerInstruction[] {layerInstruction};
videoComposition.Instructions = new AVVideoCompositionInstruction[] {instruction};
// Export
AVAssetExportSession exporterSession = new AVAssetExportSession(mixComposition, AVAssetExportSession.PresetHighestQuality){
OutputUrl = m_outputUrl,
OutputFileType = AVFileType.QuickTimeMovie,
ShouldOptimizeForNetworkUse = true,
VideoComposition = videoComposition
};
exporterSession.ExportAsynchronously((() => {
if (exporterSession.Status == AVAssetExportSessionStatus.Completed){
NSUrl outputUrl = exporterSession.OutputUrl;
ALAssetsLibrary library = new ALAssetsLibrary();
if (library.VideoAtPathIsIsCompatibleWithSavedPhotosAlbum(outputUrl)){
library.WriteVideoToSavedPhotosAlbumAsync(outputUrl);
}
})
);
}
This creates another video file with my text visible on the video for its entire duration. However, I need to change the String property of the overLayer several times per second.
overLayer.String
should show the current playback time.
I looked into several different options but could not achieve to change the text in the middle of the video:
- I tried adding different instructions but did not find a way to connect the instruction directly with my layer (it is linked to the whole composition)
I looked into CATransaction: this allowed me to change the String property but it simply overwrote the initial value
CATransaction.Begin(); CATransaction.AnimationDuration = 2; overLayer.String = "Changed string on my video"; CATransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear); CATransaction.Commit();
I tried to register my custom Selector directly to overLayer but could not get that running either.
I would appreciate any help, Objective-C or Swift solutions would help as well.
EDIT: The code above is in C# - Xamarin.iOS