AVFoundation, çekim sırasında deklanşör sesi nasıl kapatılırStillImageAsynchronouslyFromConnection?


90

AVFoundation yakalamaStillImageAsynchronouslyFromConnection ile kameradan canlı önizleme sırasında bir görüntü yakalamaya çalışıyorum . Şimdiye kadar program beklendiği gibi çalışıyor. Ancak, deklanşör sesini nasıl kapatabilirim?


5
Örneğin Japonya'da bunu yapamazsınız. Telefonun sesini kapatsanız bile deklanşör sesi her zaman çalar. (Gizlilik ihlalini önlemek için bazı tuhaf kurallar, bildiğim kadarıyla etek altı fotoğrafçılığı Japonya'da yürürlüktedir) Bu yüzden bunu yapmanın bir yolu olduğunu düşünmüyorum.
Dunkelstern

3
Evet, iPhone'unuz sessiz kamera çekimlerine izin vermiyor olabilir. ABD'deyim ve telefonum kapalıyken fotoğraf çektiğimde iPhone'um ses çıkarmıyor; Öte yandan kız arkadaşım ses çıkarıyor (onunki Kore'den).
donkim

5
Açık olmak gerekirse, bu, telefonun sessiz / titreşim modu olmadığı zamanlar için bir çözümdür. Bu modda, resim çekerken ses çıkmaz.
Yeni İskenderiye

31
@NewAlexandria Japonya'da titreşim modunda da deklanşör sesleri duydum. Bu kanun gereğidir.
k06a

3
Btw AudioServicesPlaySystemSound, aygıtın sesi kapatılırsa oynatılmaz. Yani Japon cihazları, sesi kapatıldığında ses
çıkarmaya

Yanıtlar:


1500

Bu kodu bir kez iOS varsayılan deklanşör sesini yakalamak için kullandım (ses dosyası adlarının listesi 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];

Ardından photoShutter.cafBelgeler dizininden (Mac için DiskAid) ayıklamak için üçüncü taraf uygulamasını kullandım . Bir sonraki adım photoShutter.cafAudacity ses düzenleyicide açtım ve ters çevirme efekti uyguladım, yüksek yakınlaştırmada şöyle görünüyor:

görüntü açıklamasını buraya girin

Sonra bu sesi olarak kaydettim photoShutter2.cafve bu sesi hemen önce çalmaya çalıştım 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:
...

Ve bu gerçekten işe yarıyor! Her defasında deklanşör sesi duymadığımda birkaç kez test çalıştırıyorum :)

Bu bağlantıdan iPhone 5S iOS 7.1.1'de yakalanmış halihazırda ters çevrilmiş sesi alabilirsiniz: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf


104
Çok havalı. Sadece uyarı, flaş açıldığında bunun çift deklanşör sesine neden olacağıdır, çünkü captureStillImageAsynchronouslyFromConnection: çağrıldığında varsayılan sistem sesi çalınmaz, bunun yerine görüntü gerçekten yakalandığında (flaş dizisi sırasında). Bunun yerine, yakalamanın gerçekten başladığını algılamak için keyPath 'capturingStillImage' için self.stillImageOutput üzerine bir anahtar-değer gözlemcisi ekleyin, ardından geri arama yönteminde ters ses çalın.
Jeff Mascia

16
Modern askeri uçakların radarı nasıl bozduğu budur. Bu nedenle, yeni dövüşçü tasarımlarında "gizli şekil" siluetini görmüyorsunuz: Temelde "tersine çevrilmiş" (faz kaydırmalı) bir yinelenen sinyal yayınlayan radarı bozan bir faz kaymasını işleyen bir elektronik paket var.
L0j1k

5
@ L0j1k: Ne tür bir gizli gemiden bahsettiğinize bağlı. F22 bir ilk olarak tespit edilmemekle ilgilenmiyor, ancak kilidi açılabilmeyle ilgileniyor. Faz kaydırma teknolojisi ile ilgili sorun, aynı değişimi görmeyecekleri için diğer her pozisyondan inanılmaz derecede açık olmanızdır.
Guvante

13
Gürültü önleyici kulaklıklar, sesi gerçek zamanlı olarak yakalamaları dışında bu şekilde çalışır
Daniel Serodio

4
Bu iOS7 için harikaydı, ancak artık iOS8'de çalışmıyor, bunu iOS8'de nasıl çözeceğiniz konusunda bir fikriniz var mı?
Ticko

36

Swift Çözümüm

AVCapturePhotoOutput.capturePhotoAşağıdaki kod gibi bir görüntüyü yakalamak için yöntemi çağırdığınızda .

photoOutput.capturePhoto(with: self.capturePhotoSettings, delegate: self)

AVCapturePhotoCaptureDelegate yöntemleri çağrılacaktır. Ve sistem willCapturePhotoForçağrıldıktan sonra deklanşör sesini çalmaya çalışır . Böylece sistem sesini willCapturePhotoForyöntemde atabilirsiniz .

görüntü açıklamasını buraya girin

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

    func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
        // dispose system shutter sound
        AudioServicesDisposeSystemSoundID(1108)
    }
}

Ayrıca bakınız


3
Bu güzel bir çözüm ve mükemmel çalışıyor. Çok güzel cevap. Teşekkürler @kyle
Warpling

1
Bu mükemmel bir iş. Sessiz mod ile normal modu ayırmanız gerekirse, AudioServicesPlaySytemSoundID (1108) 'i tersten kullanın. Teşekkür ederim.
MJ Studio

1
İşe yarıyor! Böyle bir yöntemle AppStore'a yükleme yaparken sorun yaşayıp yaşamadığınızı bilmek istiyorum.
Liew Jun Tung

2
@LiewJunTung Bu çözümde sorun yok. Bu çözümle uygulamaları zaten yükledim. Bu tür bir çözümü kullanan birçok uygulama var. Mutlu kodlamalar.
Won

Bir problem keşfettim. Bu sorunu keşfettiniz mi merak ediyorum. Temelde sadece AudioServicesDisposeSystemSoundID(1108)arandığında meydana gelen bir hafıza sızıntısıdır . Bunun için herhangi bir çözümünüz var mı? :)
Liew Jun Tung

21

Yöntem 1: Bunun işe yarayıp yaramayacağından emin değilim, ancak yakalama olayını göndermeden hemen önce boş bir ses dosyası çalmayı deneyin.

Bir klibi oynatmak için Audio Toolboxçerçeveyi ekleyin #include <AudioToolbox/AudioToolbox.h> ve ses dosyasını fotoğrafı çekmeden hemen önce şu şekilde oynatın :

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

İhtiyacınız olursa işte boş bir ses dosyası. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

Yöntem 2: Bu işe yaramazsa bir alternatif de var. İyi bir çözünürlüğe ihtiyacınız olmadığı sürece , video akışından bir kare yakalayabilir , böylece görüntü sesini tamamen önleyebilirsiniz .

________________________________________________________________________________________________________________________________________

Yöntem 3: Bunu yapmanın başka bir yolu da uygulamanızın "ekran görüntüsünü" almaktır. Bunu şu şekilde yapın:

UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:@"foo.png" atomically:YES];

Bunun, ekran görüntüsünün iyi görünmesi için video akışının önizlemesiyle tüm ekranı doldurmasını istiyorsanız:

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

2
Bunun işe yarayacağını sanmıyorum, sadece deklanşör sesi çalarken "boş" bir ses çıkarırdı. Aynı anda 2 ses çalmak oldukça mümkün. Diğer 2 yöntem uygulanabilir görünüyor!
Linuxmint

2
Bi dene. İşe yarayacağından emin değilim, ama umarım!
sudo rm -rf

7

SnapStillImage işlevinde bu kodu kullanarak bunu çalıştırmayı başardım ve benim için iOS 8.3 iPhone 5'te mükemmel çalışıyor. Ayrıca, bunu kullanırsanız Apple'ın uygulamanızı reddetmeyeceğini de doğruladım (reddetmediler benim)

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

Nazik davranmayı ve uygulamanız geri geldiğinde sesini açmayı unutmayın!


5

Japonya'da yaşıyorum, bu yüzden güvenlik nedeniyle fotoğraf çekerken sesi kapatamıyorum. Videoda, ancak ses kapanıyor. Nedenini anlamıyorum

Deklanşör sesi olmadan fotoğraf çekmemin tek yolu AVCaptureVideoDataOutput veya AVCaptureMovieFileOutput kullanmaktır. Sabit görüntüyü analiz etmek için AVCaptureVideoDataOutput tek yoldur. AVFoundatation örnek kodunda,

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

3GS'mde CMTimeMake (1, 1) 'i ayarladığımda çok ağır; // Saniyede bir kare.

WWDC 2010 Örnek kodunda, FindMyiCone, aşağıdaki kodu buldum,

[output setAlwaysDiscardsLateVideoFrames:YES];

Bu API kullanıldığında, zamanlama verilmez, ancak API sıralı olarak çağrılır. Ben bu en iyi çözüm.


3

Ayrıca (tam çözünürlüklü olmayan) bir görüntüyü yakalamak için video akışından bir kare de alabilirsiniz.

Burada kısa aralıklarla fotoğraf çekmek için kullanılır :

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

AVCaptureMovieFileOutput kullanılırken AVCaptureVideoDataOutput'un çalışmasını sağlayabiliyor musunuz? Her ikisini de kullanmaya çalıştığımda, AVCaptureVideoDataOutput'un temsilci yöntemleri çağrılmıyor.
Paul Cezanne

Üzgünüm, aynı anda birden fazla çıktı almayı denemedim.
Rivera


0

Aklıma gelen tek olası çözüm, "fotoğraf çek" düğmesine bastıkları zaman iphone sesini kapatmak ve bir saniye sonra sesini açmak olabilir.


İPhone sesini programlı olarak nasıl sessize alabilirim? Teşekkürler!
ohho

yapabilseniz bile Apple bunu onaylamaz

0

Bu tür durumlarda yaygın bir hile, çerçevenin bu olay için belirli bir yöntemi çağırıp çağırmadığını bulmak ve ardından geçici olarak bu yöntemin üzerine yazmak ve böylece etkisini geçersiz kılmaktır.

Üzgünüm ama bu durumda işe yarayıp yaramadığını size hemen söyleyecek kadar iyi bir bilgisayar korsanlığı değilim. Uygun bir ada sahip adlandırılmış bir işlev olup olmadığını görmek için çerçeve çalıştırılabilirlerinde "nm" komutunu deneyebilir veya nereye gittiğini izlemek için Simülatör ile gdb'yi kullanabilirsiniz.

Neyin üzerine yazılacağını öğrendikten sonra, işlev aramayı yeniden yönlendirmek için kullanabileceğiniz düşük seviyeli ObjC gönderme işlevleri olduğuna inanıyorum. Sanırım bunu bir süre önce yaptım ama ayrıntıları hatırlayamıyorum.

Umarım, ipuçlarımı bunun için birkaç çözüm yolunu Google'da kullanmak için kullanabilirsiniz. İyi şanslar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.