AVFoundation, como desligar o som do obturador quando captureStillImageAsynchronouslyFromconnection?
-
25-09-2019 - |
Pergunta
Eu estou tentando capturar uma imagem durante uma pré-visualização ao vivo da câmera, por AVFoundation captureStillImageAsynchronouslyFromconnection.Até agora, o programa funciona como o esperado.No entanto, como posso desativar o som do obturador?
Solução
Eu usei este código uma vez para capturar o som do obturador padrão do iOS (aqui está a lista de nomes de arquivos de som 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];
Então eu usei um aplicativo de terceiros para extrair photoShutter.caf
do diretório de documentos (DiskAid para Mac). Próximo passo eu abri photoShutter.caf
No Audacity Audio Editor e no efeito de inversão aplicada, parece isso em alto zoom:
Então eu salvei esse som como photoShutter2.caf
e tentou reproduzir esse som antes 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 isso realmente funciona! Eu corro o teste várias vezes, toda vez que não ouço som de obturador :)
Você já pode obter som invertido, capturado no iPhone 5S iOS 7.1.1 deste link: https://www.dropbox.com/s/1echsi6ivbb85bv/photoshutter2.caf
Outras dicas
Método 1: Não tenho certeza se isso funcionará, mas tente reproduzir um arquivo de áudio em branco antes de enviar o evento de captura.
Para tocar um clipe, adicione o Audio Toolbox
estrutura, #include <AudioToolbox/AudioToolbox.h>
e reproduza o arquivo de áudio como este imediatamente Antes de tirar a foto:
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank" ofType:@"wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
Aqui está um arquivo de áudio em branco, se você precisar.http://cl.ly/3cki
________________________________________________________________________________________________________________________________________
Método 2:Há também uma alternativa se isso não funcionar. Contanto que você não precise ter uma boa resolução, você pode Pegue um quadro do fluxo de vídeo, evitando assim o som da imagem.
________________________________________________________________________________________________________________________________________
Método 3: Outra maneira de fazer isso seria tirar uma "captura de tela" do seu aplicativo. Faça desta maneira:
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 você deseja que isso preencha a tela inteira com uma prévia do fluxo de vídeo para que sua captura de tela pareça boa:
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];
Minha solução em Swift
Quando Você ligar AVCapturePhotoOutput.capturePhoto
Método para capturar a imagem como o código abaixo.
photoOutput.capturePhoto(with: self.capturePhotoSettings, delegate: self)
Os métodos AVCAPTUTEPHOTOCAPTURELEGATE serão invocados. E o sistema tenta reproduzir som do obturador depois willCapturePhotoFor
invocado. Então você pode descartar o som do sistema em willCapturePhotoFor
método.
extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
// dispose system shutter sound
AudioServicesDisposeSystemSoundID(1108)
}
}
Veja também
Consegui fazer isso funcionar usando esse código na função SnapstillImage e funciona perfeitamente para mim no iOS 8.3 iPhone 5. Também confirmei que a Apple não rejeitará seu aplicativo se você usar isso (eles não rejeitaram minha)
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];
Lembre -se de ser legal e ativá -lo quando seu aplicativo retornar!
Eu moro no Japão, por isso não posso silenciar o áudio quando tomamos fotos por motivo de segurança.No vídeo, no entanto áudio desliga-se.Eu não entendo por que.
A única forma de eu tirar uma foto sem o som do obturador é usando AVCaptureVideoDataOutput ou AVCaptureMovieFileOutput.Para analisar a imagem AVCaptureVideoDataOutput é a única maneira.Em AVFoundatation código de exemplo,
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);
No meu 3GS é muito pesado quando eu CMTimeMake(1, 1);// Um quadro por segundo.
Na WWDC 2010 código de Exemplo, FindMyiCone, eu encontrei o seguinte código,
[output setAlwaysDiscardsLateVideoFrames:YES];
Quando esta API é usada, o momento não é concedida, mas a API é chamada de seqüência.I este é o melhor de soluções.
Você também pode pegar um quadro de um fluxo de vídeo para capturar uma imagem (não com resolução total).
É usado aqui para capturar imagens em intervalos curtos:
- (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;
}
Veja este post para um tipo diferente de resposta: capture a imagem do buffer de imagem. A captura de tela durante a visualização de vídeo falha
O único possível trabalho que eu posso pensar seria silenciar o som do iPhone quando eles pressionarem o botão "Tiro a foto" e, em seguida, une-o um segundo depois.
Um truque comum em tais casos, é descobrir se o quadro invoca um determinado método para esse evento e, em seguida, substituir o método temporariamente, assim, anulando o seu efeito.
Me desculpe, mas eu não sou bom o suficiente hack para dizer-lhe imediatamente se que neste caso funciona.Você pode tentar o "nm" comando sobre o quadro executáveis para ver se existe uma função de chamada que tem um suitatable nome, ou usar o gdb com o Simulador de rastreio para onde ele vai.
Uma vez que você sabe o que a substituir, há aqueles de baixo nível ObjC despacho de funções que você pode usar para redirecionar a pesquisa para funções, eu acredito.Eu acho que eu fiz uma vez, há um tempo atrás, mas não me lembro os detalhes.
Felizmente, você pode usar as minhas dicas para o google algumas soluções caminhos para isso.Boa sorte.