web-dev-qa-db-fra.com

AVFoundation, comment désactiver le son de l'obturateur lorsque captureStillImageAsynchronouslyFromConnection?

J'essaie de capturer une image pendant un aperçu en direct de la caméra, par AVFoundation captureStillImageAsynchronouslyFromConnection . Jusqu'à présent, le programme fonctionne comme prévu. Cependant, comment puis-je désactiver le son du déclencheur?

85
ohho

J'ai utilisé ce code une fois pour capturer le son d'obturateur par défaut d'iOS (voici la liste des noms de fichiers son https://github.com/TUNER88/iOSSystemSoundsLibrary ):

NSString *path = @"/System/Library/Audio/UISounds/photoShutter.caf";
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSData *data = [NSData dataWithContentsOfFile:path];
[data writeToFile:[docs stringByAppendingPathComponent:@"photoShutter.caf"] atomically:YES];

Ensuite, j'ai utilisé une application tierce pour extraire photoShutter.caf du répertoire Documents (DiskAid pour Mac). La prochaine étape j'ai ouvert photoShutter.caf dans l'éditeur audio Audacity et l'effet d'inversion appliqué, cela ressemble à ceci sur le zoom élevé:

enter image description here

Puis j'ai enregistré ce son sous le nom photoShutter2.caf et a essayé de jouer ce son juste avant captureStillImageAsynchronouslyFromConnection:

static SystemSoundID soundID = 0;
if (soundID == 0) {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"photoShutter2" ofType:@"caf"];
    NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)filePath, &soundID);
}
AudioServicesPlaySystemSound(soundID);

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:
...

Et ça marche vraiment! Je lance le test plusieurs fois, chaque fois que je n'entends aucun son de déclencheur :)

Vous pouvez obtenir un son déjà inversé, capturé sur iPhone 5S iOS 7.1.1 à partir de ce lien: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf

1494
k06a

Méthode 1: Vous ne savez pas si cela fonctionnera, mais essayez de lire un fichier audio vierge juste avant d'envoyer l'événement de capture.

Pour lire un clip, ajoutez le Audio Toolbox cadre, #include <AudioToolbox/AudioToolbox.h> et jouez le fichier audio comme ceci immédiatement avant de prendre la photo:

 NSString *path = [[NSBundle mainBundle] pathForResource:@"blank" ofType:@"wav"];
 SystemSoundID soundID;
 NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
 AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
 AudioServicesPlaySystemSound(soundID);

Voici un fichier audio vierge si vous en avez besoin. http://cl.ly/3cKi

________________________________________________________________________________________________________________________________

Méthode 2:Il y a aussi une alternative si cela ne fonctionne pas. Tant que vous n'avez pas besoin d'une bonne résolution, vous pouvez récupérer une image du flux vidéo , évitant ainsi totalement le son de l'image.

________________________________________________________________________________________________________________________________

Méthode 3: Une autre méthode consiste à prendre une "capture d'écran" de votre application. Faites-le de cette façon:

UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:@"foo.png" atomically:YES];

Si vous souhaitez que ceci remplisse la totalité de l'écran avec un aperçu du flux vidéo afin que votre capture d'écran paraisse bien:

AVCaptureSession *captureSession = yourcapturesession;
AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
UIView *aView = theViewYouWantTheLayerIn;
previewLayer.frame = aView.bounds; // Assume you want the preview layer to fill the view.
[aView.layer addSublayer:previewLayer];
22
sudo rm -rf

Ma solution dans Swift

Quand vous appelez AVCapturePhotoOutput.capturePhoto méthode pour capturer une image comme ci-dessous code.

photoOutput.capturePhoto(with: self.capturePhotoSettings, delegate: self)

Les méthodes AVCapturePhotoCaptureDelegate seront appelées. Et le système essaie de jouer le son de l'obturateur après l'invocation de willCapturePhotoFor. Vous pouvez donc disposer du son du système dans la méthode willCapturePhotoFor.

enter image description here

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

    func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
        // dispose system shutter sound
        AudioServicesDisposeSystemSoundID(1108)
    }
}

Voir également

13
Won

J'ai réussi à faire fonctionner cela en utilisant ce code dans la fonction snapStillImage et cela fonctionne parfaitement pour moi sur iOS 8.3 iPhone 5. J'ai également confirmé que Apple ne rejettera pas votre application si vous utilisez ceci (ils n'ont pas rejeté le mien)

MPVolumeView* volumeView = [[MPVolumeView alloc] init];
//find the volumeSlider
UISlider* volumeViewSlider = nil;
for (UIView *view in [volumeView subviews]){
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)view;
        break;
    }
}
// mute it here:
[volumeViewSlider setValue:0.0f animated:YES];
[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];

Rappelez-vous simplement d'être gentil et réactivez-le lorsque votre application revient!

7
frakman1

Je vis au Japon, je ne peux donc pas couper le son lorsque nous prenons des photos pour des raisons de sécurité. En vidéo, toutefois, le son est désactivé. Je ne comprends pas pourquoi.

Le seul moyen de prendre une photo sans le son du déclencheur est d'utiliser AVCaptureVideoDataOutput ou AVCaptureMovieFileOutput. Pour analyser une image fixe, AVCaptureVideoDataOutput n’est qu’un moyen. Dans le code de l'échantillon AVFoundatation,

AVCaptureVideoDataOutput *output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
// If you wish to cap the frame rate to a known value, such as 15 fps, set 
// minFrameDuration.
output.minFrameDuration = CMTimeMake(1, 15);

Dans mon 3GS, il est très lourd lorsque je règle CMTimeMake (1, 1); // Une image par seconde.

Dans WWDC 2010 Sample code, FindMyiCone, j’ai trouvé le code suivant,

[output setAlwaysDiscardsLateVideoFrames:YES];

Lorsque cette API est utilisée, le minutage n'est pas accordé, mais l'API est appelée de manière séquentielle. Je présente ce sont les meilleures solutions.

5
Ben

Voir cet article pour un autre type de réponse: Capturez l'image à partir du tampon d'image. La capture d'écran lors de la prévisualisation de la vidéo échoue

3
Aaron Bratcher

Vous pouvez également prendre une image d'un flux vidéo pour capturer une image (pas en pleine résolution).

Il est utilisé ici pour capturer des images à intervalles rapprochés:

- (IBAction)startStopPictureSequence:(id)sender
{
    if (!_capturingSequence)
    {
        if (!_captureVideoDataOutput)
        {
            _captureVideoDataOutput = [AVCaptureVideoDataOutput new];
            _captureVideoDataOutput.videoSettings = @{(NSString *)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)};
            [_captureVideoDataOutput setSampleBufferDelegate:self
                                                       queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)];
            if (_sequenceCaptureInterval == 0)
            {
                _sequenceCaptureInterval = 0.25;
            }
        }

        if ([_captureSession canAddOutput:_captureVideoDataOutput])
        {
            [_captureSession addOutput:_captureVideoDataOutput];
            _lastSequenceCaptureDate = [NSDate date]; // Skip the first image which looks to dark for some reason
            _sequenceCaptureOrientation = (_currentDevice.position == AVCaptureDevicePositionFront ? // Set the output orientation only once per sequence
                                           UIImageOrientationLeftMirrored :
                                           UIImageOrientationRight);
            _capturingSequence = YES;
        }
        else
        {
            NBULogError(@"Can't capture picture sequences here!");
            return;
        }
    }
    else
    {
        [_captureSession removeOutput:_captureVideoDataOutput];
        _capturingSequence = NO;
    }
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    // Skip capture?
    if ([[NSDate date] timeIntervalSinceDate:_lastSequenceCaptureDate] < _sequenceCaptureInterval)
        return;

    _lastSequenceCaptureDate = [NSDate date];

    UIImage * image = [self imageFromSampleBuffer:sampleBuffer];
    NBULogInfo(@"Captured image: %@ of size: %@ orientation: %@",
               image, NSStringFromCGSize(image.size), @(image.imageOrientation));

    // Execute capture block
    dispatch_async(dispatch_get_main_queue(), ^
                   {
                       if (_captureResultBlock) _captureResultBlock(image, nil);
                   });
}

- (BOOL)isRecording
{
    return _captureMovieOutput.recording;
}
3
Rivera

Dans de tels cas, une astuce courante consiste à déterminer si le cadre appelle une certaine méthode pour cet événement, puis à écraser cette méthode temporairement, annulant ainsi son effet.

Je suis désolé mais je ne suis pas assez doué pour vous dire tout de suite si cela fonctionne dans ce cas. Vous pouvez essayer la commande "nm" sur les exécutables du framework pour voir s’il existe une fonction nommée qui porte un nom approprié, ou utiliser gdb avec le simulateur pour tracer où elle va.

Une fois que vous savez quoi écraser, il y a ces fonctions de répartition ObjC de bas niveau que vous pouvez utiliser pour rediriger la recherche de fonctions, je crois. Je pense l'avoir fait il y a quelques temps, mais je ne me souviens pas des détails.

J'espère que vous pourrez utiliser mes astuces pour rechercher dans Google plusieurs solutions. Bonne chance.

0
Thomas Tempelmann

Le seul moyen de contourner le problème auquel je peux penser serait de couper le son de l'iphone quand ils appuient sur le bouton "Prendre une photo", puis de le réactiver une seconde plus tard.

0
Linuxmint