4 Stimmen

Wie implementiert man Multi-Shot mit captureStillImageAsynchronouslyFromConnection (iOS AVFoundation)?

Ich versuche, kontinuierliche (Mehrfach-) Hochauflösungsbilder mit captureStillImageAsynchronouslyFromConnection in einer Schleife zu erfassen, aber es kommt gelegentlich zu einer Pause, um den Fokus neu einzustellen. Ich habe den Fokusmodus gesperrt (wie in anderen Stackoverflow-Beiträgen beschrieben), aber das hat nicht verhindert, dass die Kamera gelegentlich neu fokussiert. Mein Code-Schnipsel lautet:

// [self.session beginConfiguration];
if ([device lockForConfiguration:nil] == YES) {
    if ([device isFocusModeSupported:AVCaptureFocusModeLocked]) {
        [device setFocusMode:AVCaptureFocusModeLocked];
        console.log("Fokus gesperrt");
    }
    if ([device isExposureModeSupported:AVCaptureExposureModeLocked]) {
        [device setExposureMode:AVCaptureExposureModeLocked];
        console.log("Belichtung gesperrt");
    }
    if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeLocked]) {
        [device setWhiteBalanceMode:AVCaptureWhiteBalanceModeLocked];
        console.log("Weißabgleich gesperrt");
    }
}
// [self.session commitConfiguration];

for (int n = 0; n < 5; n++) {
    [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

        if (imageDataSampleBuffer) {
            NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [[UIImage alloc] initWithData:imageData];
            [[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)image.imageOrientation completionBlock:nil];
        }
    }];
}

[device unlockForConfiguration]

Das Ausgabeprotokoll zeigt:

Fokus gesperrt
Belichtung gesperrt
Weißabgleich gesperrt

was darauf hindeutet, dass der Fokus usw. erfolgreich gesperrt worden sein sollte.

Ich habe versucht, den Sperrcode mit [device unlockForConfiguration] und [device unlockForConfiguration] zu umschließen, aber das hat das Problem nicht behoben.

Kann jemand einen Fehler in meinem Code identifizieren oder einen Schritt, den ich übersehe? (Mir ist klar, dass ich dies alternativ auch mit Videoaufnahme anstelle von Standbildaufnahme umsetzen kann, aber ich benötige Bilder mit AVCaptureSessionPresetPhoto Auflösung.) Jede Hilfe wäre sehr willkommen. Vielen Dank.

3voto

Gnorizo Punkte 71

Ok, ich habe das Problem herausgefunden. [Gerät unlockForConfiguration] wurde ausgeführt, bevor alle captureStillImageAsynchronouslyFromConnection-Aufrufe aufgrund der Thread-Zeitplanung und GCD-Aufgaben abgeschlossen waren. Eine schnelle Lösung bestand darin, einen Spinlock hinzuzufügen, zum Beispiel:

if ([Gerät lockForConfiguration:nil]) {
    if ([Gerät isFocusModeSupported:AVCaptureFocusModeLocked])
        [Gerät setFocusMode:AVCaptureFocusModeLocked];
    if ([Gerät isExposureModeSupported:AVCaptureExposureModeLocked])
        [Gerät setExposureMode:AVCaptureExposureModeLocked];
    if ([Gerät isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeLocked])
        [Gerät setWhiteBalanceMode:AVCaptureWhiteBalanceModeLocked];
}

__block int Fotoanzahl = 5; 
for (int n = Fotoanzahl; n > 0; n--) {
    [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        @synchronize(self) {
            Fotoanzahl--;
        }

        if (imageDataSampleBuffer) {
            NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [[UIImage alloc] initWithData:imageData];
            [[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)image.imageOrientation completionBlock:nil];
        }
    }];
}

while (Fotoanzahl > 0); // Spinlock, bis captureStillImageAsynchronouslyFromConnection alle Fotos im Speicher erfasst hat
[Gerät unlockForConfiguration]

Es gibt vielleicht elegantere Lösungen da draußen (und ich würde sie gerne hören), aber ein einfacher Spinlock hat den Trick getan. (Außerdem hat mein Code, da er innerhalb eines dispatch_async-Blocks lief, keine Probleme mit der UI oder der App-Reaktionsfähigkeit verursacht.)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X