AVFoundation, ¿cómo desactivar el sonido del obturador cuando captureStillImageAsynchronouslyFromConnection?

Estoy intentando capturar una imagen durante una vista previa en vivo desde la cámara, mediante AVFoundation captureStillImageAsynchronouslyFromConnection . Hasta ahora, el progtwig funciona como se esperaba. Sin embargo, ¿cómo puedo silenciar el sonido del obturador?

Utilicé este código una vez para capturar el sonido del obturador predeterminado de iOS (aquí hay una lista de nombres de archivos de sonido 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]; 

Luego usé una aplicación de terceros para extraer photoShutter.caf del directorio de Documentos (DiskAid para Mac). Siguiente paso Abrí photoShutter.caf en el editor de audio Audacity y apliqué efecto de inversión, se ve así en un zoom alto:

enter image description here

Luego photoShutter2.caf este sonido como photoShutter2.caf e intenté reproducir este sonido justo antes de 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: ... 

¡Y esto realmente funciona! Pruebo varias veces, cada vez que escucho ningún sonido de obturador 🙂

Puede obtener el sonido ya invertido, capturado en el iPhone 5S iOS 7.1.1 desde este enlace: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf

Método 1: No estoy seguro si esto funcionará, pero intente reproducir un archivo de audio en blanco justo antes de enviar el evento de captura.

Para reproducir un clip, agregue el marco de Audio Toolbox , #include y reproduzca el archivo de audio de esta manera inmediatamente antes de tomar la fotografía:

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

Aquí hay un archivo de audio en blanco si lo necesita. http://cl.ly/3cKi

________________________________________________________________________________________________________________________________________

Método 2: También hay una alternativa si esto no funciona. Siempre que no necesite una buena resolución, puede tomar un fotogtwig de la secuencia de video , evitando por lo tanto el sonido de la imagen.

________________________________________________________________________________________________________________________________________

Método 3: Otra forma de hacerlo sería tomar una “captura de pantalla” de su aplicación. Hacerlo de esta forma:

 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 desea que esto llene toda la pantalla con una vista previa de la transmisión de video para que su captura de pantalla se vea 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]; 

Pude hacer que esto funcionara al usar este código en la función snapStillImage y funciona perfectamente para mí en iOS 8.3 iPhone 5. También he confirmado que Apple no rechazará tu aplicación si la usas (no rechazaron) mía)

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

¡Solo recuerda ser amable y dejar de silenciarlo cuando vuelva tu aplicación!

Vivo en Japón, así que no puedo silenciar el audio cuando tomamos fotos por razones de seguridad. En video, sin embargo, el audio se apaga. No entiendo por qué.

La única forma en que tomo una foto sin sonido de obturador es usando AVCaptureVideoDataOutput o AVCaptureMovieFileOutput. Para analizar la imagen fija, AVCaptureVideoDataOutput es única. En el código de muestra de 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); 

En mi 3GS es muy pesado cuando configuro CMTimeMake (1, 1); // Un cuadro por segundo.

En WWDC 2010 Código de muestra, FindMyiCone, encontré el código siguiente,

 [output setAlwaysDiscardsLateVideoFrames:YES]; 

Cuando se utiliza esta API, no se otorga el tiempo, pero la API se llama secuencialmente. Estas son las mejores soluciones.

También puede tomar un fotogtwig de una secuencia de video para capturar una imagen (no de resolución completa).

Se usa aquí para capturar imágenes a intervalos cortos:

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

Consulte esta publicación para obtener un tipo de respuesta diferente: capture la imagen del buffer de imágenes. La captura de pantalla durante la vista previa del video falla

La única solución posible que se me ocurre sería silenciar el sonido del iPhone cuando presionen el botón “tomar foto”, y luego desactivarlo un segundo después.

Un truco común en tales casos es averiguar si el marco invoca un método determinado para este evento, y luego sobrescribir ese método temporalmente, anulando así su efecto.

Lo siento pero no soy lo suficientemente bueno para decírtelo de inmediato si eso funciona en este caso. Puedes probar el comando “nm” en los ejecutables del framework para ver si hay una función nombrada que tenga un nombre adecuado, o usa gdb con el simulador para rastrear a dónde va.

Una vez que sepa qué sobrescribir, hay esas funciones de despacho ObjC de bajo nivel que puede usar para redirigir la búsqueda de funciones, creo. Creo que lo hice hace un tiempo, pero no puedo recordar los detalles.

Afortunadamente, puede usar mis sugerencias para buscar en Google algunas rutas de acceso a esto. Buena suerte.