• 音视频开发笔录


    iOS平台使用播放视频,可用的选项一般有这四个,他们各自的作用和功能如下:

     使用环境优点缺点
    MPMoviePlayerController MediaPlayer 简单易用 不可定制
    AVPlayerViewController AVKit 简单易用 不可定制
    AVPlayer AVFoundation 可定制度高,功能强大 不支持流媒体
    IJKPlayer IJKMediaFramework 定制度高,支持流媒体播放 使用稍复杂

    由此可以看出,如果我们不做直播功能AVPlayer就是一个最优的选择。

    另外AVPlayer是一个可以播放任何格式的全功能影音播放器
    支持视频格式: WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等。
    支持音频格式:MP3,WMA,RM,ACC,OGG,APE,FLAC,FLV等。
    所以不得不说苹果亲儿子还是很强大的,是做视频开发的首选。

    AVPlayer:控制播放器的播放,暂停,播放速度
    AVURLAsset : AVAsset 的一个子类,使用 URL 进行实例化,实例化对象包换 URL 对应视频资源的所有信息。
    AVPlayerItem:管理资源对象,提供播放数据源
    AVPlayerLayer:负责显示视频,如果没有添加该类,只有声音没有画面

    更改速度:

    self.player.rate = 1.5;//注意更改播放速度要在视频开始播放之后才会生效

    我们使用KVO监测playItem.status,可以获取播放状态的变化

    视频的时间信息

    在AVPlayer中时间的表示有一个专门的结构体CMTime

    typedef struct{
    CMTimeValue value; // 帧数
    CMTimeScale timescale; // 帧率(影片每秒有几帧)
    CMTimeFlags flags;
    CMTimeEpoch epoch;
    } CMTime;

    CMTime是以分数的形式表示时间,value表示分子,timescale表示分母,flags是位掩码,表示时间的指定状态。

    获取当前播放时间,可以用value/timescale的方式:

    float currentTime = self.playItem.currentTime.value/item.currentTime.timescale;

    还有一种利用系统提供的方法,我们用它获取视频总时间:

    float totalTime = CMTimeGetSeconds(item.duration);

    如果我们想要添加一个计时的标签不断更新当前的播放进度,有一个系统的方法:

    • (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;

    方法名如其意, “添加周期时间观察者” ,参数1 interal 为CMTime 类型的,参数2 queue为串行队列,如果传入NULL就是默认主线程,参数3 为CMTime 的block类型。
    简而言之就是,每隔一段时间后执行 block。
    比如:我们把interval设置成CMTimeMake(1, 10),在block里面刷新label,就是一秒钟刷新10次。

    正常观察播放进度一秒钟一次就行了

    loadedTimeRange 缓存时间

    获取视频的缓存情况我们需要监听playerItem的loadedTimeRanges属性

    [self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

    在KVO的回调里:

    if ([keyPath isEqualToString:@"loadedTimeRanges"]){
    NSArray *array = _playerItem.loadedTimeRanges;
    CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
    NSLog(@"当前缓冲时间:%f",totalBuffer);
    }


    playbackBufferEmpty
    表示视频缓存内容是否可以满足播放需求,YES:显示转圈动画提示。

    监听playbackBufferEmpty我们可以获取当缓存不够,视频加载不出来的情况:

    [self.playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];


    playbackLikelyToKeepUp 缓存是否可以满足播放

    playbackLikelyToKeepUp和playbackBufferEmpty是一对,用于监听缓存足够播放的状态

    [self.playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
    /* ... */
    if([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
    //由于 AVPlayer 缓存不足就会自动暂停,所以缓存充足了需要手动播放,才能继续播放
    [_player play];
    }

     

    AVURLAsset

    播放视频只需一个url就能进行这样太不安全了,别人可以轻易的抓包盗链,为此我们需要为视频链接做一个请求头的认证,这个功能可以借助AVURLAsset完成。

    • (instancetype)URLAssetWithURL:(NSURL *)URL options:(nullable NSDictionary<NSString *, id> *)options;

    AVURLAssetPreferPreciseDurationAndTimingKey.这个key对应的value是一个布尔值, 用来表明资源是否需要为时长的精确展示,以及随机时间内容的读取进行提前准备。

    除了这个苹果官方介绍的功能外,他还可以设置请求头,这个算是隐藏功能了,因为苹果并没有明说这个功能,我是费了很大劲找到的。

    NSMutableDictionary * headers = [NSMutableDictionary dictionary];
    [headers setObject:@"yourHeader"forKey:@"User-Agent"];
    self.urlAsset = [AVURLAsset URLAssetWithURL:self.videoURLoptions:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}];
    // 初始化playerItem
    self.playerItem = [AVPlayerItem playerItemWithAsset:self.urlAsset];

    补充:后来得知这个参数是非公开的API,但是经多人测试项目上线不受影响。


    播放相关通知
    1、声音类:
    //声音被打断的通知(电话打来)
    AVAudioSessionInterruptionNotification
    //耳机插入和拔出的通知
    AVAudioSessionRouteChangeNotification
    2、播放类
    //播放完成
    AVPlayerItemDidPlayToEndTimeNotification
    //播放失败
    AVPlayerItemFailedToPlayToEndTimeNotification
    //异常中断
    AVPlayerItemPlaybackStalledNotification
    1. 首先确定好需要实现什么功能,音频播放中设计的功能非常的多,包括:
    • 上下首音频切换
    • 播放暂停
    • 拖动快进
    • 缓冲进度
    • 锁屏播放
    • 后台播放
    • 循环播放
    • 锁屏状态下的操作
    • 自动播放
    2. 确定好功能,开始架构怎么实现,由于音频播放一般需要后台播放和锁屏播放,所以这涉及到很多地方,首先播放器这个类要单独出来,创建一个全局都能使用的,方便各处使用调用。当然包括音频播放页,这个页面是不能被释放的,所以就不能使用正常的跳转方式。
    • 播放器管理类全局
    • 注意页面跳转问题


    AVPlayerItem:相当于一个资源管理工具,里边包含了音频的各种信息
    每次创建之前先移除,然后创建,设置四个监听,然后清空实时监听者,这个就是用来音频播放时候实时进度,时长,进度条的变化都在这里边实现。

    下面就是实现上边音频资源管理的四个监听方法,来执行不同情况下的处理,

    • status 准备开始播放
    • loadedTimeRanges 获取缓冲进度
    • playbackBufferEmpty 缓冲进度不足暂停
    • playbackLikelyToKeepUp 缓冲进度达到可以播放了

    但是在切换playItem前要把所有的通知,观察者移除,切换后重新添加。

    iOS中声音播放的各种方法总结:https://www.jianshu.com/p/548afbe49e67

  • 相关阅读:
    [BJOI2019] 光线
    C# 从零开始写 SharpDx 应用 笔刷
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    PowerShell 拿到显卡信息
    PowerShell 拿到显卡信息
    win10 uwp 如何使用DataTemplate
    win10 uwp 如何使用DataTemplate
  • 原文地址:https://www.cnblogs.com/daxiong520/p/11252025.html
Copyright © 2020-2023  润新知