startRecordingToOutputFileURL no active/enabled connections ios - ios

I want to record a short clip (30 sec) that should be automatically stopped after 30 sec. I started the camera using AVCAPTURESESSION and now I want to start video recording that should be automatically.
Here's my code:
AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetHigh;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
[session addInput:input];
AVCaptureVideoPreviewLayer *newCaptureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
newCaptureVideoPreviewLayer.frame = self.view.bounds;
[self.view.layer addSublayer:newCaptureVideoPreviewLayer];
[session startRunning];
How do I record video of 30 sec.
My Try:
NSString *documentsDirPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSURL *documentsDirUrl = [NSURL fileURLWithPath:documentsDirPath isDirectory:YES];
NSURL *url = [NSURL URLWithString:#"out.mp4" relativeToURL:documentsDirUrl];
[self.movieFileOutput startRecordingToOutputFileURL:url recordingDelegate:self];
- (AVCaptureMovieFileOutput *)movieFileOutput {
AVCaptureMovieFileOutput *_movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if (!_movieFileOutput) {
_movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
Float64 TotalSeconds = 30; //Total seconds
int32_t preferredTimeScale = 30; //Frames per second
CMTime maxDuration = CMTimeMakeWithSeconds(TotalSeconds, preferredTimeScale);
_movieFileOutput.maxRecordedDuration = maxDuration;
_movieFileOutput.minFreeDiskSpaceLimit = 1024 * 1024;
}
return _movieFileOutput;
}
But it gives me error, [AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] - no active/enabled connections.'
How can I record a video clip of 30 sec.

I find the reason of this error. check your session's "setSessionPreset" setting, photo's resolution setting is different from video, for iPhone5, video resolution of the back camera is 1920*1080, the front camere is 1280*720, and photo's max resolution is 3264*2488, so if you set error resolution to video, the connect will not be actived.

Related

How to show same camera video in two views

I am trying to show the same camera video in two different views; However I only get the video in one view. Could you help. Code is below
-(void) showCameraPreview{
self.camerPreviewCaptureSession =[[AVCaptureSession alloc] init];
self.camerPreviewCaptureSession.sessionPreset = AVCaptureSessionPresetHigh;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *videoInput1 = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
[self.camerPreviewCaptureSession addInput:videoInput1];
AVCaptureVideoPreviewLayer *newCaptureVideoViewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.camerPreviewCaptureSession];
newCaptureVideoViewLayer.frame = self.viewPreview.bounds;
newCaptureVideoViewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[newCaptureVideoViewLayer setFrame:CGRectMake(0.0, 0.0, self.viewPreview.bounds.size.width, self.viewPreview.bounds.size.height )];
AVCaptureVideoPreviewLayer *newCameraViewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.camerPreviewCaptureSession];
newCameraViewLayer.frame = self.viewPreview1.bounds;
newCameraViewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[newCameraViewLayer setFrame:CGRectMake(0.0, 0.0, self.viewPreview1.bounds.size.width, self.viewPreview1.bounds.size.height )];
[self.viewPreview1.layer addSublayer:newCameraViewLayer];
[self.viewPreview.layer addSublayer:newCaptureVideoViewLayer];
[self.camerPreviewCaptureSession startRunning];
}

how to correctly start a camera session using AVCapture session/AVCapture

I want to make an iOS app in objective C. Right now I'm stuck on making the preview layer to the AVCapture preview output. Could someone please tell me how to successfully start an image capture session using the AVCapture camera session in iOS Objective C? Any help is much appreciated. Thank you.
I give you answer for AVCaptureSession
-(void)capture
{
NSError *error=nil;
//Capture Session
AVCaptureSession *session = [[AVCaptureSession alloc]init];
session.sessionPreset = AVCaptureSessionPresetPhoto;
//Add device
AVCaptureDevice *inputDevice = nil;
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for(AVCaptureDevice *camera in devices)
{
if([camera position] == AVCaptureDevicePositionBack) // is Back camera
{
inputDevice = camera;
break;
}
}
[session addInput:inputDevice];
//Output
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
[session addOutput:output];
output.videoSettings = #{ (NSString *)kCVPixelBufferPixelFormatTypeKey : #(kCVPixelFormatType_32BGRA) };
//Preview Layer
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
previewLayer.frame = viewForCamera.bounds;
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[viewForCamera.layer addSublayer:previewLayer];
//Start capture session
[session startRunning];
}
Try this code to get camera id.
NSString *cameraID = nil;
NSArray *captureDeviceType = #[AVCaptureDeviceTypeBuiltInWideAngleCamera];
AVCaptureDeviceDiscoverySession *captureDevice =
[AVCaptureDeviceDiscoverySession
discoverySessionWithDeviceTypes:captureDeviceType
mediaType:AVMediaTypeVideo
position:AVCaptureDevicePositionUnspecified];
cameraID = [captureDevice.devices.lastObject localizedName];

AVAssetWriter Outputting Large File (even when applying compression settings)

I'm working on a personal iOS project that requires full screen videos (15 seconds in length) to be uploaded to a backend over a 4G connection. While I can take videos just fine, the output size of the file comes out to 30MB which makes me think I'm doing something drastically wrong when it comes to compression. Below is the code I'm using to se up the AssetWriter:
-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{
NSLog(#"Started Recording! *******************");
self.movieWriter = [AVAssetWriter assetWriterWithURL:fileURL fileType:AVFileTypeMPEG4 error:nil];
[self.movieWriter setShouldOptimizeForNetworkUse:YES];
NSDictionary *videoCleanApertureSettings = #{
AVVideoCleanApertureWidthKey: [NSNumber numberWithFloat:self.view.frame.size.width],
AVVideoCleanApertureHeightKey: [NSNumber numberWithFloat:self.view.frame.size.height],
AVVideoCleanApertureHorizontalOffsetKey: [NSNumber numberWithInt:10],
AVVideoCleanApertureVerticalOffsetKey: [NSNumber numberWithInt:10],
};
NSDictionary *videoCompressionSettings = #{
AVVideoAverageBitRateKey: [NSNumber numberWithFloat:5000000.0],
AVVideoMaxKeyFrameIntervalKey: [NSNumber numberWithInteger:1],
AVVideoProfileLevelKey: AVVideoProfileLevelH264Baseline30,
AVVideoCleanApertureKey: videoCleanApertureSettings,
};
NSDictionary *videoSettings = #{AVVideoCodecKey: AVVideoCodecH264,
AVVideoWidthKey: [NSNumber numberWithFloat:self.view.frame.size.width],
AVVideoHeightKey: [NSNumber numberWithFloat:self.view.frame.size.height],
AVVideoCompressionPropertiesKey: videoCompressionSettings,
};
self.movieWriterVideoInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
self.movieWriterVideoInput.expectsMediaDataInRealTime = YES;
[self.movieWriter addInput:self.movieWriterVideoInput];
NSDictionary *audioSettings = #{AVFormatIDKey: [NSNumber numberWithInteger:kAudioFormatMPEG4AAC],
AVSampleRateKey: [NSNumber numberWithFloat:44100.0],
AVNumberOfChannelsKey: [NSNumber numberWithInteger:1],
};
self.movieWriterAudioInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
self.movieWriterAudioInput.expectsMediaDataInRealTime = YES;
[self.movieWriter addInput:self.movieWriterAudioInput];
[self.movieWriter startWriting];
}
-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
NSLog(#"Done Recording!");
[self.movieWriterVideoInput markAsFinished];
[self.movieWriterAudioInput markAsFinished];
[self.movieWriter finishWritingWithCompletionHandler:^{
AVURLAsset *compressedVideoAsset = [[AVURLAsset alloc] initWithURL:self.movieWriter.outputURL options:nil];
//Upload video to server
}];
}
For the setup of the actual session I'm using the following code:
//Indicate that some changes will be made to the session
[self.captureSession beginConfiguration];
self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
AVCaptureInput* currentCameraInput = [self.captureSession.inputs objectAtIndex:0];
for (AVCaptureInput *captureInput in self.captureSession.inputs) {
[self.captureSession removeInput:captureInput];
}
//Get currently selected camera and use for input
AVCaptureDevice *videoCamera = nil;
if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack)
{
videoCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
}
else
{
videoCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
}
//Add input to session
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:videoCamera error:nil];
[self.captureSession addInput:newVideoInput];
//Add mic input to the session
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
[self.captureSession addInput:audioInput];
//Add movie output to session
for (AVCaptureOutput *output in self.captureSession.outputs) {
[self.captureSession removeOutput:output];
}
self.movieOutput = [AVCaptureMovieFileOutput new];
int32_t preferredTimeScale = 30; //Frames per second
self.movieOutput.maxRecordedDuration = CMTimeMakeWithSeconds(15, preferredTimeScale); //Setting the max video length
[self.captureSession addOutput:self.movieOutput];
//Commit all the configuration changes at once
[self.captureSession commitConfiguration];
I know that if I change AVCaptureSessionPresetHigh to a different preset I can reduce the file size of the final video, but unfortunately is looks like AVCaptureSessionPresetiFrame1280x720 is the only one that provides the full frame I'm trying to capture (which leaves me with an output size of about 20MB and is still too large for 4G uploads).
I've spent a lot of time googling and searching through other posts on Stack Overflow, but I can't seem to figure out what I'm doing wrong for the life of me and any help at all would be greatly appreciated.
You need a PhD to work with AVAssetWriter - it's non-trivial: https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/05_Export.html#//apple_ref/doc/uid/TP40010188-CH9-SW1
There's an amazing library for doing exactly what you want which is just an AVAssetExportSession drop-in replacement with more crucial features like changing the bit rate: https://github.com/rs/SDAVAssetExportSession
Here's how to use it:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:[info objectForKey:UIImagePickerControllerMediaURL]]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.myPathDocs = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"lowerBitRate-%d.mov",arc4random() % 1000]];
NSURL *url = [NSURL fileURLWithPath:self.myPathDocs];
encoder.outputURL=url;
encoder.outputFileType = AVFileTypeMPEG4;
encoder.shouldOptimizeForNetworkUse = YES;
encoder.videoSettings = #
{
AVVideoCodecKey: AVVideoCodecH264,
AVVideoCompressionPropertiesKey: #
{
AVVideoAverageBitRateKey: #2300000, // Lower bit rate here
AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
},
};
encoder.audioSettings = #
{
AVFormatIDKey: #(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey: #2,
AVSampleRateKey: #44100,
AVEncoderBitRateKey: #128000,
};
[encoder exportAsynchronouslyWithCompletionHandler:^
{
int status = encoder.status;
if (status == AVAssetExportSessionStatusCompleted)
{
AVAssetTrack *videoTrack = nil;
AVURLAsset *asset = [AVAsset assetWithURL:encoder.outputURL];
NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
videoTrack = [videoTracks objectAtIndex:0];
float frameRate = [videoTrack nominalFrameRate];
float bps = [videoTrack estimatedDataRate];
NSLog(#"Frame rate == %f",frameRate);
NSLog(#"bps rate == %f",bps/(1024.0 * 1024.0));
NSLog(#"Video export succeeded");
// encoder.outputURL <- this is what you want!!
}
else if (status == AVAssetExportSessionStatusCancelled)
{
NSLog(#"Video export cancelled");
}
else
{
NSLog(#"Video export failed with error: %# (%d)", encoder.error.localizedDescription, encoder.error.code);
}
}];
}

How to stop AVPlayer Ios and remove the periodicTimeObserverForInterval

I'm having a little difficulty stopping AVPlayer.
I have a method that records and plays music simultaneously. I'm using AVPlayer to play the music because I want to use the addPeriodicTimeObserverForInterval Function. I have it set up as follows:
- (IBAction) recordVoice:(id)sender {
if(!recorder.isRecording){
//set up the file name to record to
NSString *recordingLocation = [self createFileName];
recordingName = recordingLocation;
NSArray *pathComponents = [NSArray arrayWithObjects:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject],
recordingLocation, nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
recordingURL = outputFileURL;
// Setup audio session
session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
error:nil];
// Define the recording settings to record as m4a
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
// initiate and prepare the recorder
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
[session setActive:YES error:nil];
[recorder record];
// find which song to play and initiate an AVPlayer to play it
NSString *playerLocation = self.TitleLabel.text;
NSString *path = [[NSBundle mainBundle] pathForResource:playerLocation ofType:#"m4a"];
player = [[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:path]];
lastTime = nil;
//check where the player is at and update the song lines accordingly
[player addPeriodicTimeObserverForInterval:CMTimeMake(3, 10) queue:NULL usingBlock:^(CMTime time){
NSTimeInterval seconds = CMTimeGetSeconds(time);
for (NSDictionary *item in robotR33) {
NSNumber *time = item[#"time"];
if ( seconds > [time doubleValue] && [time doubleValue] >= [lastTime doubleValue] ) {
lastTime = #(seconds);
NSString *str = item[#"line"];
[self nextLine:str];
};
}
}];
[player play];
[_recordButton setImage:[UIImage imageNamed:#"micRecording.gif"] forState:UIControlStateNormal];
}
else{
[recorder stop];
player = nil;
[session setActive:NO error:nil];
}
}
If the recorder is not recording I set up both a new recorder AVAudioRecorder and an AVPlayer. In the AVPlayer I set up an AddPeriodicTimeObserverForInterval which updates the UI based on the position of the player.
If the recorder is recording I stop the recorder and I set the player to nil. This stops the audio from playing but I notice that the addPeriodicTimeObserverInterval is still running because the UI continues to update. Should I destroy the AVPlayer altogether and if so how should I do that? Many thanks in advance.
Also as an aside, I have a warning inside the addPeriodicTimeObserverForInterval block. I am looping over an Array called robotR33. Xcode tells me that 'Capturing self strongly in this block is likely to lead to a retain cycle". Could this be part of my problem?
When finished playing the observer needs to be removed from the player.
Adding [player removeTimeObserver:self.timeObserver] works.

Weird UIScrollview behaviour in IOS 7 in IPhone 4

I am working on a video-related application. For this, I used AVFoundation framework to capture image and video. I am capturing an image and showing that captured image in next view, where image view is a subview to the scrollview. It's working fine in iPhone 5,iPhone 5s and also in iPad but in iPhone 4 after capturing the image and while attaching to scrollView, the app is becoming slow. The scroll view is not scrolling smoothly as in other devices. I am not getting issue where it has gone wrong. I am using the below code to capture images:
-(void)capturePhoto
{
_ciContext = [CIContext contextWithOptions:nil];
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// - input
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL];
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
if ([device isFlashModeSupported:AVCaptureFlashModeOff])
{
device.flashMode = AVCaptureFlashModeOff;
}
[device unlockForConfiguration];
}
// - output
_dataOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
AVVideoCodecJPEG, AVVideoCodecKey, nil];
_dataOutput.outputSettings = outputSettings;
// - output
NSMutableDictionary *settings;
settings = [NSMutableDictionary dictionary];
[settings setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(__bridge id) kCVPixelBufferPixelFormatTypeKey];
_dataOutputVideo = [[AVCaptureVideoDataOutput alloc] init];
_dataOutputVideo.videoSettings = settings;
[_dataOutputVideo setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
_session = [[AVCaptureSession alloc] init];
[_session addInput:deviceInput];
[_session addOutput:_dataOutput];
[_session addOutput:_dataOutputVideo];
// _session.sessionPreset = AVCaptureSessionPresetPhoto;
_session.sessionPreset = AVCaptureSessionPresetHigh;
// _session.sessionPreset = AVCaptureSessionPresetMedium;
[_session startRunning];
// add gesture
// UIGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapGesture:)];
// gr.delegate = self;
// [self.touchView addGestureRecognizer:gr];
_focusView = [[UIView alloc] init];
CGRect imageFrame = _focusView.frame;
imageFrame.size.width = 80;
imageFrame.size.height = 80;
_focusView.frame = imageFrame;
_focusView.center = CGPointMake(160, 202);
CALayer *layer = _focusView.layer;
layer.shadowOffset = CGSizeMake(2.5, 2.5);
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowOpacity = 0.5;
layer.borderWidth = 2;
layer.borderColor = [UIColor yellowColor].CGColor;
[self.touchView addSubview:_focusView];
_focusView.alpha = 0;
_isShowFlash = NO;
[self.view bringSubviewToFront:self.touchView];
UIView *footerView = [self.view viewWithTag:2];
[self.view bringSubviewToFront:footerView];
}
Later I am attaching to scroll view like this:
scrollImgView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 320, 340)];
UIImage *image = [UIImage imageWithData:appdelegate.capturedImgData];
UIImage *tempImage=[self resizeImage:image withWidth:320 withHeight:340];
NSData *imgData=UIImageJPEGRepresentation(tempImage,1.0);//0.25f
NSLog(#"image is %#",image);
scrollImgView.image=[UIImage imageWithData:imgData];
// scrollImgView.contentMode = UIViewContentModeScaleAspectFit;
// UIViewContentModeScaleAspectFit;
[postScrollView addSubview:scrollImgView];
Please give me suggestions if any one faced the same problem.
your coding is fine , and also is not a problem in in device, it may be occur
1. network problem
2. device memory is already loaded fully.
3. some Data conversation also taken times
here
UIImage *image = [UIImage imageWithData:appdelegate.capturedImgData];
UIImage *tempImage=[self resizeImage:image withWidth:320 withHeight:340]; //
NSData *imgData=UIImageJPEGRepresentation(tempImage,1.0);//0.25f
the above code u having used
1. data conversion is taken high and also taken the 2 time of image conversion optimize any `NSData`
2. third line is improve the `quality` of your image-- this also take the time for image conversion.
in my suggestion
1. use `Asychronous method`
-- sdwebimage
-- Asychronous Imageview
-- NSOperation_Queue
-- Dispatch im main_queue
use anyone of this , it will be taken the some response for you. in my suggestion is use SDWebImage.. use this link Loading takes a while when i set UIImage to a NSData with a url.
I solved the issue by changing
_session.sessionPreset = AVCaptureSessionPresetHigh to
_session.sessionPreset = AVCaptureSessionPresetMedium

Resources