AVFoundation,如何captureStillImageAsynchronouslyFromConnectionclosures快门声音?

我正尝试从AVFoundation captureStillImageAsynchronouslyFromConnection的实时预览中捕捉图像。 到目前为止,该scheme按预期工作。 但是,怎样才能使快门声音静音?

我用这个代码一次捕捉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 。 下一步,我打开Audacityaudio编辑器中的photoShutter.caf并应用反转效果,在高变焦时看起来像这样:

在这里输入图像说明

然后我保存了这个声音作为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: ... 

这真的有用! 我跑了几次testing,每次我听不到快门声:)

你可以得到已经倒立的声音,从iPhone 5S iOS 7.1.1捕获从这个链接: https : //www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf

方法1:不知道这是否会工作,但在发送捕捉事件之前尝试播放空白audio文件。

要播放剪辑,请在添加Audio Toolbox框架#include <AudioToolbox/AudioToolbox.h>并在拍摄照片之前立即播放audio文件:

  NSString *path = [[NSBundle mainBundle] pathForResource:@"blank" ofType:@"wav"]; SystemSoundID soundID; NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO]; AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID); AudioServicesPlaySystemSound(soundID); 

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

________________________________________________________________________________________________________________________________________

方法2:如果这不起作用,也有一个select。 只要你不需要有一个好的分辨率,你可以从videostream中抓取一个帧 ,从而完全避免了图像的声音。

________________________________________________________________________________________________________________________________________

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

如果你想要这个填充整个屏幕的videostream的预览,以便您的屏幕截图看起来不错:

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

我可以通过在snapStillImage函数中使用此代码来实现此function,并且在iOS 8.3 iPhone 5上完全适用于我。我还确认,如果使用此function,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]; 

只要记住当你的应用程序返回时很好,并取消静音!

我住在日本,所以出于安全原因拍照时,我不能将audio静音。 在video中,audioclosures。 我不明白为什么。

拍摄没有快门声的照片的唯一方法是使用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被顺序地调用。 我这是最好的解决scheme。

您也可以从videostream中获取一帧来拍摄(而不是全分辨率)图像。

它在这里用于短时间间隔捕获图像:

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

看到这个post的不同types的答案:从图像缓冲区捕获图像。 video预览期间的屏幕截图失败

唯一可能的解决办法,我可以想到的是,当他们按下“拍照”button,然后取消静音一秒钟后,静音iPhone的声音。

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

我很抱歉,但如果在这种情况下工作,我不是马上就告诉你。 您可以在框架可执行文件上尝试“nm”命令来查看是否存在具有适合名称的命名函数,或者在模拟器中使用gdb来跟踪它的位置。

一旦你知道要覆盖什么,我相信有一些低级的ObjC调度函数可以用来redirect函数的查找。 我想我以前曾经这样做过,但不记得细节。

希望你可以使用我的提示谷歌几个解决scheme的path。 祝你好运。