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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4401232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:16:25  来源:igfitidea点击:

AVFoundation, how to turn off the shutter sound when captureStillImageAsynchronouslyFromConnection?

iosiphonecocoa-touchcameraavfoundation

提问by ohho

I am trying to capture an image during a live preview from the camera, by AVFoundation captureStillImageAsynchronouslyFromConnection. So far the program works as expected. However, how can I mute the shutter sound?

我正在尝试通过 AVFoundation captureStillImageAsynchronouslyFromConnection在相机的实时预览期间捕获图像。到目前为止,该程序按预期工作。但是,如何使快门声音静音?

回答by k06a

I used this code once to capture iOS default shutter sound (here is list of sound file names https://github.com/TUNER88/iOSSystemSoundsLibrary):

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

Then I used third-party app to extract photoShutter.caffrom Documents directory (DiskAid for Mac). Next step I opened photoShutter.cafin Audacity audio editor and applied inversion effect, it looks like this on high zoom:

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

enter image description here

在此处输入图片说明

Then I saved this sound as photoShutter2.cafand tried to play this sound right before captureStillImageAsynchronouslyFromConnection:

然后我将此声音另存为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:
...

And this really works! I runs test several times, every time I hear no shutter sound :)

这真的有效!我运行了几次测试,每次都没有听到快门声:)

You can get already inverted sound, captured on iPhone 5S iOS 7.1.1 from this link: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf

您可以通过以下链接获取已在 iPhone 5S iOS 7.1.1 上捕获的倒置声音:https: //www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf

回答by Won

My Solution in Swift

我的 Swift 解决方案

When you call AVCapturePhotoOutput.capturePhotomethod to capture an image like the below code.

当您调用AVCapturePhotoOutput.capturePhoto方法来捕获图像时,如下面的代码。

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

AVCapturePhotoCaptureDelegate methods will be invoked. And the system tries to play shutter sound after willCapturePhotoForinvoked. So you can dispose of system sound in willCapturePhotoFormethod.

AVCapturePhotoCaptureDelegate 方法将被调用。并且系统在willCapturePhotoFor调用后尝试播放快门声音。所以你可以用willCapturePhotoFor方法处理系统声音。

enter image description here

在此处输入图片说明

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

See also

也可以看看

回答by sudo rm -rf

Method 1:Not sure if this will work, but try playing a blank audio file right before you send the capture event.

方法 1:不确定这是否可行,但在发送捕获事件之前尝试播放空白音频文件。

To play a clip, add the Audio Toolboxframework, #include <AudioToolbox/AudioToolbox.h> and play the audio file like this immediatelybefore you take the picture:

要播放剪辑,请添加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);

Here is a blank audio file if you need it. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

如果您需要,这里有一个空白的音频文件。 https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

________________________________________________________________________________________________________________________________________

Method 2:There's also an alternative if this doesn't work. As long as you don't need to have a good resolution, you can grab a frame from the video stream, thus avoiding the picture sound altogether.

方法 2:如果这不起作用,还有一个替代方法。只要你不需要很好的分辨率,你可以从视频流中抓取一帧,从而完全避免画面声音。

________________________________________________________________________________________________________________________________________

________________________________________________________________________________________________________________________________________

Method 3:Another way to do this would be to take a "screenshot" of your application. Do it this way:

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

If you're wanting this to fill the whole screen with a preview of the video stream so that your screenshot looks good:

如果您希望通过视频流的预览填充整个屏幕,以便您的屏幕截图看起来不错:

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

回答by frakman1

I was able to get this to work by using this code in the snapStillImage function and it works perfectly for me on iOS 8.3 iPhone 5. I have also confirmed that Apple won't reject your app if you use this (they didn't reject mine)

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

Just remember to be nice and unmute it when your app returns!

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

回答by Ben

I live in in Japan, so I can not mute the audio when we take photos for security reason. In video, however audio turns off. I don't understand why.

我住在日本,所以出于安全原因我不能在拍照时静音。在视频中,但是音频关闭。我不明白为什么。

The only way I take a photo without shutter sound is using AVCaptureVideoDataOutput or AVCaptureMovieFileOutput. For analyze still image AVCaptureVideoDataOutput is only way. In AVFoundatation sample code,

我在没有快门声的情况下拍照的唯一方法是使用 AVCaptureVideoDataOutput 或 AVCaptureMovieFileOutput。分析静止图像 AVCaptureVideoDataOutput 是唯一的方法。在 AVFoundation 示例代码中,

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

In my 3GS it is very heavy when I set CMTimeMake(1, 1); // One frame per second.

在我的 3GS 中,当我设置 CMTimeMake(1, 1); 时它非常重。// 每秒一帧。

In WWDC 2010 Sample code, FindMyiCone, I found following code,

在 WWDC 2010 示例代码 FindMyiCone 中,我找到了以下代码,

[output setAlwaysDiscardsLateVideoFrames:YES];

When this API is used, the timing is not granted, but API is called sequentially. I this it is best solutions.

使用该 API 时,不授予时间,而是顺序调用 API。我这是最好的解决方案。

回答by Rivera

You can also take a frame from a video stream to capture a (not full resolution) image.

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

It is used hereto capture images at short intervals:

它是用来在这里以短的时间间隔拍摄图像:

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

回答by Aaron Bratcher

See this post for a different kind of answer: Capture the image from the image buffer. Screen capture during video preview fails

有关不同类型的答案,请参阅此帖子:从图像缓冲区捕获图像。 视频预览期间的屏幕截图失败

回答by Thomas Tempelmann

A common trick in such cases is to find out if the framework invokes a certain method for this event, and then to overwrite that method temporarily, thereby voiding its effect.

在这种情况下,一个常见的技巧是找出框架是否为此事件调用了某个方法,然后临时覆盖该方法,从而使其效果无效。

I'm sorry but I am not a good enough hack to tell you right away if that works in this case. You could try the "nm" command on the framework executables to see if there's a named function that has a suitatable name, or use gdb with the Simulator to trace where it goes.

很抱歉,但我不是一个足够好的黑客,无法立即告诉您在这种情况下是否可行。您可以在框架可执行文件上尝试“nm”命令以查看是否存在具有合适名称的命名函数,或者使用 gdb 和模拟器来跟踪它的去向。

Once you know what to overwrite, there are those low level ObjC dispatching functions that you can use to redirect the lookup for functions, I believe. I think I've done that once a while ago, but can't remember the details.

我相信,一旦您知道要覆盖的内容,就可以使用那些低级 ObjC 调度函数来重定向函数的查找。我想我曾经做过一次,但不记得细节了。

Hopefully, you can use my hints to google a few solutions paths to this. Good luck.

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

回答by Linuxmint

The only possible work-around I can think of would be to mute the iphone sound when they press the "take picture" button, and then un-mute it a second later.

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