iOS面试旗开得胜之横扫千军篇(二)
本文问题来自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来传送数据,还可以选择TCP、UDP、组播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设备(如iPhone、iPad)提供音视频直播和点播方案。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属于有损压缩的格式,与时下流行的APE、FLAC等无损格式相比音质存在“本质上”的差距。加之,传输速度更快的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.0s、21.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中推广还属于初级阶段。
QQ技术交流群:214541576
微信公众号:shavekevin
开发者头条:
热爱生活,分享快乐。好记性不如烂笔头。多写,多记,多实践,多思考。