视频预览的自定义形状:AVCaptureVideoPreviewLayer?

Posted

技术标签:

【中文标题】视频预览的自定义形状:AVCaptureVideoPreviewLayer?【英文标题】:Custom shape for video preview: 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? hackingwithswift.com/quick-start/swiftui/… .mask 适用于图像类型。它似乎不适用于 avcapturepreviewlayer 或 frame 或 layer。我对这个修饰符有什么遗漏吗? 您有任何更新吗?谢谢 【参考方案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) 然后在结果列表中选择第一个可用的设备..

以上是关于视频预览的自定义形状:AVCaptureVideoPreviewLayer?的主要内容,如果未能解决你的问题,请参考以下文章

具有自定义形状的自定义 ImageView

我想在 UIView 上绘制像苹果形状这样的自定义形状

颤动中的自定义容器形状

Android 实时视频采集—Camera预览采集与显示(平台系统camera功能理解分享)

FactoExtra 包中函数 fviz_pca 中点形状的自定义

如何在张量流的自定义损失中获取张量的形状