Метод GLKView.display() иногда вызывает сбой. EXC_BAD_ACCESS
Я пытаюсь реализовать приложение камеры в режиме реального времени с AVFoundation
, GLKit
а также Core Image
(не используется GPUImage
)
Итак, я нашел этот учебник
http://altitudelabs.com/blog/real-time-filter/
Он был написан на Objective-C, поэтому я переписал этот код в Swift4.0, XCode9
Казалось, работает нормально, но иногда (редко), он вылетал со следующей ошибкой. когда GLKView
"s display
метод был вызван
EXC_BAD_ACCESS(код =1, адреса +0x********)
Время сбоя, GLKView существует (не ноль), EAGLContext делает, CIContext делает. мой код следующий
импорт UIKit импорт AVFoundation импорт GLKit импорт класс OpenGLES ViewController: UIViewController { var videoDevice: AVCaptureDevice! var captureSession: AVCaptureSession! var captureSessionQueue: DispatchQueue! var videoPreviewView: GLKView! var ciContext: CIContext! var eaglContext: EAGLContext! var videoPreviewViewBounds: CGRect = CGRect.zero переопределить func viewDidLoad() { super.viewDidLoad() // Выполнить любую дополнительную настройку после загрузки представления, обычно с кончика. // удаляем цвет фона представления; это позволяет нам не использовать непрозрачное свойство (self.view.opaque = NO), так как мы полностью удаляем рисунок цвета фона self.view.backgroundColor = UIColor.clear // устанавливаем GLKView для просмотра видео / изображения, позволяя window: UIView = UIApplication.shared.delegate!.window!! eaglContext = EAGLContext(api: .openGLES2) videoPreviewView = GLKView(frame: videoPreviewViewBounds, context: eaglContext) videoPreviewView.enableSetNeedsDisplay = false //, потому что собственное видеоизображение с задней камеры находится в UIDeviceOrientationLeeLeNeLeGeLeGeLeLeLe) нам нужно применить преобразование по часовой стрелке на 90 градусов, чтобы мы могли нарисовать предварительный просмотр видео, как если бы мы были в альбомно-ориентированном виде; если вы используете фронтальную камеру и хотите иметь зеркальный предварительный просмотр (чтобы пользователь видел себя в зеркале), вам нужно применить дополнительный горизонтальный переворот (путем конкатенации CGAffineTransformMakeScale(-1.0, 1.0) к повороту transform) videoPreviewView.transform = CGAffineTransform(revolutionAngle: CGFloat.pi/2.0) videoPreviewView.frame = window.bounds // мы делаем наш предварительный просмотр видео подвидом окна и отправляем его обратно; это делает представление ViewController (и его элементы пользовательского интерфейса) поверх предварительного просмотра видео, а также делает просмотр видео незатронутым поворотом устройства window.addSubview(videoPreviewView) window.sendSubview(toBack: videoPreviewView) // привязывает буфер кадра, чтобы получить кадр ширина и высота буфера; // границы, используемые CIContext при рисовании в GLKView, указаны в пикселях (не в точках), // следовательно, необходимо считывать ширину и высоту буфера кадра; // кроме того, поскольку мы будем получать доступ к границам в другой очереди (_captureSessionQueue), // мы хотим получить этот фрагмент информации, чтобы не // получать доступ к свойствам _videoPreviewView из другого потока / очереди videoPreviewView.bindDrawable() videoPreviewViewBounds = CGRect.zero videoPreviewViewBounds.size.width = CGFloat(videoPreviewView.drawableWidth) videoPreviewViewBounds.size.height = CGFloat(videoPreviewView.drawableHeight) // создайте экземпляр CIContext, обратите внимание, что это должно быть выполнено после правильного задания cViewte = CIContext (eaglContext: eaglContext, параметры: [kCIContextWorkingColorSpace: NSNull()]), если AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera, .builtInTelephotoCamera, .Wide.Wide.Wide.Wide.Wide.Wide.Wide.Wide.Wide.Wide), VideoWide.Wide.WideAideVide.WideAWideAWideAg.We) > 0 { start() } else { print("Нет устройства с AVMediaTypeVideo") } } переопределить func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Удалить любое ресурсы, которые можно воссоздать. } func start() { let videoDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, позиция: .back).devices videoDevice = videoDevices.first var videoDeviceInput: AVCaptureInput! do { videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) } перехватить let error { print("Невозможно получить входные данные видеоустройства, error: \(error)") return } let preset = AVCaptureSession.Preset.high captureSession = AVCaptureSession() captureSession () captureSession.sessionPreset = предустановка // ядро изображения watns bgra формат пикселя пусть outputSetting = [String(kCVPixelBufferPixelFormatTypeKey): kCVPixelFormatType_32BGRA] // обрешетка и настройка выходных данных видео пусть videoDataOutput = AVCaptureVideoDataOutput() videoDataOutput.videoSettings = outputSetting // создание очереди отправки для обработки захват метод сессии делегат вызывает captureSessionQueue = DispatchQueue(ярлык: "capture_session_queue") videoDataOutput.setSampleBufferDelegate(самость, очереди: captureSessionQueue)! videoDataOutput.alwaysDiscardsLateVideoFrames = истина captureSession.beginConfiguration(), если captureSession.canAddOutput(videoDataOutput) {Print ("Невозможно добавить видео вывод данных ") captureSession = nil return } captureSession.addInput(videoDeviceInput) captureSession.addOutput(videoDataOutput) captureSession.commitConfiguration() captureSession.startRunning() } } расширение ViewController: AVCaptureVideoDataOutputSampleBufferDelegate {FUNC captureOutput(_ выход: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, от соединения: AVCaptureConnection) {пусть imageBuffer: CVImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! let sourceImage = CIImage(cvImageBuffer: imageBuffer, параметры: nil) CIVector(x: sourceExtent.size.width/2.0, y: sourceExtent.size.height/2.0), forKey: kCIInputCenterKey) vignetteFilter?.SetValue(sourceExtent.width/2.0, forKey: kCIInputRadiusKey), пусть selectedImage = vignetteFilter?.Output sourceAspect = sourceExtent.width/sourceExtent.height let previewAspect = videoPreviewViewBounds.width/videoPreviewViewBounds.height // мы хотим сохранить аспектное радио размера экрана, поэтому мы обрезаем видеоизображение var drawRect = sourceExtent, если sourceAspect > previewAspect { // использовать полную высоту видеоизображения и обрезать по центру ширину drawRect.origin.x += (drawRect.size.width - drawRect.size.height * previewAspect) / 2.0 drawRect.size.width = drawRect.size.height * previewAspect } else { // используем полную ширину видеоизображения и выравниваем по центру высоту drawRect.origin.y += (drawRect.size.height - drawRect.size.width / previewAspect) / 2.0; drawRect.size.height = drawRect.size.width / previewAspect; } videoPreviewView.bindDrawable() if eaglContext!= EAGLContext.current() { EAGLContext.setCurrent(eaglContext) } print("текущий поток \(Thread.current)") // очистить представление eagl до серого glClearColor(0.5, 0.5, 0.5 1,0); glClear(GLbitfield(GL_COLOR_BUFFER_BIT)); // устанавливаем режим наложения "source over", чтобы CI использовал этот glEnable(GLenum(GL_BLEND)); glBlendFunc(GLenum(GL_ONE), GLenum(GL_ONE_MINUS_SRC_ALPHA)); если позволено FilterImage = FilterImage { ciContext.draw(FilterImage, in: videoPreviewViewBounds, from: drawRect) } videoPreviewView.display() } }
И стек при сбое
* поток № 5, очередь = "com.apple.avfoundation.videodataoutput.bufferqueue", причина остановки = EXC_BAD_ACCESS (код =1, адрес =0x8000000000000000) frame #0: 0x00000001a496f098 AGXGLDriver`___lldb_unnamed_symbol149$$AGXGLDriver + 332 frame #1: 0x00000001923c029c OpenGLES`-[EAGLContext getParameter:to:] + 80 кадр № 2: 0x000000010038bca4 libglInterpose.dylib`__clang_call_terminate + 1976832 кадр № 3: 0x00000001001ab75c libglInterpose.dylib`__clang_call_terminate + 9400 кадр № 4: 0x000000010038b8b4 libglInterpose.dylib`__clang_call_terminate + 1975824 кадр № 5: 0x00000001001af098 libglInterpose.dylib`__clang_call_terminate + 24052 кадр № 6: 0x00000001001abe5c libglInterpose.dylib`__clang_call_terminate + 11192 кадр № 7: 0x000000010038f9dc libglInterpose.dylib`__clang_call_terminate + 1992504 кадр № 8: 0x000000010038d5b8 libglInterpose.dylib`__clang_call_terminate + 1983252 кадр № 9: 0x000000019a1e2a20 GLKit`-[GLKView _display:] + 308 * frame #10: 0x0000000100065e78 RealTimeCameraPractice`ViewController.captureOutput(output=0x0000000174034820, sampleBuffer=0x0000000119e25e70, соединение =0x0000000174008850, self=0x0000000119sw0d:160: 0:160 кадр № 11: 0x00000001000662dc RealTimeCameraPractice`@objc ViewController.captureOutput(_:didOutput:from:) в ViewController.swift:0 кадр № 12: 0x00000001977ec310 AVFoundation`-[AVCaptureVideoDataOutput _handleRemoteQueueOperation:] + 308 кадр № 13: 0x00000001977ec14c AVFoundation`__47-[AVCaptureVideoDataOutput _updateRemoteQueue:]_block_invoke + 100 frame #14: 0x00000001926bdf38 CoreMedia`__FigRemoteOperationReceiverCreateMessageReceiver_block_invoke + 260 frame #15: 0x00000001926dce9c CoreMedia`__FigRemoteQueueReceiverSetHandler_block_invoke.2 + 224 frame #16: 0x000000010111da10 libdispatch.dylib`_dispatch_client_callout + 16 кадр № 17: 0x0000000101129a84 libdispatch.dylib`_dispatch_continuation_pop + 552 кадр № 18: 0x00000001011381f8 libdispatch.dylib`_dispatch_source_latch_and_call + 204 кадр № 19: 0x000000010111fa60 libdispatch.dylib`_dispatch_source_invoke + 828 кадр № 20: 0x000000010112b128 libdispatch.dylib`_dispatch_queue_serial_drain + 692 кадр № 21: 0x0000000101121634 libdispatch.dylib`_dispatch_queue_invoke + 852 кадр № 22: 0x000000010112b128 libdispatch.dylib`_dispatch_queue_serial_drain + 692 кадр № 23: 0x0000000101121634 libdispatch.dylib`_dispatch_queue_invoke + 852 кадр № 24: 0x000000010112c358 libdispatch.dylib`_dispatch_root_queue_drain_deferred_item + 276 кадр № 25: 0x000000010113457c libdispatch.dylib`_dispatch_kevent_worker_thread + 764 кадр № 26: 0x000000018ee56fbc libsystem_pthread.dylib`_pthread_wqthread + 772 кадр № 27: 0x000000018ee56cac libsystem_pthread.dylib`start_wqthread + 4
Мой проект в github
https://github.com/hegrecom/iOS-RealTimeCameraPractice
1 ответ
Вот решение: iOS 11 beta 4 присутствует крушение Renderbuffer
Перейдите в Управление схемами-> Параметры-> Захват кадров GPU-> Отключено