iOS開發音頻、視頻

一、音頻
播放音頻可以使用框架: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(@"導出成功!");
    }];  
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章