AVFoundation、captureStillImageAsynchronouslyFromConnectionのときにシャッター音をオフにする方法は?


89

AVFoundation captureStillImageAsynchronouslyFromConnectionを使用して、ライブプレビュー中にカメラから画像をキャプチャしようとしています。これまでのところ、プログラムは期待どおりに機能しています。しかし、どうすればシャッター音をミュートできますか?


5
たとえば日本ではそれはできません。電話をミュートしてもシャッター音は常に鳴ります。(私が知る限り、プライバシー侵害を防ぐためのいくつかの奇妙なルール、別名アップスカートの写真が日本で実施されています)だから、それを行う方法はないと思います。
Dunkelstern

3
ええ、あなたのiPhoneはミュートされたカメラショットを許可していないかもしれません。私は米国にいて、電話をミュートにして写真を撮ってもiPhoneから音が出ません。一方、ガールフレンドは音を出します(彼女は韓国出身です)。
10

5
明確にするために、これは電話がミュート/バイブレーションモードでない場合の解決策です。そのモードでは、写真を撮るときに音は出ません。
新しいアレクサンドリア

31
@NewAlexandria振動モードでもシャッター音が聞こえる。これは法律の要件です。
k06a 2014年

3
デバイスがミュートされている場合、Btw AudioServicesPlaySystemSoundは再生されません。したがって、日本のデバイスは、ミュートされても音は鳴りますが、ミュートされていない場合は鳴りません...
Filip Radelic 2014年

回答:


1501

このコードを1回使用して、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];

次に、サードパーティのアプリを使用photoShutter.cafしてDocumentsディレクトリ(DiskAid for Mac)から抽出しました。photoShutter.cafAudacityオーディオエディターで次のステップを開き、反転効果を適用しました。高ズームでは次のようになります。

ここに画像の説明を入力してください

次に、このサウンドをとして保存し、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


104
とてもかっこいい。唯一の注意点は、フラッシュがオンの場合、デフォルトのシステムサウンドは、captureStillImageAsynchronouslyFromConnection:が呼び出されたときではなく、実際にイメージがキャプチャされたとき(フラッシュシーケンス中に)に再生されるため、ダブルシャッターサウンドが発生することです。代わりに、keyPath 'capturingStillImage'のself.stillImageOutputにキーと値のオブザーバーを追加して、キャプチャが実際にいつ開始されるかを検出し、コールバックメソッドで逆サウンドを再生します。
ジェフマスシア2014年

16
これが現代の軍用機がレーダーを打ち負かす方法です。これが、新しい戦闘機のデザインに「ステルス形状」のシルエットが表示されない理由です。「反転」(位相シフト)複製信号をブロードキャストする基本的にレーダーを無効にする位相シフトを処理するエレクトロニクスパッケージがあります。
L0j1k 2014年

5
@ L0j1k:それはあなたが話しているステルス船の種類に依存します。F22 an ilkは、検出されないことではなく、ロック解除できることには関心があります。位相シフトテクノロジーの問題は、他のすべてのポジションからあなたが信じられないほど明白であるということです。彼らは同じシフトを見ないからです。
グバンテ2014年

13
リアルタイムでサウンドをキャプチャすることを除いて、これはノイズキャンセリングヘッドフォンの動作です
Daniel Serodio

4
これはiOS7には最適でしたが、iOS8では機能しなくなりました。iOS8でこれを解決する方法はありますか?
Ticko 2014年

33

Swiftでの私のソリューション

AVCapturePhotoOutput.capturePhoto次のコードのような画像をキャプチャするためにメソッドを呼び出すとき。

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

AVCapturePhotoCaptureDelegateメソッドが呼び出されます。そして、システムはwillCapturePhotoFor呼び出された後にシャッター音を再生しようとします。そのため、willCapturePhotoForメソッドでシステムサウンドを破棄できます。

ここに画像の説明を入力してください

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

こちらもご覧ください


3
これは美しいソリューションであり、完全に機能します。すばらしい答えでもあります。ありがとう@kyle
Warpling

1
これは完全に機能します。サイレントモードと通常モードを分離する必要がある場合は、AudioServicesPlaySytemSoundID(1108)を逆に使用します。ありがとうございました。
MJ Studio

1
できます!このような方法でAppStoreにアップロードするときに問題があるかどうか知りたいのですが。
Liew Jun Tung

2
@LiewJunTungこのソリューションでは問題ありません。このソリューションですでにアプリをアップロードしました。この種のソリューションを使用したアプリはたくさんあります。ハッピーコーディング。

問題を発見しました。あなたはこの問題を発見したのかと思います。これは基本的に、AudioServicesDisposeSystemSoundID(1108)が呼び出されたときにのみ発生するメモリリークです。これに対する解決策はありますか?:)
Liew Jun Tung

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

必要な場合は、空のオーディオファイルを次に示します。 https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

方法2:これが機能しない場合の代替策もあります。解像度を高くする必要がない限り、ビデオストリームからフレームを取得できるため、画像のサウンドを完全に回避できます。

________________________________________________________________________________________________________________________________________

方法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
私はそれがうまくいくとは思わない、それはシャッターノイズが鳴っている間「空白」の音を鳴らすだけだろう。2つのサウンドを同時に再生することも可能です。他の2つの方法は実行可能です。
Linuxmint 2010

2
試してみます。私はそれがうまくいくとは確信していませんが、期待しています!
sudo rm -rf

7

このコードをsnapStillImage関数で使用することでこれを機能させることができました。iOS8.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];

アプリが戻ってきたら、いいことを忘れずにミュートを解除してください!


5

私は日本に住んでいるので、安全のため写真を撮るときは音声をミュートできません。ただし、ビデオでは、オーディオはオフになります。理由がわかりません。

シャッター音なしで写真を撮る唯一の方法は、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)を設定すると非常に重くなります。// 1秒あたり1フレーム。

WWDC 2010のサンプルコードFindMyiConeで、次のコードを見つけました、

[output setAlwaysDiscardsLateVideoFrames:YES];

このAPIを使用すると、タイミングは許可されませんが、APIは順次呼び出されます。私はこれが最善の解決策です。


3

ビデオストリームからフレームを取得して、(フル解像度ではない)画像をキャプチャすることもできます。

ここでは、短い間隔で画像をキャプチャするために使用さます。

- (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のデリゲートメソッドが呼び出されません。
ポールセザンヌ

申し訳ありませんが、同時に複数の出力を取得しようとはしていません。
Rivera


0

私が考えることができる唯一の可能な回避策は、「写真を撮る」ボタンを押したときにiphoneの音をミュートにして、1秒後にミュートを解除することです。


プログラムでiPhoneサウンドをミュートする方法は?ありがとう!
ohho

たとえできたとしても、アップルはそれを承認しません

0

このような場合の一般的なトリックは、フレームワークがこのイベントの特定のメソッドを呼び出すかどうかを確認し、そのメソッドを一時的に上書きして、その効果を無効にすることです。

申し訳ありませんが、このケースで機能するかどうかをすぐに説明するのに十分なハックではありません。フレームワーク実行可能ファイルで「nm」コマンドを試して、適切な名前の名前付き関数があるかどうかを確認するか、シミュレーターでgdbを使用して、どこにあるかを追跡できます。

何を上書きするかがわかったら、関数の検索をリダイレクトするために使用できる低レベルのObjCディスパッチ関数があると思います。少し前にやったと思いますが、詳細は思い出せません。

うまくいけば、私のヒントを使用して、これへのいくつかのソリューションパスをググることができます。幸運を。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.