AVFoundation, как отключить звук затвора при захвате StillImageAsynchronouslyFromConnection? - PullRequest
82 голосов
/ 09 декабря 2010

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

Ответы [ 9 ]

1495 голосов
/ 20 мая 2014

Я использовал этот код один раз для захвата звука затвора 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

21 голосов
/ 13 декабря 2010

Метод 1: Не уверен, что это сработает, но попробуйте воспроизвести пустой аудиофайл прямо перед отправкой события захвата.

Чтобы воспроизвести клип, добавьте Audio Toolboxframework, #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];
8 голосов
/ 19 марта 2019

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

При вызове метода 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)
    }
}

См. Также

6 голосов
/ 26 июля 2015

Мне удалось заставить это работать, используя этот код в функции 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];

Просто не забывайте быть хорошим и включить его, когда ваше приложение вернется!

4 голосов
/ 24 декабря 2010

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

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

2 голосов
/ 08 июня 2015

См. Этот пост для ответа другого типа: захват изображения из буфера изображения. Снимок экрана во время предварительного просмотра видео не удается

2 голосов
/ 26 мая 2014

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

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

- (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;
}
0 голосов
/ 20 декабря 2010

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

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

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

0 голосов
/ 09 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...