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


J'essaie de capturer une image lors d'une prévisualisation en direct depuis la caméra, par AVFoundation captureStillImageAsynchronouslyFromConnection. Jusqu'à présent, le programme fonctionne comme prévu. Cependant, comment couper le son de l'obturateur?


71
2017-12-09 17:27


origine


Réponses:


J'ai utilisé ce code une fois pour capturer le son de l'obturateur par défaut iOS (voici la liste des noms de fichiers audio 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é l'application tierce pour extraire photoShutter.caf à partir du répertoire Documents (DiskAid pour Mac). Prochaine étape j'ai ouvert photoShutter.caf dans Audacity éditeur audio et effet d'inversion appliquée, il ressemble à ceci sur zoom élevé:

enter image description here

Puis j'ai enregistré ce son comme 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! J'exécute le test plusieurs fois, chaque fois que je n'entends pas de son d'obturateur :)

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


1472
2018-05-20 11:42



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

Pour lire un clip, ajoutez le Audio Toolbox cadre, #include <AudioToolbox/AudioToolbox.h> et jouer le fichier audio comme ça 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'avoir une bonne résolution, vous pouvez récupérer une image dans le flux vidéo, évitant ainsi le son de l'image.

________________________________________________________________________________________________________________________________________

Méthode 3: Une autre façon de le faire serait de 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 le souhaitez, remplissez tout l'écran avec un aperçu du flux vidéo afin que votre capture d'écran soit satisfaisante:

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];

19
2017-12-13 18:43



J'ai pu faire fonctionner ceci en utilisant ce code dans la fonction snapStillImage et cela fonctionne parfaitement pour moi sur iOS 8.3 iPhone 5. J'ai également confirmé qu'Apple ne rejettera pas votre application si vous l'utilisez (ils n'ont pas rejeté 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 juste d'être gentil et de le réactiver quand votre application revient!


6
2017-07-26 18:44



Je vis au Japon, donc je ne peux pas couper le son lorsque nous prenons des photos pour des raisons de sécurité. En vidéo, cependant l'audio s'éteint. Je ne comprends pas pourquoi.

La seule façon de prendre une photo sans son de l'obturateur est d'utiliser AVCaptureVideoDataOutput ou AVCaptureMovieFileOutput. Pour analyser l'image fixe AVCaptureVideoDataOutput est seulement moyen. Dans l'exemple de code 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 c'est très lourd quand je mets 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, la synchronisation n'est pas accordée, mais l'API est appelée séquentiellement. Je ceci c'est les meilleures solutions.


4
2017-12-24 01:21



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

C'est utilisé ici pour capturer des images à de courts intervalles:

- (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;
}

2
2018-05-26 02:18



Voir ce post pour un autre type de réponse: Capture l'image à partir du tampon d'image. La capture d'écran pendant la prévisualisation vidéo échoue


2
2018-06-08 11:57



La seule solution de rechange que je puisse imaginer serait de couper le son de l'iphone quand ils appuieront sur le bouton "Prendre une photo", puis de le désactiver une seconde plus tard.


0
2017-12-09 18:44



Une astuce courante dans de tels cas est de savoir si le framework invoque une certaine méthode pour cet événement, puis d'écraser temporairement cette méthode, annulant ainsi son effet.

Je suis désolé mais je ne suis pas assez bon 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 y a une fonction nommée qui a un nom approprié, ou utiliser gdb avec le simulateur pour voir où ça va.

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

J'espère que vous pouvez utiliser mes conseils pour google quelques pistes de solutions à cela. Bonne chance.


0
2017-12-19 22:40