AVFoundation, come disattivare il suono dell'otturatore quando captureStillImageAsynchronouslyFromConnection?
-
25-09-2019 - |
Domanda
Sto cercando di catturare un'immagine durante un'anteprima in tempo reale dalla telecamera, da AVFoundation captureStillImageAsynchronouslyFromConnection . Finora il programma funziona come previsto. Tuttavia, come posso disattivare il suono di scatto?
Soluzione
Ho usato questo codice una volta alla cattura iOS suono dell'otturatore di default (in questo caso è la lista di nomi di file 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];
Poi ho usato app di terze parti per estrarre photoShutter.caf
dalla directory Documenti (DiskAid for Mac). Il passo successivo ho aperto photoShutter.caf
in Audacity editor audio e l'effetto di inversione applicato, sembra che questo in alto zoom:
Poi ho salvato questo suono come photoShutter2.caf
e ho cercato di riprodurre questo suono a destra prima 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:
...
E questo funziona davvero! I test viene eseguito più volte, ogni volta che sento alcun suono di scatto:)
È possibile ottenere già invertito suono, catturato su iPhone 5S iOS 7.1.1 da questo link: https: // www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf
Altri suggerimenti
Metodo 1:. Non so se questo lavoro sarà, ma prova a riprodurre un file audio vuoto a destra prima di inviare l'evento di cattura
Per riprodurre un clip, aggiungere il quadro Audio Toolbox
, #include <AudioToolbox/AudioToolbox.h>
and riprodurre il file audio come questo immediatamente prima di scattare la foto:
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank" ofType:@"wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
Ecco un file vuoto audio se ne avete bisogno. http://cl.ly/3cKi
________________________________________________________________________________________________________________________________________
Metodo 2: C'è anche un'alternativa se questo non funziona. Finché non c'è bisogno di avere una risoluzione buona, è possibile grab un fotogramma del flusso video , evitando così il suono immagine del tutto.
________________________________________________________________________________________________________________________________________
Metodo 3: Un altro modo per farlo sarebbe quello di prendere una "screenshot" della vostra applicazione. Farlo in questo modo:
UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:@"foo.png" atomically:YES];
Se hai intenzione questo per riempire l'intero schermo con un'anteprima del flusso video in modo che la vostra screenshot sembra buono:
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];
La mia soluzione a Swift
Quando si chiama il metodo AVCapturePhotoOutput.capturePhoto
Acquisizione Immagine per come qui di seguito il codice.
photoOutput.capturePhoto(with: self.capturePhotoSettings, delegate: self)
verrà richiamato metodi AVCapturePhotoCaptureDelegate.
E il sistema tenta di riprodurre il suono di scatto dopo willCapturePhotoFor
invocato.
Così si può smaltire audio del sistema in modo willCapturePhotoFor
.
extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
// dispose system shutter sound
AudioServicesDisposeSystemSoundID(1108)
}
}
Vedi anche
sono stato in grado di ottenere questo al lavoro utilizzando questo codice nella funzione snapStillImage e funziona perfettamente per me su iOS 8.3 iPhone 5. Ho anche confermato che Apple non rifiuterà la vostra applicazione se si utilizza questo (che didn 't rifiutano mio)
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];
Basta ricordarsi di essere bello e riattivare quando i rendimenti app!
Io vivo a in Giappone, quindi non posso disattivare l'audio quando prendiamo le foto per motivi di sicurezza. Nel video, si trasforma tuttavia audio spento. Non capisco perché.
L'unico modo che scattare foto anche senza suono dell'otturatore sta usando AVCaptureVideoDataOutput o AVCaptureMovieFileOutput. Per analizzare un'immagine ancora AVCaptureVideoDataOutput è unico modo. In AVFoundatation codice di esempio,
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);
Nel mio 3GS è molto pesante quando ho impostato CMTimeMake (1, 1); // Un frame per secondo.
In WWDC 2010 di codice di esempio, FindMyiCone, ho trovato seguente codice,
[output setAlwaysDiscardsLateVideoFrames:YES];
Quando si utilizza questa API, la sincronizzazione non viene concessa, ma API viene chiamato in sequenza. Ho questo è migliori soluzioni.
Si può anche prendere un fotogramma da un flusso video per catturare un'immagine (non piena risoluzione).
E 'utilizzato qui per catturare immagini a intervalli brevi:
- (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;
}
Vedere questo post per un diverso tipo di risposta: Cattura l'immagine dal buffer di immagini. durante l'anteprima video non riesce
Il possibile solo work-around mi viene in mente sarebbe quello di disattivare l'audio iPhone quando si preme il pulsante "Scatta foto", e quindi riattivare un secondo più tardi.
Un trucco comune in questi casi è quello di scoprire se il quadro richiama un certo metodo per questo evento, e quindi per sovrascrivere il metodo temporaneamente, annullando così il suo effetto.
Mi dispiace, ma io non sono un buon trucco abbastanza per dirvi subito se funziona in questo caso. Si potrebbe provare il comando "nm" sulle eseguibili quadro per vedere se c'è una funzione denominata che ha un nome suitatable, o l'uso gdb con il simulatore di rintracciare dove va.
Una volta che sai cosa sovrascrivere, ci sono quelli di basso livello objC funzioni che è possibile utilizzare per reindirizzare la ricerca per le funzioni di dispacciamento, credo. Credo di aver fatto che una volta che qualche tempo fa, ma non ricordo i dettagli.
Si spera, è possibile utilizzare i miei suggerimenti a Google un paio di soluzioni percorsi per questo. Buona fortuna.