一、音频
播放音频可以使用框架:AVFoundation.framework
1、音效播放
又称“短音频”,通常在程序中的播放时长为30秒以内

在应用程序中起到点缀效果,提升整体用户体验


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    //1、设置播放音效的地址
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"buyao.wav" withExtension:nil];
    
    //2、定义系统音效文件的id,根据该id查找到音效文件
    SystemSoundID soundID;
    
    //3、创建音效文件
    AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
    
    //4、播放音效文件
    //4.1、不带震动的播放
    AudioServicesPlaySystemSound(soundID);
    
    //4.2、带震动的播放
//    AudioServicesPlayAlertSound(soundID);

    //5、释放音效所占的内存
//    AudioServicesDisposeSystemSoundID(soundID);
    
}
//在AppDelegate中进行音效文件的释放
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    
}



音效播放工具类的封装


#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

@interface ZMAudioTools : NSObject

//不带震动的播放
+ (void)playSystemSoundWithURL:(NSURL *)url;

//带震动的播放
+ (void)playAlertSystemSoundWithURL:(NSURL *)url;

//清空音效文件,在控制器收到内存警告时调用
+ (void)ClearMemory;

@end
#import "ZMAudioTools.h"

//缓存字典
static NSMutableDictionary *soundIDDict;

@implementation ZMAudioTools

//只要头文件参与了编译,就会调用
//+ (void)load {
//    
//}

+ (void)initialize {
    //缓存字典初始化
    soundIDDict = [NSMutableDictionary dictionary];
}

//不带震动的播放
+ (void)playSystemSoundWithURL:(NSURL *)url{
    
    AudioServicesPlaySystemSound([self loadSoundIDWithURL:url]);
}

//带震动的播放
+ (void)playAlertSystemSoundWithURL:(NSURL *)url {
    AudioServicesPlayAlertSound([self loadSoundIDWithURL:url]);
}

+ (void)ClearMemory{
    [soundIDDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        SystemSoundID soundID = [obj intValue];
        AudioServicesDisposeSystemSoundID(soundID);
    }];
    
}

+ (SystemSoundID)loadSoundIDWithURL:(NSURL *)url {
    
    NSString *urlStr = url.absoluteString;
    
    //从缓存字典中取出soundID
    //2、定义系统音效文件的id,根据该id查找到音效文件
    SystemSoundID soundID = [soundIDDict[urlStr] intValue];
    
    if (soundID == 0) {
        //3、创建音效文件
        AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
        
        soundIDDict[urlStr] = @(soundID);
    } else {
        
    }
    return soundID;
}

@end



2、音乐播放
一般播放时间较长,音乐播放用到一个叫做AVAudioPlayer的类


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1、设置音乐文件的URL路径
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"爱.mp3" withExtension:nil];
    
    //2、创建音乐播放器
    NSError *error;
    self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    if (error) {
        NSLog(@"%@", error.localizedDescription);
    }
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    /***<   播放音乐    **/
    //1、准备播放,把音频文件加载到内存中,默认会隐式被调用,可以省略
    [self.player prepareToPlay];
    //2、开始播放
    [self.player play];
    
    /***<   暂停播放    **/
    [self.player pause];
    
    
    /***<   停止播放    **/
    [self.player stop];
    //把播放时刻归零
    self.player.currentTime = 0;
}



3、录音


3.1、录音的简单使用




- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1、定义录音文件的存放地址,不改变录音文件的位置,重复录音会覆盖
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"1.wav"];
    
    NSURL *url = [NSURL fileURLWithPath:path];
    
    
    //2、录音参数设置字典,如果传值为空默认就是高质量录音
    NSDictionary *settings = [NSDictionary dictionary];
    
    //3、创建录音对象
    //NSError的标准定义
    __autoreleasing NSError *error;
    _recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
    
}

- (void)prepareRecorder {
    //1、准备录音
    [self.recorder prepareToRecord];
    
    //2、开始录音
    [self.recorder record];
}

- (void)pauseRecorder {
    //暂停录音,不会保存录音文件,需要进行停止
    [self.recorder pause];
}

- (void)stopRecorder {
    //停止录音,会产生最终的录音文件
    [self.recorder stop];
}




3.2、检测自动停止录音

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1、定义录音文件的存放地址,不改变录音文件的位置,重复录音会覆盖
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"1.wav"];
    
    NSURL *url = [NSURL fileURLWithPath:path];
    
    
    //2、录音参数设置字典,如果传值为空默认就是高质量录音
    NSDictionary *settings = [NSDictionary dictionary];
    
    //3、创建录音对象
    //NSError的标准定义
    __autoreleasing NSError *error;
    _recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
    
    //4、打开录音分贝检测
    self.recorder.meteringEnabled = YES;
    
    //5、在真机上需要
    AVAudioSession *session = [AVAudioSession new];
    [session setCategory:AVAudioSessionCategoryRecord error:nil];
}
- (void)prepareRecorder {
    //1、准备录音
    [self.recorder prepareToRecord];
    //2、开始录音
    [self.recorder record];
    //3、添加计时器,对录音分贝进行循环检测
    [self updateMetering];
}
- (void)updateMetering{
    if (self.displayLink == nil) {
        //1、创建录音计时器
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMeterSay)];
        //2、把计时器加入到运行循环中
        [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    }
    //如果录音计时器暂停了,就打开
    if (self.displayLink.isPaused) {
        self.displayLink.paused = NO;
    }
}
//录音计时器循环调用的方法
- (void)updateMeterSay {
    //根据分贝的大小,来自动停止录音
    //1、更新分贝信息
    [self.recorder updateMeters];
    //2、获取分贝信息
    //取值为:0(大)~-160
    CGFloat power = [self.recorder averagePowerForChannel:0];
    //3、若2秒没有声音,自动停止录音
    static NSInteger number;
    //4、displayLink,一秒默认60次
    if (power < -30) {
        //判断是否很安静
        number++;
        if (number/120 > 2)
        {
            [self stopRecorder];
        }
    }
}

- (void)pauseRecorder {
    //暂停录音,不会保存录音文件,需要进行停止
    [self.recorder pause];
    //暂停循环
    self.displayLink.isPaused = YES;
}

- (void)stopRecorder {
    //停止录音,会产生最终的录音文件
    [self.recorder stop];
    //暂停循环
    self.displayLink.paused = YES;
}



3.3、录音参数的设置


#import<AVFoundation/AudioSettings.h>
//settings 设置参数 录音相关参数 声道 速率 采样率 
NSMutableDictionary *setting = [NSMutableDictionary dictionary];
 // 音频格式
 setting[AVFormatIDKey] = @(kAudioFormatAppleIMA4); 
// 音频采样率 
setting[AVSampleRateKey] = @(600.0);
 // 音频通道数
 setting[AVNumberOfChannelsKey] = @(1); 
// 线性音频的位深度 
setting[AVLinearPCMBitDepthKey] = @(8);

3.4、录音编码

1、编码是信息从一种形式转换为另一种形式的过程。 编码格式:

 2、文件格式(不同的文件格式, 可保存不同的编码格式编码的文件):   

 .wav:特点: 音质最好的格式, 对应PCM编码;适用: 多媒体开发、保存音乐和音效素材。   

 .mp3:特点: 音质好,压缩比比较高,被大量软件和硬件支持;适用: 适合用于比较高要求的音乐欣赏。        

.caf:特点: 适用于几乎iOS中所有的编码格式 注:caf 文件格式, 因为某些编码设置, 文件有可能会很大, 而且caf, 格式并不是很通用, 所以在开发过程中, 一般会进行压缩转码MP3;

二、视频

iOS提供了MPMoviePlayerController、MPMoviePlayerViewController两个类,可以用来轻松播放视频和网络流媒体/网络音频,MPMoviePlayerViewController只能全屏播放视频,这两个类都定义在了MediaPlayer框架中。

 MPMoviePlayerController类的简介:继承自NSObject 内部有个view可以展示视频内容将该视图添加其他控制器的view上,即可显示视频内容 MPMoviePlayerController可以播放的视频格式包括:H.264、MPEG-4等支持的文件扩展名包括:avi,mkv,mov,m4v,mp4等 

可以从苹果官网:http://support.apple.com/kb/HT1425下载一些用来测试的视频文件,文件都比较小 

提示:MPMoviePlayerController并不支持所有的视频格式,如果要播放不支持的视频格式,需要借助第三方框架进行解码,如VLC   https://github.com/videolan/vlc


1、视频播放 实现方案四种

1.1、AVPlayer

优点:       

可以自定义UI, 进行控制

 缺点:      

 单纯的播放, 没有控制UI, 而且如果要显示播放界面, 需要借助AVPlayerLayer, 添加图层到需要展示的图层上

//1、通过远程URL创建AVPlayer对象
    NSURL *remoteURL = [NSURL URLWithString:@"http://xxx.com/e-b734-ac55ab528aa8/L.mp4"];
    _player = [AVPlayer playerWithURL:remoteURL];
    开始播放
    
    [self.player play];
    
    //2、存在问题
    //只能播放声音, 看不到图像
    //解决方案: 需要借助AVPlayerLayer对象, 根据player创建图层, 添加到视图上
    //3、 实现视频显示功能
    AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    
    layer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height * 9 / 16);
    //添加到需要展示的视图上即可
    
    [self.view.layer addSublayer:layer];



1.2、MPMoviePlayerController


优点:      

自带的播放控制UI, 不需要手动添加

缺点:    

不能自定义UI    

只能将此控制器视图添加到其他视图进行展示    

此控制器不是视图控制器, 不能弹出


#import <MediaPlayer/MediaPlayer.h>
#import <AVKit/AVKit.h>

- (IBAction)playNoViewMovie:(UIButton *)sender { 
	//方式二:不带view的播放器的控制器 
	//1、获取视频文件的url地址
	NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"Cupid_高清.mp4" withExtension:nil]; 
	//2、创建不带view的视频播放器 
	//ios9.0过期 
	_mpC = [[MPMoviePlayerController alloc] initWithContentURL:fileUrl]; 
	//3、设置View.frame 
	_mpC.view.frame = CGRectMake(0, 0, 300, 400); 
	//4、添加到控制器view 
	// [self.view addSubview:_mpC.view]; 
	//5、准备播放,默认play隐式调用 
	[_mpC prepareToPlay]; 
	//6、开始播放 
	[_mpC play]; 
	//7、控制模式 
	self.mpC.controlStyle = MPMovieControlStyleNone;
}


1.3、MPMoviePlayerViewController


优点:      

自带的播放控制UI, 不需要手动添加     

此控制器是视图控制器, 可以弹出, 可以压栈    

也可以手动调整视图大小, 添加到其他视图上

缺点:     

不能自定义UI


#import <MediaPlayer/MediaPlayer.h>
#import <AVKit/AVKit.h>

- (IBAction)moviePlayer:(UIButton *)sender {
    //方式一:带view的播放器的控制器,播放完成会自动退出
    //1、获取视频文件的url地址
    NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"minion_01.mp4" withExtension:nil];
    //2、创建带view的视频播放器
    //ios9.0过期
    MPMoviePlayerViewController *mpMV = [[MPMoviePlayerViewController alloc] initWithContentURL:fileUrl];
    //3、模态跳出播放器
    [self presentViewController:mpMV animated:YES completion:nil];
}



1.4、MPMoviePlayerController、MPMoviePlayerViewController视频播放的通知监听


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //监听播放完成的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerPlaybackDidFinishNotification:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
}

- (void)moviePlayerPlaybackDidFinishNotification:(NSNotification *)notif {
    
    MPMovieFinishReason reason = [notif.userInfo[MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] integerValue];
    switch (reason) {
        case MPMovieFinishReasonPlaybackEnded:
            NSLog(@"播放结束");
            //进行视频切换,更换播放视频的地址
            break;
        case MPMovieFinishReasonPlaybackError:
            NSLog(@"播放错误");
            break;
        case MPMovieFinishReasonUserExited:
            NSLog(@"播放退出");
            break;
        default:
            break;
    }
}



1.5、针对于第2种和第3种实现方案, 在iOS9.0之后, 统一使用AVPlayerViewController


优点: 

     自带的播放控制UI, 不需要手动添加

     此控制器是视图控制器, 可以弹出, 可以压栈

     也可以手动调整视图大小, 添加到其他视图上

缺点:

     不能自定义UI


#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
- (IBAction)playNoViewMovie:(UIButton *)sender {
    //1、获取视频文件的url地址
    NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"Cupid_高清.mp4" withExtension:nil];
    //2、创建播放器
    AVPlayerViewController *playerVc = [AVPlayerViewController new];
    //3、创建player
    playerVc.player = [AVPlayer playerWithURL:fileUrl];
    //4、开始播放
    [playerVc.player play];
    //5、模态播放器
    // [self presentViewController:playerVc animated:YES completion:nil];
    //5、自定义播放器视图的大小
    playerVc.view.frame = CGRectMake(0, 0, 300, 400);
    [self.view addSubview:playerVc.view];
}


2、视频截图


把视频中的某一帧作为视频的封面



#import <AVFoundation/AVFoundation.h>
//点击屏幕开始截图
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //1、获取视频文件的url地址
    NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"Cupid_高清.mp4" withExtension:nil];
    //2、创建资源
    AVAsset *asset = [AVAsset assetWithURL:fileUrl];
    //3、创建资源图片生成器
    AVAssetImageGenerator *imgGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    //4、开始生成图片
    //要截取哪一帧
    //参数1:视频每秒的帧数
    //参数2:当前视频每秒的帧数
    CMTime time = CMTimeMake(30, 1);
    NSValue *value = [NSValue valueWithCMTime:time];
    [imgGenerator generateCGImagesAsynchronouslyForTimes:@[value] completionHandler:^(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) { //线程同步
        dispatch_sync(dispatch_get_main_queue(), ^{
            self.image = [UIImage imageWithCGImage:image]; });
    }];
}



3、视频的录制


#import <MobileCoreServices/MobileCoreServices.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AssetsLibrary/AssetsLibrary.h>

//录制视频
- (void)didClickMovie {
    //1、判断相机是否可用
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; }
    //2、创建图片选择器
    UIImagePickerController *picker = [UIImagePickerController new];
    //3、设置类型
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    //4、设置媒体类型
    picker.mediaTypes = @[(NSString *)kUTTypeMovie];
    //5、设置相机的检测模式
    picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
    //6、设置视频的质量
    picker.videoQuality = UIImagePickerControllerQualityTypeHigh;
    //7、设置代理
    picker.delegate = self;
    //8、模态弹出
    [self presentViewController:picker animated:YES completion:nil];
}
#pragma mark - UIImagePickerControllerDelegate
//选中视频时,进行播放
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
    //1、判断是否是视频媒体
    NSString *mediaType = info[UIImagePickerControllerMediaType];
    id url = info[UIImagePickerControllerMediaURL];
    //2、播放视频
    if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
        if (self.playerVc == nil) {
            self.playerVc = [MPMoviePlayerController new];
            self.playerVc.view.frame = CGRectMake(0, 0, 300, 400);
            [self.view addSubview:self.playerVc.view];
        }
        self.playerVc.contentURL = url; [self.playerVc play];
    }
    //3、保存视频
    if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
        ALAssetsLibrary *assetsLibrary = [ALAssetsLibrary new];
        //参数一:要保存视频的url
        [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) { }];
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}



4、视频压缩

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>

@interface ViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate> 
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

//录制视频
- (void)didClickMovie {
    //1、相册是否可用
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
        return;
    }
    
    //2. 创建图像选择器
    UIImagePickerController *picker = [UIImagePickerController new];
    
    //3. 设置类型
    picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    
    //4. 设置媒体类型
    picker.mediaTypes = @[(NSString *)kUTTypeMovie];
    
    //5. 设置代理
    picker.delegate = self;
    
    //6. 模态弹出
    [self presentViewController:picker animated:YES completion:nil];
    
}

#pragma mark - UIImagePickerControllerDelegate
//选中视频的时候进行压缩
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
    
    //1、判断是否是视频媒体
    NSString *mediaType = info[UIImagePickerControllerMediaType];
    
    id url = info[UIImagePickerControllerMediaURL];
    
    //2、开始导出  -->  压缩
    [self exportWithURL:url];
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)exportWithURL:(NSURL *)url {
    
    //1、获取资源
    AVAsset *asset = [AVAsset assetWithURL:url];
    
    //2、创建资源会话对象
    AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
    
    //3、设置导出路径
    session.outputURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"123.mov"]];
    
    //4、设置导出类型
    session.outputFileType = AVFileTypeQuickTimeMovie;
    
    //5、开始导出
    [session exportAsynchronouslyWithCompletionHandler:^{
        NSLog(@"导出成功!");
    }];  
}