AVFoundation, як вимкнути звук затвора при захопленніStillImageAsynchronouslyFromConnection?


89

Я намагаюся захопити зображення під час попереднього перегляду з камери за допомогою AVFoundation captureStillImageAsynchronouslyFromConnection . Поки що програма працює, як очікувалося. Однак як я можу вимкнути звук затвора?


5
Наприклад, в Японії цього не можна зробити. Там звук затвора завжди відтворюється, навіть якщо ви приглушили телефон. (Наскільки мені відомо, в Японії діють деякі дивні правила для запобігання порушенням конфіденційності, зокрема, фотографії під спідницею). Тому я не думаю, що існує спосіб зробити це.
Dunkelstern

3
Так, можливо, ваш iPhone не дозволяє робити приглушені камери. Я перебуваю в США, і мій iPhone не видає звуку, коли я фотографую із приглушеним телефоном; навпаки, моя подруга видає звук (її з Кореї).
донкім

5
Щоб бути зрозумілим, це рішення, коли телефон не вимкнено звуку / режим вібрації. У цьому режимі під час фотографування звук не видається.
Нова Олександрія

31
@NewAlexandria Я також чув у Японії звуки затвора у вібраційному режимі. Це вимога закону.
k06a

3
До речі, AudioServicesPlaySystemSound не відтворюватиметься, якщо пристрій вимкнено. Тож японські пристрої все одно видаватимуть звук, коли приглушено, але не коли не вимкнено звук ...
Філіп Раделіч

Відповіді:


1501

Я використав цей код один раз для захоплення звуку затвора за замовчуванням iOS (ось список назв звукових файлів 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];

Потім я використовував сторонній додаток для вилучення photoShutter.cafз каталогу Документи (DiskAid для Mac). Наступним кроком я відкрив photoShutter.cafаудіоредактор Audacity і застосував ефект інверсії, він виглядає так при високому масштабуванні:

введіть тут опис зображення

Потім я записав цей звук як photoShutter2.cafі спробував відтворити його безпосередньо перед цим 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:
...

І це справді працює! Я запускаю тест кілька разів, кожен раз, коли не чую звуку затвора :)

Ви можете отримати вже перевернутий звук, знятий на iPhone 5S iOS 7.1.1, за цим посиланням: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf


104
Дуже круто. Єдиним застереженням є те, що коли увімкнено спалах, це призведе до подвійного звуку затвора, оскільки системний звук за замовчуванням не відтворюється під час виклику captureStillImageAsynchroniouslyFromConnection:, а коли зображення фактично знімається (під час послідовності спалаху). Натомість додайте спостерігача ключ-значення на self.stillImageOutput для keyPath 'capturingStillImage', щоб виявити, коли захоплення справді починається, а потім відтворити зворотний звук у методі зворотного виклику.
Джефф Массія,

16
Саме так сучасна військова авіація перемагає радіолокатор. Ось чому ви не бачите силуету "стелс-форми" на нових конструкціях винищувачів: існує пакет електроніки, який обробляє, в основному, фазовий зсув фази, що перешкоджає радіолокації, що передає "інвертований" (з фазовим зсувом) дублікат сигналу.
L0j1k

5
@ L0j1k: Це залежить від того, про який стелс-корабель ви говорите. F22 ank не зацікавлений в тому, щоб його не виявили, а в тому, щоб його можна було розблокувати. Проблема технології фазового зсуву полягає в тому, що ви неймовірно очевидні з будь-якої іншої позиції, оскільки вони не побачать такого самого зсуву.
Гуванте

13
Ось як працюють навушники з шумопоглинанням, за винятком того, що вони захоплюють звук у режимі реального часу
Даніель Серодіо

4
Це було чудово для iOS7, але це вже не працює на iOS8, є ідея, як це вирішити на iOS8?
Ticko

33

Моє рішення в Swift

Коли ви викликаєте AVCapturePhotoOutput.capturePhotoметод, щоб захопити зображення, як наведений нижче код.

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

Будуть викликані методи AVCapturePhotoCaptureDelegate. І система намагається відтворити звук затвора після willCapturePhotoForвикликання. Таким чином, ви можете утилізувати системний звук willCapturePhotoForметодом.

введіть тут опис зображення

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

Дивитися також


3
Це прекрасне рішення, і воно чудово працює. Чудова відповідь теж. Спасибі @kyle
Warpling

1
Це чудова робота. Якщо вам потрібно розділити безшумний режим і звичайний режим, використовуйте AudioServicesPlaySytemSoundID (1108) навпаки. Дякую.
MJ Studio

1
Це працює! Я хочу знати, чи виникають у вас проблеми із завантаженням в AppStore таким методом?
Liew Jun Tung

2
@LiewJunTung Немає проблем з цим рішенням. Я вже завантажував програми з цим рішенням. Є багато програм, які використовували подібне рішення. Щасливого кодування.
Виграно

Я виявив проблему. Мені цікаво, чи ви виявили цю проблему. В основному це витік пам'яті, який відбувається лише тоді, коли AudioServicesDisposeSystemSoundID(1108)його викликають. Чи є у вас рішення для цього? :)
Liew Jun Tung

21

Спосіб 1: Не впевнений, що це буде працювати, але спробуйте відтворити порожній аудіофайл безпосередньо перед тим, як надіслати подію захоплення.

Щоб відтворити кліп, додайте Audio Toolboxфреймворк #include <AudioToolbox/AudioToolbox.h> і відтворіть такий аудіофайл безпосередньо перед тим, як зробити знімок:

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

Ось порожній звуковий файл, якщо він вам потрібен. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

Спосіб 2: Є також альтернатива, якщо це не працює. Поки вам не потрібно мати хорошу роздільну здатність, ви можете захопити кадр із відеопотоку , уникаючи таким чином звуку зображення.

________________________________________________________________________________________________________________________________________

Метод 3: Іншим способом зробити це було б зробити "скріншот" програми. Зробіть це так:

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

Якщо ви хочете, щоб це заповнило весь екран попереднім переглядом відеопотоку, щоб ваш знімок екрана виглядав добре:

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
Я не думаю, що це могло б спрацювати, це просто відтворило б «порожній» звук під час відтворення шуму затвора. Цілком можливо відтворити 2 звуки одночасно. Інші 2 методи здаються працездатними!
Linuxmint

2
Спробуй. Я не впевнений, що це спрацює, але тут є надія!
sudo rm -rf

7

Я зміг змусити це працювати, використовуючи цей код у функції snapStillImage, і він ідеально працює для мене на iOS 8.3 iPhone 5. Я також підтвердив, що Apple не відхилить ваш додаток, якщо ви використовуєте це (вони не відхиляли Шахта)

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

Просто пам’ятайте про приємність і вмикайте його, коли ваш додаток повертається!


5

Я живу в Японії, тому не можу вимкнути звук, коли ми робимо фотографії з міркувань безпеки. У відео, проте звук вимикається. Я не розумію чому.

Єдиний спосіб зробити фотографію без звуку затвора - це використання AVCaptureVideoDataOutput або AVCaptureMovieFileOutput. Для аналізу нерухомого зображення AVCaptureVideoDataOutput - це єдиний спосіб. У зразку коду 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);

У моєму 3GS дуже важко, коли я встановлюю CMTimeMake (1, 1); // Один кадр на секунду.

У зразку коду WWDC 2010, FindMyiCone, я знайшов такий код,

[output setAlwaysDiscardsLateVideoFrames:YES];

Коли використовується цей API, синхронізація не надається, але API викликається послідовно. Я це найкраще рішення.


3

Ви також можете взяти кадр із відеопотоку, щоб зробити зображення (не з повною роздільною здатністю).

Він використовується тут для зображень захоплення через короткі проміжки часу:

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

Чи можете ви отримати AVCaptureVideoDataOutput для роботи під час використання AVCaptureMovieFileOutput? Коли я намагаюся використовувати їх обидва, методи делегування AVCaptureVideoDataOutput не викликаються.
Paul Cezanne

На жаль, я не намагався мати більше одного виводу одночасно.
Rivera


0

Єдиним можливим обхідним рішенням, яке я можу придумати, було б вимкнути звук iphone, коли вони натискають кнопку "сфотографувати", а потім відключити його через секунду.


Як програмувати звук iPhone програмно? Дякую!
ого

навіть якби ти міг, Apple не схвалила б цього

0

Поширеним трюком у таких випадках є з’ясувати, чи фреймворк викликає певний метод для цієї події, а потім тимчасово замінити цей метод, тим самим анулюючи його ефект.

Вибачте, але я недостатньо вдалий хакер, щоб негайно сказати вам, якщо це спрацює в цьому випадку. Ви можете спробувати команду "nm" у виконуваних файлових системах, щоб побачити, чи є названа функція, яка має відповідне ім'я, або скористатися gdb із симулятором, щоб простежити, куди вона йде.

Як тільки ви знаєте, що перезаписати, я вважаю, що є такі низькорівневі функції диспетчеризації ObjC, які ви можете використовувати для перенаправлення пошуку функцій. Думаю, я зробив це колись давно, але не можу згадати подробиці.

Сподіваємось, ви можете використовувати мої підказки, щоб прогуглити кілька шляхів вирішення цього питання. Удачі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.