AVFoundation yakalamaStillImageAsynchronouslyFromConnection ile kameradan canlı önizleme sırasında bir görüntü yakalamaya çalışıyorum . Şimdiye kadar program beklendiği gibi çalışıyor. Ancak, deklanşör sesini nasıl kapatabilirim?
AVFoundation yakalamaStillImageAsynchronouslyFromConnection ile kameradan canlı önizleme sırasında bir görüntü yakalamaya çalışıyorum . Şimdiye kadar program beklendiği gibi çalışıyor. Ancak, deklanşör sesini nasıl kapatabilirim?
Yanıtlar:
Bu kodu bir kez iOS varsayılan deklanşör sesini yakalamak için kullandım (ses dosyası adlarının listesi 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];
Ardından photoShutter.caf
Belgeler dizininden (Mac için DiskAid) ayıklamak için üçüncü taraf uygulamasını kullandım . Bir sonraki adım photoShutter.caf
Audacity ses düzenleyicide açtım ve ters çevirme efekti uyguladım, yüksek yakınlaştırmada şöyle görünüyor:
Sonra bu sesi olarak kaydettim photoShutter2.caf
ve bu sesi hemen önce çalmaya çalıştım 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:
...
Ve bu gerçekten işe yarıyor! Her defasında deklanşör sesi duymadığımda birkaç kez test çalıştırıyorum :)
Bu bağlantıdan iPhone 5S iOS 7.1.1'de yakalanmış halihazırda ters çevrilmiş sesi alabilirsiniz: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf
AVCapturePhotoOutput.capturePhoto
Aşağıdaki kod gibi bir görüntüyü yakalamak için yöntemi çağırdığınızda .
photoOutput.capturePhoto(with: self.capturePhotoSettings, delegate: self)
AVCapturePhotoCaptureDelegate yöntemleri çağrılacaktır. Ve sistem willCapturePhotoFor
çağrıldıktan sonra deklanşör sesini çalmaya çalışır . Böylece sistem sesini willCapturePhotoFor
yöntemde atabilirsiniz .
extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
// dispose system shutter sound
AudioServicesDisposeSystemSoundID(1108)
}
}
AudioServicesDisposeSystemSoundID(1108)
arandığında meydana gelen bir hafıza sızıntısıdır . Bunun için herhangi bir çözümünüz var mı? :)
Yöntem 1: Bunun işe yarayıp yaramayacağından emin değilim, ancak yakalama olayını göndermeden hemen önce boş bir ses dosyası çalmayı deneyin.
Bir klibi oynatmak için Audio Toolbox
çerçeveyi ekleyin #include <AudioToolbox/AudioToolbox.h>
ve ses dosyasını fotoğrafı çekmeden hemen önce şu şekilde oynatın :
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank" ofType:@"wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
İhtiyacınız olursa işte boş bir ses dosyası. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav
________________________________________________________________________________________________________________________________________
Yöntem 2: Bu işe yaramazsa bir alternatif de var. İyi bir çözünürlüğe ihtiyacınız olmadığı sürece , video akışından bir kare yakalayabilir , böylece görüntü sesini tamamen önleyebilirsiniz .
________________________________________________________________________________________________________________________________________
Yöntem 3: Bunu yapmanın başka bir yolu da uygulamanızın "ekran görüntüsünü" almaktır. Bunu şu şekilde yapın:
UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:@"foo.png" atomically:YES];
Bunun, ekran görüntüsünün iyi görünmesi için video akışının önizlemesiyle tüm ekranı doldurmasını istiyorsanız:
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];
SnapStillImage işlevinde bu kodu kullanarak bunu çalıştırmayı başardım ve benim için iOS 8.3 iPhone 5'te mükemmel çalışıyor. Ayrıca, bunu kullanırsanız Apple'ın uygulamanızı reddetmeyeceğini de doğruladım (reddetmediler benim)
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];
Nazik davranmayı ve uygulamanız geri geldiğinde sesini açmayı unutmayın!
Japonya'da yaşıyorum, bu yüzden güvenlik nedeniyle fotoğraf çekerken sesi kapatamıyorum. Videoda, ancak ses kapanıyor. Nedenini anlamıyorum
Deklanşör sesi olmadan fotoğraf çekmemin tek yolu AVCaptureVideoDataOutput veya AVCaptureMovieFileOutput kullanmaktır. Sabit görüntüyü analiz etmek için AVCaptureVideoDataOutput tek yoldur. AVFoundatation örnek kodunda,
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'mde CMTimeMake (1, 1) 'i ayarladığımda çok ağır; // Saniyede bir kare.
WWDC 2010 Örnek kodunda, FindMyiCone, aşağıdaki kodu buldum,
[output setAlwaysDiscardsLateVideoFrames:YES];
Bu API kullanıldığında, zamanlama verilmez, ancak API sıralı olarak çağrılır. Ben bu en iyi çözüm.
Ayrıca (tam çözünürlüklü olmayan) bir görüntüyü yakalamak için video akışından bir kare de alabilirsiniz.
Burada kısa aralıklarla fotoğraf çekmek için kullanılır :
- (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;
}
Farklı bir cevap türü için bu gönderiye bakın: Görüntü arabelleğinden görüntüyü yakalayın. Video önizlemesi sırasında ekran yakalama başarısız oluyor
Bu tür durumlarda yaygın bir hile, çerçevenin bu olay için belirli bir yöntemi çağırıp çağırmadığını bulmak ve ardından geçici olarak bu yöntemin üzerine yazmak ve böylece etkisini geçersiz kılmaktır.
Üzgünüm ama bu durumda işe yarayıp yaramadığını size hemen söyleyecek kadar iyi bir bilgisayar korsanlığı değilim. Uygun bir ada sahip adlandırılmış bir işlev olup olmadığını görmek için çerçeve çalıştırılabilirlerinde "nm" komutunu deneyebilir veya nereye gittiğini izlemek için Simülatör ile gdb'yi kullanabilirsiniz.
Neyin üzerine yazılacağını öğrendikten sonra, işlev aramayı yeniden yönlendirmek için kullanabileceğiniz düşük seviyeli ObjC gönderme işlevleri olduğuna inanıyorum. Sanırım bunu bir süre önce yaptım ama ayrıntıları hatırlayamıyorum.
Umarım, ipuçlarımı bunun için birkaç çözüm yolunu Google'da kullanmak için kullanabilirsiniz. İyi şanslar.