Runt
2025-06-27 5e101b6d445d9bbff119d308c454c55d0a03de14
主窗口
设备列表弹框
底部弹框
自动换行view
7 files added
200 ■■■■■ changed files
LiveProject/data/DeviceInfo.swift patch | view | raw | blame | history
LiveProject/enum/StreamType.swift patch | view | raw | blame | history
LiveProject/shape/IconBack.swift 8 ●●●●● patch | view | raw | blame | history
LiveProject/tool/MetalRenderer.swift 78 ●●●●● patch | view | raw | blame | history
LiveProject/views/FlowLayout.swift 7 ●●●●● patch | view | raw | blame | history
LiveProject/views/TitleBarView.swift 44 ●●●●● patch | view | raw | blame | history
LiveProject/views/VideoRendererView.swift 63 ●●●●● patch | view | raw | blame | history
LiveProject/data/DeviceInfo.swift
LiveProject/enum/StreamType.swift
LiveProject/shape/IconBack.swift
New file
@@ -0,0 +1,8 @@
//
//  IconBack.swift
//  LiveProject
//
//  Created by 倪路朋 on 6/26/25.
//
import Foundation
LiveProject/tool/MetalRenderer.swift
New file
@@ -0,0 +1,78 @@
//
//  Renderer.swift
//  LiveProject
//  渲染工具
//  Created by 倪路朋 on 6/26/25.
//
import Metal
import MetalKit
class Renderer: NSObject, MTKViewDelegate {
    static var shared: Renderer?
    private var device: MTLDevice!
    private var commandQueue: MTLCommandQueue!
    private var pipelineState: MTLRenderPipelineState!
    private var texture: MTLTexture?
    private var textureDescriptor: MTLTextureDescriptor!
    private var currentData: [UInt8]?
    private var textureWidth = 0
    private var textureHeight = 0
    weak var mtkView: MTKView? {
        didSet {
            guard let view = mtkView else { return }
            device = view.device
            commandQueue = device.makeCommandQueue()
            let library = device.makeDefaultLibrary()
            let pipelineDesc = MTLRenderPipelineDescriptor()
            pipelineDesc.vertexFunction = library?.makeFunction(name: "vertexShader")
            pipelineDesc.fragmentFunction = library?.makeFunction(name: "fragmentShader")
            pipelineDesc.colorAttachments[0].pixelFormat = view.colorPixelFormat
            pipelineState = try? device.makeRenderPipelineState(descriptor: pipelineDesc)
            Renderer.shared = self
        }
    }
    func updateFrame(data: [UInt8], width: Int, height: Int) {
        currentData = data
        textureWidth = width
        textureHeight = height
    }
    func draw(in view: MTKView) {
        guard let drawable = view.currentDrawable,
              let descriptor = view.currentRenderPassDescriptor,
              let data = currentData else { return }
        if texture == nil || texture?.width != textureWidth || texture?.height != textureHeight {
            textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
                pixelFormat: .rgba8Unorm,
                width: textureWidth,
                height: textureHeight,
                mipmapped: false
            )
            textureDescriptor.usage = [.shaderRead, .shaderWrite]
            texture = device.makeTexture(descriptor: textureDescriptor)
        }
        let region = MTLRegionMake2D(0, 0, textureWidth, textureHeight)
        data.withUnsafeBytes { ptr in
            texture?.replace(region: region, mipmapLevel: 0, withBytes: ptr.baseAddress!, bytesPerRow: textureWidth * 4)
        }
        let commandBuffer = commandQueue.makeCommandBuffer()
        let encoder = commandBuffer?.makeRenderCommandEncoder(descriptor: descriptor)
        encoder?.setRenderPipelineState(pipelineState)
        encoder?.setFragmentTexture(texture, index: 0)
        encoder?.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
        encoder?.endEncoding()
        commandBuffer?.present(drawable)
        commandBuffer?.commit()
    }
    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
}
LiveProject/views/FlowLayout.swift
New file
@@ -0,0 +1,7 @@
//
//  Untitled.swift
//  LiveProject
//
//  Created by 倪路朋 on 6/26/25.
//
LiveProject/views/TitleBarView.swift
New file
@@ -0,0 +1,44 @@
//
//  TitleBarView.swift
//  aones
//
//  Created by 倪路朋 on 2/16/23.
//
import SwiftUI
struct TitleBarView: View {
    @Environment(\.presentationMode) var presentationMode
    var title = ""
    var imgLeft = "IconBack";
    var imgRight = "";
    var titleColor = "ColorText"
    var body: some View {
            HStack(spacing: 0){
                Spacer().frame(width: 16)
                Button(action: {
                    print("Click back button")
                    self.presentationMode.wrappedValue.dismiss()
                }) {
                    Image(imgLeft)
                        .frame(width: 28,height: 28)
                }
                Spacer()
                Text(title).foregroundColor(Color.init(titleColor))
                    .bold().font(Font.system(size: 16))
                Spacer()
                Image(imgRight).frame(width: 28,height: 28)
                Spacer().frame(width: 16)
            }.frame(height: 48)
    }
}
struct TitleBarView_Previews: PreviewProvider {
    static var previews: some View {
        TitleBarView(title: "标题")
    }
}
LiveProject/views/VideoRendererView.swift
New file
@@ -0,0 +1,63 @@
//
//  MetalVideoView.swift
//  LiveProject
//  视频绘制
//  Created by 倪路朋 on 6/26/25.
//
import SwiftUI
import MetalKit
struct MetalVideoRenderView: UIViewRepresentable {
    // 统一接口,接收各种视频源的帧数据
    var frameData: VideoFrameData?
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    func makeUIView(context: Context) -> MTKView {
        let mtkView = MTKView()
        mtkView.device = context.coordinator.device
        mtkView.delegate = context.coordinator
        mtkView.framebufferOnly = false
        mtkView.colorPixelFormat = .bgra8Unorm
        mtkView.autoResizeDrawable = true
        return mtkView
    }
    func updateUIView(_ uiView: MTKView, context: Context) {
        // 更新帧数据
        context.coordinator.updateFrame(frameData)
    }
    class Coordinator: NSObject, MTKViewDelegate {
        var parent: MetalVideoRenderView
        var device: MTLDevice
        var commandQueue: MTLCommandQueue
        var pipelineState: MTLRenderPipelineState
        var textureCache: CVMetalTextureCache?
        // YUV转RGB的着色器
        var yuvConversionPipeline: MTLComputePipelineState?
        init(_ parent: MetalVideoRenderView) {
            self.parent = parent
            self.device = MTLCreateSystemDefaultDevice()!
            self.commandQueue = device.makeCommandQueue()!
            // 初始化Metal资源
            // (这里需要设置渲染管线和纹理缓存)
        }
        func updateFrame(_ frameData: VideoFrameData?) {
            // 根据不同的帧数据格式(YUV/RGBA)进行处理
            // 将数据转换为Metal纹理
        }
        func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
        func draw(in view: MTKView) {
            // 执行Metal绘制命令
        }
    }
}