ios swift画中画技术尝试

继上篇:iOS swift 后台运行应用尝试失败-CSDN博客

为什么想到画中画,起初是看到后台模式里有一个picture in picture,去了解了后发现这个就是小窗口视频播放,方便用户执行多任务。看小窗口视频的同时,可以作其他的事情。

画中画功能在20世纪80年代开始在电视机中应用,使得用户可以在一个屏幕上同时观看两个频道的内容。‌

这个技术在安卓里已经非常普遍了。各种视频内容网站都有类似功能。

而苹果支持画中画是在ios14已经开始支持。目前在使用的大多数机型,比如iphone 8p,升级系统后可到ios16.7,都能支持画中画技术。

后台任务苹果管理太严格,不好搞,那么使用画中画这种技术,直接做成多任务,这样也是另一条可以尝试的路径。

1、标准PIP使用

首先,标准写法是采用AVPlayer,输入url需要是MP4等视频文件,如果是加密后的网址,无法播放,比如b站的网址。

创建AVPlayer,使用AVPlayerLayer来初始化AVPictureInPictrueController。

        // 创建 AVPlayer 对象
        let videoURL = URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!
        player = AVPlayer(url: videoURL)
        
        // 创建 AVPlayerLayer 并添加到视图层上
        playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = view.bounds
        view.layer.addSublayer(playerLayer)
        
        // 设置画中画控制器
        pipController = AVPictureInPictureController(playerLayer: playerLayer)
        pipController.delegate = self

        player.play()   // 直接播放

按home键退出,就会自动启动小窗口继续播放视频。

这里有一个坑,需要初始化音频,否则播放mp4无声音,且画中画也不会触发。

    do {
        // 设置AVAudioSession为后台模式
        try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {
        print("无法设置AVAudioSession: \(error)")
    }

视频画中画,iphone 8p

2、摄像头预览

摄像头捕捉并预览,这个算法也很容易找到,使用AVCaptureSession

func setupCamera(forgroundFlag: Bool, view: UIView) {
        farView = view
        flag = forgroundFlag
        captureSession = AVCaptureSession()
        captureSession?.beginConfiguration()
        captureSession?.sessionPreset = .high
        
        guard let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) else {
            print("No front camera available")
            return
        }
        
        guard let input = try? AVCaptureDeviceInput(device: captureDevice) else {
            print("Unable to access front camera")
            return
        }
        
        captureSession!.addInput(input)
        
        videoOutput = AVCaptureVideoDataOutput()
        videoOutput?.automaticallyConfiguresOutputBufferDimensions = true
        videoOutput!.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
        captureSession!.addOutput(videoOutput!)
        
        if (forgroundFlag) {
            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
            guard let preLayer = videoPreviewLayer else { return }
            preLayer.frame = view.frame
            view.layer.addSublayer(preLayer)
            
            // 设置 UILabel 的属性
            label = UILabel()
            label!.text = "Hello, Swift!" // 设置文本内容
            label!.textColor = UIColor.systemBlue // 设置文本颜色
            label!.font = UIFont.systemFont(ofSize: 20) // 设置字体和大小
            label!.textAlignment = .left // 设置文本对齐方式
            label!.numberOfLines = 0 // 设置行数,0表示自动换行
            
            // 设置 UILabel 的位置和大小
            label!.frame = CGRect(x: 8, y: 20, width: 200, height: 30)
        }
        captureSession?.commitConfiguration()
    }

AVCaptureSession输出的是AVCaptureVideoPreviewLayer,这个layer无法直接用来初始化AVPictureInPictrueController。

3、摄像头输出PIP

swift代码在标准案例上实现都很简洁,但要自定义实现一些功能时,就会发现材料很难找。

比如怎样把摄像头预览与PIP结合。

深度搜索AI给出了一个结果,看上去好像可以,实践下来编辑都不能通过。但是它给出了一个提示,就是AVSampleBufferDisplayLayer。

这里吐槽下AI,最喜欢把不可用的东西包装成很好看的样子,在技术搜索方面,某些时候还不如原始的搜索引擎来得方便。

搜索AVCaptureVideoPreviewLayer转为AVSampleBufferDisplayLayer,也有方法,但是算法看上去稍显复杂。

官方文档Adopting Picture in Picture in a Custom Player | Apple Developer Documentation里也提到了可以使用AVSampleBufferDisplayLayer来初始化PIPController。

网上另一篇文章,说在捕获处理接口里,还有一个视频数据

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)

CMSampleBuffer可以直接转为AVSampleBufferDisplayLayer,使用enqueu接口,如下:

    func setupSampleBufferDisplayLayer() {
        sampleBufferDisplayLayer = AVSampleBufferDisplayLayer()
        sampleBufferDisplayLayer.frame = view.bounds
        sampleBufferDisplayLayer.videoGravity = .resizeAspect
        view.layer.addSublayer(sampleBufferDisplayLayer)
    }


    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
。。。。。。        
        if (sampleBufferDisplayLayer.status == AVQueuedSampleBufferRenderingStatus.failed) {
            sampleBufferDisplayLayer.flush() // 异常处理
        }
        sampleBufferDisplayLayer.enqueue(sampleBuffer)
。。。。。。
        

这样整个流程就能打通了。

通过AVSampleBufferDisplayLayer,可以用任何视频流来初始化AVPictureInPictureController。

    private func setupPiPController() {
        guard AVPictureInPictureController.isPictureInPictureSupported() else {
            print("Picture in Picture is not supported on this device")
            return
        }
        print("support pip!!!")
        
        if pipController == nil {
            pipController = AVPictureInPictureController(contentSource: .init(sampleBufferDisplayLayer: sampleBufferDisplayLayer, playbackDelegate: self))
        }
        
        if let pipController = pipController {
            pipController.delegate = self
            if pipController.isPictureInPicturePossible {
                pipController.startPictureInPicture()
            }
        }
    }

4、摄像头多任务需要硬件支持

前面生成的工程,在iphone 8p上测试效果如下,进入画中画模式时,在1s以内视频捕获就停止了。

摄像头画中画,iphone 8p

原因在于苹果对摄像头硬件管理非常严格,摄像头开小窗口,那么用户就可能用摄像头打开另一个任务,意味着摄像头需要支持多任务。

参考官方说明:

增加代码检查如下:

    
    func setupCamera(forgroundFlag: Bool, view: UIView) {
。。。。。。        
        guard let tempcap = captureSession else { return }
        if (tempcap.isMultitaskingCameraAccessSupported) {
            print("camera supp multitask")
            // Enable use of the camera in multitasking modes.
            captureSession?.isMultitaskingCameraAccessEnabled = true
        } else {
            print("camera not supp multitask")
        }
        captureSession?.commitConfiguration()
    }

从调试打印来看,iphone 8p的摄像头不支持多任务。

根据AI查询结果,可能需要iphone 12以上的机型才能支持摄像头多任务。

对于AI返回结果比较存疑,因为多次返回的结果可能会不一样。比如iphone XR,有的说支持,有的说不支持。

参考另外的官方文章,视频通话、直播画中画都是一样的。

Adopting Picture in Picture for video calls | Apple Developer Documentation

因为本人手上只有iphone 8p,没有其他新机型,所以后面的调试验证没法继续下去了。在没有订单推动情况下,也不会投入了。

如果有相关项目需求的,可以找我咨询合作。
     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962030.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++,STL 六大组件:容器、迭代器、算法、函数对象、适配器、分配器

文章目录 引言一、容器(Containers)主要分类 二、迭代器(Iterators)三、算法(Algorithms)四、函数对象(Functors)五、适配器(Adapters)六、分配器&#xff08…

STM32项目分享:智能鱼缸

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、包含内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: STM32智能鱼缸/水族箱 (资料分享见文末…

基于MinIO的对象存储增删改查

MinIO是一个高性能的分布式对象存储服务。Python的minio库可操作MinIO,包括创建/列出存储桶、上传/下载/删除文件及列出文件。 查看帮助信息 minio.exe --help minio.exe server --help …

14-6-1C++STL的list

(一)list容器的基本概念 list容器简介: 1.list是一个双向链表容器,可高效地进行插入删除元素 2.list不可以随机存取元素,所以不支持at.(pos)函数与[ ]操作符 (二)list容器头部和尾部的操作 list对象的默…

汽车网络信息安全-ISO/SAE 21434解析(中)

目录 第七章-分布式网络安全活动 1. 供应商能力评估 2. 报价 3. 网络安全职责界定 第八章-持续的网络安全活动 1. 网路安全监控 2. 网络安全事件评估 3. 漏洞分析 4. 漏洞管理 第九章-概念阶段 1. 对象定义 2. 网路安全目标 3. 网络安全概念 第十章 - 产品开发 第十…

C#分页思路:双列表数据组合返回设计思路

一、应用场景 需要分页查询(并非全表查载入物理内存再筛选),返回列表1和列表2叠加的数据时 二、实现方式 列表1必查,列表2根据列表1的查询结果决定列表2的分页查询参数 三、示意图及其实现代码 1.示意图 黄色代表list1的数据&a…

YOLOv8源码修改(4)- 实现YOLOv8模型剪枝(任意YOLO模型的简单剪枝)

目录 前言 1. 需修改的源码文件 1.1添加C2f_v2模块 1.2 修改模型读取方式 1.3 增加 L1 正则约束化训练 1.4 在tensorboard上增加BN层权重和偏置参数分布的可视化 1.5 增加剪枝处理文件 2. 工程目录结构 3. 源码文件修改 3.1 添加C2f_v2模块和模型读取 3.2 添加L1正则…

【Block总结】DynamicFilter,动态滤波器降低计算复杂度,替换传统的MHSA|即插即用

论文信息 标题: FFT-based Dynamic Token Mixer for Vision 论文链接: https://arxiv.org/pdf/2303.03932 关键词: 深度学习、计算机视觉、对象检测、分割 GitHub链接: https://github.com/okojoalg/dfformer 创新点 本论文提出了一种新的标记混合器(token mix…

设计模式Python版 原型模式

文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:关注类和对…

一文讲解Java中的BIO、NIO、AIO之间的区别

BIO、NIO、AIO是Java中常见的三种IO模型 BIO:采用阻塞式I/O模型,线程在执行I/O操作时被阻塞,无法处理其他任务,适用于连接数比较少的场景;NIO:采用非阻塞 I/O 模型,线程在等待 I/O 时可执行其…

使用 postman 测试思源笔记接口

思源笔记 API 权鉴 官方文档-中文:https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md 权鉴相关介绍截图: 对应的xxx,在软件中查看 如上图:在每次发送 API 请求时,需要在 Header 中添加 以下键值对&a…

AWTK 骨骼动画控件发布

Spine 是一款广泛使用的 2D 骨骼动画工具,专为游戏开发和动态图形设计设计。它通过基于骨骼的动画系统,帮助开发者创建流畅、高效的角色动画。本项目是基于 Spine 实现的 AWTK 骨骼动画控件。 代码:https://gitee.com/zlgopen/awtk-widget-s…

新年手搓--本地化部署DeepSeek-R1,全程实测

1.环境准备安装ollma ollma官网链接: Download Ollama on Linux ubuntu命令行安装: curl -fsSL https://ollama.com/install.sh | sh 选择运行模型,用7b模型试一下(模型也差不多5G): ollama run deepseek-r1:7b 运行qwen: ollama run qwen2.5:7b 2.为方便运行…

STM32使用VScode开发

文章目录 Makefile形式创建项目新建stm项目下载stm32cubemx新建项目IED makefile保存到本地arm gcc是编译的工具链G++配置编译Cmake +vscode +MSYS2方式bilibiliMSYS2 统一环境配置mingw32-make -> makewindows环境变量Cmake CmakeListnijia 编译输出elfCMAKE_GENERATOR查询…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.21 索引宗师:布尔索引的七重境界

1.21 索引宗师:布尔索引的七重境界 目录 #mermaid-svg-Iojpgw5hl0Ptb9Ti {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Iojpgw5hl0Ptb9Ti .error-icon{fill:#552222;}#mermaid-svg-Iojpgw5hl0Ptb9Ti .…

毕业设计--具有车流量检测功能的智能交通灯设计

摘要: 随着21世纪机动车保有量的持续增加,城市交通拥堵已成为一个日益严重的问题。传统的固定绿灯时长方案导致了大量的时间浪费和交通拥堵。为解决这一问题,本文设计了一款智能交通灯系统,利用车流量检测功能和先进的算法实现了…

课题推荐:基于matlab,适用于自适应粒子滤波的应用

自适应粒子滤波(Adaptive Particle Filter, APF)是一种用于状态估计的有效方法,特别适用于非线性和非高斯系统。 文章目录 应用场景MATLAB 代码示例代码说明结果扩展说明 以下是一个基于自适应粒子滤波的简单应用示例,模拟一个一维…

Redis(5,jedis和spring)

在前面的学习中,只是学习了各种redis的操作,都是在redis命令行客户端操作的,手动执行的,更多的时候就是使用redis的api(),进一步操作redis程序。 在java中实现的redis客户端有很多,…

基于聚类与相关性分析对马来西亚房价数据进行分析

碎碎念:由于最近太忙了,更新的比较慢,提前祝大家新春快乐,万事如意!本数据集的下载地址,读者可以自行下载。 1.项目背景 本项目旨在对马来西亚房地产市场进行初步的数据分析,探索各州的房产市…

(2025 年最新)MacOS Redis Desktop Manager中文版下载,附详细图文

MacOS Redis Desktop Manager中文版下载 大家好,今天给大家带来一款非常实用的 Redis 可视化工具——Redis Desktop Manager(简称 RDM)。相信很多开发者都用过 Redis 数据库,但如果你想要更高效、更方便地管理 Redis 数据&#x…