Почему мой AVVideoCapturePreview не отображается в слое?

#swiftui #avfoundation #swift5 #ios-camera

#swiftui #avfoundation #swift5 #ios-камера

Вопрос:

Я пытаюсь реализовать предварительный просмотр камеры в SwiftUI, для чего у меня есть следующий код:

 import SwiftUI
import AVFoundation

struct CameraPreview: UIViewRepresentable {
    let session: AVCaptureSession
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        view.backgroundColor = .gray

        let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
        videoPreviewLayer.frame = view.bounds
        videoPreviewLayer.videoGravity = .resizeAspectFill
        videoPreviewLayer.connection?.videoOrientation = .portrait

        view.layer.addSublayer(videoPreviewLayer)

        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        for layer in uiView.layer.sublayers ?? [] {
            layer.frame = uiView.bounds
        }
    }
}
 

Однако я вижу вид серого фона, который я установил в представлении, но он никогда не начинает показывать выходные данные камеры. Я установил AVCaptureVideoDataOutputSampleBufferDelegate класс, и я вижу, что кадры захватываются и обрабатываются, но по какой-то причине он не начинает визуализировать выходные данные.

У меня есть этот другой фрагмент, который отображает выходные данные, но он делает это, устанавливая слой предварительного просмотра в качестве корневого слоя, чего я хочу избежать, вот код, который работает:

 struct CameraPreview: UIViewRepresentable {
    let session: AVCaptureSession
    
    func makeUIView(context: Context) -> UIView {
        let view = VideoView()
        view.backgroundColor = .gray

        view.previewLayer.session = session
        view.previewLayer.videoGravity = .resizeAspectFill
        view.previewLayer.connection?.videoOrientation = .portrait

        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        for layer in uiView.layer.sublayers ?? [] {
            layer.frame = uiView.bounds
        }
    }
    
    class VideoView: UIView {
        override class var layerClass: AnyClass {
            AVCaptureVideoPreviewLayer.self
        }
        
        var previewLayer: AVCaptureVideoPreviewLayer {
           layer as! AVCaptureVideoPreviewLayer
        }
    }
}
 

Некоторые примеры, которые я нашел, показали, что я должен иметь возможность показывать предварительный просмотр, как в первом примере. Я пробовал инициализировать сеанс с помощью входных данных до и после создания предварительного просмотра, и я получил тот же результат. Я что-то пропустил? я не сохраняю слой или есть специальная конфигурация для сеанса, на которую нужно обратить внимание? чтобы заставить это работать, я просто меняю местами реализации, и та, у которой есть внутренний класс, выполняет рендеринг?

Любая помощь действительно ценится.

Некоторые ресурсы:

Комментарии:

1. Вы пробовали устанавливать zPosition для слоя значение > 0?

2. Кроме того, мне на самом деле больше нравится второй подход (с VideoView ), поскольку вам на самом деле не нужно обновлять фрейм слоя updateUIView . Размер слоя всегда должен изменяться вместе с видом.

3. @FrankSchlegel Я только что сделал, тот же результат. Я действительно могу удалить код внутри updateUIView , и это никак не влияет на оба фрагмента.