AVFoundation, как отключить звук затвора при захватеStillImageAsynchronouslyFromConnection?

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

Ответ 1

Я использовал этот код один раз, чтобы записать звук затвора по умолчанию для 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 из каталога Documents (DiskAid для Mac). Следующий шаг я открыл photoShutter.caf в аудиоредакторе Audacity и применил эффект инверсии, он выглядит так на большом увеличении:

enter image description here

Затем я сохранил этот звук как 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

Ответ 2

Метод 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);

Вот пустой звуковой файл, если он вам нужен. http://cl.ly/3cKi

________________________________________________________________________________________________________________________________________

Способ 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];

Ответ 3

Мое решение в Swift

Когда вы вызываете метод AVCapturePhotoOutput.capturePhoto для захвата изображения, как AVCapturePhotoOutput.capturePhoto ниже.

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

Методы AVCapturePhotoCaptureDelegate будут вызваны. И система пытается воспроизвести звук затвора после вызова willCapturePhotoFor. Таким образом, вы можете использовать системный звук в методе willCapturePhotoFor.

enter image description here

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

Смотрите также

Ответ 4

Мне удалось заставить это работать, используя этот код в функции snapStillImage, и он отлично работает для меня на iOS 8.3 iPhone 5. Я также подтвердил, что Apple не отклонит ваше приложение, если вы его используете (они didn 't отказываюсь от моего)

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 вызывается последовательно. Я это лучшие решения.

Ответ 6

Вы также можете взять кадр из видеопотока для захвата изображения (не полного разрешения).

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

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

Ответ 8

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

Ответ 9

Общим трюком в таких случаях является выяснение того, использует ли фрейм определенный метод для этого события, а затем временно перезаписывает этот метод, тем самым освобождая его эффект.

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

Как только вы знаете, что перезаписывать, есть те функции диспетчеризации ObjC с низким уровнем, которые вы можете использовать для перенаправления поиска функций. Я думаю, что сделал это некоторое время назад, но не могу вспомнить детали.

Надеюсь, вы можете использовать мои подсказки для Google несколькими путями решений для этого. Удачи.