GPS routing (Shortest path) in iPhone using Mapkit and Google map - objective-c

I am developing on Xcode 4.3.3, iOS 5 and using Mapkit library.
The app should show current location on Google map, get the destination address and finally draw the shortest path between those two points.
I used this tutorial for implementing the app and I have current location now:
http://blog.objectgraph.com/index.php/2009/04/02/iphone-sdk-30-playing-with-map-kit/
I looked for routing but I haven't found any resource.
Please guide me how I can draw the shortest path between the current location and the destination.
Thanks!

You can try this will only work for ios 6.
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newLocation = [[CLLocation alloc]initWithLatitude:getLatitude
longitude:getLongitude];
[geocoder reverseGeocodeLocation:newLocation
completionHandler:^(NSArray *placemarks, NSError *error) {
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithPlacemark:[placemarks objectAtIndex:0]];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:placeMark];
MKMapItem *mapItem2 = [MKMapItem mapItemForCurrentLocation];
NSArray *mapItems = #[mapItem, mapItem2];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeStandard],
MKLaunchOptionsShowsTrafficKey:#YES
};
[MKMapItem openMapsWithItems:mapItems launchOptions:options];
} ];
}
else
{
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to Get Your Location"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
}

Did you google for map kit and route?
You'd find this: http://inlight.com.au/posts/mapkit which explains how to use Google Maps and decode the response to extract points to get a route.
There's also a commercial kit: http://mtdirectionsk.it/

iOS MapKit does not provide routing information for Apps as a service. Instead, your choices now are either to get routing information from a third-party mechanism, or to build the routes yourself (which, if you don't have the underlying street data is basically impossible).
You might look at CloudMade as an alternative map system if you need to provide routing information in your own App, or consider just calling Maps to route to a location if you want to take advantage of Apple's Map for navigation.
If you want to call out to the Map App for navigation, you basically need to open a URL with the source and destination location. Here's an example:
CLLocationManager *manager = [[[CLLocationManager alloc] init] autorelease];
CLLocationCoordinate2D currentLocation = [manager location].coordinate;
NSString *from = [NSString stringWithFormat: #"%f,%f",
currentLocation.latitude, currentLocation.longitude];
// used to be able to (3.2 iPad) "Current+Location", now we have to send: lat,long
NSString *encodedAddress = [address stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *url = [NSString stringWithFormat:
#"http://maps.google.com/maps?saddr=%#&daddr=%#", from, encodedAddress];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];

Below ans work for all ios:
NSString *deviceVersion = [[UIDevice currentDevice] systemVersion];
NSLog(#"My Device version is :%# ",deviceVersion);
//********* For ios 6 supporting devices *********
if ([deviceVersion isEqualToString:#"6.0"])
{
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newLocation = [[CLLocation alloc]initWithLatitude:getLatitude
longitude:getLongitude];
[geocoder reverseGeocodeLocation:newLocation
completionHandler:^(NSArray *placemarks, NSError *error) {
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithPlacemark:[placemarks objectAtIndex:0]];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:placeMark];
MKMapItem *mapItem2 = [MKMapItem mapItemForCurrentLocation];
NSArray *mapItems = #[mapItem, mapItem2];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeStandard],
MKLaunchOptionsShowsTrafficKey:#YES
};
[MKMapItem openMapsWithItems:mapItems launchOptions:options];
} ];
}
else
{
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to Get Your Location"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
}
//********* For other ios supporting devices *********
else {
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = getLatitude;
region.center.longitude = getLongitude;
MKCoordinateRegion currentRegion = { {0.0, 0.0 }, { 0.0, 0.0 } };
currentRegion.center.latitude = currentLatitude;
currentRegion.center.longitude = currentLongitude;
region.span.longitudeDelta = 4.0f;
region.span.latitudeDelta = 4.0f;
currentRegion.span.longitudeDelta = 4.0f;
currentRegion.span.latitudeDelta = 4.0f;
CLLocationCoordinate2D start = { currentRegion.center.latitude, currentRegion.center.longitude };
CLLocationCoordinate2D destination = { region.center.latitude, region.center.longitude };
NSString *googleMapsURLString = [NSString stringWithFormat:#"http://maps.google.com/?saddr=%1.6f,%1.6f&daddr=%1.6f,%1.6f",start.latitude, start.longitude, destination.latitude, destination.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:googleMapsURLString]];
}
}

Related

Why I am not able to get Latitude and longitude on real device in Objective C

I am new in iOS and I am facing problem to get current Latitude and Longitude on the real device where as I am able to get latitude and Longitude on simulator.
My code is like this
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//Configure Accuracy depending on your needs, default is kCLLocationAccuracyBest
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
// Set a movement threshold for new events.
locationManager.distanceFilter = kCLDistanceFilterNone; // meters
[locationManager startUpdatingLocation];
Currentlatitude = locationManager.location.coordinate.latitude;
Currentlongitude = locationManager.location.coordinate.longitude;
NSLog(#"Latitude =%f",Currentlatitude);
NSLog(#"Longitude =%f",Currentlongitude);
CheckString=#"2";
// Your location from latitude and longitude
CLLocation *location = [[CLLocation alloc] initWithLatitude:Currentlatitude longitude:Currentlongitude];
// Call the method to find the address
[self getAddressFromLocation:location completionHandler:^(NSMutableDictionary *d) {
NSLog(#"address informations : %#", d);
// NSLog(#"formatted address : %#", [placemark.addressDictionary valueForKey:#"FormattedAddressLines"]);
NSLog(#"Street : %#", [d valueForKey:#"Street"]);
NSLog(#"ZIP code : %#", [d valueForKey:#"ZIP"]);
NSLog(#"City : %#", [d valueForKey:#"City"]);
CityNameCurrent=[d valueForKey:#"City"];
// etc.
} failureHandler:^(NSError *error) {
NSLog(#"Error : %#", error);
}];
- (void)getAddressFromLocation:(CLLocation *)location completionHandler:(void (^)(NSMutableDictionary *placemark))completionHandler failureHandler:(void (^)(NSError *error))failureHandler
{
NSMutableDictionary *d = [NSMutableDictionary new];
CLGeocoder *geocoder = [CLGeocoder new];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
if (failureHandler && (error || placemarks.count == 0)) {
failureHandler(error);
} else {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
if(completionHandler) {
completionHandler(placemark.addressDictionary);
}
}
}];
}
In ViewDidLod()
mapViewMap.delegate=self;
mapViewMap.myLocationEnabled=YES;
locationtbl.hidden=YES;
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//Configure Accuracy depending on your needs, default is kCLLocationAccuracyBest
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
// Set a movement threshold for new events.
locationManager.distanceFilter = kCLDistanceFilterNone; // meters
[locationManager startUpdatingLocation];
Currentlatitude = locationManager.location.coordinate.latitude;
Currentlongitude = locationManager.location.coordinate.longitude;
NSLog(#"Latitude =%f",Currentlatitude);
NSLog(#"Longitude =%f",Currentlongitude);
mapViewMap.settings.myLocationButton = YES;
mapViewMap.settings.scrollGestures = YES;
mapViewMap.settings.zoomGestures = YES;
mapViewMap.settings.tiltGestures=YES;
mapViewMap.settings.rotateGestures=NO;
mapViewMap.settings.compassButton = YES;
I am not getting what I am doing wrong.Please help.Thanks in Advance!
The simulator doesn't have to wait for a fix before generating a location. The device does. You have to implement a delegate for the location manager and wait for the delegate to be called with an update.
You need to implement CLLocationManager delegate method didUpdateLocations, it is where you get location updates.
You can do it like this.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
// latest location
self.currentLocation = [locations lastObject];
float longitude = self.currentLocation.coordinate.longitude;
float latitude = self.currentLocation.coordinate.latitude;
// Here you can perform operations with your location coordinates
}
You also need to add following entries in your .plist file based on your location need.
NSLocationWhenInUseUsageDescription
or
NSLocationAlwaysUsageDescription
And request the permission for location usage by calling
[locationManager requestWhenInUseAuthorization];
or
[locationManager requestAlwaysAuthorization]
Documentation link Location and Maps Programming Guide
You also need to add one (or both) of the following keys to you plist:
NSLocationWhenInUseUsageDescription
or
NSLocationAlwaysUsageDescription
and call correspondingly either
[self.locationManager requestWhenInUseAuthorization]
or
[self.locationManager requestAlwaysAuthorization]

Objective-C - Search for streets based on user-entered query

I want to allow the users to search for a street name and have the results displayed in a UITableView.
For the moment the region is not important, it can be from any region.
I could not find any relevant example in my searches and I don't know if I should use CLLocation or MKLocalSearch.
Based on docs, I should use MKLocalSearch:
Although local search and geocoding are similar, they support
different use cases. Use geocoding when you want to convert between
map coordinates and a structured address, such as an Address Book
address. Use local search when you want to find a set of locations
that match the user’s input.
But I have tried both methods and it gives me only 1 result (even-though there is an NSArray returned.
This is the CLGeocoder approach:
CLGeocoder *geocoding = [[CLGeocoder alloc] init];
[geocoding geocodeAddressString:theTextField.text completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSLog(#"%i", [placemarks count]);
for(CLPlacemark *myStr in placemarks) {
NSLog(#"%#", myStr);
}
}
}];
And this is my MKLocalSearch try:
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = theTextField.text;
request.region = self.region;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
if (error != nil) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Map Error",nil)
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
if ([response.mapItems count] == 0) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"No Results",nil)
message:nil
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
self.streets = response;
[self.streetsTableView reloadData];
}];
MKLocalSearch seems to return more than 1 response in some cases, but these are related to places not street names searches.
Thanks in advance.
This is the closest I could get. This involves using google places API Web Service.
Note: You could probably use their Google Maps API, etc. I am sure there are other ways to get this information from the various Google APIs.
NSURL *googlePlacesURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&location=%f,%f&sensor=true&key=API_KEY", formattedSearchText, location.coordinate.latitude,
location.coordinate.longitude]];
The response is a JSON object. Convert it to a dictionary.
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:_googlePlacesResponse
options:NSJSONReadingMutableContainers error:&error];
if([[response objectForKey:#"status"] isEqualToString:#"OK"])
{
NSArray *predictions = [response objectForKey:#"predictions"];
for(NSDictionary *prediction in predictions)
{
NSArray *addressTypes = [prediction objectForKey:#"types"];
if([addressTypes containsObject:#"route"])
{
//This search result contains a street name.
//Now get the street name.
NSArray *terms = [prediction objectForKey:#"terms"];
NSDictionary *streetNameKeyValuePair = [terms objectAtIndex:0];
NSLog(#"%#",[streetNameKeyValuePair objectForKey#"value"]);
}
}
}
The possible types seem to be
Route -> Street name
Locality -> City/location name
Political -> State, etc
Geocode -> lat/long available
You could populate the table view with those predictions that ONLY contain route as an address type. This could work.
CLGeocoder simply returns address format.
Slap this in your code and play with the contents of mapitems
MKLocalSearchRequest *request = [MKLocalSearchRequest new];
request.naturalLanguageQuery = #"Pizza";
request.region = MKCoordinateRegionMake(location.coordinate, MKCoordinateSpanMake(.01, .01));
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
NSArray *mapItems = response.mapItems;
for (MKMapItem *mapItem in mapItems) {
MKPointAnnotation *point = [MKPointAnnotation new];
point.coordinate = mapItem.placemark.coordinate;`
}
}];
The array returned contains mapItems, you can iterate over the array to pull out all the mapItems like this:
myMatchingItems = [[NSMutableArray alloc] init];
for (MKMapItem *item in response.mapItems){
[myMatchingItems addObject:item];
}
Each mapItem.placemark.thoroughfare contains the Street of the location that was found.

Change starting location when opening Apple Maps from within app

By default when opening Apple Maps through a MKMapItem it uses the device's location as the starting point but i'm trying to allow a user to add their own starting point by entering in the proper fields (address, city, state, zipcode) and passing the address string to
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
NSString *addressString = [NSString stringWithFormat:#"%# %# %# %#",
self.address.text,
self.city.text,
self.state.text,
self.zip.text];
[geocoder geocodeAddressString:addressString
completionHandler:^(NSArray *placemarks, NSError *error)
{
CLLocationCoordinate2D addressCoordinates;
if (error.code == 2)
{
UIAlertView *networkConnectionAlert = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"The internet connections appears to be offline. Ensure that data is enabled or that your device is connected to a wireless connection." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[networkConnectionAlert show];
NSLog(#"Geocode failed with error: %#", error);
return;
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
// Location of address passed in
CLLocation *location = placemark.location;
// Coordinates of address passed in
addressCoordinates = location.coordinate;
}
// Destination address dictionary values
NSDictionary *address = #{
(NSString *)kABPersonAddressStreetKey: self.address.text,
(NSString *)kABPersonAddressCityKey: self.city.text,
(NSString *)kABPersonAddressStateKey: self.state.text,
(NSString *)kABPersonAddressZIPKey: self.zip.text
};
MKPlacemark *place = [[MKPlacemark alloc] initWithCoordinate:addressCoordinates
addressDictionary:address];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:place];
NSDictionary *options = #{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};
[mapItem openInMapsWithLaunchOptions:options];
}];
Of course every time I run the app it uses the device's location as the starting point and the destination point as the address entered which is understandable given the code above but is there not a property that can be called to change the starting point? I know that you can change the starting address/location when you open the actual Apple Maps so I assume that there has to be a way and that I'm just doing something wrong or missing something. Any help on this would be greatly appreciated, thanks.

kindly advice me to display x number of annotation points in mkmap

Good morning, I am very new to objective-c now I am developing my first app. It's a vehicle tracking app. I received the x-number of lat & long from the json service. Now I displayed a single annotation but I need to display all the annotation points which i received from the service here I search for a whole day to find this but am fails to find displaying x-num of annotations. So kindly advice me by using some sample codes. Thanks in Advance... My code is..
- (void)viewDidLoad
{
[super viewDidLoad];
//MAP VIEW WebService
NSString *urlMapString=[NSString stringWithFormat:#"http://www.logix.com/logix_webservice/map.php?format=json&truckno=%#",nam2];
NSURL *urlMap=[NSURL URLWithString:urlMapString];
NSData *dataMap=[NSData dataWithContentsOfURL:urlMap];
NSError *errorMap;
NSDictionary *jsonMap = [NSJSONSerialization JSONObjectWithData:dataMap options:kNilOptions error:&errorMap]; NSArray *resultsMap = [jsonMap valueForKey:#"posts"];
NSArray *resMap = [resultsMap valueForKey:#"post"];
NSArray *latitudeString=[resMap valueForKey:#"latitude"];
if([resMap count]){
NSString *latOrgstring = [latitudeString objectAtIndex:0];
double latitude=[latOrgstring doubleValue];
NSArray *longitudeString=[resMap valueForKey:#"longitude"];
NSString *longOrgstring = [longitudeString objectAtIndex:0];
double longitude=[longOrgstring doubleValue];
NSString *ignation=[[resMap valueForKey:#"ignition"]objectAtIndex:0];
i=[ignation intValue];
//MAP VIEW Point
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
//Span
MKCoordinateSpan span;
span.latitudeDelta=0.01f;
span.longitudeDelta=0.01f;
myRegion.center=center;
myRegion.span=span;
//Set our mapView
[MapViewC setRegion:myRegion animated:YES];
//Annotation
//1.create coordinate for use with the annotation
CLLocationCoordinate2D wimbLocation;
wimbLocation.latitude=latitude;
wimbLocation.longitude=longitude;
Annotation * myAnnotation= [Annotation alloc];
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
addressOutlet=[dictionary valueForKey:#"Street"];
City=[dictionary valueForKey:#"City"];
State=[dictionary valueForKey:#"State"];
myAnnotation.coordinate=wimbLocation;
if (addressOutlet!=NULL&&City!=NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
}
else if (addressOutlet==NULL&&City!=NULL)
{
myAnnotation.title=City;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
}
else if (addressOutlet!=NULL&&City==NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#", State];
}
else if(addressOutlet==NULL&&City==NULL)
{
myAnnotation.title=State;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#",State];
}
[self.MapViewC addAnnotation:myAnnotation];
}];
}
}
Please make an individual class and use by importing .
Now use
-(id)initWithCoordinate:(CLLocationCoordinate2D)c;
and its .m file
-(id)initWithCoordinate:(CLLocationCoordinate2D)c
{
coordinate=c;
}
Now call this class anywhere and call this method and send your location coordinates.
and then add its objects into NSArray.
Now call [YourMapView addAnnotations:arrayOfAnnotations];
You will get it what you want.It works in my case I hope you will find it supportive.
Now add annotations on mapView:
-(MKAnnotationView *) mapView:(MKMapView *)mapV
viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[pinAnnotation class]])
{
static NSString *defaultPinID = #"com.ABC.pin";//Your unique identifier anything
MKAnnotationView *pinView = nil;
if(!pinView)
{
pinView = (MKAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
pinView = [[MKAnnotationView alloc] initWithAnnotation:
annotation reuseIdentifier:defaultPinID] ;
return pinView;
}
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView* pin =
(MKAnnotationView*) [mapV dequeueReusableAnnotationViewWithIdentifier:
AnnotationViewID];
if ( pin == nil ) {
pin = [(MKAnnotationView*) [MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier: AnnotationViewID] ;
pin.canShowCallout = YES;
}
else
{
[pin setAnnotation: annotation];
}
((MKUserLocation *)annotation).title = #"You are here";
return pin;
}

When button click switch camera front and back in iOS [duplicate]

I am developing an iPhone App. In that, there is a requirement for Pausing and resuming the camera. So i used AVFoundation for that instead of using UIImagePickerController.
My code is :
- (void) startup :(BOOL)isFrontCamera
{
if (_session == nil)
{
NSLog(#"Starting up server");
self.isCapturing = NO;
self.isPaused = NO;
_currentFile = 0;
_discont = NO;
// create capture device with video input
_session = [[AVCaptureSession alloc] init];
AVCaptureDevice *cameraDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if(isFrontCamera)
{
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *captureDevice = nil;
for (AVCaptureDevice *device in videoDevices)
{
if (device.position == AVCaptureDevicePositionFront)
{
captureDevice = device;
break;
}
}
cameraDevice = captureDevice;
}
cameraDevice=[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:cameraDevice error:nil];
[_session addInput:input];
// audio input from default mic
AVCaptureDevice* mic = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput* micinput = [AVCaptureDeviceInput deviceInputWithDevice:mic error:nil];
[_session addInput:micinput];
// create an output for YUV output with self as delegate
_captureQueue = dispatch_queue_create("uk.co.gdcl.cameraengine.capture", DISPATCH_QUEUE_SERIAL);
AVCaptureVideoDataOutput* videoout = [[AVCaptureVideoDataOutput alloc] init];
[videoout setSampleBufferDelegate:self queue:_captureQueue];
NSDictionary* setcapSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange], kCVPixelBufferPixelFormatTypeKey,
nil];
videoout.videoSettings = setcapSettings;
[_session addOutput:videoout];
_videoConnection = [videoout connectionWithMediaType:AVMediaTypeVideo];
[_videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
NSDictionary* actual = videoout.videoSettings;
_cy = [[actual objectForKey:#"Width"] integerValue];
_cx = [[actual objectForKey:#"Height"] integerValue];
AVCaptureAudioDataOutput* audioout = [[AVCaptureAudioDataOutput alloc] init];
[audioout setSampleBufferDelegate:self queue:_captureQueue];
[_session addOutput:audioout];
_audioConnection = [audioout connectionWithMediaType:AVMediaTypeAudio];
[_session startRunning];
_preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
}
}
Here i am facing the problem when i change the camera to Front. when i calling the above method by changing the camera to front, the preview layer is getting stuck and no preview is coming. My doubt is "Can we change the capture device in the middle of capture session ?". Please guide me where i am going wrong (or) Suggest me with a solution on how to navigate between front and back camera while recording.
Thanks in Advance.
Yes, you can. There are just a few of things you need to cater to.
Need to be using AVCaptureVideoDataOutput and its delegate for recording.
Make sure you remove the previous deviceInput before adding the new deviceInput.
You must remove and recreate the AVCaptureVideoDataOutput as well.
I am using these two functions for it right now and it works while the session is running.
- (void)configureVideoWithDevice:(AVCaptureDevice *)camera {
[_session beginConfiguration];
[_session removeInput:_videoInputDevice];
_videoInputDevice = nil;
_videoInputDevice = [AVCaptureDeviceInput deviceInputWithDevice:camera error:nil];
if ([_session canAddInput:_videoInputDevice]) {
[_session addInput:_videoInputDevice];
}
[_session removeOutput:_videoDataOutput];
_videoDataOutput = nil;
_videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
[_videoDataOutput setSampleBufferDelegate:self queue:_outputQueueVideo];
NSDictionary* setcapSettings = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange], kCVPixelBufferPixelFormatTypeKey, nil];
_videoDataOutput.videoSettings = setcapSettings;
[_session addOutput:_videoDataOutput];
_videoConnection = [_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
if([_videoConnection isVideoOrientationSupported]) {
[_videoConnection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
}
[_session commitConfiguration];
}
- (void)configureAudioWithDevice:(AVCaptureDevice *)microphone {
[_session beginConfiguration];
_audioInputDevice = [AVCaptureDeviceInput deviceInputWithDevice:microphone error:nil];
if ([_session canAddInput:_audioInputDevice]) {
[_session addInput:_audioInputDevice];
}
[_session removeOutput:_audioDataOutput];
_audioDataOutput = nil;
_audioDataOutput = [[AVCaptureAudioDataOutput alloc] init];
[_audioDataOutput setSampleBufferDelegate:self queue:_outputQueueAudio];
[_session addOutput:_audioDataOutput];
_audioConnection = [_audioDataOutput connectionWithMediaType:AVMediaTypeAudio];
[_session commitConfiguration];
}
You can't change the captureDevice mid-session. And you can only have one capture session running at a time. You could end the current session and create a new one. There will be a slight lag (maybe a second or two depending on your cpu load).
I wish Apple would allow multiple sessions or at least multiple devices per session... but they do not... yet.
have you considered having multiple sessions and then afterwards processing the video files to join them together into one?