ฉันพยายามที่จะถ่ายภาพในระหว่างการแสดงตัวอย่างสดจากกล้องโดย 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
จากไดเร็กทอรี 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
เมื่อคุณเรียก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;
}
ดูโพสต์นี้สำหรับคำตอบประเภทอื่น: จับภาพจากบัฟเฟอร์รูปภาพ การจับภาพหน้าจอระหว่างการแสดงตัวอย่างวิดีโอล้มเหลว
วิธีแก้ปัญหาเดียวที่เป็นไปได้ที่ฉันคิดได้คือปิดเสียง iphone เมื่อพวกเขากดปุ่ม "ถ่ายภาพ" จากนั้นจึงยกเลิกการปิดเสียงในวินาทีต่อมา
เคล็ดลับทั่วไปในกรณีเช่นนี้คือการตรวจสอบว่าเฟรมเวิร์กเรียกใช้วิธีการบางอย่างสำหรับเหตุการณ์นี้หรือไม่จากนั้นจึงเขียนทับเมธอดนั้นชั่วคราวจึงทำให้เอฟเฟกต์เป็นโมฆะ
ฉันขอโทษ แต่ฉันแฮ็คไม่ดีพอที่จะบอกคุณได้ทันทีว่ากรณีนี้ใช้ได้หรือไม่ คุณสามารถลองใช้คำสั่ง "nm" บนไฟล์เรียกทำงานของเฟรมเวิร์กเพื่อดูว่ามีฟังก์ชันที่ตั้งชื่อที่มีชื่อที่เหมาะสมหรือไม่หรือใช้ gdb กับ Simulator เพื่อติดตามว่าไปที่ใด
เมื่อคุณรู้ว่าจะเขียนทับอะไรแล้วมีฟังก์ชันการจัดส่ง ObjC ระดับต่ำที่คุณสามารถใช้เพื่อเปลี่ยนเส้นทางการค้นหาฟังก์ชันได้ฉันเชื่อว่า คิดว่าเคยทำมาแล้วครั้งหนึ่ง แต่จำรายละเอียดไม่ได้
หวังว่าคุณจะใช้คำแนะนำของฉันกับ Google ได้บ้าง โชคดี.