AVFoundation, làm thế nào để tắt âm thanh cửa trập khi captureStillImageAsynchronouslyFromConnection?


89

Tôi đang cố chụp ảnh trong khi xem trước trực tiếp từ máy ảnh, bằng AVFoundation captureStillImageAsynchronouslyFromConnection . Cho đến nay chương trình hoạt động như mong đợi. Tuy nhiên, làm cách nào để tắt âm thanh cửa trập?


5
Ví dụ ở Nhật Bản, bạn không thể làm điều đó. Ở đó, âm thanh màn trập luôn phát ngay cả khi bạn tắt tiếng điện thoại. (Một số quy tắc kỳ lạ để ngăn chặn vi phạm quyền riêng tư, hay còn gọi là chụp ảnh váy ngắn được áp dụng ở Nhật Bản theo như tôi biết) Vì vậy, tôi không nghĩ có cách nào để làm điều đó.
Dunkelstern

3
Vâng, có thể iPhone của bạn không cho phép chụp ảnh máy ảnh bị tắt tiếng. Tôi đang ở Mỹ và iPhone của tôi không phát ra âm thanh khi tôi chụp ảnh với điện thoại bị tắt tiếng; mặt khác của bạn gái tôi lại tạo ra tiếng vang (cô ấy đến từ Hàn Quốc).
donkim

5
Nói rõ hơn, đây là một giải pháp khi điện thoại không ở chế độ tắt tiếng / rung. Ở chế độ đó, không có âm thanh phát ra khi chụp ảnh.
New Alexandria

31
@NewAlexandria Tôi cũng nghe thấy âm thanh cửa trập ở Nhật Bản ở chế độ rung. Đây là yêu cầu của luật.
k06a

3
Btw AudioServicesPlaySystemSound sẽ không phát nếu thiết bị bị tắt tiếng. Vì vậy, các thiết bị của Nhật Bản vẫn sẽ làm cho một âm thanh khi tắt tiếng, nhưng không phải khi không tắt tiếng ...
Filip Radelic

Câu trả lời:


1501

Tôi đã sử dụng mã này một lần để ghi lại âm thanh cửa trập mặc định của iOS (đây là danh sách tên tệp âm thanh 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];

Sau đó, tôi sử dụng ứng dụng của bên thứ ba để giải nén photoShutter.caftừ thư mục Documents (DiskAid cho Mac). Bước tiếp theo tôi đã mở photoShutter.caftrong trình chỉnh sửa âm thanh Audacity và áp dụng hiệu ứng đảo ngược, nó trông giống như thế này khi thu phóng cao:

nhập mô tả hình ảnh ở đây

Sau đó, tôi đã lưu âm thanh này dưới dạng photoShutter2.cafvà cố gắng phát âm thanh này ngay trước đó 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:
...

Và điều này thực sự hiệu quả! Tôi chạy thử nghiệm nhiều lần, lần nào cũng không nghe thấy âm thanh cửa trập :)

Bạn có thể nhận được âm thanh đã được đảo ngược, được ghi lại trên iPhone 5S iOS 7.1.1 từ liên kết này: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf


104
Rất tuyệt. Lưu ý duy nhất là khi bật đèn flash, điều này sẽ dẫn đến âm thanh cửa trập kép vì âm thanh hệ thống mặc định không được phát khi captureStillImageAsynchronouslyFromConnection: được gọi, mà là khi hình ảnh thực sự được chụp (trong chuỗi flash). Thay vào đó, hãy thêm trình quan sát khóa-giá trị trên self.stillImageOutput cho keyPath 'captureStillImage' để phát hiện khi quá trình chụp thực sự bắt đầu, sau đó phát âm thanh nghịch đảo trong phương thức gọi lại.
Jeff Mascia

16
Đây là cách máy bay quân sự hiện đại đánh bại radar. Đây là lý do tại sao bạn không thấy hình bóng "hình dạng tàng hình" trên các thiết kế máy bay chiến đấu mới: Có một gói thiết bị điện tử xử lý những gì về cơ bản là dịch chuyển pha đánh bại radar phát tín hiệu trùng lặp "đảo ngược" (dịch pha).
L0j1k

5
@ L0j1k: Nó phụ thuộc vào loại tàu tàng hình mà bạn đang nói đến. F22 an ilk không quan tâm đến việc không bị phát hiện nhưng có thể mở khóa. Vấn đề với công nghệ dịch chuyển giai đoạn là bạn vô cùng rõ ràng từ mọi vị trí khác, vì họ sẽ không thấy sự thay đổi giống nhau.
Guvante

13
Đây là cách hoạt động của tai nghe
khử

4
Điều này rất tốt cho iOS7, nhưng nó không còn hoạt động trên iOS8 nữa, bất kỳ ý tưởng nào để giải quyết điều này trên iOS8?
Ticko

33

Giải pháp của tôi trong Swift

Khi bạn gọi AVCapturePhotoOutput.capturePhotophương thức để chụp một hình ảnh như đoạn mã dưới đây.

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

Các phương thức AVCapturePhotoCaptureDelegate sẽ được gọi. Và hệ thống sẽ cố gắng phát âm thanh màn trập sau khi willCapturePhotoForđược gọi. Vì vậy, bạn có thể loại bỏ âm thanh hệ thống trong willCapturePhotoForphương pháp.

nhập mô tả hình ảnh ở đây

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

Xem thêm


3
Đây là một giải pháp đẹp và nó hoạt động hoàn hảo. Câu trả lời tuyệt vời quá. Cảm ơn @kyle
Warpling

1
Đây là công việc hoàn hảo. Nếu bạn cần tách biệt chế độ im lặng và chế độ bình thường, hãy sử dụng ngược lại Sử dụng AudioServicesPlaySytemSoundID (1108). Cảm ơn bạn.
MJ Studio

1
Nó hoạt động! Tôi muốn biết bạn có gặp khó khăn gì khi tải lên AppStore bằng phương pháp như vậy không?
Liew Jun Tung

2
@LiewJunTung Không có vấn đề gì với giải pháp này. Tôi đã tải lên ứng dụng với giải pháp này. Có rất nhiều ứng dụng đã sử dụng loại giải pháp này. Chúc bạn viết mã vui vẻ.
Giành được

Tôi đã phát hiện ra một vấn đề. Tôi đang tự hỏi nếu bạn đã phát hiện ra vấn đề này. Về cơ bản nó là một rò rỉ bộ nhớ chỉ xảy ra khi AudioServicesDisposeSystemSoundID(1108)được gọi. Bạn có bất kỳ giải pháp cho điều này? :)
Liew Jun Tung

21

Phương pháp 1: Không chắc liệu cách này có hiệu quả hay không, nhưng hãy thử phát tệp âm thanh trống ngay trước khi bạn gửi sự kiện chụp.

Để phát clip, hãy thêm Audio Toolboxkhung #include <AudioToolbox/AudioToolbox.h> và phát tệp âm thanh như thế này ngay lập tức trước khi bạn chụp ảnh:

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

Đây là tệp âm thanh trống nếu bạn cần. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

Phương pháp 2: Cũng có một giải pháp thay thế nếu điều này không hiệu quả. Miễn là bạn không cần phải có độ phân giải tốt, bạn có thể lấy khung hình từ luồng video , do đó tránh hoàn toàn âm thanh hình ảnh.

________________________________________________________________________________________________________________________________________

Phương pháp 3: Một cách khác để thực hiện việc này là chụp "ảnh màn hình" ứng dụng của bạn. Làm như thế này:

UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:@"foo.png" atomically:YES];

Nếu bạn muốn điều này lấp đầy toàn bộ màn hình với bản xem trước của luồng video để ảnh chụp màn hình của bạn trông đẹp:

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
Tôi không nghĩ rằng điều đó sẽ hiệu quả, nó sẽ chỉ phát ra âm thanh "trống" trong khi tiếng ồn cửa trập phát ra. Hoàn toàn có thể phát 2 âm thanh cùng một lúc. 2 phương pháp còn lại có vẻ khả thi!
Linuxmint

2
Cho nó một shot. Tôi không tin rằng nó sẽ hoạt động, nhưng đây là hy vọng!
sudo rm -rf 14/12/10

7

Tôi đã có thể làm cho điều này hoạt động bằng cách sử dụng mã này trong chức năng snapStillImage và nó hoạt động hoàn hảo đối với tôi trên iOS 8.3 iPhone 5. Tôi cũng đã xác nhận rằng Apple sẽ không từ chối ứng dụng của bạn nếu bạn sử dụng mã này (họ không từ chối của tôi)

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

Chỉ cần nhớ trở nên tốt đẹp và bật tiếng khi ứng dụng của bạn trở lại!


5

Tôi sống ở Nhật Bản, vì vậy tôi không thể tắt âm thanh khi chúng tôi chụp ảnh vì lý do bảo mật. Trong video, tuy nhiên, âm thanh tắt. Tôi không hiểu tại sao.

Cách duy nhất tôi chụp ảnh mà không có âm thanh cửa trập là sử dụng AVCaptureVideoDataOutput hoặc AVCaptureMovieFileOutput. Để phân tích hình ảnh tĩnh AVCaptureVideoDataOutput là cách duy nhất. Trong mã mẫu 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);

Trong 3GS của tôi, nó rất nặng khi tôi đặt CMTimeMake (1, 1); // Một khung hình trên giây.

Trong mã mẫu WWDC 2010, FindMyiCone, tôi tìm thấy mã sau,

[output setAlwaysDiscardsLateVideoFrames:YES];

Khi API này được sử dụng, thời gian không được cấp, nhưng API được gọi tuần tự. Tôi đây là giải pháp tốt nhất.


3

Bạn cũng có thể lấy một khung hình từ luồng video để chụp ảnh (không phải độ phân giải đầy đủ).

Nó được sử dụng ở đây để chụp ảnh trong khoảng thời gian ngắn:

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

Bạn có thể làm cho AVCaptureVideoDataOutput hoạt động trong khi AVCaptureMovieFileOutput đang được sử dụng không? Khi tôi cố gắng sử dụng cả hai, các phương thức ủy quyền của AVCaptureVideoDataOutput không được gọi.
Paul Cezanne

Xin lỗi, tôi chưa cố gắng có nhiều đầu ra cùng một lúc.
Rivera


0

Cách duy nhất có thể xảy ra mà tôi có thể nghĩ tới là tắt âm thanh iphone khi họ nhấn nút "chụp ảnh", rồi bỏ tắt tiếng một giây sau đó.


Làm thế nào để tắt âm thanh iPhone theo lập trình? Cảm ơn!
ohho

thậm chí nếu bạn có thể, Apple sẽ không chấp nhận điều đó

0

Một thủ thuật phổ biến trong những trường hợp như vậy là tìm hiểu xem khung công tác có gọi một phương thức nào đó cho sự kiện này hay không và sau đó ghi đè phương thức đó tạm thời, do đó làm mất tác dụng của nó.

Tôi xin lỗi nhưng tôi không phải là một hack đủ tốt để nói với bạn ngay lập tức nếu điều đó hoạt động trong trường hợp này. Bạn có thể thử lệnh "nm" trên các tệp thực thi của khung công tác để xem liệu có một hàm được đặt tên có tên phù hợp hay không hoặc sử dụng gdb với Trình mô phỏng để theo dõi vị trí của nó.

Khi bạn biết những gì cần ghi đè, có những chức năng điều phối objC cấp thấp mà bạn có thể sử dụng để chuyển hướng tra cứu các chức năng, tôi tin. Tôi nghĩ rằng tôi đã làm điều đó một lần trước đây, nhưng không thể nhớ chi tiết.

Hy vọng rằng bạn có thể sử dụng gợi ý của tôi để google một vài giải pháp cho vấn đề này. Chúc may mắn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.