AVFoundation, como desligar o som do obturador quando captureStillImageAsynchronouslyFromconnection?

StackOverflow https://stackoverflow.com/questions/4401232

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?

Foi útil?

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:

enter image description here

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.

enter image description here

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top