织梦网站栏目访问目录,微信公众号手机网站开发,百度公司官网招聘,做PPT素材用到的网站继上篇#xff1a;iOS swift 后台运行应用尝试失败-CSDN博客 为什么想到画中画#xff0c;起初是看到后台模式里有一个picture in picture#xff0c;去了解了后发现这个就是小窗口视频播放#xff0c;方便用户执行多任务。看小窗口视频的同时#xff0c;可以作其他的事情…继上篇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没有其他新机型所以后面的调试验证没法继续下去了。在没有订单推动情况下也不会投入了。
如果有相关项目需求的可以找我咨询合作。