AVFoundation,如何在captureStillImageAsynchronouslyFromConnection时关闭快门声音?

时间:2010-12-09 17:27:11

标签: ios iphone cocoa-touch camera avfoundation

我试图通过AVFoundation captureStillImageAsynchronouslyFromConnection在相机的实时预览中捕捉图像。到目前为止,该计划按预期工作。但是,如何将快门声静音?

9 个答案:

答案 0 :(得分:1492)

我使用此代码一次捕获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];

然后我使用第三方应用从Documents目录(DiskAid for Mac)中提取photoShutter.caf。下一步我在Audacity音频编辑器中打开photoShutter.caf并应用了反转效果,它在高变焦时看起来像这样:

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

答案 1 :(得分: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);

如果需要,这是一个空白的音频文件。 http://cl.ly/3cKi

<强> ________________________________________________________________________________________________________________________________________

方法2:如果不起作用,还有其他选择。只要您不需要具有良好的分辨率,就可以grab a frame from the video stream,从而完全避免图像声音。

<强> ________________________________________________________________________________________________________________________________________

方法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 :(得分:6)

我能够通过在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];

当你的应用程序返回时,请记住保持良好并取消静音!

答案 3 :(得分:5)

我的Swift 4解决方案

当您调用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 :(得分:4)

我住在日本,因此出于安全原因拍照时我无法将音频静音。在视频中,音频会关闭。我不明白为什么。

我拍摄没有快门声的照片的唯一方法是使用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。我认为这是最好的解决方案。

答案 5 :(得分:2)

您还可以从视频流中取一帧来捕捉(非全分辨率)图像。

使用here以短间隔捕获图像:

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

答案 6 :(得分:2)

有关其他类型的答案,请参阅此帖:从图像缓冲区中捕获图像。 Screen capture during video preview fails

答案 7 :(得分:0)

我能想到的唯一可能的解决方法是在按下“拍照”按钮时静音iphone声音,然后在一秒钟后取消静音。

答案 8 :(得分:0)

在这种情况下,一个常见的技巧是找出框架是否为此事件调用某种方法,然后暂时覆盖该方法,从而消除其影响。

我很抱歉,但如果在这种情况下有效,我就不会马上告诉你。您可以在框架可执行文件上尝试“nm”命令,看看是否有一个具有适合名称的命名函数,或者使用gdb和Simulator来跟踪它的去向。

一旦你知道要覆盖什么,我相信你可以使用那些低级别的ObjC调度函数来重定向函数的查找。我想我刚刚做过这件事,但不记得细节。

希望您可以使用我的提示谷歌一些解决方案路径。祝你好运。