Objective-c Changing UIImagePickerController to video mode - objective-c

I have an application which I want onlt to show in the background the video source from the camera. I have the following code in my viewcontroller:
#if !TARGET_IPHONE_SIMULATOR
imagePickerController = [[UIImagePickerController alloc] initWithRootViewController:self];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.navigationBarHidden = YES;
imagePickerController.toolbarHidden = NO;
imagePickerController.showsCameraControls = NO;
//...
[self.view addSubview:self.imagePickerController.view];
[imagePickerController viewWillAppear:YES];
[imagePickerController viewDidAppear:YES];
#endif
//...
[self.view addSubview:otherthings];
Then I add other views on top and I have sounds too. However I changed the imagepicker mode to video but it freezes when a sound plays. here's what i changed:
#if !TARGET_IPHONE_SIMULATOR
imagePickerController = [[UIImagePickerController alloc] init];//initWithRootViewController:self];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
NSArray *mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
NSArray *videoMediaTypesOnly = [mediaTypes filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(SELF contains %#)", #"movie"]];
BOOL movieOutputPossible = (videoMediaTypesOnly != nil);
if (movieOutputPossible) {
imagePickerController.mediaTypes = videoMediaTypesOnly;
imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
imagePickerController.navigationBarHidden = YES;
imagePickerController.toolbarHidden = YES;
imagePickerController.showsCameraControls = NO;
}
#endif
Anyone knows why the camera pickers freezes when a sound plays? The sound is an AVAudioPlayer by the way.

Solution: Use AVFOundation instead of UIImagePickerController.
videoBackground = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetMedium;
CALayer *viewLayer = videoBackground.layer;
NSLog(#"viewLayer = %#", viewLayer);
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
captureVideoPreviewLayer.frame = videoBackground.bounds;
[videoBackground.layer addSublayer:captureVideoPreviewLayer];
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
// Handle the error appropriately.
NSLog(#"ERROR: trying to open camera: %#", error);
}
[session addInput:input];
[session startRunning];
[self.view addSubview:videoBackground];

Related

Image not centered vertically in scrollview

What am I missing? The inner scrollview and the image view fill the entire screen. But somehow my image is not centered. The top left corner of the image starts in the center of the view, but I would like to have the image nicely centered. Also during zooming.
-(void)prepareScrollView
{
for(int i =0;i<[self.layoverPhotoAssets count];i++){
PHAsset *asset = self.layoverPhotoAssets[i];
FMImageZoomViewController *zoomController = [[FMImageZoomViewController alloc] init];
// UIImageView *imageView = [[UIImageView alloc] init];
int x = self.scrollView.frame.size.width * i;
zoomController.view.frame = CGRectMake(x, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
//zoomController.view.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
[self.scrollView addSubview:zoomController.view];
zoomController.zoomScroller.delegate = self;
zoomController.imageView.tag = 1;
[self.zoomControllers addObject:zoomController];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeFast;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:zoomController.zoomScroller.frame.size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(result){
zoomController.imageView.image = result;
zoomController.imageView.backgroundColor = [UIColor redColor];
}
});
}];
//self.scrollView.contentSize= ;
}
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * [self.layoverPhotoAssets count], 0)];
[self scrollToAsset:self.selectedAsset];
}
Consider:
zoomController.view.frame = CGRectMake(x, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
[self.scrollView addSubview:zoomController.view];
That cannot be right. If zoomController.view is to be a subview of self.scrollView, its frame within self.scrollView is in terms of the bounds of self.scrollView, not the frame of self.scrollView.
Solved it like this:
-(void)prepareScrollView
{
for(int i =0;i<[self.layoverPhotoAssets count];i++){
PHAsset *asset = self.layoverPhotoAssets[i];
FMImageZoomViewController *zoomController = [[FMImageZoomViewController alloc] init];
// UIImageView *imageView = [[UIImageView alloc] init];
int x = self.scrollView.frame.size.width * i;
zoomController.view.frame = CGRectMake(x, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
//zoomController.view.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
[self.scrollView addSubview:zoomController.view];
zoomController.zoomScroller.delegate = self;
[self.zoomControllers addObject:zoomController];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeExact;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:zoomController.zoomScroller.bounds.size contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(result){
zoomController.imageView = [[UIImageView alloc] initWithImage:result];
zoomController.imageView.frame = zoomController.zoomScroller.bounds;
[zoomController.imageView setContentMode:UIViewContentModeScaleAspectFit];
zoomController.imageView.clipsToBounds = YES;
[zoomController.imageView setCenter: self.scrollView.center];
zoomController.imageView.tag = 1;
[zoomController.zoomScroller addSubview:zoomController.imageView];
// zoomController.imageView.contentMode = UIViewContentModeCenter;
// if (zoomController.imageView.bounds.size.width > result.size.width && zoomController.imageView.bounds.size.height > result.size.height) {
// zoomController.imageView.contentMode = UIViewContentModeScaleAspectFit;
// }
}
});
}];
//self.scrollView.contentSize= ;
}
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * [self.layoverPhotoAssets count], 0)];
[self scrollToAsset:self.selectedAsset];
}

How do I dismiss a UIView after scanning a barcode?

I have an iPad app that I want to add a barcode reader to... this is the code for the initialization of the barcoder code:
-(void) scanInitializationCode {
_highlightView = [[UIView alloc] init];
_highlightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin;
_highlightView.layer.borderColor = [UIColor greenColor].CGColor;
_highlightView.layer.borderWidth = 3;
[self.view addSubview:_highlightView];
// define the label to display the results of the scan
_label = [[UILabel alloc] init];
_label.frame = CGRectMake(0, self.view.bounds.size.height - 40, self.view.bounds.size.width, 40);
_label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
_label.backgroundColor = [UIColor colorWithWhite:0.15 alpha:0.65];
_label.textColor = [UIColor whiteColor];
_label.textAlignment = NSTextAlignmentCenter;
_label.text = #"(none)";
[self.view addSubview:_label];
// session initialization
_session = [[AVCaptureSession alloc] init];
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
// define the input device
_input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];
if (_input) {
[_session addInput:_input];
} else {
NSLog(#"Error: %#", error);
}
// and output device
_output = [[AVCaptureMetadataOutput alloc] init];
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[_session addOutput:_output];
_output.metadataObjectTypes = [_output availableMetadataObjectTypes];
// and preview layer
_prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_prevLayer.frame = self.view.bounds;
_prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:_prevLayer];
}
This is the AVCaptureMetadataOutputObjectsDelegate code:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeEAN13Code];
for (AVMetadataObject *metadata in metadataObjects) {
for (NSString *type in barCodeTypes) {
if ([metadata.type isEqualToString:type])
{
barCodeObject = (AVMetadataMachineReadableCodeObject *)[_prevLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata];
highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
if (detectionString != nil) {
_label.text = detectionString;
oISBNField.text = detectionString; // move detectionString to ISBN textbox
[_session stopRunning];
[_highlightView removeFromSuperview];
break;
}
else
_label.text = #"(none)";
}
This is the code that starts the scanning process by having the user tap a UIButton:
- (IBAction)aReadBarcode:(UIButton *)sender {
[self scanInitializationCode];
[_session startRunning];
// display the activity
[self.view bringSubviewToFront:_highlightView];
[self.view bringSubviewToFront:_label];
oISBNField.text = scanResults;
}
The problem is that once the scan has found the barcode, it stays visible; what I want to do is have it return to the UIView that has the button that caused it to start scanning (in other words, I want the _highlightView to disappear). I have tried all kinds of "dismissal" methods, even putting it at the back of the z-order, but none of them work. How can I make the highlightView disappear from the screen?
The answer:
[_prevLayer removeFromSuperlayer]; after [_session stopRunning]

How to make a full screen landscape camera without any buttons?

When the app launches I just want to make it display a camera view in full screen, without any on screen buttons, just the actual part which the camera is seeing.
You wont want to use the camera then. There are multiple ways to do this, the quickest is through a AVCaptureVideoPreviewLayer
Check out this answer: Get Camera Preview to AVCaptureVideoPreviewLayer
- (void)initCapture
{
AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:nil];
if (!captureInput) {
return;
}
AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];
/* captureOutput:didOutputSampleBuffer:fromConnection delegate method !*/
[captureOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
[captureOutput setVideoSettings:videoSettings];
self.captureSession = [[AVCaptureSession alloc] init];
NSString* preset = 0;
if (!preset) {
preset = AVCaptureSessionPresetMedium;
}
self.captureSession.sessionPreset = preset;
if ([self.captureSession canAddInput:captureInput]) {
[self.captureSession addInput:captureInput];
}
if ([self.captureSession canAddOutput:captureOutput]) {
[self.captureSession addOutput:captureOutput];
}
//handle prevLayer
if (!self.captureVideoPreviewLayer) {
self.captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
}
//if you want to adjust the previewlayer frame, here!
self.captureVideoPreviewLayer.frame = self.view.bounds;
self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer: self.captureVideoPreviewLayer];
[self.captureSession startRunning];
}
Also see:
Live camera in UIImageView
https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureVideoPreviewLayer_Class/Reference/Reference.html

How to add Dynamic Visual effects to running videos in iOS?

I want to change a visual effects dynamically to running videos. Am using GPUImage framework for changing the visual effects. I downloaded the sample project from Here. In this GPUImage, I choosed SimpleVideoFileFilter example. This example runs with one filter, just i modified the code and currently it supports 10 filters. My issue is, Video file is playing in GPUImageView, now i select another filter. Suddenly the video effect is also changing. But that video is starts from beginning. I want to change the filter dynamically for current playing video.
My Code is :
#pragma mark - Play Video with Effects
- (void)getVideo:(NSURL *)url
{
movieFile = [[GPUImageMovie alloc] initWithURL:url];
movieFile.runBenchmark = YES;
movieFile.playAtActualSpeed = YES;
// filter = [[GPUImagePixellateFilter alloc] init];
[movieFile addTarget:filter];
// Only rotate the video for display, leave orientation the same for recording
filterView = (GPUImageView *)self.view;
[filter addTarget:filterView];
// In addition to displaying to the screen, write out a processed version of the movie to disk
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Movie.m4v"];
unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
NSURL *movieURL1 = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL1 size:CGSizeMake(640.0, 480.0)];
[filter addTarget:movieWriter];
// Configure this for video from the movie file, where we want to preserve all video frames and audio samples
movieWriter.shouldPassthroughAudio = YES;
movieFile.audioEncodingTarget = movieWriter;
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
[movieWriter setCompletionBlock:^{
[filter removeTarget:movieWriter];
[movieWriter finishRecording];
UISaveVideoAtPathToSavedPhotosAlbum(pathToMovie, nil, nil, nil);
}];
}
- (void)event:(UIButton*)sender
{
[filter removeTarget:filterView];
UIButton *selectedBtn = sender;
[movieFile removeTarget:filter];
switch (selectedBtn.tag)
{
case 0:
filter = [[GPUImageBrightnessFilter alloc] init];
break;
case 1:
filter = [[GPUImageGrayscaleFilter alloc] init];
break;
case 2:
filter = [[GPUImageSketchFilter alloc] init];
break;
case 3:
filter = [[GPUImageToonFilter alloc] init];
break;
case 4:
filter = [[GPUImageMonochromeFilter alloc] init];
break;
case 5:
filter = [[GPUImagePixellateFilter alloc] init];
break;
case 6:
filter = [[GPUImageCrosshatchFilter alloc] init];
break;
case 7:
filter = [[GPUImageVignetteFilter alloc] init];
break;
case 8:
filter = [[GPUImageColorInvertFilter alloc] init];
break;
case 9:
filter = [[GPUImageLevelsFilter alloc] init];
[(GPUImageLevelsFilter *)filter setRedMin:1.0 gamma:1.0 max:0.0 minOut:0.5 maxOut:0.5];
break;
default:
break;
}
[self getVideo:movieURL];
}
Please help me to resolve this issue.
I found the answer by myself. Solution is,
- (void)event:(UIButton*)sender
{
// isMoviePlayCompleted = NO;
if (btnTag != sender.tag)
{
btnTag = (int)sender.tag;
NSLog(#"tag:%d",btnTag);
[self applyFilter:sender.tag];
}
}
Applying Filter
-(void) applyFilter:(NSInteger) tag
{
[[NSFileManager defaultManager] removeItemAtURL:saveTempUrl error:nil];
recording = NO;
switch (tag)
{
case 0:
filter =nil;
filter = [[GPUImagePixellateFilter alloc] init];
[(GPUImagePixellateFilter *)filter setFractionalWidthOfAPixel:0.0];
break;
case 1:
filter =nil;
filter = [[GPUImageGrayscaleFilter alloc] init];
break;
case 2:
filter =nil;
filter = [[GPUImageSketchFilter alloc] init];
break;
case 3:
filter =nil;
filter = [[GPUImageToonFilter alloc] init];
break;
case 4:
filter =nil;
filter = [[GPUImageMonochromeFilter alloc] init];
break;
case 5:
filter =nil;
filter = [[GPUImageVignetteFilter alloc] init];
break;
default:
break;
}
[self getVideo:movieURL];
}
Play Video with Effects
- (void)getVideo:(NSURL *)url
{
[filter removeAllTargets];
movieFile.audioEncodingTarget = nil;
[movieWriter cancelRecording];
[movieFile cancelProcessing];
[movieWriter finishRecording];
movieWriter = nil;
movieFile = nil;
filterView = nil;
recording = YES;
anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
movieFile = [[GPUImageMovie alloc] initWithURL:url];
movieFile.delegate = self;
movieFile.runBenchmark = NO;
movieFile.playAtActualSpeed = YES;
[movieFile addTarget:filter];
// Only rotate the video for display, leave orientation the same for recording
filterView = (GPUImageView *)self.view;
[filter addTarget:filterView];
NSString *pathName = [NSString stringWithFormat:#"Doc.MOV"];
// In addition to displaying to the screen, write out a processed version of the movie to disk
NSString *pathToMovie = [NSTemporaryDirectory() stringByAppendingPathComponent:pathName];
NSFileManager *fileTmp = [[NSFileManager alloc] init];
if ([fileTmp fileExistsAtPath:pathToMovie]) {
[fileTmp removeItemAtPath:pathToMovie error:nil];
}
unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
saveTempUrl = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:saveTempUrl size:size];
[filter addTarget:movieWriter];
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
__unsafe_unretained typeof(self) weakSelf = self;
[weakSelf->movieWriter setCompletionBlock:^{
NSLog(#"write completed");
[filter removeTarget:movieWriter];
[movieWriter finishRecording];
movieWriter = nil;
movieFile = nil;
filterView = nil;
recording = NO;
if (saveFilter)
{
saveFilter = NO;
UISaveVideoAtPathToSavedPhotosAlbum([saveTempUrl path], self, #selector(video:didFinishSavingWithError:contextInfo:), nil);
shareFilter = YES;
}
}];
}
Thats it. now when i choose any filter, it witt fill newly. so memory issue is solved. now its working fine for my application.
// Use this code
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinished) name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayer];
[videoPlayer play];
-(void)movieFinished
{
[videoPlayer play];
}
-(void) playTheVideo:(NSURL *)videoURL
{
NSTimeInterval time= videoPlayer.currentPlaybackTime;
UIView *parentView = imageViewFiltered; // adjust as needed
CGRect bounds = parentView.bounds; // get bounds of parent view
CGRect subviewFrame = CGRectInset(bounds, 0, 0);
videoPlayer.view.frame = subviewFrame;
videoPlayer.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[parentView addSubview:videoPlayer.view];
videoPlayer.contentURL = videoURL;
[videoPlayer setCurrentPlaybackTime:time];
[videoPlayer stop];
NSLog(#"Videoplayer stop or play in this view ");
[videoPlayer play];
self.showLoading = NO;
self.showLoading =NO;
}

didFinishPickingMediaWithInfo for two images

I have two image views named obsPic1 and obsPic2
They receive an image from picker/camera. This works fine for one image but any more and the images are the same. How do I do this for more than one image? Ive tried accessing the buttons sender tag but get undeclared identifier error, ive also tried using if statements. Whats the correct way to do this?
- (IBAction)addObsPhotoBtnPresssed:(id)sender {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
LogCmd();
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
imagePicker.allowsEditing = YES;
[self.editController presentModalViewController:imagePicker animated:YES];
//iPad
}
else {
if (self.pop) {
[self.pop dismissPopoverAnimated:YES];
}
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.delegate = self;
imagePickerController.allowsEditing = YES;
self.pop=[[UIPopoverController alloc] initWithContentViewController:imagePickerController];
[self.pop presentPopoverFromRect:((UIButton *)sender).bounds inView:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
self.obsPic1.backgroundColor = [UIColor whiteColor];
self.obsPic1.image = image;
NSData *imageData = UIImagePNGRepresentation(image);
NSString *path = [ICUtils pathForDocument:#"obsPic.png"];
[imageData writeToFile:path atomically:NO];
UIImage *image2 = [info objectForKey:UIImagePickerControllerEditedImage];
self.obsPic2.backgroundColor = [UIColor whiteColor];
self.obsPic2.image = image2;
NSData *imageData2 = UIImagePNGRepresentation(image);
NSString *path2 = [ICUtils pathForDocument:#"obsPic2.png"];
[imageData2 writeToFile:path2 atomically:NO];
}
Both your image and image2 reference the same image:
[info objectForKey:UIImagePickerControllerEditedImage]
Are you perhaps looking to reference the Edited and Original images:
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
and
UIImage *image2 = [info objectForKey:UIImagePickerControllerOriginalImage];
or vice versa? If OTOH you're trying to allow for multiple image picking look into ELCImagePickerController