swiftUI使用VideoPlayer和AVPlayer播放视频

使用VideoPlayer包播放视频:https://github.com/wxxsw/VideoPlayer

提供一些可供测试的视频链接,不保证稳定可用哦:

https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4https://vfx.mtime.cn/Video/2019/06/29/mp4/190629004821240734.mp4https://vfx.mtime.cn/Video/2019/06/27/mp4/190627231412433967.mp4https://vfx.mtime.cn/Video/2019/06/25/mp4/190625091024931282.mp4https://vfx.mtime.cn/Video/2019/06/16/mp4/190616155507259516.mp4https://vfx.mtime.cn/Video/2019/06/05/mp4/190605101703931259.mp4

安装VideoPlayer

使用spm安装包,直接在xcode项目的依赖包右键,添加包:

在右上角输入包地址:添加到项目中即可

使用VideoPlayer

在项目中导入:

import VideoPlayer

如果提示没有这个包:No such module 'VideoPlayer'

需要在项目的通用设置里面添加这个包到项目中:

选中 VideoPlayer 点击 add:

播放在线视频代码

直接使用在线视频url即可播放

    @State private var play: Bool = truevar body: some View {VideoPlayer(url: URL(string: "你的视频URL链接")!, play: $play)}

实现的效果: 

播放本地视频

把视频添加到项目中,点击File > Add Files to 项目 > 选中要添加的视频,就可以了

然后在项目代码中添加视频:

// 本地文件
let localMp4Url = Bundle.main.url(forResource: "localMp4", withExtension: "mp4")@State private var play: Bool = truevar body: some View {VideoPlayer(url: localMp4Url!, play: $play)
}

实现的效果:

视频控制

在视频上显示播放控制按钮等配置,可以通过给播放器绑定变量来实现控制

//
//  ContentView.swift
//  swiftPro
//
//  Created by song on 2024/5/21.
//import Alamofire
import AVKit
import GIFImage
import Kingfisher
import SwiftUI
import VideoPlayerprivate var videoURLs: [URL] = [URL(string: "https://vfx.mtime.cn/Video/2019/06/29/mp4/190629004821240734.mp4")!,URL(string: "https://vfx.mtime.cn/Video/2019/06/27/mp4/190627231412433967.mp4")!,URL(string: "https://vfx.mtime.cn/Video/2019/06/25/mp4/190625091024931282.mp4")!,URL(string: "https://vfx.mtime.cn/Video/2019/06/16/mp4/190616155507259516.mp4")!,URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")!,URL(string: "https://vfx.mtime.cn/Video/2019/06/05/mp4/190605101703931259.mp4")!,
]struct ContentView: View {// 本地文件let localMp4Url = Bundle.main.url(forResource: "localMp4", withExtension: "mp4")// 远程视频let remoteUrl = URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")// 获取当前播放时间func getTimeString() -> String {let m = Int(time.seconds / 60)let s = Int(time.seconds.truncatingRemainder(dividingBy: 60))return String(format: "%d:%02d", arguments: [m, s])}// 获取视频所有的时间func getTotalDurationString() -> String {let m = Int(totalDuration / 60)let s = Int(totalDuration.truncatingRemainder(dividingBy: 60))return String(format: "%d:%02d", arguments: [m, s])}// 视频列表索引@State var index = 0// 播放状态@State private var play: Bool = true// 视频播放时间@State private var time: CMTime = .zero// 是否自动播放@State private var autoReplay: Bool = true// 是否开启声音(mute:沉默的,无声的)@State private var mute: Bool = false// 视频播放状态文字提示@State private var stateText: String = ""// 总共持续时间@State private var totalDuration: Double = 0// 播放速度@State private var speedRate: Float = 1.2// 使用状态来跟踪播放状态@State private var isPlaying = falsevar body: some View {VStack(content: {// 视频播放控制是通过绑定变量来实现的VideoPlayer(url: videoURLs[index % videoURLs.count], play: $play, time: $time).autoReplay(autoReplay).mute(mute).speedRate(speedRate).onBufferChanged { progress in print("onBufferChanged \(progress)") }.onPlayToEndTime { print("onPlayToEndTime") }.onReplay { print("onReplay") }.onStateChanged { state inswitch state {case .loading:self.stateText = "Loading..."case .playing(let totalDuration):self.stateText = "Playing!"self.totalDuration = totalDurationcase .paused(let playProgress, let bufferProgress):self.stateText = "Paused: play \(Int(playProgress * 100))% buffer \(Int(bufferProgress * 100))%"case .error(let error):self.stateText = "Error: \(error)"}}.aspectRatio(1.78, contentMode: .fit).cornerRadius(16).shadow(color: Color.black.opacity(0.7), radius: 6, x: 0, y: 2).padding()// 视频状态Text(stateText).padding()// 视频控制:暂停/声音控制/自动重播/后退前进5秒/下一个视频HStack {Button(self.play ? "Pause" : "Play") {self.play.toggle()}Divider().frame(height: 20)Button(self.mute ? "Sound Off" : "Sound On") {self.mute.toggle()}Divider().frame(height: 20)Button(self.autoReplay ? "Auto Replay On" : "Auto Replay Off") {self.autoReplay.toggle()}}HStack {Button("Backward 5s") {self.time = CMTimeMakeWithSeconds(max(0, self.time.seconds - 5), preferredTimescale: self.time.timescale)}Divider().frame(height: 20)Text("\(getTimeString()) / \(getTotalDurationString())")Divider().frame(height: 20)Button("Forward 5s") {self.time = CMTimeMakeWithSeconds(min(self.totalDuration, self.time.seconds + 5), preferredTimescale: self.time.timescale)}}Button("Next Video") { self.index += 1 }})}
}#Preview {ContentView()
}

播放效果:

使用AVPlayer

导入AVPlayer:

import AVKit
import VideoPlayer

创建一个player:

注意视频链接协议要为https的,http的视频链接需要单独设置

    // 使用状态来跟踪播放状态@State private var isPlaying = false// AVPlayer 实例private let player = AVPlayer(url: URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")!)// 在ui层放入播放器var body: some View {VStack {// 视频播放器控件VideoPlayer(player: player).ignoresSafeArea().frame(maxWidth: .infinity, maxHeight: .infinity).onAppear {player.play()}}}

加载本地视频资源:

需要将本地视频资源加载到项目中,然后通过Bundle引入

    // 加载本地资源let player = AVPlayer(url: Bundle.main.url(forResource: "localMp4", withExtension: "mp4")!)var body: some View {VideoPlayer(player: player).ignoresSafeArea().frame(maxWidth: .infinity, maxHeight: .infinity).onAppear {player.play()}}

 

显示效果:

播放也没有问题,视频控制也没有问题,很不错了

ipad的效果:果然是看剧神器,视觉效果还是不错的

可以添加自定义控制:

struct VideoPlayerView: View {// 使用状态来跟踪播放状态@State private var isPlaying = false// AVPlayer 实例private let player = AVPlayer(url: URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")!)var body: some View {VStack {// 视频播放器控件AVPlayerViewController().embed(player: player)// 添加自定义控制Button(action: togglePlay) {Text(isPlaying ? "暂停" : "播放")}}}// 切换播放状态的方法func togglePlay() {isPlaying ? player.pause() : player.play()isPlaying.toggle()}
}extension AVPlayerViewController {func embed(player: AVPlayer) -> some View {return VideoPlayer(player: player).frame(maxWidth: .infinity, maxHeight: .infinity).edgesIgnoringSafeArea(.all).onAppear {player.play()}.onDisappear {player.pause()}}
}

效果:

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

B端UI设计,演绎高情逸态之妙

B端UI设计,演绎高情逸态之妙

Unity 实现让物体渲染在最前面

演示 实现方案 1.创建一个shader脚本 2.删掉原来的内容:我们自己写 附上完整的shader代码: Shader "Custom/ZTestAlways" {Properties {_Color ("Color Tint",Color) (1,1,1,1)_MainTex("Main Tex",2D) "white&q…

神经网络与深度学习——第3章 线性模型

本文讨论的内容参考自《神经网络与深度学习》https://nndl.github.io/ 第3章 线性模型 线性模型 线性模型(Linear Model)是机器学习中应用最广泛的模型,指通过样本特征的线性组合来进行预测的模型,给定一个 D D D维样本 x [ x …

Java—认识异常

1. 异常的概念与体系结构 1.1 异常的概念 在生活中,一个人表情痛苦,出于关心,可能会问:你是不是生病了,需要我陪你去看医生吗? 在程序中也是一样,程序猿是一帮办事严谨、追求完美的高科技人才…

【风控】可解释机器学习之InterpretML

【风控】可解释机器学习之InterpretML 在金融风控领域,机器学习模型因其强大的预测能力而备受青睐。然而,随着模型复杂性的增加,模型的可解释性逐渐成为一个挑战。监管要求、业务逻辑的透明度以及对模型决策的信任度,都迫切需要我…

getway整合sentinel流控降级

3. 启动sentinel控制台增加流控规则: 根据API分组进行流控: 1.设置API分组: 2.根据API分组进行流控: 自定义统一异常处理: nginx负载配置:

FinRobot:一个由大型语言模型(LLM)支持的新型开源AI Agent平台,支持多个金融专业AI Agent

财务分析一直是解读市场趋势、预测经济结果和提供投资策略的关键。这一领域传统上依赖数据,但随着时间的推移,越来越多地使用人工智能(AI)和算法方法来处理日益增长的复杂数据。AI在金融领域的作用显著增强,它自动化了…

Netty中半包粘包的产生与处理:短连接、固定长度、固定分隔符、预设长度;redis、http协议举例;网络数据的发送和接收过程

目录 粘包、半包 相关概念 网络数据发送和接收过程 Netty半包粘包解决方案 ByteBuf获取和默认大小 短链接 固定长度 固定分隔符 预设长度 常见协议代码举例 redis协议 http协议 参考链接 粘包、半包 相关概念 程序处理过程中我们会通过缓冲区接收数据&#xff0c…

R语言绘图 | 双Y轴截断图

教程原文:双Y轴截断图绘制教程 本期教程 本期教程,我们提供的原文的译文,若有需求请回复关键词:20240529 小杜的生信笔记,自2021年11月开始做的知识分享,主要内容是R语言绘图教程、转录组上游分析、转录组…

HarmonyOS鸿蒙学习笔记(27)resources目录说明

resources目录说明 目录结构目录说明base目录rawfile目录resfile目录资源组目录 参考资料 目录结构 在HarmonyOS的项目结构中,有resources目录,用于存放应用/服务所用到的资源文件,如图形、多媒体、字符串、布局文件等。关于资源文件&#x…

基于Linux的文件操作(socket操作)

基于Linux的文件操作(socket操作) 1. 文件描述符基本概念文件描述符的定义:标准文件描述符:文件描述符的分配: 2. 文件描述符操作打开文件读取文件中的数据 在linux中,socket也被认为是文件的一种&#xff…

redis 高可用及哨兵模式 @by_TWJ

目录 1. 高可用2. redis 哨兵模式3. 图文的方式让我们读懂这几个算法3.1. Raft算法 - 图文3.2. Paxos算法 - 图文3.3. 区别: 1. 高可用 在 Redis 中,实现 高可用 的技术主要包括 持久化、复制、哨兵 和 集群,下面简单说明它们的作用&#xf…

jpom ruoyi 发布后端

添加ssh 添加标签 添加仓库 添加构建 构建 命令 APP_NAMEenterprise IMAGE_NAMEenterprise:latest APP_PORT8080 RUN_ENVjenkins cd ruoyi-admin docker stop $APP_NAME || true docker rm $APP_NAME || true docker rmi $IMAGE_NAME || true docker build -f Dockerfil…

排序算法(一) 基础排序算法

排序算法 基础排序算法 排序本质:减小逆序对的过程 在基础排序算法中,将待排序序列分为相对有序区与相对无序区。 每次遍历到数组末尾称为一轮。 冒泡排序(无序区-有序区, O ( n 2 ) O(n^2) O(n2),稳定,就地) 在每一轮中,逐次与下一邻项…

DNF手游攻略:勇士进阶指南!

在即将到来的6月5日,《DNF手游》将迎来一场盛大的更新,此次更新带来了大量新内容和玩法,极大丰富了游戏的体验。本文将为广大玩家详细解析此次更新的亮点,包括新增的组队挑战玩法“罗特斯入门团本”、新星使宠物的推出、宠物进化功…

Sectigo EV代码签名证书费用是多少?

随着数字化时代的到来,软件开发者和企业面临着日益严峻的安全挑战。为了确保他们的软件产品免受恶意篡改和仿冒的威胁,代码签名证书应运而生,成为了业界广泛认可的安全解决方案。在众多代码签名证书提供商中,Sectigo以其卓越的信誉…

整理GTX收发器示例工程(高速收发器十一)

前文分析了xilinx官方提供的GTX IP示例工程,该代码的结构比较混乱,本文将该代码进行梳理,形成一个便于使用的模块,后续如果要使用多通道的收发器,多次例化某个模块就行了。 下图是官方例程中GTX IP相关模块的RTL视图&a…

停车场车位引导系统方案升级实施步骤流程是什么,有什么注意事项

停车场车位引导系统是一种现代化的停车管理系统,它通过实时监测车位占用情况,并向驾驶员提供准确的空闲车位导航信息,从而提高停车场的使用效率和用户体验。随着城市交通的快速发展和车辆数量的不断增加,停车场车位引导系统已成为…

薄膜沉积的均匀性怎么计算?

知识星球(星球名:芯片制造与封测技术社区,星球号:63559049)里的学员问:经常听带我的工程师说膜层的均匀性不好,均匀性是怎么计算的? 什么是薄膜沉积的均匀性?薄膜均匀性指的是薄膜…

Leetcode刷题笔记7

69. x 的平方根 69. x 的平方根 - 力扣(LeetCode) 假设求17的平方根 解法一:暴力解法 从1开始依次尝试 比如1的平方是1,2的平方是4...直到5的平方,25>17,所以一定是4点几的平方,所以等于4…