AVFoundation, bagaimana cara mematikan suara rana saat captureStillImageAsynchronouslyFromConnection?

90

Saya mencoba untuk menangkap gambar selama pratinjau langsung dari kamera, dengan AVFoundation captureStillImageAsynchronouslyFromConnection . Sejauh ini program berjalan sesuai harapan. Namun demikian, bagaimana cara membungkam suara rana?

ohho
sumber
5
Di Jepang misalnya Anda tidak bisa melakukan itu. Di sana, suara rana selalu diputar bahkan jika Anda mematikan telepon. (Sejauh yang saya tahu, beberapa aturan aneh untuk mencegah pelanggaran privasi, alias fotografi upskirt ada di Jepang) Jadi menurut saya tidak ada cara untuk melakukan itu.
Dunkelstern
3
Ya, mungkin iPhone Anda tidak mengizinkan jepretan kamera tanpa suara. Saya berada di AS dan iPhone saya tidak bersuara saat saya mengambil gambar dengan telepon dibisukan; pacar saya, di sisi lain, mengeluarkan suara (miliknya berasal dari Korea).
donkim
5
Untuk lebih jelasnya, ini adalah solusi ketika ponsel tidak dalam mode mute / getar. Dalam mode itu, tidak ada suara yang keluar saat mengambil gambar.
Aleksandria Baru
31
@NewAlexandria Saya mendengar suara rana di Jepang dalam mode getar juga. Ini adalah persyaratan hukum.
k06a
3
Btw AudioServicesPlaySystemSound tidak akan diputar jika perangkat dibisukan. Jadi perangkat Jepang masih akan mengeluarkan suara saat dimatikan, tetapi tidak saat tidak dimatikan ...
Filip Radelic

Jawaban:

1500

Saya menggunakan kode ini sekali untuk menangkap suara rana default iOS (berikut adalah daftar nama file suara 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];

Kemudian saya menggunakan aplikasi pihak ketiga untuk mengekstrak photoShutter.cafdari direktori Dokumen (DiskAid untuk Mac). Langkah selanjutnya saya buka photoShutter.cafdi editor audio Audacity dan menerapkan efek inversi, terlihat seperti ini pada zoom tinggi:

masukkan deskripsi gambar di sini

Kemudian saya menyimpan suara ini photoShutter2.cafdan mencoba memutar suara ini sebelumnya 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:
...

Dan ini benar-benar berhasil! Saya menjalankan tes beberapa kali, setiap kali saya tidak mendengar suara rana :)

Anda bisa mendapatkan suara yang sudah terbalik, ditangkap di iPhone 5S iOS 7.1.1 dari tautan ini: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf

k06a
sumber
104
Sangat keren. Satu-satunya peringatan adalah saat flash dinyalakan, ini akan menghasilkan suara rana ganda karena suara sistem default tidak diputar saat captureStillImageAsynchronouslyFromConnection: dipanggil, melainkan saat gambar benar-benar diambil (selama urutan flash). Sebagai gantinya, tambahkan pengamat nilai kunci pada self.stillImageOutput untuk keyPath 'capturingStillImage' guna mendeteksi kapan pengambilan benar-benar dimulai, lalu putar suara inversi dalam metode callback.
Jeff Mascia
16
Inilah cara pesawat militer modern mengalahkan radar. Inilah sebabnya mengapa Anda tidak melihat siluet "bentuk siluman" pada desain pesawat tempur baru: Ada paket elektronik yang menangani apa yang pada dasarnya adalah pergeseran fase yang mengalahkan radar yang menyiarkan sinyal duplikat "terbalik" (pergeseran fase).
L0j1k
5
@ L0j1k: Itu tergantung pada jenis kapal siluman yang Anda bicarakan. F22 sejenisnya tidak tertarik untuk tidak terdeteksi tetapi tidak dapat dibuka kuncinya. Masalah dengan teknologi pergeseran fasa adalah Anda sangat jelas terlihat dari setiap posisi lain, karena mereka tidak akan melihat pergeseran yang sama.
Guvante
13
Beginilah cara kerja headphone peredam bising, kecuali headphone ini menangkap suara secara realtime
Daniel Serodio
4
Ini bagus untuk iOS7, tetapi tidak lagi berfungsi di iOS8, ada ide bagaimana menyelesaikannya di iOS8?
Centang
36

Solusi Saya di Swift

Ketika Anda memanggil AVCapturePhotoOutput.capturePhotometode untuk menangkap gambar seperti kode di bawah ini.

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

Metode AVCapturePhotoCaptureDelegate akan dipanggil. Dan sistem mencoba memutar suara rana setelah willCapturePhotoFordipanggil. Jadi Anda dapat membuang suara sistem dalam willCapturePhotoFormetode.

masukkan deskripsi gambar di sini

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {

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

Lihat juga

Won
sumber
3
Ini adalah solusi yang bagus dan bekerja dengan sempurna. Jawaban yang bagus juga. Terima kasih @kyle
Warpling
1
Ini bekerja dengan sempurna. Jika Anda perlu memisahkan mode diam dan mode normal, Gunakan AudioServicesPlaySytemSoundID (1108) secara terbalik. Terima kasih.
MJ Studio
1
Berhasil! Saya ingin tahu apakah Anda mengalami masalah saat mengunggah ke AppStore dengan metode seperti itu?
Liew Jun Tung
2
@LiewJunTung Tidak ada masalah dengan solusi ini. Saya sudah mengunggah aplikasi dengan solusi ini. Ada banyak aplikasi yang menggunakan solusi semacam ini. Selamat membuat kode.
Menang
Saya telah menemukan masalah. Saya ingin tahu apakah Anda telah menemukan masalah ini. Ini pada dasarnya adalah kebocoran memori yang hanya terjadi saat AudioServicesDisposeSystemSoundID(1108)dipanggil. Apakah Anda punya solusi untuk ini? :)
Liew Jun Tung
21

Metode 1: Tidak yakin apakah ini akan berhasil, tetapi coba putar file audio kosong tepat sebelum Anda mengirim acara pengambilan.

Untuk memutar klip, tambahkan Audio Toolboxkerangka kerja, #include <AudioToolbox/AudioToolbox.h> dan putar file audio seperti ini segera sebelum Anda mengambil gambar:

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

Ini adalah file audio kosong jika Anda membutuhkannya. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

Metode 2: Ada juga alternatif jika ini tidak berhasil. Selama Anda tidak perlu memiliki resolusi yang bagus, Anda dapat mengambil bingkai dari aliran video , sehingga menghindari suara gambar sama sekali.

________________________________________________________________________________________________________________________________________

Metode 3: Cara lain untuk melakukannya adalah dengan mengambil "tangkapan layar" dari aplikasi Anda. Lakukan dengan cara ini:

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

Jika Anda ingin ini memenuhi seluruh layar dengan pratinjau aliran video sehingga tangkapan layar Anda terlihat bagus:

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];
sudo rm -rf
sumber
2
Saya tidak berpikir itu akan berhasil, itu hanya akan memainkan suara "kosong" saat kebisingan rana diputar. Sangat mungkin untuk memainkan 2 suara pada saat yang bersamaan. 2 metode lainnya tampaknya bisa diterapkan!
Linuxmint
2
Cobalah. Saya tidak yakin itu akan berhasil, tapi saya berharap!
sudo rm -rf
7

Saya bisa membuat ini berfungsi dengan menggunakan kode ini di fungsi snapStillImage dan berfungsi dengan sempurna untuk saya di iOS 8.3 iPhone 5. Saya juga telah mengonfirmasi bahwa Apple tidak akan menolak aplikasi Anda jika Anda menggunakan ini (mereka tidak menolak Milikku)

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

Ingatlah untuk bersikap baik dan menyuarakannya saat aplikasi Anda kembali!

frakman1
sumber
5

Saya tinggal di Jepang, jadi saya tidak dapat menonaktifkan audio saat kami mengambil foto untuk alasan keamanan. Dalam video, bagaimanapun audio dimatikan. Saya tidak mengerti kenapa.

Satu-satunya cara saya mengambil foto tanpa suara rana adalah menggunakan AVCaptureVideoDataOutput atau AVCaptureMovieFileOutput. Untuk menganalisis gambar diam AVCaptureVideoDataOutput hanya cara. Dalam kode contoh 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);

Di 3GS saya, ini sangat berat ketika saya mengatur CMTimeMake (1, 1); // Satu frame per detik.

Dalam kode Contoh WWDC 2010, FindMyiCone, saya menemukan kode berikut,

[output setAlwaysDiscardsLateVideoFrames:YES];

Saat API ini digunakan, waktunya tidak diberikan, tetapi API dipanggil secara berurutan. Saya ini adalah solusi terbaik.

Ben
sumber
3

Anda juga dapat mengambil bingkai dari aliran video untuk mengambil gambar (bukan resolusi penuh).

Ini digunakan di sini untuk mengambil gambar dalam interval pendek:

- (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;
}
Rivera
sumber
Apakah Anda bisa membuat AVCaptureVideoDataOutput bekerja saat AVCaptureMovieFileOutput sedang digunakan? Ketika saya mencoba menggunakan keduanya, metode delegasi AVCaptureVideoDataOutput tidak dipanggil.
Paul Cezanne
Maaf, saya belum mencoba memiliki lebih dari satu keluaran pada waktu yang sama.
Rivera
0

Satu-satunya solusi yang mungkin saya pikirkan adalah mematikan suara iphone saat mereka menekan tombol "ambil gambar", dan kemudian mengaktifkannya beberapa saat kemudian.

Linuxmint
sumber
Bagaimana cara mematikan suara iPhone secara terprogram? Terima kasih!
ohho
bahkan jika Anda bisa, Apple tidak akan menyetujuinya
0

Trik umum dalam kasus seperti itu adalah mencari tahu apakah kerangka kerja memanggil metode tertentu untuk kejadian ini, dan kemudian menimpa metode itu untuk sementara, sehingga menghilangkan efeknya.

Saya minta maaf, tetapi saya bukan peretas yang cukup baik untuk segera memberi tahu Anda apakah itu berhasil dalam kasus ini. Anda dapat mencoba perintah "nm" pada kerangka kerja yang dapat dieksekusi untuk melihat apakah ada fungsi bernama yang memiliki nama yang sesuai, atau gunakan gdb dengan Simulator untuk melacak kemana perginya.

Setelah Anda tahu apa yang harus ditimpa, ada fungsi pengiriman ObjC tingkat rendah yang dapat Anda gunakan untuk mengarahkan pencarian fungsi, saya yakin. Saya pikir saya telah melakukannya sekali beberapa waktu yang lalu, tetapi tidak dapat mengingat detailnya.

Mudah-mudahan, Anda dapat menggunakan petunjuk saya ke google beberapa jalur solusi untuk ini. Semoga berhasil.

Thomas Tempelmann
sumber