当前位置: 首页 > news >正文

【OC】AVPlayerLayer的学习

文章目录

  • 前言
  • 关于AVPlayer
    • 概念及作用
    • 具体方法及使用
  • 关于AVPlayerLayer
    • 基本概念及作用
    • 具体用法
  • AVPlayer与AVPlayerLayer结合实现视频播放应用
    • 使用本地视频
    • 使用网络请求申请视频数据
  • 总结

前言

  在编写类视频软件项目时,涉及到视频播放的问题,我们需要给已有的或者用网络申请拉下来的视频一个承载器,来更好的在客户端展示和播放视频。这里就要用到AVPlayer和APlayerLayer,本篇博客会简单介绍一下AVPlayer和APlayerLayer的用法以及两者之间的关系,最后会有一个具体应用的小demo。

关于AVPlayer

概念及作用

  AVPlayer 是 AVFoundation 框架中的核心类,是播放控制核心,主要用于管理和控制音频或视频的播放。它抽象了播放逻辑(如时间控制、速率调整、多源切换等),但不直接处理视频渲染。
  主要用途有播放控制、数据源绑定、状态监听等。

播放控制​​:即管理播放、暂停、跳转、速率调整(如 0.5x 慢放、2x 快进)。
​​数据源绑定​​:通过 AVPlayerItem 关联媒体数据(本地文件、网络流媒体)。
​​状态监听​​:提供播放状态、缓冲进度、错误信息等回调(如通过 KVO 或通知)。
​​高级功能​​:支持多角度视频、画中画(PiP)、后台播放等。

具体方法及使用

1.创建及初始化(这里先以本地视频为例子)

//用于获取本地视频文件的路径 URL
NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"video_test" withExtension:@"mp4"];
//参数一:视频文件的名称(不包含扩展名) 
//参数二:视频文件的扩展名(如 .mp4, .mov 等)//创建一个 AVPlayerItem 对象,作为 AVPlayer 的数据源
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:videoURL];//初始化 AVPlayer 实例,绑定 AVPlayerItem 数据源
self.player = [AVPlayer playerWithPlayerItem:playerItem];

注意:在使用获取视频URL得方法时,要确保这个本地视频必须存在于项目的 ​​Bundle 资源目录​​中(在 Xcode 中勾选 “Target Membership”)。
在这里插入图片描述
2.播放控制

[self.player play];   // 播放
[self.player pause];  // 暂停
[self.player seekToTime:kCMTimeZero]; // 跳转到开头

3.速率控制

self.player.rate = 1.0; // 正常速度(0.0~2.0,1.0为正常)

4.状态监听

// 监听播放状态(通过通知中心)
//当 AVPlayerItem 播放到结尾时,触发 AVPlayerItemDidPlayToEndTimeNotification 通知,调用 playerItemDidReachend 方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachend) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
//参数一:观察者对象(当前类实例),需实现 playerItemDidReachend 方法
//参数二:回调方法,播放完成时触发,需在类中实现此方法
//参数三:系统定义的通知名称,表示播放项已播放到结尾
//参数四:被监听的 AVPlayerItem 对象。仅当该对象触发通知时,才会调用回调方法                                           

涉及到的关键属性:
在这里插入图片描述

关于AVPlayerLayer

基本概念及作用

  AVPlayerLayer 是 CALayer 的子类,继承自 Core Animation 框架,专门用于将 AVPlayer 的视频内容渲染到屏幕上。我们刚刚在介绍AVPlayer时,提到AVPlayer并不会对视频进行渲染处理,AVPlayer 需要通过 AVPlayerLayer 渲染视频,而AVPlayerLayer 必须绑定一个 AVPlayer 实例才能工作。AVPlayer 负责播放逻辑(如控制时间、速率),AVPlayerLayer 负责视频显示(如图层效果、缩放模式)。

对视频的渲染处理是指将原始视频数据(如未经处理的视频流、图像序列或3D场景数据)转换为最终可视化图像或视频的过程。这一过程涉及多个技术环节,目的是优化视觉效果、适配播放设备或满足特定需求(如实时性、格式兼容性等)。

  其主要用途有视频渲染、图层控制、硬件加速等。

​​视频渲染​​:将 AVPlayer 的解码后的视频帧绘制到图层。
​​图层控制​​:支持缩放模式(videoGravity)、旋转、裁剪、叠加其他图层(如水印)。
硬件加速​​:高效处理高分辨率视频,利用 GPU 加速渲染。

具体用法

1.创建与绑定

// 创建 AVPlayerLayer 并绑定到 AVPlayer
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.frame = CGRectMake(0, 100, self.view.bounds.size.width, 300);
[self.view.layer addSublayer:self.playerLayer];

2.缩放模式

// 等比例缩放(默认)
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;// 等比例填充(可能裁剪)
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;// 拉伸填充(可能变形)
self.playerLayer.videoGravity = AVLayerVideoGravityResize;

3.动态调整尺寸(这个功能笔者只是简单了解,具体实现与应用还有待完善)

// 监听屏幕旋转,调整图层尺寸
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];- (void)orientationChanged {self.playerLayer.frame = self.view.bounds;
}

其中涉及到的关键属性:
在这里插入图片描述

AVPlayer与AVPlayerLayer结合实现视频播放应用

使用本地视频

//VideoPlayerView.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>NS_ASSUME_NONNULL_BEGIN@interface VideoPlayerView : UIView
@property(nonatomic, strong)AVPlayerLayer *playerLayer;
@endNS_ASSUME_NONNULL_END//VideoPlayerView.m
#import "VideoPlayerView.h"@implementation VideoPlayerView+(Class)layerClass {return [AVPlayerLayer class];
}
- (AVPlayerLayer *)playerLayer {return (AVPlayerLayer *)self.layer;
}@end
//ViewController.m
#import "ViewController.h"
#import "VideoPlayerView.h"
#import "AVFoundation/AVFoundation.h"@interface ViewController ()@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerLayer *playerLayer;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];//1.创建视频URLNSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"video_test" withExtension:@"mp4"];if (videoURL) {NSLog(@"视频文件 URL: %@", videoURL);} else {NSLog(@"未找到视频文件");}//2.创建AVPlayerself.player = [AVPlayer playerWithURL:videoURL];//3.创建VideoPlayerViewVideoPlayerView *playerView = [[VideoPlayerView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 300)];playerView.playerLayer.player = self.player;//4.设置videoGravity(视频填充模式)playerView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;//5.将VideoOlayerView添加到视频上[self.view addSubview:playerView];//6.开始播放[self.player play];//7.监听播放结束[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachend) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}- (void)playerItemDidReachend {//播放结束后执行的操作NSLog(@"播放结束🎵");//如果需要循环播放,可以在这里重新设置播放时间[self.player seekToTime:kCMTimeZero];[self.player play];
}- (void)dealloc {//移除监听[[NSNotificationCenter defaultCenter] removeObserver:self];
}@end

效果图(可以看到视频播放结束后会自动重播):
在这里插入图片描述

使用网络请求申请视频数据

#import "ViewController.h"
#import <AFNetworking/AFNetworking.h>
#import "AVFoundation/AVFoundation.h"
#import <WebKit/WebKit.h>@interface ViewController ()<WKNavigationDelegate>
@property (nonatomic, strong) WKWebView *webView;@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerLayer *playerLayer;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.// 创建 WKWebViewself.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];self.webView.navigationDelegate = self;[self.view addSubview:self.webView];// 加载抖音短链接NSURL *shortURL = [NSURL URLWithString:@"https://v.douyin.com/L4FJNR3/"];NSURLRequest *request = [NSURLRequest requestWithURL:shortURL];[self.webView loadRequest:request];
}- (void)parseDouyinShortURL:(NSString *)shortURLString {// 创建 AFHTTPSessionManagerAFHTTPSessionManager *manager = [AFHTTPSessionManager manager];manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // 设置响应为原始数据// 发送 GET 请求[manager GET:shortURLString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {// 获取重定向后的 URLNSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;if (httpResponse.statusCode == 302) {NSString *redirectURLString = httpResponse.allHeaderFields[@"Location"];if (redirectURLString) {NSLog(@"重定向 URL: %@", redirectURLString);[self parseDouyinPageWithURL:redirectURLString];} else {NSLog(@"未找到重定向 URL");}} else {NSLog(@"未找到重定向 URL");}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"解析短链接失败: %@", error.localizedDescription);}];
}- (void)parseDouyinPageWithURL:(NSString *)pageURLString {// 创建 AFHTTPSessionManagerAFHTTPSessionManager *manager = [AFHTTPSessionManager manager];manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // 设置响应为原始数据// 发送 GET 请求[manager GET:pageURLString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {// 解析 HTMLNSString *htmlString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];if (htmlString) {// 使用正则表达式提取视频 URLNSString *pattern = @"\"playAddr\":\"(.*?)\"";NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];NSTextCheckingResult *result = [regex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)];if (result) {NSString *videoURLString = [htmlString substringWithRange:[result rangeAtIndex:1]];videoURLString = [videoURLString stringByReplacingOccurrencesOfString:@"\\" withString:@""];NSLog(@"提取的视频 URL: %@", videoURLString);// 播放视频[self playVideoWithURL:[NSURL URLWithString:videoURLString]];} else {NSLog(@"未找到视频 URL");}} else {NSLog(@"HTML 解析失败");}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"加载页面失败: %@", error.localizedDescription);}];
}- (void)playVideoWithURL:(NSURL *)videoURL {dispatch_async(dispatch_get_main_queue(), ^{// 创建 AVPlayerself.player = [AVPlayer playerWithURL:videoURL];// 创建 AVPlayerLayerself.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];self.playerLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, 300);self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;// 将 AVPlayerLayer 添加到视图上[self.view.layer addSublayer:self.playerLayer];// 开始播放[self.player play];//监听播放结束[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachend) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];});
}- (void)playerItemDidReachend {//播放结束后执行的操作NSLog(@"播放结束🎵");//如果需要循环播放,可以在这里重新设置播放时间[self.player seekToTime:kCMTimeZero];[self.player play];
}- (void)dealloc {//移除监听[[NSNotificationCenter defaultCenter] removeObserver:self];
}@end

效果图:
在这里插入图片描述

总结

  AVPlayer 和 AVPlayerLayer 是 AVFoundation 框架中用于音视频播放的两个核心类。
参数间的协作关系​​:
​​videoURL → playerItem​​:AVPlayerItem 通过 videoURL 加载媒体数据。
​​playerItem → player​​:AVPlayer 通过 playerItem 获取媒体数据并控制播放。
​​player → AVPlayerLayer​​:AVPlayerLayer 需绑定 AVPlayer 实例才能渲染视频。
在这里插入图片描述
推荐文章:iOS AVPlayer的使用

相关文章:

  • 深入解析主流数据库体系架构:从关系型到云原生
  • 从malloc到free:动态内存管理全解析
  • 【某比特币网址请求头部sign签名】RSA加密逆向分析
  • 在 Linux 上部署 .NET Core 应用并配置为开机自动启动
  • select、poll、epoll实现多路复用IO并对比差异
  • 家庭电脑隐身后台自动截屏软件,可远程查看
  • 十倍开发效率 - IDEA插件之 Maven Helper
  • QT常见输入类控件及其属性
  • SpringCloud小白入门+项目搭建
  • 秒杀抢购系统架构与优化全解:从业务特性到技术落地
  • 软考高级系统架构设计师-第13章 软件可靠性基础知识
  • 32-工艺品商城小程序
  • Redis 事件循环(Event Loop)
  • 无法右键下载文档?网页PDF下载方法大全
  • Opencv图像处理:模板匹配对象
  • 基于docker-java封装的工具类
  • Spring Boot 集成Poi-tl实现动态Word文档生成
  • Linux学习——TCP
  • C++ 相关系统软件简介与学习方法【最水的一期】
  • nuxt3前端开发以及nuxt3和nuxt2项目的详细差异点
  • 金价新高不断,上金所再发风险提示,黄金能否持续闪耀?
  • 著名政治学学者、中国人民大学教授仝志敏逝世
  • 探索未来课堂更多可能,“人工智能课堂分析循证实验室”在沪成立
  • 俄“联盟MS-26”载人飞船安全返回地球
  • 云南省交通发展投资有限责任公司原党委书记、董事长陈以东接受审查调查
  • 信心从何而来|当消博会展商遇上关税战