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.boundsview.layer.addSublayer(playerLayer)// 设置画中画控制器pipController = AVPictureInPictureController(playerLayer: playerLayer)pipController.delegate = selfplayer.play() // 直接播放
按home键退出,就会自动启动小窗口继续播放视频。
这里有一个坑,需要初始化音频,否则播放mp4无声音,且画中画也不会触发。
do {// 设置AVAudioSession为后台模式try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)try AVAudioSession.sharedInstance().setActive(true)} catch {print("无法设置AVAudioSession: \(error)")}
视频画中画,iphone 8p_哔哩哔哩_bilibili
2、摄像头预览
摄像头捕捉并预览,这个算法也很容易找到,使用AVCaptureSession
func setupCamera(forgroundFlag: Bool, view: UIView) {farView = viewflag = forgroundFlagcaptureSession = AVCaptureSession()captureSession?.beginConfiguration()captureSession?.sessionPreset = .highguard 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 = truevideoOutput!.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))captureSession!.addOutput(videoOutput!)if (forgroundFlag) {videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)guard let preLayer = videoPreviewLayer else { return }preLayer.frame = view.frameview.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.boundssampleBufferDisplayLayer.videoGravity = .resizeAspectview.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 = selfif pipController.isPictureInPicturePossible {pipController.startPictureInPicture()}}}
4、摄像头多任务需要硬件支持
前面生成的工程,在iphone 8p上测试效果如下,进入画中画模式时,在1s以内视频捕获就停止了。
摄像头画中画,iphone 8p_哔哩哔哩_bilibili
原因在于苹果对摄像头硬件管理非常严格,摄像头开小窗口,那么用户就可能用摄像头打开另一个任务,意味着摄像头需要支持多任务。
参考官方说明:
增加代码检查如下:
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,没有其他新机型,所以后面的调试验证没法继续下去了。在没有订单推动情况下,也不会投入了。
如果有相关项目需求的,可以找我咨询合作。
相关文章:

ios swift画中画技术尝试
继上篇:iOS swift 后台运行应用尝试失败-CSDN博客 为什么想到画中画,起初是看到后台模式里有一个picture in picture,去了解了后发现这个就是小窗口视频播放,方便用户执行多任务。看小窗口视频的同时,可以作其他的事情…...
MyBatis 写法
MyBatis 高效使用技巧 常见 MyBatis 使用技巧,这些技巧有助于简化数据库操作,提高开发效率,并增强系统的性能。 1. 动态 SQL 动态 SQL 让开发者能够依据参数灵活地构建 SQL 语句,避免了手动拼接字符串带来的复杂性和错误风险。…...

Three城市引擎地图插件Geo-3d
一、简介 基于Three开发,为Three 3D场景提供GIS能力和城市底座渲染能力。支持Web墨卡托、WGS84、GCJ02等坐标系,支持坐标转换,支持影像、地形、geojson建筑、道路,植被等渲染。支持自定义主题。 二、效果 三、代码 //插件初始化…...
【贪心算法】洛谷P1106 - 删数问题
2025 - 01 - 22 - 第 46 篇 【洛谷】贪心算法题单 - 【贪心算法】 - 【学习笔记】 作者(Author): 郑龙浩 / 仟濹(CSND账号名) 目录 文章目录 目录P1106 删数问题题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路代码 P1106 删数问题 题目描述 键盘输入一个高…...

WPS计算机二级•幻灯片的页面布局
听说这是目录哦 设置PPT页面尺寸🖼️PPT母版怎么用🎨巧用PPT母版统一修改 字体颜色与背景🎡如何快速更改应用 幻灯片中的不同母版👑能量站😚 设置PPT页面尺寸🖼️ 在制作PPT时,我们需要先选定一…...
从入门到精通:HttpClient深度剖析与实战指南
一、引言 1.1 背景引入 在当今数字化时代,网络编程已成为软件开发中不可或缺的一部分。而 HTTP 通信作为网络编程的核心,承担着客户端与服务器之间数据传输的重任。无论是 Web 应用、移动应用,还是分布式系统,HTTP 协议都扮演着…...

IoTDB 2025 春节值班与祝福
2025 春节快乐 瑞蛇迎吉庆,祥光映华年,2025 春节已近在眼前。社区祝福 IoTDB 的所有关注者、支持者、使用者 2025 新年快乐,“蛇”来运转! IoTDB 团队的春节放假时间为 2025 年 1 月 27 日至 2 月 4 日,1 月 25 日、26…...

Java 大视界 -- Java 大数据中的隐私增强技术全景解析(64)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...

【2024年华为OD机试】 (A卷,100分)- 整理扑克牌(JavaScriptJava PythonC/C++)
一、问题描述 题目描述 给定一组数字,表示扑克牌的牌面数字,忽略扑克牌的花色,请按如下规则对这一组扑克牌进行整理: 步骤1:分组形成组合牌 炸弹:当牌面数字相同张数大于等于4时。葫芦:3张相同牌面数字 + 2张相同牌面数字,且3张牌与2张牌不相同。三张:3张相同牌面数…...
周末总结(2024/01/25)
工作 人际关系核心实践: 要学会随时回应别人的善意,执行时间控制在5分钟以内 坚持每天早会打招呼 遇到接不住的话题时拉低自己,抬高别人(无阴阳气息) 朋友圈点赞控制在5min以内,职场社交不要放在5min以外 职场的人际关系在面对利…...
Apache Flink 概述学习笔记
一、引言 在大数据处理领域,Apache Flink 是一个极具影响力的开源流批一体化计算框架,它以其独特的架构和强大的功能,为大规模数据处理提供了高效、灵活的解决方案。 二、基本概念 Flink 是什么:Flink 是一个分布式流批处理框架…...
双足机器人开源项目
双足机器人(也称为人形机器人或仿人机器人)是一个复杂的领域,涉及机械设计、电子工程、控制理论、计算机视觉等多个学科。对于想要探索或开发双足机器人的开发者来说,有许多开源项目可以提供帮助。这些项目通常包括硬件设计文件、…...
Linux 部署 Java 项目:Tomcat、Redis、MySQL 教程
在 Linux 服务器上部署 Java 项目通常需要配置应用服务器(如 Tomcat)、数据库(如 MySQL)和缓存服务器(如 Redis)。本文将详细介绍如何在 Linux 环境中部署一个 Java 项目,涵盖 Tomcat、Redis 和…...
Django 多环境配置实战指南
在现代 Web 开发中,一个项目通常需要在多个环境中运行,例如开发环境、测试环境和生产环境。每个环境的配置可能不同,比如数据库连接、调试模式、密钥等。为了确保项目在不同环境中的灵活性和安全性,我们需要合理地管理多环境配置。 本文将详细介绍如何在 Django 项目中实现…...

【C++高并发服务器WebServer】-6:信号
本文目录 信号的概念1.1 core文件1.2 kill命令1.3 alarm函数1.4 setitimer调用1.5 signal捕捉信号1.6 信号集1.7 内核实现信号捕捉的过程1.8 sigaction1.9 sigchld 信号的概念 信号是 Linux 进程间通信的最古老的方式之一,是事件发生时对进程的通知机制,…...
HBase的原理
一、什么是HBase HBase是一个分布式,版本化,面向列的数据库,依赖Hadoop和Zookeeper (1)HBase的优点 提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统 (2) HBase 表的特性 Region包含多行 列族包含多…...

[b01lers2020]Life on Mars1
打开题目页面如下 看了旁边的链接,也没有什么注入点,是正常的科普 利用burp suite抓包,发现传参 访问一下 http://5edaec92-dd87-4fec-b0e3-501ff24d3650.node5.buuoj.cn:81/query?searchtharsis_rise 接下来进行sql注入 方法一…...

Go学习:常量
变量:程序运行期间,可以改变的量,变量声明需要使用 var 常量:程序运行期间,不可以改变的量,常量声明需要使用 const 目录 1. 常量不允许修改 2. 常量赋值不使用 : 3. 常量能够自动推导类型 1. 常量不允许…...
Python 爬虫——爬取Web页面图片
从网页页面上批量下载jpg格式图片,并按照数字递增命名保存到指定的文件夹。 Web地址:http://p.weather.com.cn/2017/06/2720826.shtml#p1 import urllib import urllib.request import re #正则表达式#解析页面 def load_page(url):requesturllib.reque…...

微信小程序1.1 微信小程序介绍
1.1 微信小程序介绍 内容提要 1.1 什么是微信小程序 1.2 微信小程序的功能 1.3 微信小程序使用场景 1.4 微信小程序能取代App吗 1.5 微信小程序的发展历程 1.6微信小程序带来的机会...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...