AVPlayer视频播放

2023-11-14

AVFoundation中的元数据

Apple环境下的媒体类型主要有四种:

  • QuickTime(mov)
  • MPEG-4 video(mp4和m4v)
  • MPEG-4 audio(m4a)
  • MPEG-Layer III audio(mp3)

使用元数据

大部分使用AVAsset提供元数据,但是当涉及获取曲目一级元数据等情况时也会使用AVAssetTrack

获取资源中包含的所有元数据

NSURL *url = [NSURL URLWithString:@"url"];
AVAsset *asset = [AVAsset assetWithURL:url];
//需要加载的属性数组
NSArray *keys = @[@"availableMetadataFormats"];
//异步加载属性
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
    //获取属性的加载状态
AVKeyValueStatus status = [asset statusOfValueForKey:@"availableMetadataFormats"error:nil];
    if(status == AVKeyValueStatusLoaded){
        //将资源的元数据放入数组
        NSMutableArray *metadata = [NSMutableArray array];
        for(NSString *format in asset.availableMetadataFormats){
            [metadata addObject:format];
        }
    }
}];

筛选元数据

NSArray *metadata = @[];//AVMetadataItems
//常用的键空间
//AVMetadataFormatQuickTimeMetadata,
//AVMetadataFormatiTunesMetadata,
//AVMetadataFormatID3Metadata
NSString *keySpace = AVMetadataKeySpaceiTunes;
NSString *artisKey = AVMetadataiTunesMetadataKeyArtist;
NSString *albumKey = AVMetadataiTunesMetadataKeyAlbum;
//筛选获取演唱者的元数据
NSArray *artisMetadata = [AVMetadataItem metadataItemsFromArray:metadata withKey:artisKey keySpace:keySpace];
//获取唱片的元数据
NSArray *albumMetadata = [AVMetadataItem metadataItemsFromArray:metadata withKey:albumKey keySpace:keySpace];

AVMetadataItem *artisItem,*albumItem;
if(artisMetadata.count > 0){
    artisItem = artisMetadata[0];
}
if(albumMetadata.count > 0){
    albumItem = albumMetadata[0];
}

1.AVPlayer

AVPlayer可以支持播放本地、分布下载或通过HTTP Live Streaming协议得到的流媒体

注: AVPlayer只管理单独资源的播放,AVQueuePlayer可以管理一个资源队列

创建对象

//两个类方法创建
+ (instancetype)playerWithURL:(NSURL *)URL;
+ (instancetype)playerWithPlayerItem:(AVPlayerItem *)item;
//两个实例方法
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithPlayerItem:(AVPlayerItem *)item;

属性

//状态
@property (nonatomic, readonly) AVPlayerStatus status;
//AVPlayerStatusUnknown,
//AVPlayerStatusReadyToPlay
//AVPlayerStatusFailed

statusAVPlayerStatusFailedAVPlayer将不能播放,才是需要重新创建对象

拓展AVPlayerPlaybackControl

//当前播放速度,值为0.0时停止播放,值为1.0时为正常播放速度
@property (nonatomic) float rate;
//播放和暂停的方法
- (void)play;
- (void)pause;

拓展AVPlayerItemControl

//当前播放的项目
@property (nonatomic, readonly, nullable) AVPlayerItem *currentItem;
//替换当前播放的项目,可以用于切换视频或音频,当需要替换的item和currentItem为同一个时不做任何操作,音视频据需播放,没有任何影响
- (void)replaceCurrentItemWithPlayerItem:(nullable AVPlayerItem *)item;

//当播放完毕时的操作
@property (nonatomic) AVPlayerActionAtItemEnd actionAtItemEnd;
//AVPlayerActionAtItemEndAdvance 该属性只有AVQueuePlayer才可以用,表示继续播放下一个项目
//AVPlayerActionAtItemEndPause  播放完毕后暂停
//AVPlayerActionAtItemEndNone   不错任何处理

拓展AVPlayerTimeControl

//当前的播放时间
- (CMTime)currentTime;
//播放到指定时间位置
- (void)seekToDate:(NSDate *)date;
- (void)seekToDate:(NSDate *)date completionHandler:(void (^)(BOOL finished))completionHandler
- (void)seekToTime:(CMTime)time;
//直接播放到一个时间的范围
- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter;

拓展AVPlayerMediaControl

//当前播放的声音,如果想做媒体播放声音的进度条不要用这个,可以使用MPVolumeView,这个只是控制当前item播放音量而不是所有的item音量
@property (nonatomic) float volume

2.AVPlayerLayer

//需要一个AVPlayer对象做参数获取一个AVPlayerLayer实例
//AVPlayerLayer负责展示画面,AVPlayer负责链接资源
+ (AVPlayerLayer *)playerLayerWithPlayer:(nullable AVPlayer *)player
@property (nonatomic, retain, nullable) AVPlayer *player

//播放画面的缩放比例,和iamgeview的contentmode差不多
//AVLayerVideoGravityResizeAspect  默认值
//AVLayerVideoGravityResizeAspectFill
//AVLayerVideoGravityResize
@property(copy) NSString *videoGravity

//当前视频图像的大小位置
@property (nonatomic, readonly) CGRect videoRect

3.CMTime

//CMTime的定义
typedef struct
{
  CMTimeValue   value;          分子
  CMTimeScale   timescale;      分母
  CMTimeFlags   flags;
  CMTimeEpoch   epoch;
} CMTime;

//0.5秒
CMTime halfSecond = CMTimeMake(1, 2);
//5秒
CMTime fiveSecond = CMTimeMake(5, 1);
//44.1kHZ
CMTime oneSample = CMTimeMake(1, 44100);

4.播放视频

//根据url获得视频资源
_asset = [AVAsset assetWithURL:url];
//需要加载的属性数组
NSArray *keys = @[@"tracks",
                  @"duration",
                  @"commonMetadata",
       @"availableMediaCharacteristicsWithMediaSelectionOptions"];
//这种初始化方法可以同时加载属性    
_playerItem = [AVPlayerItem playerItemWithAsset:_asset automaticallyLoadedAssetKeys:keys];
//AVPlayerItem对象初始化AVPlayer
_player = [AVPlayer playerWithPlayerItem:_playerItem];
//为AVPlayerLayer设置AVPlayer
[(AVPlayerLayer *)self.layer setPlayer:_player];
//监听AVPlayerItem的播放状态
[_playerItem addObserver:self forKeyPath:@"status" options:0 context:&PlayerStatus];

监听方法

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {

    if(context == &PlayerStatus){
      //因为不知道在哪个线程,所以指定组线程执行
        dispatch_async(dispatch_get_main_queue(), ^{
            if(_playerItem.status == AVPlayerStatusReadyToPlay){
              //移除监听状态
              [self.playerItem removeObserver:self forKeyPath:@"status"];
            //1.获取标题
            //2.获取播放时间,设置进度条
            //3.添加播放时间的监听
            //4.监听播放结束事件 
            //播放
              [_player play];
            }
        });
    }
}

设置标题

//首先获取commonMetadata属性的加载状态
AVKeyValueStatus status = [_asset statusOfValueForKey:@"commonMetadata" error:nil];
    if(status == AVKeyValueStatusLoaded){
        //获取标题项数据
        NSArray *items = [AVMetadataItem metadataItemsFromArray:_asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
        if(items.count > 0){
            AVMetadataItem *titleItem = items[0];
            self.titleLabel.text = titleItem.stringValue;
        }else{
            self.titleLabel.text = @"";
        }
    }

获取播放总时间

CMTime duration = _playerItem.duration;
fload durationTime = CMTimeGetSeconds(duration);

添加播放时间的监听

CMTime interval = CMTimeMakeWithSeconds(1, 2);
__block typeof(self) weakSelf = self;
//这个返回的对象要强引用
self.timeObserver = [self.player addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {

    [weakSelf setSliderWithCurrentTime:CMTimeGetSeconds(time) durationTime:CMTimeGetSeconds(weakSelf.playerItem.duration)];
}];

播放结束通知

//注意强引用
self.playEndObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {

}];

拖动进度条

- (void)beginSlider {
  //可以存储播放速度
  //停止播放然后移除播放时间监听
  [self.player pause];
  [self.player removeTimeObserver:self.timeObserver];
}

- (void)progressSlider {
  //取消上一次的查找
  [self.playerItem cancelPendingSeeks];
  //移动到播放对应时间
  [self.player seekToTime:CMTimeMakeWithSeconds(self.slider.value, 1) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}

- (void)endSlider {
  //存储拖动前的播放速度前提下,可以根据播放速度进一步进行处理
  //添加播放时间监听
  [self addTimeObserver];
  [self.player play];
}

获取对应时间的图像

//需要强引用对象
self.imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];
//指定获取图片的大小,图片会根据宽度自动调整高度
self.imageGenerator.maximumSize = CGSizeMake(200, 0);

CMTime durationTime = _asset.duration;
//存储需要获取图片的时间点
NSMutableArray *times = [NSMutableArray array];
//将影片时间分为20个点
CMTimeValue increment = durationTime.value/20;
CMTimeValue currentValue = kCMTimeZero.value;
while (currentValue <= durationTime.value) {
    CMTime currentTime = CMTimeMake(currentValue, durationTime.timescale);
    [times addObject:[NSValue valueWithCMTime:currentTime]];
    currentValue += increment;
}
//请求图片
[self.imageGenerator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef  _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {

    if(result == AVAssetImageGeneratorSucceeded){
        //主线线程处理
    }
}];

显示字幕

//加载字幕或者语音需要先加载资源的availableMediaCharacteristicsWithMediaSelectionOptions属性
AVMediaSelectionGroup *group = [self.asset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
//获取和本地一样的语言字幕
NSArray *options = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:group.options withLocale:[NSLocale currentLocale]];
[_playerItem selectMediaOption:options[0] inMediaSelectionGroup:group];
//遍历循环查找英文字幕
for(AVMediaSelectionOption *option in group.options){
    if([option.displayName isEqualToString:@"English"]){
        [_playerItem selectMediaOption:option inMediaSelectionGroup:group];
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AVPlayer视频播放 的相关文章

  • 创建类似于邮件应用程序菜单的 iPhone 弹出菜单

    当您想要回复消息时 我想创建一个类似于邮件应用程序中的弹出菜单 我在多个应用程序中看到过这一点 所以我不确定框架中是否内置了某些内容或一些示例代码 在 Swift 中创建操作表 代码已使用 Swift 5 进行测试 从 iOS 8 开始 U
  • Swift - 本地通知不会被触发

    我正在 Swift 3 中编码 我只是想发送通知now没有任何延迟或间隔 然而 通知永远不会被触发 这是我的代码 视图控制器代码 import UserNotifications class HomeViewController UIVie
  • 部署目标是什么意思?

    这是我假设的一个非常简单的问题 有人可以告诉我部署目标是什么意思吗 如果我选择 iOS 10 是否意味着只有 iOS 10 的用户才能下载该应用程序 选择较低的部署目标是否不好 另外 继续部署目标 是否不建议在较低的部署目标上运行 假设您已
  • tableView.dequeueReusableCellWithIdentifier() 导致应用程序挂起

    原帖 我们最近将我们的应用程序转换为 Swift 2 0 和 iOS9 我看到的一个奇怪的问题是调用 tableView dequeueReusableCellWithIdentifier 会导致应用程序挂在模拟器中 The code fu
  • iOS 中如何清除特定域的 cookie?

    我已经搜索了 StackOverflow 上的几乎所有问题来寻找我的问题的答案 我还没有找到任何有用的链接或教程来说明哪种方式最好清除特定域的 cookie 如果有人可以帮助我 请 我自己找到了解决方案 如果您想删除 UIWebView 中
  • 将第 3 方库 ZXing 导入 Xcode

    我尝试了多种方法将第 3 方库 ZXing 导入我的 iOS 应用程序 但所有方法都很痛苦 或者根本不起作用 如果有人可以建议我做错了什么 或者提出导入 ZXing 等库的更好方法 我将非常感激 一定比这个容易 这就是我所做的 结果是 My
  • iOS8 CoreData“使用未实现的初始化程序”

    我尝试运行我的应用程序时收到以下错误 致命错误 对类 rcresttest CatalogItem 使用未实现的初始化程序 init entity insertIntoManagedObjectContext 我可以通过将数据模型中的实体类
  • 本地化现有的 iOS 应用程序

    我不敢相信以前没有人问过这个问题 要么是我的编码实践太无组织性 要么是我没有使用正确的关键字 How can I localize an existing iOS app that does not use NSLocalizedStrin
  • 打乱 NSMutableArray 而不重复并显示在 UIButton 中

    在我看来 我有 12 个按钮 一个数组包含 6 个名称 我想在其中打印数组名称UIButton标题 这是我的代码 texts NSMutableArray alloc initWithObjects 1 2 3 4 5 6 nil UIBu
  • 如何在 Firebase 控制台中使用 Apple 新的 APN .p8 证书

    随着最近 Apple 开发者帐户的升级 我面临着一个困难 在尝试创建推送通知证书时 它为我提供了 p8 证书 而不是可以导出到 p12 的 APNs 证书 Firebase 控制台仅接受 p12 证书 那么我如何从这些新的 p8 证书中获取
  • 在横向中自动调整 UITableCells 内容的大小

    在 UITableView 中 我通过 UILabels 将内容添加到单元格中 定义最佳尺寸 与单元格宽度允许的一样大 我注意到只有tableView contentSize width是可靠的 因为cell contentView bou
  • 如何知道我的应用程序使用了多少 iCloud 空间?

    有没有办法查看我的应用程序正在备份到 iCloud 的内容以及它消耗了多少内存 Settings gt iCloud gt Storage Backup gt Manage Storage将显示正在备份的总计内容 iOS 会备份位于应用程序
  • 如何在 iOS 9 上可靠地检测是否连接了外部键盘?

    在 iOS 9 之前 确定是否连接外部键盘的最可靠方法是监听UIKeyboardWillShowNotification并使文本字段成为第一响应者 如中所述这个问题 https stackoverflow com questions 289
  • 如何使用AudioKit保存音频文件?

    我有音频文件 我给它做了一些效果 let pitchshifter AKPitchShifter self audioPlayer pitchshifter shift 10 AudioKit output pitchshifter 如果我
  • 如何接收有关与我共享的记录中所做更改的 CloudKit 通知?

    我有两个 iCloud 帐户 A and B 在两个不同的设备上 来自其中之一 A 我将 ckrecord 分享给另一个人 B 像这样 let controller UICloudSharingController controller p
  • 覆盖层不与 UITableView 一起滚动 - iOS

    我有一个 UITableView 类 它使用以下方法在转到下一个屏幕时调用加载覆盖 问题是这个加载屏幕不随列表滚动 所以如果你滚动一点并单击某些东西 加载屏幕不会显示 因为它位于顶部 如何让加载屏幕始终保持在 UITableView 的顶部
  • 减少 CoreData 的调试输出?

    我正在开发一个使用 CoreData 的 iOS macOS 项目 它工作正常 但它会向控制台输出大量调试信息 这使得控制台无法使用 因为我的打印语句隐藏在所有与 CoreData 相关的内容中 我有一个非常简单的 CoreData 设置
  • 推送动画,没有阴影和停电

    我有一个简单的iOS NavigationController基于应用程序 二UICollectionViews 相继 如果元素打开 第一个合集 被点击时 第二集 将被打开 非常简单 重要的提示 Both UICollectionViews
  • AVAssetExportSession 为零 iPhone 7 - Plus 模拟器

    AVAssetExportSession在 iPhone 6 及以下版本上运行良好 但在 iPhone 7 iPhone 7 Plus 模拟器上运行不佳 Xcode 8 0 这段代码return nil在exportSession中 当在i
  • PFQueryTableViewController 错误

    我正在遵循在线教程 使用 Parse 作为后端创建照片共享应用程序 我已经运行了两次教程 两次都从头开始创建应用程序 但在同一位置仍然出现相同的错误 我到处寻找解决方案 但仍然没有运气 我正在使用 PFQueryTableViewContr

随机推荐