音效
- 1.iOS中音乐可以暂停,音效不能操作;而且音效可以立即播放,加载到本地,而音乐需要缓冲,边下边播.在iOS中只有小于30s的音乐才可以使用音效的方式进行播放.
- 2.播放音效的实现思路:初始化soundID -> 获取音频文件的本地路径(NSURL类型) ->创建soundID -> 进行播放.
音效播放的优化:以键值对的形式对音频文件和对应的soundID进行缓存,
获取之前先判断对应的soundID是否已经在,存在的话直接在内存中取,不存在才创建:
SystemSoundID systemSoundID;
NSURL *url = [[NSBundle mainBundle] URLForResource:@"buyao.caf" withExtension:nil];
AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &systemSoundID);
AudioServicesPlaySystemSound(systemSoundID);
在接收到内存警告的情况下:释放soundID对应的内存地址,清空内存缓存.
//释放soundID对应的内存地址
for (NSNumber *soundIDNum in self.soundIDCache.allValues) {
AudioServicesDisposeSystemSoundID([soundIDNum unsignedIntValue]);
}
- 3.框架:AVFoundation.
- 4.关键类:SystemSoundID,每个音频文件使用音效方式处理时,会完整的添加到内存中,并被赋予一个声音ID.
- 5.C的对象和OC对象的转化中内存管理:
__bridge 用于Foundation中的类和CoreFoundation中的类相互转换,
并且内存管理所有权不会改变。
__bridge_retained 只能用于Foundation对象转CoreFoundation引用,
而且内存管理的所有权会移交给引CoreFoundation的引用(注意手动内存管理)。
__bridge_transfer 只能用于CoreFoundation引用转Foundation对象,
而且内存管理的所有权会移交给引Foundation(会自动内存管理,不需要手动释放)。
音乐
- 1.框架:AVFoundation
- 2.关键类:AVAudioPlayer (只能播放本地音乐).
对象方法创建: _player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- 3.音乐的播放.暂停和停止的实现:根据音频文件路径初始化播放器 -> 进行缓冲
[self.player prepareToPlay];
- 4.注意点:停止播放是音乐停止缓冲,但播放进度并不会清零.暂停音乐是暂时停止播放,但缓冲继续.音乐播放,隐式缓冲.
关键方法:
-(void)play;//播放
-(void)prepareToPlay;//缓存播放
-(void)pause;//暂停
-(void)stop;//停止
录音
- 1.录音功能的实现:
生成录音的存放路径(沙盒路径,拼接文件名:stringByAppendingPathComponent:@"音频名.caf") -> 设置采样率和位深 -> 对象方法创建录音机对象
- 2.框架:AVFoundation.
关键类:AVFoundationRecorder.
关键方法:
-(void)record;//录制
-(void)pause;//暂停
-(void)stop;//停止
- 3.设置采样率和位深:
NSDictionary *settings = @{AVSampleRateKey:@44100,AVLinearPCMBitDepthKey:@16};
- 4.注意点:
真机进行录音时,需要请求用户授权.在info.plist进行麦克风的授权说明.
- 5.检测录音音量变化(&静默2s停止录音)
//开启检测音量变化
self.recorder.meteringEnabled = YES;
//开启定时器
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
- (void)updateMeters{
//更新音量变化
[self.recorder updateMeters];
//获取瞬时音量
float power = [self.recorder peakPowerForChannel:0];
NSLog(@"%f", power);
//静默两秒后就停止录音
if (power < -30) {
//累计静默计数
self.muteCount++;
if (self.muteCount >= 120) { //静默两秒钟
//停止录音
[self.recorder stop];
//停止定时器
[self.displayLink invalidate];
}
} else {
//有声音,就重新计数
self.muteCount = 0;
}
}
视频
- 1.播放视频的三个框架
- AVFoundation:提供了相对底层的API,不带界面效果.
- MediaPlayer:对AVFoundation进行了封装,提供了较为简便的播放器使用.
- AVKit:ios9推出,集AVFoundation和MediaPlayer之大成.
- 2.播放器的创建
- 1.MPMoviewPlayerViewController(带界面的视频播放器):
获取视频文件的url路径 ->对象方法创建视频播放控制器 ->modal展示.
- 2.MPMoviewPlayerController(不带界面的视频播放器):
获取视频文件路径 ->创建控制器对象 ->将播放器的视图添加到要展示的界面上 ->[控制器对象 play];
- 3.AVPlayer,偏底层,既可以播放音频又可以播放视频,播放视频需要添加layer到父视图上.
//创建资源对象 获取文件信息
AVAsset *asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://baobab.wdjcdn.com/14676170652191(23).mp4"]];
//创建播放项目 曲目
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];
//AVPlayer既可以播音频也可以播视频,可以本地也可以播网络
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:item];
//设置视图layer
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
[self.view.layer addSublayer:layer];
layer.frame = [UIScreen mainScreen].bounds;
//播放
[self.avPlayer play];
- 4.AVPlayerViewController
//带界面的播放器
AVPlayerViewController *playerVc = [[AVPlayerViewController alloc] init];
//设置播放器
//创建资源对象 获取文件信息
AVAsset *asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://baobab.wdjcdn.com/14676170652191(23).mp4"]];
//创建播放项目 曲目
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];
AVPlayer *avPlayer = [AVPlayer playerWithPlayerItem:item];
playerVc.player = avPlayer;
//进行modal展示
[self presentViewController:playerVc animated:YES completion:nil];
[avPlayer play];
- 3.特殊功能:
1> 横屏全屏播放(视图旋转90度,frame设置为屏幕大小)
[UIView animateWithDuration:0.25 animations:^{
self.playerController.view.transform = CGAffineTransformRotate(self.playerController.view.transform, M_PI_2);
self.playerController.view.frame = [UIScreen mainScreen].bounds;
}];
2> 获取全屏的Down事件(viewDidLoad中用通知监听退出全屏事件) 退出全屏&暂停时,说明触发了Down事件
//监听通知 退出全屏时
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didExitFullScreen) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
3> 已经退出全屏后调用
- (void)didExitFullScreen{
//判断播放状态
if (self.playerController.playbackState == MPMoviePlaybackStatePaused) {
NSLog(@"点击Down");
//移除视图
[self.playerController.view removeFromSuperview];
}
}
视频截图(本质获取媒体文件中需求的关键帧图片)
- 1.实现思路
-> 根据文件路径,创建视频文件资源(AVAsset)
-> 创建媒体文件图片生成器(AVAssetImageGenerator)
-> 获取当前播放时间
-> 生成图片:[图片生成器对象 generateCGImageAsynchronouslyForTimes:...];
- 2.关键类:
AVAsset(资源)
媒体文件图片生成器(AVAssetImageGenerator)
- 3.关键方法:
创建媒体资源:AVAsset的类方法创建
创建媒体文件图片生成器对象: AVAssetImageGenerator(类方法创建).
获取当前媒体文件的播放时间:CMTime time = self.avplayer.currentTime.
生成图片:[媒体文件图片生成器对象 generateCGImagesAsynchronouslyForTimes...];
//死锁: 在某个线程中嵌套该线程的同步任务才会死锁
视频录制
- 1.框架:AVFoundation.
- 2.关键类:
AVCaptureDeviceInput(摄入设备)
AVCaptureMoviewFileOutput(输出设备)
AVCaptureSession(采集会话)
AVCaptureVideoPreviewLayer(预览视图)
- 3.视频录制的实现思路:
-> 输入设备(音频输入麦克风,视频输入摄像头)
-> 输出设备(视频文件)
->管理输入设备和输出设备的会话
->预览视图
->开始录制
->录制视频的保存路径,输出设备开始录制
->停止录制.
1>输入音频设备:
AVCaptureDevice *video = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
2>输入视频设备:
self.videoInput = [AVCaptureDeviceInput deviceInputWithDevice:video error:nil];
3>输出设备:
self.output = [[AVCaptureMovieFileOutput alloc] init];
4>会话:
self.session = [[AVCaptureSession alloc] init];
//加入输入设备
if ([self.session canAddInput:self.videoInput]) {
[self.session addInput:self.videoInput];
}
if ([self.session canAddInput:self.audioInput]) {
[self.session addInput:self.audioInput];
}
//加入输出设备
if ([self.session canAddOutput:self.output]) {
[self.session addOutput:self.output];
}
5>预览视图:
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
6>开始采集:
[self.session startRunning];
7>开始录制:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"录制.mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
[self.output startRecordingToOutputFileURL:url recordingDelegate:self];
8>停止录制(三步:停止录制 停止采集和移除预览视图)
[self.output stopRecording];
[self.session stopRunning];
[self.previewLayer removeFromSuperlayer];
- 4.在访问麦克风和摄像头时应请求用户授权,在info,plist文件中对麦克风和摄像头进行描述.
视频转制(输出相册中的视频并压缩)
- 1.实现思路:
-> 创建UIImagePickerController对象
->设置代理,设置资源类型(获取图片)和媒体类型(获取视频)
->modal展示
->在代理方法中获取路径获取媒体文件
->创建媒体转制会话 ->设置输出的路径
->设置可支持的输出格式
->输出视频
->销毁UIImagePickerController对象
- 2.步骤:
1>创建控制器:
UIImagePickerController *imgVc = [[UIImagePickerController alloc] init];
2>设置代理:
imgVc.delegate = self;
3>设置类型:
imgVc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
4>获取相册中视频 需要设置媒体类型:
imgVc.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
5>modal展示:
[self presentViewController:imgVc animated:YES completion:nil];
7>转制视频:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
NSLog(@"%@", info);
//获取媒体文件
NSURL *url = info[UIImagePickerControllerMediaURL];
AVAsset *asset = [AVAsset assetWithURL:url];
//创建媒体转制会话
AVAssetExportSession *session = [AVAssetExportSession exportSessionWithAsset:asset presetName:AVAssetExportPresetLowQuality];
//设置转出的路径
NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"转出的视频.mp4"];
session.outputURL = [NSURL fileURLWithPath:filePath];
//获取支持的转出格式
[session determineCompatibleFileTypesWithCompletionHandler:^(NSArray<NSString *> * _Nonnull compatibleFileTypes) {
NSLog(@"%@", compatibleFileTypes);
}];
//设置转出的格式 转出格式必须支持
session.outputFileType = @"public.mpeg-4";
//转出视频
[session exportAsynchronouslyWithCompletionHandler:^{
NSLog(@"完成转出");
//销毁控制器
[picker dismissViewControllerAnimated:YES completion:nil];
}];
}