ChatGPT解决这个技术问题 Extra ChatGPT

通过没有快门声的 captureStillImageAsynchronouslyFromConnection 捕获图像 [重复]

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

例如,在日本你不能这样做。即使您将手机静音,快门声也会一直播放。 (据我所知,日本有一些防止侵犯隐私的奇怪规则,也就是掀裙摄影)所以我认为没有办法做到这一点。
是的,可能是您的 iPhone 不允许静音相机拍摄。我在美国,当我在手机静音的情况下拍照时,我的 iPhone 没有声音;另一方面,我女朋友的声音确实会发出声音(她的来自韩国)。
需要明确的是,这是手机未静音/振动模式时的解决方案。在该模式下,拍照时不会发出声音。
@NewAlexandria 我在日本也听到了振动模式下的快门声。这是法律要求。
顺便说一句,如果设备静音,AudioServicesPlaySystemSound 将不会播放。所以日本设备在静音时仍然会发出声音,但在非静音时不会...

k
k06a

我曾经使用此代码来捕获 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 目录(Mac 的 DiskAid)中提取 photoShutter.caf。下一步我在 Audacity 音频编辑器中打开 photoShutter.caf 并应用了反转效果,它在高缩放时看起来像这样:

https://i.stack.imgur.com/mzFez.png

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


很酷。唯一需要注意的是,当闪光灯打开时,这将导致双快门声音,因为在调用 captureStillImageAsynchronouslyFromConnection: 时不会播放默认系统声音,而是在实际捕获图像时播放(在闪光序列期间)。而是在 self.stillImageOutput 上为 keyPath 'capturingStillImage' 添加一个键值观察器,以检测捕获真正开始的时间,然后在回调方法中播放反向声音。
这就是现代军用飞机击败雷达的方式。这就是为什么你在新的战斗机设计上看不到“隐形形状”轮廓的原因:有一个电子组件可以处理基本上是一种破坏雷达的相移,它会广播一个“反相”(相移)重复信号。
@L0j1k:这取决于你说的是哪种隐形船。 F22 之流对不被发现但可解锁不感兴趣。相移技术的问题是你在其他位置上都非常明显,因为他们不会看到相同的转变。
这就是降噪耳机的工作原理,除了它们实时捕捉声音
这对 iOS7 来说很棒,但它不再适用于 iOS8,知道如何在 iOS8 上解决这个问题吗?
W
Won

我在 Swift 中的解决方案

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

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

将调用 AVCapturePhotoCaptureDelegate 方法。并且系统在调用 willCapturePhotoFor 后尝试播放快门声音。因此,您可以在 willCapturePhotoFor 方法中处理系统声音。

https://i.stack.imgur.com/ZkT8g.png

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

也可以看看

AVCapturePhotoDelegate


这是一个漂亮的解决方案,而且效果很好。答案也很好。谢谢@kyle
这是完美的工作。如果需要将静音模式和普通模式分开,请反向使用 AudioServicesPlaySytemSoundID(1108)。谢谢你。
有用!我想知道您使用这种方法上传到 AppStore 是否有任何问题?
@LiewJunTung 这个解决方案没问题。我已经使用此解决方案上传了应用程序。有很多应用程序使用了这种解决方案。快乐编码。
这个答案通常有效,但它会创建一个依赖于系统负载的竞争条件。有时,iOS 直到播放完部分快门声音后才会调用 photoOutput
C
Cœur

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

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

______________________________________________________________________________________________________________________________

方法 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 个声音。其他两种方法似乎可行!
试一试。我不相信它会起作用,但希望如此!
f
frakman1

我可以通过在 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];

请记住在您的应用返回时保持友好并取消静音!


B
Ben

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

我拍摄没有快门声音的照片的唯一方法是使用 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);

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

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

[output setAlwaysDiscardsLateVideoFrames:YES];

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


R
Rivera

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

它用于 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;
}

您能否在使用 AVCaptureMovieFileOutput 时让 AVCaptureVideoDataOutput 工作?当我尝试同时使用它们时,不会调用 AVCaptureVideoDataOutput 的委托方法。
抱歉,我没有尝试同时拥有多个输出。
C
Community

请参阅此帖子以获取另一种答案:从图像缓冲区捕获图像。 Screen capture during video preview fails


L
Linuxmint

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


如何以编程方式使 iPhone 静音?谢谢!
即使可以,Apple 也不会批准
T
Thomas Tempelmann

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

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

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

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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅