Talvolta ricevo un'eccezione NSInvalidArgumentException
quando avvio la registrazione di video in un viewController
ma solo dopo aver scattato le foto in un controller di visualizzazione precedente. Ho provato un paio di suggerimenti da Google e così, ma ottengo ancora questo errore alla chiamata startRecordingToOutputFileURL:fileURL
.AVCaptureMovieFileOutput NSInvalidArgumentException nessuna connessione attiva/abilitata
Non riesco mai a visualizzare l'errore se non visito l'altro controller di visualizzazione che scatta le foto: si verifica solo quando scatta foto e quindi passa al nuovo controller di visualizzazione che esegue la registrazione video.
Penso che ci sia un po 'di cruft lasciato indietro dalle foto, ma quando inizializzo il mio controller di visualizzazione del videoregistratore non ottengo errori nell'impostare le sessioni e quant'altro. Qualche idea su cosa sta succedendo o su come recuperarlo? Perché è un'eccezione NSInvalidArgumentException
? Grazie!
Ecco il mio codice:
dispatch_async(dispatch_get_main_queue(), ^{
// Try to Fix bug:
// http://stackoverflow.com/questions/5979962/error-while-recording-video-on-iphone-using-avfoundation
[self.captureSession beginConfiguration];
// Ensure session is running
if ([self.captureSession isRunning] == NO) {
NSLog(@"Capture session is NOT running... Starting it now!");
[self.captureSession startRunning];
}
else {
NSLog(@"Capture session is ALREADY running...");
}
NSLog(@"File URL is: %@",fileURL);
NSLog(@"FileOutput is: %@",self.fileOutput);
[self.fileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];
// Try to Fix bug:
// http://stackoverflow.com/questions/5979962/error-while-recording-video-on-iphone-using-avfoundation
[self.captureSession commitConfiguration];
});
Ecco il traceback errore:
2014-05-18 16:01:38.818 app[1699:60b] *** Start recording
2014-05-18 16:01:38.820 app[1699:60b] Capture session is ALREADY running...
2014-05-18 16:01:38.827 app[1699:60b] Capture session is ALREADY running...
2014-05-18 16:01:38.828 app[1699:60b] File URL is: file:////var/mobile/Applications/73FFC590-05A8-4D74-82D9-EBA122B00A20/Documents/2014-05-18-16-01-38-0.mp4
2014-05-18 16:01:38.828 app[1699:60b] FileOutput is: <AVCaptureMovieFileOutput: 0x16513b10>
2014-05-18 16:01:38.829 app[1699:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] - no active/enabled connections.'
*** First throw call stack:
(0x2fe5ff0b 0x3a5f6ce7 0x2ed5751d 0xfb4b5 0x3aadfd53 0x3aadfd3f 0x3aae26c3 0x2fe2a681 0x2fe28f4d 0x2fd93769 0x2fd9354b 0x34d006d3 0x326f2891 0xe40c9 0x3aaf4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
Questo è come il captureSession viene inizializzato (dal progetto OpenSource qui: https://github.com/shu223/SlowMotionVideoRecorder):
- (id)initWithPreviewView:(UIView *)previewView {
self = [super init];
if (self) {
NSError *error;
self.captureSession = [[AVCaptureSession alloc] init];
self.captureSession.sessionPreset = AVCaptureSessionPresetInputPriority;
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if (error) {
NSLog(@"Video input creation failed");
return nil;
}
if (![self.captureSession canAddInput:videoIn]) {
NSLog(@"Video input add-to-session failed");
return nil;
}
[self.captureSession addInput:videoIn];
// save the default format
self.defaultFormat = videoDevice.activeFormat;
defaultVideoMaxFrameDuration = videoDevice.activeVideoMaxFrameDuration;
AVCaptureDevice *audioDevice= [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput *audioIn = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
[self.captureSession addInput:audioIn];
self.fileOutput = [[AVCaptureMovieFileOutput alloc] init];
[self.captureSession addOutput:self.fileOutput];
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
self.previewLayer.frame = previewView.bounds;
self.previewLayer.contentsGravity = kCAGravityResizeAspectFill;
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[previewView.layer insertSublayer:self.previewLayer atIndex:0];
[self.captureSession startRunning];
}
return self;
}
Il mio codice utilizza questo codice di inizializzazione come questo in viewDi DLOAD:
self.captureManager = [[AVCaptureManager alloc] initWithPreviewView:self.view];
self.captureManager.delegate = self;
Il codice che in realtà avvia e arresta la registrazione viene eseguita da un metodo IBAction come questo:
- (IBAction)recButtonTapped:(id)sender {
// REC START
if (self.captureManager.isRecording == NO) {
NSLog(@"*** Start recording");
// change UI
[self.recBtn setImage:self.recStopImage
forState:UIControlStateNormal];
self.fpsControl.enabled = NO;
// timer start
startTime = [[NSDate date] timeIntervalSince1970];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(timerHandler:)
userInfo:nil
repeats:YES];
[self.captureManager startRecording];
}
// REC STOP
else {
NSLog(@"*** Stop recording");
isNeededToSave = YES;
[self.captureManager stopRecording];
[self.timer invalidate];
self.timer = nil;
// change UI
[self.recBtn setImage:self.recStartImage
forState:UIControlStateNormal];
self.fpsControl.enabled = YES;
}
}
EDIT - Sono sicuramente la chiusura della sessione nella vista Foto, qui è che il codice . Ho verificato che venga chiamato quando esco dal controller di visualizzazione foto.
NSLog(@"RELEASE PHOTO SESSION NOW!");
for(AVCaptureInput *input1 in _mySesh.inputs) {
[_mySesh removeInput:input1];
}
for(AVCaptureOutput *output1 in _mySesh.outputs) {
[_mySesh removeOutput:output1];
}
[_mySesh stopRunning];
// Fix closing of session
dispatch_after(
dispatch_time(0,500000000),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
_mySesh = nil;
}
);
UPDATE #####
Secondo l'unica risposta di seguito, ho cercato di 'unlink' il file prima di iniziare la registrazione. Ancora non ha funzionato.
NSURL *fileURL = [NSURL URLWithString:[@"file://" stringByAppendingString:filePath]];
//NSLog(@"Beginning to record to output file...");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Wait for session to start
//[NSThread sleepForTimeInterval:1.0];
dispatch_async(dispatch_get_main_queue(), ^{
// Ensure session is running
if ([self.captureSession isRunning] == NO) {
NSLog(@"Capture session is NOT running... Starting it now!");
[self.captureSession startRunning];
}
else {
NSLog(@"Capture session is ALREADY running...");
}
NSLog(@"File URL is: %@",fileURL);
NSLog(@"FileOutput is: %@",self.fileOutput);
// Delete the file
unlink([[@"file://" stringByAppendingString:filePath] UTF8String]);
[self.fileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];
});
});
UPDATE
Solo per i posteri, io chiamo il 'didFinishRecordingToOutputFileAtURL' metodo delegato:
- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections error:(NSError *)error
{
// Print any errors
if (error) {
NSLog(@"Error Recording Video! %@",error.localizedDescription);
}
_isRecording = NO;
if ([self.delegate respondsToSelector:@selector(didFinishRecordingToOutputFileAtURL:error:)]) {
[self.delegate didFinishRecordingToOutputFileAtURL:outputFileURL error:error];
}
}
Il tuo 'beginConfiguration' e' commitConfiguration' sono inutili perché _non stai facendo nessuna configurazione_. In effetti, l'intera domanda, che non stai affrontando nel codice che hai mostrato, è il modo in cui 'self.captureSession' è configurato. Quando è stato fatto e cosa è stato fatto? – matt
Grazie per il commento: ho aggiunto ulteriori informazioni alla domanda. – PhilBot
Sei sicuro di distruggere correttamente le sessioni quando hai finito con loro? iOS non supporta più versioni di AVCaptureSession. Forse la sessione per l'acquisizione di foto non è stata rilasciata. Quando si crea un'altra sessione, non è possibile creare connessioni perché le porte di input sono trattenute da un'altra istanza di sessione. O controllalo tu stesso o mostraci il codice per l'acquisizione di foto e video con allocazione e deallocazione delle sessioni. – creker