• 音视频处理


    之前介绍的系统声音服务(System Sound Services)提供了一个接口,用于播放不超过30秒的声音。要进一步使用iOS的音频功能,有两个框架:Media Player和AV Foundation。

    Media Player框架

    Media Player框架用于播放本地和远程资源中的视频和音频。在应用程序中,可使用它来打开模态iPod界面、选择歌曲以及控制播放。这个框架让您能够与设备提供的所有内置多媒体功能集成。

    框架有5个常用类:

    MPMoviePlayerController — 电影播放器控制器。

    MPMusicPlayerController — 音乐播放器控制器。

    MPMediaPickerController — 向用户提供用于选择要播放的多媒体的界面。您可以筛选媒体选择器显示的文件,也可以让用户从多媒体库中选择文件。

    MPMediaItem — 单个多媒体项,如一首歌曲。

    MPMediaItemCollection — 多媒体项集合。MPMediaPickerController实例提供一个MPMediaItemCollection实例,可在下一个类(音乐播放器控制器)中直接使用它。

    要使用任何多媒体播放器功能,都必须导入框架Media Player:

    #import <MediaPlayer/MediaPlayer.h>

    电影播放器(MPMoviePlayerController)示例:

    #import "ViewController.h"
    #import <MediaPlayer/MediaPlayer.h>
    
    @interface ViewController ()
    - (IBAction)btnPlayerClickHandler:(id)sender;
    @property (strong, nonatomic) MPMoviePlayerController *moviePlayer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        NSString *strFile = [[NSBundle mainBundle] pathForResource:@"movie1" ofType:@"mp4"];
        
        self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:strFile]];
        self.moviePlayer.allowsAirPlay = YES;
        [self.moviePlayer.view setFrame:CGRectMake(50.0, 50.0, 240.0, 200.0)];
        [self.view addSubview:self.moviePlayer.view];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playMovieFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer];
    }
    
    - (IBAction)btnPlayerClickHandler:(id)sender
    {
        [self.moviePlayer play];
    }
    
    - (void)playMovieFinished:(NSNotification *)theNotification
    {
        MPMoviePlayerController *player = [theNotification object];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:player];
        [player.view removeFromSuperview];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    @end

    有两个细节需要注意:

    1. MPMoviePlayerController实例要添加成属性(@property)。

    2. 将视频文件添加到项目时,要勾选“add to targets”。

    电影播放器播放完文件时,可能需要做些清理工作,包括将电影播放器从视图中删除。为此,可使用NSNotificationCenter类注册一个”观察者”,该观察者将监视来自对象moviePlayer的特定通知,并在收到这种通知时调用指定的方法。

    音乐播放器(MPMusicPlayerController)示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    @property (strong, nonatomic) IBOutlet UILabel *lblPlayingSong;
    @property (strong, nonatomic) IBOutlet UILabel *lblSongList;
    - (IBAction)btnPlayClickHandler:(id)sender;
    - (IBAction)btnPickerClickHandler:(id)sender;
    
    @property (nonatomic, strong) MPMusicPlayerController *musicPlayer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
    }
    
    - (IBAction)btnPlayClickHandler:(id)sender
    {
        if(self.musicPlayer.playbackState==MPMusicPlaybackStatePaused||self.musicPlayer.playbackState==MPMusicPlaybackStateStopped)
        {
            [self.musicPlayer play];
        }
        else if(self.musicPlayer.playbackState==MPMusicPlaybackStatePlaying)
        {
            [self.musicPlayer pause];
        }
    //    [self.musicPlayer stop];
    //    [self.musicPlayer skipToBeginning];
    //    [self.musicPlayer skipToPreviousItem];
    //    [self.musicPlayer skipToNextItem];
        
        //列出当前播放歌曲
        self.lblPlayingSong.text = [self.musicPlayer.nowPlayingItem valueForProperty:MPMediaItemPropertyTitle];
        
    //    MPMediaItemPropertyArtist -- 艺术家
    //    MPMediaItemPropertyGenre -- 流派
    //    MPMediaItemPropertyLyrics -- 歌词
    }
    
    - (IBAction)btnPickerClickHandler:(id)sender
    {
        MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
    //    MPMediaTypePodcast;
    //    MPMediaTypeAnyAudio;
        
        mediaPicker.prompt = @"Choose Songs";
        mediaPicker.allowsPickingMultipleItems = YES;
        mediaPicker.delegate = self;
        
        [self presentViewController:mediaPicker animated:YES completion:nil];
    }
    
    - (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
    {
        [self.musicPlayer setQueueWithItemCollection:mediaItemCollection];
        
        //列出选择歌曲清单
        NSMutableString *strTitle = [[NSMutableString alloc] initWithString:@""];
        for(MPMediaItem *item in [mediaItemCollection items])
        {
            
            [strTitle appendString:[item valueForProperty:MPMediaItemPropertyTitle]];
            [strTitle appendString:@"
    "];
        }
        self.lblSongList.text = strTitle;
        
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    - (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end

    AV Foundation框架

    虽然Media Player框架可满足所有普通多媒体播放需求,但Apple推荐使用AV Foundation框架来实现大部分系统声音服务不支持的、超过30秒的音频播放功能。另外,AV Foundation框架还提供了录音功能。

    要在应用程序中添加音频播放和录音功能,只需要两个新类:

    AVAudioRecorder — 以各种不同的格式将声音录制到内存或设备本地文件中。

    AVAudioPlayer — 播放任意长度的音频。

    要使用AV Foundation框架,必须将其加入到项目中,再导入两个接口文件:

    #import <AVFoundation/AVFoundation.h>
    #import <CoreAudio/CoreAudioTypes.h>

    CoreAudioTypes.h定义了多种音频类型,便于在代码中通过名称引用。

    播放声音文件示例:

    #import <AVFoundation/AVFoundation.h>
    #import <CoreAudio/CoreAudioTypes.h>
    
    @interface ViewController : UIViewController <AVAudioPlayerDelegate>
    
    @end
    #import "ViewController.h"
    
    @interface ViewController ()
    @property (nonatomic,strong) AVAudioPlayer *audioPlayer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        NSString *strSoundFile = [[NSBundle mainBundle] pathForResource:@"mymusic" ofType:@"mp3"];
        
        self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:strSoundFile] error:nil];
        self.audioPlayer.delegate = self;
        [self.audioPlayer play];
    }
    
    - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
    {
        NSLog(@"播放结束");
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    @end

    在应用程序中录制音频需要指定用于存储录音的文件(NSURL),配置要创建的声音文件参数(NSDictionary),再使用上述文件和设置分配并初始化一个AVAudioRecorder实例。

    如果不想将录音文件持久性保存,可以录音存在到tmp目录,这样当app退出时,该录音可能被自动删除;否则,应存储到Documents目录。下面的代码创建了一个NSURL,它指向temp目录中的文件sound0605.caf:

    NSURL *soundFileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingString:@"sound0605.caf"]];

    然后创建一个NSDictionary,它包含录制的音频的设置:

    NSDictionary *soundSetting = @{AVSampleRateKey:@44100.0F,
                                   AVFormatIDKey:@(kAudioFormatMPEG4AAC),
                                   AVNumberOfChannelsKey:@2,
                                   AVEncoderAudioQualityKey:@(AVAudioQualityHigh)
                                   };

    AVSampleRateKey — 录音机每秒采集的音频样本数。

    AVFormatIDKey — 录音的格式。

    AVNumberOfChannelsKey — 录音的声道数。例如,立体声为双声道。

    AVEncoderAudioQualityKey — 编码器的质量设置。

    要了解更多的设置,可以参考Xcode开发文档中的AVAudioRecorder Class Reference(滚动到Constants部分)。

    指定声音文件和设置后,就可创建AV录音机实例并开始录音了:

    AVAudioRecorder *soundRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:soundSetting error:nil];
    
    [soundRecorder record];

    录制声音文件并播放示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (strong, nonatomic) IBOutlet UIButton *btnRecord;
    @property (nonatomic,strong) AVAudioRecorder *soundRecorder;
    @property (nonatomic,strong) AVAudioPlayer *audioPlayer;
    
    - (IBAction)btnRecordClickHandler:(id)sender;
    - (IBAction)btnPlayRecordHandler:(id)sender;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        //Setup the audio recorder
        [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error: nil];
        
        
        NSURL *soundFileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingString:@"sound0605.caf"]];
        
        NSDictionary *soundSetting = @{AVSampleRateKey:@44100.0F,
                                       AVFormatIDKey:@(kAudioFormatMPEG4AAC),
                                       AVNumberOfChannelsKey:@2,
                                       AVEncoderAudioQualityKey:@(AVAudioQualityHigh)
                                       };
        
        NSError* error = NULL;
        self.soundRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:soundSetting error:&error];
        NSLog(@"Error: %@", error);
    }
    
    - (IBAction)btnRecordClickHandler:(id)sender
    {
        if([self.btnRecord.titleLabel.text isEqualToString:@"录制"])
        {
            [self.soundRecorder record];
            [self.btnRecord setTitle:@"暂停" forState:UIControlStateNormal];
        }
        else
        {
            [self.soundRecorder stop];
            [self.btnRecord setTitle:@"录制" forState:UIControlStateNormal];
        }
    }
    
    - (IBAction)btnPlayRecordHandler:(id)sender
    {
        NSURL *recordFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingString:@"sound0605.caf"]];
        
        self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordFile error:nil];
        
        [self.audioPlayer play];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end

    P.s. 上面的代码每次点击播放时,都会分配并初始化一个新的AVAudioPlayer实例,其实不用担心带来的内存问题,因为每次新建音频播放器时,指向旧播放器的引用都将被删除,即ARC自动释放占用的内存。然后,如果您担心这一点,可实现AVAudioPlayer委托方法audioPlayerDidFinishPlaying:successfully,在其中将对象audioPlayer设置为nil。

    播放包含在应用程序束中的音频时,应使用AVAudioPlayer;而播放音乐库中的文件时,应使Media Player框架的MPMusicPlayerController。虽然MPMusicPlayerController也能够播放本地文件,但其主要用途是集成现有的音乐库多媒体。

  • 相关阅读:
    再谈反射
    XmlElement和XmlNode的区别
    几个常用的集合类的使用
    node.js 练习3 调用函数
    ioc 的好文章 转自 GavinJun
    sqlserver 使用小技巧总结
    node.js 练习2 (调用函数)
    c# 面向对象基础
    linq 和 lmabda 表达式 的用法 和优劣 转自 农码一生
    memcache 基本操作
  • 原文地址:https://www.cnblogs.com/CoderWayne/p/3772160.html
Copyright © 2020-2023  润新知