本文问题来自 iOS 面试旗开得胜之问题篇 中的横扫千军之战胜篇
5. 请你谈谈你对视频播放器 / 直播的理解如果封装一个视频播放器你会怎么做? 封装中遇到哪些问题? 你是怎么解决的?
视频播放器 / 直播的理解:
流媒体协议: 常用的流媒体协议有以下几种:
实时传输协议 RTP 与 RTCP RTP(Real-time Transport Protocol) 是用于 Internet 上针对多媒体数据流的一种传输协议 RTP 由两个紧密连接部分组成:
RTP: 传送具有实时属性的数据
RTP 控制协议(RTCP): 监控服务质量并传送正在进行的会话参与者的相关信息
RTP 协议是建立在 UDP 协议上的 RTP 本身并没有提供按时发送机制或其它服务质量 (QoS) 保证, 它依赖于低层服务去实现这一过程 RTP 并不保证传送或防止无序传送, 也不确定底层网络的可靠性 RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列, 同时序列号也能用于决定适当的包位置, 例如: 在视频解码中, 就不需要顺序解码
实时传输控制协议 (Real-time Transport Control Protocol,RTCP) 是实时传输协议 (RTP) 的一个姐妹协议 RTCP 为 RTP 媒体流提供信道外控制 RTCP 定期在流多媒体会话参加者之间传输控制数据 RTCP 的主要功能是为 RTP 所提供的服务质量提供反馈 RTCP 收集相关媒体连接的统计信息, 例如: 传输字节数, 传输分组数, 丢失分组数, 时延抖动, 单向和双向网络延迟等等网络应用程序可以利用 RTCP 所提供的信息试图提高服务质量, 比如限制信息流量或改用压缩比较小的编解码器 RTCP 本身不提供数据加密或身份认证, 其伴生协议 SRTCP(安全实时传输控制协议)则可用于此类用途
实时流协议 RTSP RTSP(Real Time Streaming Protocol)是由 Real Networks 和 Netscape 共同提出的该协议定义了一对多应用程序如何有效地通过 IP 网络传送多媒体数据 RTSP 提供了一个可扩展框架, 使实时数据, 如音频与视频的受控点播成为可能数据源包括现场数据与存储在剪辑中的数据该协议目的在于控制多个数据发送连接, 为选择发送通道, 如 UDP 多播 UDP 与 TCP 提供途径, 并为选择基于 RTP 上发送机制提供方法
RTSP(Real Time Streaming Protocol)是用来控制声音或影像的多媒体串流协议, 并允许同时多个串流需求控制, 传输时所用的网络通讯协定并不在其定义的范围内, 服务器端可以自行选择使用 TCP 或 UDP 来传送串流内容, 它的语法和运作跟 HTTP 1.1 类似, 但并不特别强调时间同步, 所以比较能容忍网络延迟而前面提到的允许同时多个串流需求控制(Multicast), 除了可以降低服务器端的网络用量, 更进而支持多方视讯会议(Video Conference) 因为与 HTTP1.1 的运作方式相似, 所以代理服务器 Proxy 的快取功能 Cache 也同样适用于 RTSP, 并因 RTSP 具有重新导向功能, 可视实际负载情况来转换提供服务的服务器, 以避免过大的负载集中于同一服务器而造成延迟
RTSP 和 RTP 的关系 :
RTP 不象 http 和 ftp 可完整的下载整个影视文件, 它是以固定的数据率在网络上发送数据, 客户端也是按照这种速度观看影视文件, 当影视画面播放过后, 就不可以再重复播放, 除非重新向服务器端要求数据
RTSP 与 RTP 最大的区别在于: RTSP 是一种双向实时数据传输协议, 它允许客户端向服务器端发送请求, 如回放快进倒退等操作当然, RTSP 可基于 RTP 来传送数据, 还可以选择 TCPUDP 组播 UDP 等通道来发送数据, 具有很好的扩展性它时一种类似与 http 协议的网络应用层协议
实时消息传输协议 RTMP/RTMPS
RTMP(Real Time Messaging Protocol)实时消息传送协议是 Adobe Systems 公司为 Flash 播放器和服务器之间音频视频和数据传输 开发的开放协议 它有三种变种: (1)工作在 TCP 之上的明文协议, 使用端口 1935 (2)TMPT 封装在 HTTP 请求之中, 可穿越防火墙 (3)RTMPS 类似 RTMPT, 但使用的是 HTTPS 连接
RTMP 协议 (Real Time Messaging Protocol) 是被 Flash 用于对象, 视频, 音频的传输. 这个协议建立在 TCP 协议或者轮询 HTTP 协议之上.
RTMP 协议就像一个用来装数据包的容器, 这些数据既可以是 AMF 格式的数据, 也可以是 FLV 中的视 / 音频数据. 一个单一的连接可以通过不同的通道传输多路网络流. 这些通道中的包都是按照固定大小的包传输的 RTMP 视频播放的特点: (1)RTMP 协议是采用实时的流式传输, 所以不会缓存文件到客户端, 这种特性说明用户想下载 RTMP 协议下的视频是比较难的; (2)视频流可以随便拖动, 既可以从任意时间点向服务器发送请求进行播放, 并不需要视频有关键帧相比而言, HTTP 协议下视频需要有关键帧才可以随意拖动 (3)RTMP 协议支持点播 / 回放 (通俗点将就是支持把 flv,f4v,mp4 文件放在 RTMP 服务器, 客户端可以直接播放), 直播(边录制视频边播放) RTMP 环境的架设: 因为该协议是 adobe 公司开发的, 所以最初服务器端架设的环境是 FMS(Flash Media Server), 该软件为收费软件, 价格昂贵后来, 开源软件 red5 的推出, 使 rtmp 协议的架设成本大大缩小, 但是在性能方面不如 fms 的稳定此外, wowza 虽然是收费的, 但价格比较适中 - 微软媒体服务器协议 MMS MMS(Microsoft Media Server Protocol) 是用来访问并流式接收 Window Media 服务器中. asf 文件的一种协议 MMS 协议用于访问 Windows Media 发布点上的单播内容 MMS 是连接 Windows Media 单播服务的默认方法若观众在 Windows Media Player 中键入一个 URL 以连接内容, 而不是通过超级链接访问内容, 则他们必须是 MMS 协议引用该流 MMS 的预设端口是 1755 - HLS HTTP Live Streaming(HLS)是苹果公司 (Apple Inc.) 实现的基于 HTTP 的流媒体传输协议, 可实现流媒体的直播和点播, 主要应用在 iOS 系统, 为 iOS 设备 (如 iPhoneiPad) 提供音视频直播和点播方案 HLS 点播, 基本上就是常见的分段 HTTP 点播, 不同在于, 它的分段非常小 相对于常见的流媒体直播协议, 例如 RTMP 协议 RTSP 协议 MMS 协议等, HLS 直播最大的不同在于, 直播客户端获取到的, 并不是一个完整的数据流 HLS 协议在服务器端将直播数据流存储为连续的很短时长的媒体文件 (MPEG-TS 格式), 而客户端则不断的下载并播放这些小文件, 因为服务器端总是会将最新的直播数据生成新的小文件, 这样客户端只要不停的按顺序播放从服务器获取到的文件, 就实现了直播由此可见, 基本上可以认为, HLS 是以点播的技术方式来实现直播由于数据通过 HTTP 协议传输, 所以完全不用考虑防火墙或者代理的问题, 而且分段文件的时长很短, 客户端可以很快的选择和切换码率, 以适应不同带宽条件下的播放不过 HLS 的这种技术特点, 决定了它的延迟一般总是会高于普通的流媒体直播协议 - 编解码 编解码器(codec) 指的是一个能够对一个信号或者一个数据流进行变换的设备或者程序这里指的变换既包括将 信号或者数据流进行编码 (通常是为了传输存储或者加密) 或者提取得到一个编码流的操作, 也包括为了观察或者处理从这个编码流中恢复适合观察或操作的形式的操作编解码器经常用在视频会议和流媒体等应用中 - H.264 是由 ITU-T 视频编码专家组 (VCEG) 和 ISO/IEC 动态图像专家组 MPEG)联合组成的联合视频组 (JVT,Joint Video Team) 提出的高度压缩数字视频编解码器标准这个标准通常被称之为 H.264/AVC(或者 AVC/H.264 或者 H.264/MPEG-4 AVC 或 MPEG-4/H.264 AVC)而明确的说明它两方面的开发者 - 优势: 1.低码率 (Low Bit Rate): 和 MPEG2 和 MPEG4 ASP 等压缩技术相比, 在同等图像质量下, 采用 H.264 技术压缩后的数据量只有 MPEG2 的 1/8,MPEG4 的 1/3 2.高质量的图像: H.264 能提供连续流畅的高质量图像(DVD 质量) 3.容错能力强: H.264 提供了解决在不稳定网络环境下容易发生的丢包等错误的必要工具 4.网络适应性强: H.264 提供了网络抽象层(Network Abstraction Layer), 使得 H.264 的文件能容易地在不同网络上传输(例如互联网, CDMA,GPRS,WCDMA,CDMA2000 等) - 特点: 1.更高的编码效率: 同 H.263 等标准的特率效率相比, 能够平均节省大于 50% 的码率 2.高质量的视频画面: H.264 能够在低码率情况下提供高质量的视频图像, 在较低带宽上提供高质量的图像传输是 H.264 的应用亮点 3.提高网络适应能力: H.264 可以工作在实时通信应用(如视频会议) 低延时模式下, 也可以工作在没有延时的视频存储或视频流服务器中 4.采用混合编码结构: 同 H.263 相同, H.264 也使用采用 DCT 变换编码加 DPCM 的差分编码的混合编码结构, 还增加了如多模式运动估计帧内预测多帧预测基于内容的变长编码 4x4 二维整数变换等新的编码方式, 提高了编码效率 5.H.264 的编码选项较少: 在 H.263 中编码时往往需要设置相当多选项, 增加了编码的难度, 而 H.264 做到了力求简洁的回归基本, 降低了编码时复杂度 6.H.264 可以应用在不同场合: H.264 可以根据不同的环境使用不同的传输和播放速率, 并且提供了丰富的错误处理工具, 可以很好的控制或消除丢包和误码 7.错误恢复功能: H.264 提供了解决网络传输包丢失的问题的工具, 适用于在高误码率传输的无线网络中传输视频数据 8.较高的复杂度: 264 性能的改进是以增加复杂性为代价而获得的据估计, H.264 编码的计算复杂度大约相当于 H.263 的 3 倍, 解码复杂度大约相当于 H.263 的 2 倍 - FFmpeg 是一套可以用来记录转换数字音频视频, 并能将其转化为流的开源计算机程序采用 LGPL 或 GPL 许可证它提供了录制转换以及流化音视频的完整解决方案它包含了非常先进的音频 / 视频编解码库 libavcodec, 为了保证高可移植性和编解码质量, libavcodec 里很多 code 都是从头开发的 - 功能 多媒体视频处理工具 FFmpeg 有非常强大的功能包括视频采集功能视频格式转换视频抓图给视频加水印等 ffmpeg 视频采集功能非常强大, 不仅可以采集视频采集卡或 USB 摄像头的图像, 还可以进行屏幕录制, 同时还支持以 RTP 方式将视频流传送给支持 RTSP 的流媒体服务器, 支持直播应用 - AAC 全称 Advanced Audio Coding, 是一种专为声音数据设计的文件压缩格式与 MP3 不同, 它采用了全新的算法进行编码, 更加高效, 具有更高的性价比利用 AAC 格式, 可使人感觉声音质量没有明显降低的前提下, 更加小巧苹果 ipod 诺基亚手机支持 AAC 格式的音频文件相对于 mp3,AAC 格式的音质更佳, 文件更小 - 优点 1 提升的压缩率: 可以以更小的文件大小获得更高的音质 2 支持多声道: 可提供最多 48 个全音域声道 3 更高的解析度: 最高支持 96KHz 的采样频率 4 提升的解码效率: 解码播放所占的资源更少 - 不足 AAC 属于有损压缩的格式, 与时下流行的 APEFLAC 等无损格式相比音质存在本质上的差距加之, 传输速度更快的 USB3.0 和 16G 以上大容量 MP3 正在加速普及, 也使得 AAC 头上小巧的光环不复存在 - HLS 分段生成策略及 m3u8 索引文件 m3u8, 是 HTTP Live Streaming 直播的索引文件 m3u8 基本上可以认为就是. m3u 格式文件, 区别在于, m3u8 文件使用 UTF-8 字符编码
- #EXTM3U m3u 文件头, 必须放在第一行
- #EXT-X-MEDIA-SEQUENCE 第一个 TS 分片的序列号
- #EXT-X-TARGETDURATION 每个分片 TS 的最大的时长
- #EXT-X-ALLOW-CACHE 是否允许 cache
- #EXT-X-ENDLIST m3u8 文件结束符
- #EXTINF extra info, 分片 TS 的信息, 如时长, 带宽等
- HLS 的分段策略, 基本上推荐是 10 秒一个分片, 当然, 具体时间还要根据分好后的分片的实际时长做标注通常来说, 为了缓存等方面的原因, 在索引文件中会保留最新的三个分片地址, 以类似滑动窗口的形式, 进行更新
直播现在大部分都是引用第三方服务的简单封装播放器如下:
- #import <UIKit/UIKit.h>
- #import <MediaPlayer/MediaPlayer.h>
- #import <AVKit/AVKit.h>
- @interface ZrMoviePlayer : UIView
- @property (nonatomic,strong) MPMoviePlayerController *moviePlayer;// 视频播放控制器
- /**
- * 播放资源地址
- */
- @property (nonatomic,strong) NSString *videoUrl;
- /**
- * 播放资源缩略图
- */
- @property (nonatomic,strong) UIImageView *caver;
- /**
- * 初始化
- *
- * @param frame frame
- * @param url videoUrl
- *
- * @return self
- */
- -(instancetype)initWithFrame:(CGRect)frame videoUrl:(NSString *)url;
- /**
- * 播放资源缩略图
- *
- * @param url picUrl
- */
- - (void)showCoverWithUrl:(NSString *)url;
- @end
- .m
- #import "ZrMoviePlayer.h"
- @interface ZrMoviePlayer ()
- @end
- @implementation ZrMoviePlayer
- -(instancetype)initWithFrame:(CGRect)frame videoUrl:(NSString *)url{
- self.videoUrl = url;
- self = [super initWithFrame:frame];
- if (self) {
- /** [用户手动点击播放 默认暂停]*$/[self.moviePlayer play];
- [selfaddNotification];
- /** 获取缩略图 *$/[self thumbnaiImageRequest];
- [self addGest];
- }
- return self;
- }
- /**
- * 添加手势
- */
- -(void)addGest {
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(moviePicCoverTapGesture)];
- [self addGestureRecognizer:tapGesture];
- }
- /**
- * 移除缩略图 播放视频
- */
- -(void)moviePicCoverTapGesture {
- [self.caver removeFromSuperview];
- [self.moviePlayer play];
- }
- - (void)dealloc{
- /** 移除所有通知监控 */
- [[NSNotificationCenter defaultCenter]removeObserver:self];
- }
- #pragma mark -- 私有方法 `
- /**
- * 获得本地文件路径
- *
- * @return 文件路径
- */
- - (NSURL *)getFileUrl{
- NSString *urlStr = [[NSBundle mainBundle]pathForResource:@"" ofType:nil];
- return [NSURL URLWithString:urlStr];
- }
- /**
- * 取得网络文件路径
- *
- * @return 文件路径
- */
- - (NSURL *)getNetworkUrl{
- NSString *urlStr = _videoUrl;
- urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- return [NSURL URLWithString:urlStr];
- }
- /**
- * 创建媒体播放器
- *
- * @return moviePlayer
- */
- - (MPMoviePlayerController *)moviePlayer{
- if (!_moviePlayer) {
- NSURL *url = [self getNetworkUrl];
- _moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:url];
- _moviePlayer.view.frame = self.bounds;
- _moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
- [self addSubview:_moviePlayer.view];
- }
- return _moviePlayer;
- }
- /**
- * 获取视频缩略图
- */
- - (void)thumbnaiImageRequest{
- /** 获取 13.0s21.5s 的缩略图 */
- [self.moviePlayer requestThumbnailImagesAtTimes:@[@13.0,@21.5] timeOption:MPMovieTimeOptionNearestKeyFrame];
- }
- #pragma mark - 控制器通知
- /**
- * 添加通知监控多媒体控制器状态
- */
- - (void)addNotification{
- NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
- [notificationCenter addObserver:self
- selector:@selector(mediaPlayerPlaybackFinished:)
- name:MPMoviePlayerPlaybackDidFinishNotification
- object:self.moviePlayer];
- [notificationCenter addObserver:self
- selector:@selector(mediaPlayerPlaybackStateChange:)
- name:MPMoviePlayerPlaybackStateDidChangeNotification
- object:self.moviePlayer];
- [notificationCenter addObserver:self
- selector:@selector(mediaPlayerThumbnailRequestFinished:)
- name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
- object:self.moviePlayer];
- }
- /**
- * 播放状态改变, 注意播放完成时的状态是暂停
- *
- * @param notify 通知对象
- */
- - (void)mediaPlayerPlaybackStateChange:(NSNotification *)notify{
- switch (self.moviePlayer.playbackState) {
- case MPMoviePlaybackStatePlaying:
- NSLog(@"正在播放");
- // [[NSNotificationCenter defaultCenter] postNotificationName:MoviePlayNotification object:nil];
- break;
- case MPMoviePlaybackStatePaused:
- NSLog(@"暂停播放");
- // [[NSNotificationCenter defaultCenter] postNotificationName:MoviePauseOrStopNotification object:nil];
- break;
- case MPMoviePlaybackStateStopped:
- NSLog(@"停止播放");
- // [[NSNotificationCenter defaultCenter] postNotificationName:MoviePauseOrStopNotification object:nil];
- break;
- default:
- NSLog(@"播放状态:%ld",(long)self.moviePlayer.playbackState);
- break;
- }
- }
- - (void)mediaPlayerPlaybackFinished:(NSNotification *)notify{
- NSLog(@"播放完成");
- }
- /**
- * 缩略图请求完成, 此方法每次截图成功后都会调用一次
- *
- * @param notify 通知对象
- */
- - (void)mediaPlayerThumbnailRequestFinished:(NSNotification *)notify{
- NSLog(@"视频截图成功");
- UIImage *image = notify.userInfo[MPMoviePlayerThumbnailImageKey];
- // 保存图片到相册(首次调用会请求用户获访问相册权限)
- UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
- }
- /**
- * 播放资源缩略图
- *
- * @param url picUrl
- */
- - (void)showCoverWithUrl:(NSString *)url {
- UIImageView *caver = [[UIImageView alloc] init];
- _caver = caver;
- [caver sd_setImageWithURL:[NSURL URLWithString:url]placeholderImage:[UIImage imageNamed:@"videoPlaceHolder"]];
- [self addSubview:caver];
- UIImageView *pause = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
- pause.image = [UIImage imageNamed:@"zr_pause"];
- [caver addSubview:pause];
- caver.sd_layout
- .leftSpaceToView(self,0)
- .topSpaceToView(self,0)
- .rightSpaceToView(self,0)
- .bottomSpaceToView(self,0);
- pause.center = CGPointMake(self.center.x, self.center.y-20);
- }
- @end
这篇文章 讲解了 得到 和 喜马拉雅 FM 的播放器的实现 喜马拉雅 FM 的 头文件点击下载 密码: u4uu
6. 谈谈你对 JSON XML 的理解
JSON 是什么?
JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
JSON 是轻量级的文本数据交换格式
JSON 独立于语言(JSON 使用 JavaScript 语法来描述数据对象, 但是 JSON 仍然独立于语言和平台 JSON 解析器和 JSON 库支持许多不同的编程语言)
JSON 具有自我描述性, 更易理解
JSON 的规则很简单: 对象是一个无序的 名称 / 值 对 集合一个对象以 {(左括号) 开始,}(右括号)结束每个名称后跟一个:(冒号); 名称 / 值 对之间使用,(逗号)分隔
什么是 XML?
XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言, 很类似 html
XML 的设计宗旨是传输数据, 而非显示数据
XML 标签没有被预定义您需要自行定义标签
XML 被设计为具有自我描述性
JSON 与 XML 的互相比较
简单的数据 XML
- <person>
- <name>xiaoMing</name>
- <age>20</age>
- </person>
- JSON
- {
- "name":"xiaoMing",
- "age":20
- }
复杂的数据 XML
- <section>
- <title>BOOK</title>
- <signing>
- <author name="author-1"/>
- <book title="book1" price="$11"/>
- </signing>
- <signing>
- <author name="author-2"/>
- <book title="book2" price="$22"/>
- </signing>
- </section>
- JSON
- "section":{
- "title":"BOOK",
- "signing":[
- {
- "author":
- {
- "name":"author-1"
- },
- "book":
- {
- "title":"book1",
- "price":"$11"
- }
- },
- {
- "author":
- {
- "name":"author-2"
- },
- "book":
- {
- "title":"book2",
- "price":"$22"
- }
- }]
- }
JSON 和 XML 的优缺点 XML
优点 (1)格式统一, 符合标准; (2)容易与其他系统进行远程交互, 数据传输比较方便 - 缺点 (1)XML 文件庞大, 文件格式复杂, 传输占带宽; (2)服务器端和客户端都需要花费大量代码来解析 XML, 导致服务器端和客户端代码变得异常复杂且不易维护; (3)客户端不同浏览器之间解析 XML 的方式不一致, 需要重复编写很多代码; (4)服务器端和客户端解析 XML 花费较多的资源和时间 JSON
优点 (1)数据格式比较简单, 易于读写, 格式都是压缩的, 占用带宽小;
(2)易于解析, 客户端 JavaScript 可以简单的通过 eval_r()进行 JSON 数据的读取;
(3)支持多种语言, 包括 ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby 等服务器端语言, 便于服务器端的解析;
(4)在 PHP 世界, 已经有 PHP-JSON 和 JSON-PHP 出现了, 偏于 PHP 序列化后的程序直接调用, PHP 服务器端的对象数组等能直接生成 JSON 格式, 便于客户端的访问提取;
(5)因为 JSON 格式能直接为服务器端代码使用, 大大简化了服务器端和客户端的代码开发量, 且完成任务不变, 并且易于维护 - 缺点 (1)没有 XML 格式这么推广的深入人心和喜用广泛, 没有 XML 那么通用性; (2)JSON 格式目前在 web Service 中推广还属于初级阶段
来源: https://www.thinksaas.cn/group/topic/839014/