Monday, October 13, 2014

How to add overlay to Video?



Sometimes you want to add overlay to the captured video for adding copyright label & watermark image.

You can use AVFoundation framework which provides the ability to edit the captured video. Using this framework, we can edit & add the watermark image & text over the captured video. 

You can use this method by passing the image & video url. You should pass the image which you want to add as a overlay  to the captured video. This method will export the new video with watermark image over the video.


- (void) createWatermark:(UIImage*)image video:(NSURL*)videoURL
{
if (videoURL == nil)
return;
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:videoURL options:nil];
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack* compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo  preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack* clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
  ofTrack:clipVideoTrack
atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];
//  create the layer with the watermark image
CALayer* aLayer = [CALayer layer];
aLayer.contents = (id)image.CGImage;
aLayer.frame = CGRectMake(50, 100, image.size.width, image.size.height);
aLayer.opacity = 0.9;
//sorts the layer in proper order
AVAssetTrack* videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGSize videoSize = [videoTrack naturalSize];
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:aLayer];
// create text Layer
CATextLayer* titleLayer = [CATextLayer layer];
titleLayer.backgroundColor = [UIColor clearColor].CGColor;
titleLayer.string = @"Dummy text";
titleLayer.font = CFBridgingRetain(@"Helvetica");
titleLayer.fontSize = 28;
titleLayer.shadowOpacity = 0.5;
titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.frame = CGRectMake(0, 50, videoSize.width, videoSize.height / 6);
[parentLayer addSublayer:titleLayer];
//create the composition and add the instructions to insert the layer:
AVMutableVideoComposition* videoComp = [AVMutableVideoComposition videoComposition];
videoComp.renderSize = videoSize;
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
/// instruction
AVMutableVideoCompositionInstruction* instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
AVAssetTrack* mixVideoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mixVideoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];
// export video
_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
_assetExport.videoComposition = videoComp;
NSLog (@"created exporter. supportedFileTypes: %@", _assetExport.supportedFileTypes);
NSString* videoName = @"NewWatermarkedVideo.mov";
NSString* exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL* exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
 
//Final code
 
switch (_assetExport.status)
{
case AVAssetExportSessionStatusUnknown:
NSLog(@"Unknown");
break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"Waiting");
break;
case AVAssetExportSessionStatusExporting:
NSLog(@"Exporting");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(@"Created new water mark image");
_playButton.hidden = NO;
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"Failed- %@", _assetExport.error);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Cancelled");
break;
}
}
];   
}

You can download the sample app from github.

8 comments:

  1. nice article , suggestion : Add more descriptions with the code

    ReplyDelete
  2. Thanks for the suggestion. I will update the article soon

    ReplyDelete
  3. Is this only work with recorded video or all videos included device gallery??

    ReplyDelete
  4. How can I use AVFoundation or AVAsset to create Subtitles in my video?

    ReplyDelete
  5. Hi,Meenakshi Pathani
    I want to add text for specific duration of video not in whole video. for example suppose video has duration 5:00 then I want to add text to duration from 2:00 to 4:00 . How to achieve this. Can you help me?

    ReplyDelete
  6. Can someone do it for swift please? And can you help me out to apply these overlays to individual or a set of frames.

    ReplyDelete
  7. Can you please help me to set Text layer to particular position.

    ReplyDelete
    Replies
    1. if your want set the text at particular postion just set the frame of titleLayer.

      Delete