Метод 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-> Отключено

Другие вопросы по тегам