From 7b3ecfffc59d2d980d9f7628365b64c20fe015be Mon Sep 17 00:00:00 2001 From: Runt <qingingrunt2010@qq.com> Date: Sun, 27 Jul 2025 09:42:03 +0000 Subject: [PATCH] 多个小窗缩放问题修复 --- LiveProject/activity/stream/LiveViewModel.swift | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 148 insertions(+), 0 deletions(-) diff --git a/LiveProject/activity/stream/LiveViewModel.swift b/LiveProject/activity/stream/LiveViewModel.swift index e69de29..bb31219 100644 --- a/LiveProject/activity/stream/LiveViewModel.swift +++ b/LiveProject/activity/stream/LiveViewModel.swift @@ -0,0 +1,148 @@ +// +// LiveViewModel.swift +// LiveProject +// +// Created by 倪路朋 on 6/27/25. +// +import UIKit +import AVFoundation + +class LiveViewModel: ObservableObject { + @Published var pixelBuffer: CVPixelBuffer? + + //let encoder = H264Encoder(width: 1080, height: 1920, fps: 30, bitrate: 1_000_000) + var frameIndex: Int64 = 0 + //let encodeQueue = DispatchQueue(label: "encoder.queue") + + lazy var camera = CameraCapture() + var timestamp = Int(Date().timeIntervalSince1970 * 1000) + + func newWindowAction(minidata:MiniWindowData,completion: @escaping (Bool) -> Void = {b in}){ + switch minidata.streamType{ + case StreamType.CAMERA: + requestCameraPermission(mediaType: .video){ staus in + if(staus){ + var ts1 = Int(Date().timeIntervalSince1970 * 1000) + self.camera.onFrame = { [weak self] buffer in + guard let self = self else { return } + + let width = CVPixelBufferGetWidth(buffer) + let height = CVPixelBufferGetHeight(buffer) + + guard width > 0 && height > 0 else { + print("Invalid pixel buffer size: \(width)x\(height)") + return + } + if(minidata.size.width != CGFloat(width) || minidata.size.height != CGFloat(height)){ + minidata.size = CGSize(width:width,height:height); + } + self.frameIndex += 1 + let ts = Int(Date().timeIntervalSince1970 * 1000) + + self.timestamp = ts; + let cmTime = CMTimeMake(value: Int64(CACurrentMediaTime() * 1000), timescale: 1000); + //self.encoder.encode(pixelBuffer: buffer, pts: cmTime) + DispatchQueue.main.async { + minidata.pixelBuffer = buffer; + + } + //print("画面更新") + } + DispatchQueue.global(qos: .userInitiated).async { + self.camera.start() + } + print("启动相机") + /*self.encoder.onEncoded = { (data: Data, ctime: CMTime, isKey: Bool) in + let timestamp2 = Int(Date().timeIntervalSince1970 * 1000) + print("编码时间2 \(timestamp2 - self.timestamp)") + print("Encoded NALU size: \(data.count), key frame: \(isKey)") + + }*/ + }else{ + + } + completion(staus) + } + break; + default: + completion(true) + break; + } + } + + func closeWindowAction(miniData:MiniWindowData){ + switch miniData.streamType{ + case StreamType.CAMERA: + print("关闭相机") + camera.stop(); + break; + default: + break; + } + } + + + + func requestCameraPermission(mediaType: AVMediaType,completion: @escaping (Bool) -> Void) { + let status = AVCaptureDevice.authorizationStatus(for: mediaType) + switch status { + case .authorized: + completion(true) + case .notDetermined: + AVCaptureDevice.requestAccess(for: .video) { granted in + DispatchQueue.main.async { + completion(granted) + } + } + default: + // denied / restricted + completion(false) + } + } + + func copyPixelBuffer(_ src: CVPixelBuffer) -> CVPixelBuffer? { + let width = CVPixelBufferGetWidth(src) + let height = CVPixelBufferGetHeight(src) + let pixelFormat = CVPixelBufferGetPixelFormatType(src) + + var dst: CVPixelBuffer? + let attrs: [String: Any] = [ + kCVPixelBufferIOSurfacePropertiesKey as String: [:] + ] + + let status = CVPixelBufferCreate( + kCFAllocatorDefault, + width, + height, + pixelFormat, + attrs as CFDictionary, + &dst + ) + + guard status == kCVReturnSuccess, let dstBuffer = dst else { + print("❌ 复制 PixelBuffer 失败") + return nil + } + + CVPixelBufferLockBaseAddress(src, .readOnly) + CVPixelBufferLockBaseAddress(dstBuffer, []) + + let planeCount = CVPixelBufferGetPlaneCount(src) + for i in 0..<planeCount { + let srcAddr = CVPixelBufferGetBaseAddressOfPlane(src, i) + let dstAddr = CVPixelBufferGetBaseAddressOfPlane(dstBuffer, i) + + let height = CVPixelBufferGetHeightOfPlane(src, i) + let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(src, i) + + memcpy(dstAddr, srcAddr, height * bytesPerRow) + } + + CVPixelBufferUnlockBaseAddress(src, .readOnly) + CVPixelBufferUnlockBaseAddress(dstBuffer, []) + + return dstBuffer + } + + +} -- Gitblit v1.9.1