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
AVFoundation, how to turn off the shutter sound when captureStillImageAsynchronouslyFromConnection?
提问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.caf
from Documents directory (DiskAid for Mac). Next step I opened photoShutter.caf
in Audacity audio editor and applied inversion effect, it looks like this on high zoom:
然后我使用第三方应用程序photoShutter.caf
从 Documents 目录(Mac 的 DiskAid)中提取。下一步我photoShutter.caf
在 Audacity 音频编辑器中打开并应用了反转效果,它在高变焦上看起来像这样:
Then I saved this sound as photoShutter2.caf
and 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.capturePhoto
method 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 willCapturePhotoFor
invoked.
So you can dispose of system sound in willCapturePhotoFor
method.
AVCapturePhotoCaptureDelegate 方法将被调用。并且系统在willCapturePhotoFor
调用后尝试播放快门声音。所以你可以用willCapturePhotoFor
方法处理系统声音。
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 Toolbox
framework, #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 的声音静音,然后在一秒钟后取消静音。