J'essaie de capturer une image lors d'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 couper le son de l'obturateur?
J'essaie de capturer une image lors d'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 couper le son de l'obturateur?
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é une application tierce pour extraire photoShutter.caf
du répertoire Documents (DiskAid pour Mac). Étape suivante, j'ai ouvert photoShutter.caf
l'éditeur audio Audacity et appliqué l'effet d'inversion, cela ressemble à ceci avec un zoom élevé:
Ensuite, j'ai enregistré ce son photoShutter2.caf
et 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 cela fonctionne vraiment! Je fais des tests plusieurs fois, à chaque fois que je n'entends aucun son d'obturateur :)
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
Lorsque vous appelez la AVCapturePhotoOutput.capturePhoto
méthode pour capturer une image comme le code ci-dessous.
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 son willCapturePhotoFor
appel. Ainsi, vous pouvez disposer du son système par willCapturePhotoFor
méthode.
extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
// dispose system shutter sound
AudioServicesDisposeSystemSoundID(1108)
}
}
AudioServicesDisposeSystemSoundID(1108)
est appelée. Avez-vous des solutions pour cela? :)
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 lisez le fichier audio comme celui-ci 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. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav
________________________________________________________________________________________________________________________________________
Méthode 2: Il existe également une alternative si cela ne fonctionne pas. Tant que vous n'avez pas besoin d'une bonne résolution, vous pouvez saisir une image du flux vidéo , évitant ainsi complètement le son de l'image.
________________________________________________________________________________________________________________________________________
Méthode 3: Une autre façon de 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 souhaitez que cela remplisse tout l'écran avec un aperçu du flux vidéo afin que votre capture d'écran soit bonne:
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];
J'ai pu 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é 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];
N'oubliez pas d'être gentil et de réactiver le son lorsque votre application revient!
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 est désactivé. Je ne comprends pas pourquoi.
La seule façon de prendre une photo sans le son de l'obturateur est d'utiliser AVCaptureVideoDataOutput ou AVCaptureMovieFileOutput. Pour analyser l'image fixe AVCaptureVideoDataOutput est le seul 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, il est très lourd lorsque je règle CMTimeMake (1, 1); // Une image par seconde.
Dans l'exemple de code WWDC 2010, FindMyiCone, j'ai trouvé le code suivant,
[output setAlwaysDiscardsLateVideoFrames:YES];
Lorsque cette API est utilisée, le timing n'est pas accordé, mais l'API est appelée séquentiellement. Je ce que ce sont les meilleures solutions.
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 à 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;
}
Voir cet article pour un autre type de réponse: Capturez l'image à partir du tampon d'image. La capture d'écran pendant l'aperçu vidéo échoue
La seule solution possible à laquelle 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.
Une astuce courante dans de tels cas est de savoir si le framework appelle 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 existe une fonction nommée qui a un nom convenable, ou utiliser gdb avec le simulateur pour tracer où elle va.
Une fois que vous savez quoi écraser, il y a ces fonctions de distribution 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 quelque temps, mais je ne me souviens pas des détails.
J'espère que vous pourrez utiliser mes conseils pour rechercher sur Google quelques solutions à ce problème. Bonne chance.