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.

Thursday, October 9, 2014

Document Directory path in iOS 8




Problem-

You may have noticed that iOS8 simulator is not visible when you go to the given path-

 Users/Library/Application Support/iPhone Simulator/ 





Solution-

Now in XCode6, data directories are per-devices rather than per-version.

To find the document directory for Xcode6 & iOS8 is not as easy as it was earlier. You have to play guessing game twice. Once for finding the appropriate device. Once you find the device you have to search the application. 

You can find the document directory in the given path.

Library/Developer/CoreSimulator/Devices/cryptic number/data/Containers/Data/Application/cryptic number

Steps to Find Document Directory-

1) Follow the given path.

Users/Library/Developer/CoreSimulator/Devices/ 

2) Now, Device folder will have some cryptic number folders. Each folder will have Data folder & device.plist. Check the devicePlist to know about the deviceType.






3) Once you find your device, you have to follow the given path to find the application & document directory.
Data/Containers/Data/Application/cryptic number


4) Now this cryptic number folder will have 3 folders- Documents ( Document directory), Library & temp.




Note- As finding the document directory path become tedious. So, if you are testing the application then you can check the document directory path programaticaly.
NSLog(@"Documents Directory: %@", [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]);




Wednesday, October 8, 2014

How to update location in iOS 8?

Problem- 

In iOS 8 you will face the issue that location manager delegates unable to get callback when the location is updating if you are using the given code snippet for getting location updates.

  _locationManager = [[CLLocationManager alloc] init];
  
  _locationManager.delegate = self;
  _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
  
  [_locationManager startUpdatingLocation]; 


Solution-

In iOS 8 you have to call requestWhenInUseAuthorization or requestAlwaysAuthorization method before calling startUpdatingLocation methods.

  _locationManager = [[CLLocationManager alloc] init];
  
  _locationManager.delegate = self;
  _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
  
  if(IS_OS_8_OR_LATER)
   [_locationManager requestWhenInUseAuthorization];
  
  [_locationManager startUpdatingLocation]; 

Also, you have to add NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key in the plist.

If you did’t specify the key into the plist then requestAlwaysAuthorization method will do nothing, as your app should be assumed not to support Always authorization. 

If you always wants to use the locations update even when the app is in background then you have to call requestAlwaysAuthorization & specify NSLocationAlwaysUsageDescription key in the plist. 

In other cases where you don’t want to call location method update always, you can use requestWhenInUseAuthorization & specify NSLocationWhenInUseUsageDescription key in the plist.


Thursday, September 25, 2014

CocoaPods

Cocoapods is the dependency manager tool to manage library dependencies in Objective C projects. It will fetch library source code, resolve dependencies between libraries and create, maintain the right environment to build the project with minimum hassle.

CocoaPods can download code from Github & copy it to your project. You don't need to do this manually.

Basically, CocoaPods is built with Ruby and installable with default Ruby in OSX.

Following are the steps to install cocoapods-

1) Update the RubyGems
$ sudo gem update --system

2) Write this command in terminal to install the gem-
$ sudo gem install cocoapods


Note- During this process RubyGems might ask you if you want to overwrite the rake executable. This warning is raised because the rake gem will be updated as part of this process. Simply confirm by typing y.

3) Setup the cocoapods
$ pod setup

Installing the dependency-

1) Create the empty project & open it in terminal or open the existing project in terminal.

$ cd <pojectpath>

2) Create pod file. This pod file will include all the dependencies for the project.
$ pod init

3) Now,open the pod file & add the library with version number for installation.

target "ProjectName" do

pod 'AFNetworking', '2.2.1' // add this line to pod file to download AFNetworking source code

end


4) Install the pod file. This command will install the dependency for the project & create the workspace. Now you have to use this workspace instead of project file.
$ pod install

Note- If you want to delete the workspace you can use the given command to delete the workspace from the project.
$ rm -rf <workspaceName>