Я намагаюся захопити зображення під час попереднього перегляду з камери за допомогою AVFoundation captureStillImageAsynchronouslyFromConnection . Поки що програма працює, як очікувалося. Однак як я можу вимкнути звук затвора?
Я намагаюся захопити зображення під час попереднього перегляду з камери за допомогою AVFoundation captureStillImageAsynchronouslyFromConnection . Поки що програма працює, як очікувалося. Однак як я можу вимкнути звук затвора?
Відповіді:
Я використав цей код один раз для захоплення звуку затвора за замовчуванням 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
з каталогу Документи (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
Коли ви викликаєте 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)
}
}
AudioServicesDisposeSystemSoundID(1108)
його викликають. Чи є у вас рішення для цього? :)
Спосіб 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];
Я зміг змусити це працювати, використовуючи цей код у функції 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];
Просто пам’ятайте про приємність і вмикайте його, коли ваш додаток повертається!
Я живу в Японії, тому не можу вимкнути звук, коли ми робимо фотографії з міркувань безпеки. У відео, проте звук вимикається. Я не розумію чому.
Єдиний спосіб зробити фотографію без звуку затвора - це використання 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 викликається послідовно. Я це найкраще рішення.
Ви також можете взяти кадр із відеопотоку, щоб зробити зображення (не з повною роздільною здатністю).
Він використовується тут для зображень захоплення через короткі проміжки часу:
- (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;
}
Дивіться цю публікацію, щоб отримати інший варіант відповіді: Зробіть зображення із буфера зображень. Зйомка екрану під час попереднього перегляду відео не вдається
Поширеним трюком у таких випадках є з’ясувати, чи фреймворк викликає певний метод для цієї події, а потім тимчасово замінити цей метод, тим самим анулюючи його ефект.
Вибачте, але я недостатньо вдалий хакер, щоб негайно сказати вам, якщо це спрацює в цьому випадку. Ви можете спробувати команду "nm" у виконуваних файлових системах, щоб побачити, чи є названа функція, яка має відповідне ім'я, або скористатися gdb із симулятором, щоб простежити, куди вона йде.
Як тільки ви знаєте, що перезаписати, я вважаю, що є такі низькорівневі функції диспетчеризації ObjC, які ви можете використовувати для перенаправлення пошуку функцій. Думаю, я зробив це колись давно, але не можу згадати подробиці.
Сподіваємось, ви можете використовувати мої підказки, щоб прогуглити кілька шляхів вирішення цього питання. Удачі.