AVFoundation วิธีปิดเสียงชัตเตอร์เมื่อ captureStillImageAsynchronouslyFromConnection?


91

ฉันพยายามที่จะถ่ายภาพในระหว่างการแสดงตัวอย่างสดจากกล้องโดย AVFoundation captureStillImageAsynchronouslyFromConnection จนถึงตอนนี้โปรแกรมทำงานได้ตามที่คาดไว้ อย่างไรก็ตามฉันจะปิดเสียงชัตเตอร์ได้อย่างไร?


5
ตัวอย่างเช่นในญี่ปุ่นคุณไม่สามารถทำเช่นนั้นได้ เสียงชัตเตอร์จะดังอยู่เสมอแม้ว่าคุณจะปิดเสียงโทรศัพท์ก็ตาม (กฎแปลก ๆ บางอย่างเพื่อป้องกันการละเมิดความเป็นส่วนตัวหรือที่เรียกว่าการถ่ายภาพใต้กระโปรงมีอยู่ในญี่ปุ่นเท่าที่ฉันรู้) ดังนั้นฉันไม่คิดว่าจะมีวิธีทำเช่นนั้น
Dunkelstern

3
ใช่อาจเป็นไปได้ว่า iPhone ของคุณไม่อนุญาตให้ปิดเสียงกล้องถ่ายรูป ฉันอยู่ในสหรัฐอเมริกาและ iPhone ของฉันไม่ส่งเสียงเมื่อฉันถ่ายภาพโดยปิดเสียงโทรศัพท์ ในทางกลับกันแฟนของฉันส่งเสียง (เธอมาจากเกาหลี)
donkim

5
เพื่อความชัดเจนนี่เป็นวิธีแก้ปัญหาเมื่อโทรศัพท์ไม่ได้ปิดเสียง / โหมดสั่น ในโหมดนั้นจะไม่มีเสียงเมื่อถ่ายภาพ
New Alexandria

31
@NewAlexandria ฉันได้ยินเสียงชัตเตอร์ในญี่ปุ่นในโหมดกันสั่นด้วย นี่คือข้อกำหนดของกฎหมาย
k06a

3
Btw AudioServicesPlaySystemSound จะไม่เล่นหากปิดเสียงอุปกรณ์ ดังนั้นอุปกรณ์ของญี่ปุ่นจะยังคงส่งเสียงเมื่อปิดเสียง แต่จะไม่ส่งเสียงเมื่อไม่ได้ปิดเสียง ...
Filip Radelic

คำตอบ:


1502

ฉันใช้รหัสนี้หนึ่งครั้งเพื่อบันทึกเสียงชัตเตอร์เริ่มต้นของ 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 สำหรับ Mac) ขั้นตอนต่อไปฉันเปิดphotoShutter.cafในโปรแกรมแก้ไขเสียง Audacity และใช้เอฟเฟกต์ผกผันดูเหมือนว่าจะมีการซูมสูง:

ป้อนคำอธิบายภาพที่นี่

จากนั้นฉันบันทึกเสียงนี้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: แต่จะเป็นการจับภาพจริงๆ (ในระหว่างลำดับแฟลช) ให้เพิ่มผู้สังเกตการณ์คีย์ - ค่าใน self.stillImageOutput แทนสำหรับ keyPath 'capturingStillImage' เพื่อตรวจจับเมื่อการจับภาพเริ่มต้นอย่างแท้จริงจากนั้นเล่นเสียงผกผันในวิธีการเรียกกลับ
Jeff Mascia

16
นี่คือวิธีที่เครื่องบินทหารสมัยใหม่เอาชนะเรดาร์ นี่คือเหตุผลที่คุณไม่เห็นภาพเงา "รูปทรงล่องหน" ในการออกแบบเครื่องบินรบใหม่: มีชุดอุปกรณ์อิเล็กทรอนิกส์ที่จัดการกับสิ่งที่เป็นพื้นฐานของการเปลี่ยนเฟสที่เอาชนะเรดาร์ซึ่งถ่ายทอดสัญญาณซ้ำ
L0j1k

5
@ L0j1k: ขึ้นอยู่กับว่าคุณกำลังพูดถึงเรือล่องหนประเภทใด F22 an ilk ไม่สนใจที่จะถูกตรวจไม่พบ แต่ในการปลดล็อค ปัญหาเกี่ยวกับเทคโนโลยีการกะระยะคือคุณเห็นได้ชัดอย่างไม่น่าเชื่อจากตำแหน่งอื่น ๆ เนื่องจากพวกเขาจะไม่เห็นการกะแบบเดียวกัน
Guvante

13
นี่คือวิธีการทำงานของหูฟังตัดเสียงรบกวนยกเว้นว่าจะจับเสียงแบบเรียลไทม์
Daniel Serodio

4
สิ่งนี้ยอดเยี่ยมสำหรับ iOS7 แต่ไม่สามารถใช้งานได้บน iOS8 อีกต่อไปมีความคิดอย่างไรในการแก้ปัญหานี้บน iOS8
Ticko

36

โซลูชันของฉันใน 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

2
ให้มันยิง ฉันไม่มั่นใจว่ามันจะได้ผล แต่หวังว่าจะได้!
sudo rm -rf

7

ฉันสามารถทำให้สิ่งนี้ทำงานได้โดยใช้รหัสนี้ในฟังก์ชัน 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];

อย่าลืมทำตัวดีและเปิดเสียงเมื่อแอปของคุณกลับมา!


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); // หนึ่งเฟรมต่อวินาที

ใน 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;
}

คุณสามารถรับ AVCaptureVideoDataOutput ในขณะที่ใช้ AVCaptureMovieFileOutput ได้หรือไม่ เมื่อฉันพยายามใช้ทั้งสองวิธีจะไม่มีการเรียกวิธีการมอบหมายของ AVCaptureVideoDataOutput
Paul Cezanne

ขออภัยฉันไม่ได้พยายามให้มีเอาต์พุตมากกว่าหนึ่งรายการในเวลาเดียวกัน
ริเวร่า


0

วิธีแก้ปัญหาเดียวที่เป็นไปได้ที่ฉันคิดได้คือปิดเสียง iphone เมื่อพวกเขากดปุ่ม "ถ่ายภาพ" จากนั้นจึงยกเลิกการปิดเสียงในวินาทีต่อมา


วิธีปิดเสียง iPhone โดยทางโปรแกรม? ขอบคุณ!
ohho

แม้ว่าคุณจะทำได้ Apple ก็ไม่อนุมัติ

0

เคล็ดลับทั่วไปในกรณีเช่นนี้คือการตรวจสอบว่าเฟรมเวิร์กเรียกใช้วิธีการบางอย่างสำหรับเหตุการณ์นี้หรือไม่จากนั้นจึงเขียนทับเมธอดนั้นชั่วคราวจึงทำให้เอฟเฟกต์เป็นโมฆะ

ฉันขอโทษ แต่ฉันแฮ็คไม่ดีพอที่จะบอกคุณได้ทันทีว่ากรณีนี้ใช้ได้หรือไม่ คุณสามารถลองใช้คำสั่ง "nm" บนไฟล์เรียกทำงานของเฟรมเวิร์กเพื่อดูว่ามีฟังก์ชันที่ตั้งชื่อที่มีชื่อที่เหมาะสมหรือไม่หรือใช้ gdb กับ Simulator เพื่อติดตามว่าไปที่ใด

เมื่อคุณรู้ว่าจะเขียนทับอะไรแล้วมีฟังก์ชันการจัดส่ง ObjC ระดับต่ำที่คุณสามารถใช้เพื่อเปลี่ยนเส้นทางการค้นหาฟังก์ชันได้ฉันเชื่อว่า คิดว่าเคยทำมาแล้วครั้งหนึ่ง แต่จำรายละเอียดไม่ได้

หวังว่าคุณจะใช้คำแนะนำของฉันกับ Google ได้บ้าง โชคดี.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.