zoukankan      html  css  js  c++  java
  • 音视频开发笔录

    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

  • 相关阅读:
    如何快速建立自己的知识体系
    让你的网站变成灰色
    Java多线程-锁升级
    冰河正则大全
    Win硬盘/U盘设置图片
    MySQL——三范式
    MySQL——事务
    MySQL_explain
    HDFS的一些常用指令
    Hadoop集群的搭建准备
  • 原文地址:https://www.cnblogs.com/daxiong520/p/11252025.html
Copyright © 2011-2022 走看看