【问题标题】:Custom shape for video preview: AVCaptureVideoPreviewLayer?视频预览的自定义形状:AVCaptureVideoPreviewLayer?
【发布时间】:2019-11-19 10:24:09
【问题描述】:

是否可以像剪辑图像一样剪辑视频预览层?

    image
        .clipShape(Circle())
        .overlay(Circle().stroke(Color.green, lineWidth: 1)) 

视频预览层的来源:

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.frame = CGRect(x: 20, y: 60, width: 335, height: 200)
    previewLayer.videoGravity = .resizeAspectFill
    view.layer.addSublayer(previewLayer)

我一直在寻找,但没有运气。谢谢!

【问题讨论】:

  • .mask 适用于图像类型。它似乎不适用于 avcapturepreviewlayer 或 frame 或 layer。我对这个修饰符有什么遗漏吗?
  • 您有任何更新吗?谢谢

标签: ios avfoundation swiftui swift5


【解决方案1】:

在 macOS 10.15 Catalina 上测试

下面的演示代码是针对 SwiftUI/macOS 的,但它可能会有所帮助,因为只需对代码进行一些小改动即可使其与 iOS 保持一致。

注意:这是一个演示,所以代码有点粗糙

结果如下:

这里是演示模块代码:

import SwiftUI
import AppKit
import AVFoundation

class PreviewView: NSView {
    private var captureSession: AVCaptureSession?

    init() {
        super.init(frame: .zero)

        var allowedAccess = false
        let blocker = DispatchGroup()
        blocker.enter()
        AVCaptureDevice.requestAccess(for: .video) { flag in
            allowedAccess = flag
            blocker.leave()
        }
        blocker.wait()

        if !allowedAccess {
            print("!!! NO ACCESS TO CAMERA")
            return
        }

        // setup session
        let session = AVCaptureSession()
        session.beginConfiguration()

        // this part might be different in iOS
        let videoDevice = AVCaptureDevice.default(for: .video)

        guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice!),
            session.canAddInput(videoDeviceInput)
            else { return }
        session.addInput(videoDeviceInput)
        session.commitConfiguration()
        self.captureSession = session

        // instead of below, use layerClass on iOS
        self.wantsLayer = true
        self.layer = AVCaptureVideoPreviewLayer()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        return layer as! AVCaptureVideoPreviewLayer
    }

    override func viewDidMoveToSuperview() { // on iOS .didMoveToSuperview
        super.viewDidMoveToSuperview()

        if nil != self.superview {
            self.videoPreviewLayer.session = self.captureSession
            self.videoPreviewLayer.videoGravity = .resizeAspect
            self.captureSession?.startRunning()
        } else {
            self.captureSession?.stopRunning()
        }
    }
}

// for iOS NSView just rename to UIView
struct PreviewHolder: NSViewRepresentable {
    func makeNSView(context: NSViewRepresentableContext<PreviewHolder>) -> PreviewView {
        PreviewView()
    }

    func updateNSView(_ uiView: PreviewView, context: NSViewRepresentableContext<PreviewHolder>) {
    }

    typealias NSViewType = PreviewView
}

struct DemoPreviewLayer: View {
    var body: some View {
        VStack {
            PreviewHolder()
                .mask(Circle())
        }.frame(width: 400, height: 300)
    }
}

struct DemoPreviewLayer_Previews: PreviewProvider {
    static var previews: some View {
        DemoPreviewLayer()
    }
}

【讨论】:

  • 只是想补充一点,如果您想将它与外部 Mac 相机一起使用,而不是按照示例中的默认设置,它真的非常简单。只需将 AVCaptureDevice.default 替换为以下内容。 let videoDevice = AVCaptureDevice.DiscoverySession.init(deviceTypes: [.builtInWideAngleCamera, .externalUnknown], mediaType: .video, position: .unspecified) 然后在结果列表中选择第一个可用的设备..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-28
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 2015-09-01
相关资源
最近更新 更多