程序员面试闪充 -- iOS音视频
Posted 程序员面试闪充
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序员面试闪充 -- iOS音视频相关的知识,希望对你有一定的参考价值。
ios对于多媒体的支持是非常强大的,无论是音视频播放、录制,还是对麦克风、摄像头的操作都提供了多套API。
一、音频
在iOS中音频播放从形式上可以分为音效播放和音乐播放。前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度、循环等控制。通常在程序中的播放时长为1~2秒。后者指的是一些较长的音频,通常是主音频,对于这些音频的播放通常需要进行精确的控制。在iOS中播放两类音频分别使用AudioToolbox.framework和AVFoundation.framework来完成音效和音乐播放。
AudioToolbox.framework是一套基于C语言的框架,可以使用它来播放音效。它的本质是将短音频注册到系统声音服务(System Sound Service)。System Sound Service是一种简单、底层的声音播放服务,但是它本身也存在着一些限制:
音频播放时间不能超过30s
数据必须是PCM或者IMA4格式
音频文件必须打包成.caf、.aif、.wav中的一种(注意这是官方文档的说法,实际测试发现一些.mp3也可以播放)
使用System Sound Service 播放音效的步骤如下:
调用AudioServicesCreateSystemSoundID( aCFURLRef inFileURL, SystemSoundID* outSystemSoundID)函数获得系统声音ID。
如果需要监听播放完成操作,则使用AudioServicesAddSystemSoundCompletion( SystemSoundID inSystemSoundID,CFRunLoopRef inRunLoop, CFStringRef inRunLoopMode, AudioServicesSystemSoundCompletionProc inCompletionRoutine, void* inClientData)方法注册回调函数。
调用AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID) 或者AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID) 方法播放音效(后者带有震动效果)。
引入头文件
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
封装音频文件处理的方法
调用获取系统声音的方法,函数会将音效文件加入到系统音频服务中并返回一个长整形ID。传入音频文件的url和声音的id作为参数。
-(void)playSoundEffect:(NSString *)name{
NSString *audioFile=[[NSBundle mainBundle] pathForResource:name ofType:nil];
NSURL *fileUrl=[NSURL fileURLWithPath:audioFile]; //音频文件url
SystemSoundID soundID=0; //outSystemSoundID:声音id
AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID);
}
调用播放完成后的方法
如果需要在播放完之后执行某些操作,可以调用系统方法注册一个播放完成的回调函数
播放音频
调用该方法并传入音频文件名称
- (void)viewDidLoad {
[super viewDidLoad];
[self playSoundEffect:@"1.mp3"];
}
如果播放较大的音频或者要对音频有精确的控制系统声音服务 可能就很难满足实际需求了,通常这种情况会选择使用AVFoundation.framework中的AVAudioPlayer来实现。AVAudioPlayer可以看成一个播放器,它支持多种音频格式,而且能够进行进度、音量、播放速度等控制呢。
属性说明和代理方法
@property(readonly, getter=isPlaying) BOOL playing 是否正在播放,只读
@property(readonly) NSUInteger numberOfChannels 音频声道数,只读
@property(readonly) NSTimeInterval duration 音频时长
@property(readonly) NSURL *url 音频文件路径,只读
@property(readonly) NSData *data 音频数据,只读
@property float pan 立体声平衡,如果为-1.0则完全左声道,如果0.0则左右声道平衡,如果为1.0则完全为右声道
@property float volume 音量大小,范围0-1.0
@property BOOL enableRate 是否允许改变播放速率
@property float rate 播放速率,范围0.5-2.0,如果为1.0则正常播放,如果要修改播放速率则必须设置enableRate为YES
@property NSTimeInterval currentTime 当前播放时长
@property(readonly) NSTimeInterval deviceCurrentTime 输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加
@property NSInteger numberOfLoops 循环播放次数,如果为0则不循环,如果小于0则无限循环,大于0则表示循环次数
@property(readonly) NSDictionary *settings 音频播放设置信息,只读
@property(getter=isMeteringEnabled) BOOL meteringEnabled 是否启用音频测量,默认为NO,一旦启用音频测量可以通过updateMeters方法更新测量值
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError 使用文件URL初始化播放器,注意这个URL不能是HTTP URL,AVAudioPlayer不支持加载网络媒体流,只能播放本地文件
- (instancetype)initWithData:(NSData *)data error:(NSError **)outError 使用NSData初始化播放器,注意使用此方法时必须文件格式和文件后缀一致,否则出错,所以相比此方法更推荐使用上述方法或- (instancetype)initWithData:(NSData *)data fileTypeHint:(NSString *)utiString error:(NSError **)outError方法进行初始化
- (BOOL)prepareToPlay; 加载音频文件到缓冲区,注意即使在播放之前音频文件没有加载到缓冲区程序也会隐式调用此方法。
- (BOOL)play; 播放音频文件
- (BOOL)playAtTime:(NSTimeInterval)time 在指定的时间开始播放音频
- (void)pause; 暂停播放
- (void)stop; 停止播放
- (void)updateMeters 更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息
- (float)peakPowerForChannel:(NSUInteger)channelNumber; 获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法
- (float)averagePowerForChannel:(NSUInteger)channelNumber 获得指定声道的分贝平均值,注意如果要获得分贝平均值必须在此之前调用updateMeters方法
@property(nonatomic, copy) NSArray *channelAssignments 获得或设置播放声道
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag 音频播放完成
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error 音频解码发生错误
AVAudioPlayer的使用比较简单:
初始化AVAudioPlayer对象,此时通常指定本地文件路径。
设置播放器属性,例如重复次数、音量大小等。
调用play方法播放。
创建一个AVAudioPlayer对象作为属性
获取指定的url对象并设置代理
self.player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
self.player.delegate = self;
调用系统的播放、暂停等方法
if ([self.player isPlaying]) {
[self.startBtn setBackgroundImage:[UIImage imageNamed:@"播放"] forState:0];
[self.player pause];
}
else
{
[self.startBtn setBackgroundImage:[UIImage imageNamed:@"暂停"] forState:0];
[self.player play];
}
AAC: AAC其实是“高级音频编码(advanced audio coding)”的缩写,它是被设计用来取代MP3格式的。
HE-AAC: HE-AAC是AAC的一个超集,这个“HE”代表的是“High efficiency”。 HE-AAC是专门为低比特率所优化的一种音频编码格式
AMR: AMR全称是“Adaptive Multi-Rate”,它也是另一个专门为“说话(speech)”所优化的编码格式,也是适合低比特率环境下采用
ALAC: 它全称是“Apple Lossless”,这是一种没有任何质量损失的音频编码方式,也就是我们说的无损压缩
IMA4: 这是一个在16-bit音频文件下按照4:1的压缩比来进行压缩的格式。
LPCM : 即线性脉冲编码调制,是一种非压缩音频数字化技术,是一种未压缩的原音重现。
WAV :音质最好的格式, 对应PCM编码。适用多媒体开发、保存音乐和音效素材。
MP3 :音质好,压缩比比较高,被大量软件和硬件支持。适用: 适合用于比较高要求的音乐欣赏。
caf :虽然适用于几乎iOS中所有的编码格式。因为某些编码设置, 文件有可能会很大, 而且caf, 格式并不是很通用, 所以在开发过程中, 一般会进行压缩转码, MP3。
二、视频
在iOS中播放视频可以使用MediaPlayer.framework中的MPMoviePlayerController类来完成,它支持本地视频和网络视频播放。这个类实现了MPMediaPlayback协议,因此具备一般的播放器控制功能,例如播放、暂停、停止等。但是MPMediaPlayerController自身并不是一个完整的视图控制器,如果要在UI中展示视频需要将view属性添加到界面中。
1)本地视频播放
导入框架
#import<MediaPlayer/MediaPlayer.h>
创建播放器对象
设置URL
添加播放器界面到控制器的view上面
虽然它是个视图控制器,但使用时需要把它的view添加到父视图上才能显示。
mpc.view.frame = CGRectMake(10,50,300,200);
[self.view addSubview:mpc.view];
定义强引用属性
播放器会在跳出方法后就被销毁,因此需要定义一个属性强引用
将播放器赋值给播放器属性
self.mpc = mpc;
调用播放方法
MPMoviePlayerController支持MOV、MP4、M4V、3GP等常用格式的视频,它提供了可以进行播放、暂停、停止、全屏的操作的方法。
设置当用户点击屏幕就调用play方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.mpc play];
}
若是要自定义播放器界面,则需要隐藏系统自带的控制面板
隐藏自带的控制面板
添加自己创建的控制面板
在iOS9.0之后, 统一使用AVPlayerViewController
来做视频处理。
优点:
自带的播放控制UI,不需要手动添加
此控制器是视图控制器, 可以弹出, 可以压栈
也可以手动调整视图大小,添加到其他视图上
缺点:
不能自定义UI
MPMoviePlayerController足够强大,几乎不用写几行代码就能完成一个播放器,但是正是由于它的高度封装使得要自定义这个播放器变得很复杂,甚至是不可能完成。例如有些时候需要自定义播放器的样式,那么如果要使用MPMoviePlayerController就不合适了,此时可以使用AVPlayer。
在开发中,单纯的使用AVPlayer类是无法实现视频播放的,要将视频添加到AVPlayerLayer中,这样才能将视频显示出来,所以我们先在
@interface中添加一下属性
@property (strong, nonatomic)AVPlayer *myPlayer;//播放器
@property (strong, nonatomic)AVPlayerItem *item;//播放单元
@property (strong, nonatomic)AVPlayerLayer *playerLayer;//播放界面
先简单介绍一下这三个属性之间的关系。我们之所以能够看到视频是因为AVPlayerLayer帮我们把视频呈现出来了,可以说是AVPlayerLayer就是一个视频播放器的载体,它负责需要播放的画面。用MVC比喻,就是AVPlayerLayer属于V层,负责对用户的呈现。从AVPlayerLayer的便利构造器方法中可以看出我们在创建一个AVPlayerLayer的时候需要一个AVPlayer类型的参数。所以在创建AVPlayerLayer的时候,我们需要先有一个AVPlayer,它用MVC来分类的话就相当于MVC中的C层,负责播放单元和播放界面的协调工作,我们在它的便利构造器方法中可以看到他需要我们传入一个AVPlayerItem也就是播放单元,所谓的播放单元就是给播放器提供了一个数据的来源,用MVC来类比的话,它就属于M层,在创建一个播放单元的时候,我们首先得需要一个网址。
综上所述,将一个视频播放出来可分为如下几个步骤。
首先我们需要一个播放的网址
初始化一个播放单元
初始化一个播放器对象
self.myPlayer = [AVPlayer playerWithPlayerItem:self.item];
初始化一个播放器的Layer
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.myPlayer];
self.playerLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, 500);
[self.view.layer addSublayer:self.playerLayer];
开始播放
只要顺序执行上面的五个步骤,就可以将一个视频播放到界面上。
面试题
1、下面不是iPhoneOS提供的播放音频的方法是()
A、 SystemSound Services
B、 OpenAL
C、 AVAudioPlayer
D、AVPlayer
答:选D。iOS提供四种方式播放音频,除了A、B、C之外,还有Audio Queue Services。AVPlayer用于视频播放。
2、请说明一下iOS直播技术的流程
答:直播技术的流程大致可以分为几个步骤:数据采集(通过摄像头和麦克风获得实时的音视频数据)、图像处理(将数据采集的输入流进行实时滤镜,得到我们美化之后的视频帧)、视频编码、封包、上传、云端(转码、录制、分发)、直播播放器。
3、请简单说一下录音的步骤
答:录音需要导入AVFoundation头文件。首先创建录音文件的存放路径,接着设置录音附加设置项,比如说编码格式、采样率、通道数、音频质量等。根据路径和设置项,使用AVAudioRecorder类创建录音对象。之后就可以调用准备录音、开始录音和结束录音的方法完成对录音的操作。
参考文章:
https://juejin.im/entry/571cc05071cfe4006b4ce8ff
https://www.jianshu.com/p/746cec2c3759
以上是关于程序员面试闪充 -- iOS音视频的主要内容,如果未能解决你的问题,请参考以下文章