iOS - 使用AVPlayer播放音频、视频

来源:互联网 发布:yii2.0源码分析 编辑:程序博客网 时间:2024/05/17 22:37

最近有个项目需要自定义播放器界面,要求能调节声音、和播放进度并显示播放时间,效果图如下:



开始准备用AVAudioPlayer,但是不好控制播放进度,最后使用了AVPlayer ;同时也学习到了怎么自定义UISlider


需要引入的framework:  AVFoundation.framework  、MediaPlayer.framework  、CoreMedia.framework


首先我定义了一个xib文件:



类的.h文件

#import <UIKit/UIKit.h>#import <AVFoundation/AVFoundation.h> #import <MediaPlayer/MediaPlayer.h>#import <CoreMedia/CoreMedia.h>@interface AudioPlayerView : UIView <AVAudioPlayerDelegate>{     __weak IBOutlet UILabel *timeLabel;    __weak IBOutlet UISlider *processSlider;    __weak IBOutlet UISlider *volumeSlider;    __weak IBOutlet UIButton *startOrStopButton;        float totalDuration;    float currentDuration;         BOOL isPlay; //是否正在播放    id mTimeObserver;} @property (nonatomic , strong) AVPlayer *mediaPlayer;- (void)setAudioName:(NSString *)name;- (void)dismissFromSuperview;- (IBAction)startOrStopButtonAction:(id)sender;  @end

.m文件

/* 1、添加播放器() AudioPlayerView *audioView = [[[NSBundle mainBundle] loadNibNamed:@"AudioPlayerView" owner:self options:nil] objectAtIndex:0]; [self.view addSubview:audioView]; [audioView setAudioName:@"demo.mp3"]; 2、移除播放器 [audioView dismissFromSuperview]; audioView = nil;*/#import "AudioPlayerView.h"#define animationDuration  0.3@implementation AudioPlayerView@synthesize mediaPlayer = _mediaPlayer; - (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Initialization code    }    return self;} - (id)initWithCoder:(NSCoder *)aDecoder{    self = [super initWithCoder:aDecoder];    if(self){        //your corder        currentDuration = 0;        totalDuration = 0;     }    return self;}- (void)willMoveToSuperview:(UIView *)newSuperview{    if(newSuperview){    //视图将要出现时的动画        CGRect audioFrame = self.frame;        audioFrame.origin.y = newSuperview.bounds.size.height;        self.frame = audioFrame;        audioFrame.origin.y = newSuperview.bounds.size.height-self.bounds.size.height;        [UIView animateWithDuration:animationDuration animations:^{            self.frame = audioFrame;        }];    } }- (void)dismissFromSuperview{    [self stopAVPlayer];     CGRect audioFrame = self.frame;    audioFrame.origin.y = self.frame.size.height+self.frame.origin.y;    [UIView animateWithDuration:animationDuration animations:^{        self.frame = audioFrame;    } completion:^(BOOL finished){        [self removeFromSuperview];     }];}- (void)setAudioName:(NSString *)name{    NSFileManager *fileManage = [NSFileManager defaultManager];    if(![fileManage fileExistsAtPath:PathOfFileNamed(name)]){        [self performSelector:@selector(showAlertViewWithMessage:) withObject:@"语音文件不存在" afterDelay:.5];        return ;    }         NSURL *audioURL = [NSURL fileURLWithPath:PathOfFileNamed(name)];        AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:audioURL options:nil];    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:urlAsset];;     self.mediaPlayer = [AVPlayer playerWithPlayerItem:playerItem];     [self initProcessSliderTimer];        ALog(@"totalDuration %f",totalDuration);    CMTime totalTime = playerItem.duration;  //获取音频的总时间    totalDuration = (CGFloat)totalTime.value/totalTime.timescale;      [self initTimelabel];     [self performSelector:@selector(startOrStopButtonAction:) withObject:startOrStopButton afterDelay:animationDuration];    //播放视频时使用//    AVPlayerLayer * playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.mediaPlayer]; //    [playerLayer setFrame:CGRectMake(0, 0, 320, 280)];  //    [self.superview.layer addSublayer:playerLayer];}- (void)showAlertViewWithMessage:(NSString *)message{    [[[UIAlertView alloc] initWithTitle:nil                                message:message                               delegate:self                      cancelButtonTitle:@"确定"                      otherButtonTitles:nil, nil] show];}- (void)awakeFromNib{    self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"audioPlayerBg.png"]];    [self initSlider];}- (CMTime)playerItemDuration{AVPlayerItem *playerItem = [self.mediaPlayer currentItem];if (playerItem.status == AVPlayerItemStatusReadyToPlay) {return([playerItem duration]);}return(kCMTimeInvalid);}-(void)initProcessSliderTimer{    if(!mTimeObserver){        CMTime time = CMTimeMake(1,1);        __weak typeof(self) weakSelf = self;        mTimeObserver = [self.mediaPlayer addPeriodicTimeObserverForInterval:time                                                                       queue:NULL                                                                  usingBlock:^(CMTime time){                                                                      [weakSelf syncProcessSlider];                                                                  }];    }    CMTime playerDuration = [self playerItemDuration];if (CMTIME_IS_INVALID(playerDuration)) {        processSlider.value = 0;}}- (void)syncProcessSlider{    //实时刷新播放进度条  CMTime playerDuration = [self playerItemDuration];if (CMTIME_IS_INVALID(playerDuration)) {processSlider.minimumValue = 0.0;return;}totalDuration = CMTimeGetSeconds(playerDuration);if (isfinite(totalDuration)){float minValue = [processSlider minimumValue];float maxValue = [processSlider maximumValue];currentDuration = CMTimeGetSeconds([self.mediaPlayer currentTime]);        [self initTimelabel];[processSlider setValue:(maxValue - minValue) * currentDuration / totalDuration + minValue];}    if (processSlider.value == 1.0) {        [self.mediaPlayer seekToTime:kCMTimeZero];        [startOrStopButton setImage:[UIImage imageNamed:@"audioPlayerStart.png"] forState:UIControlStateNormal];    }}- (IBAction)startOrStopButtonAction:(id)sender{     if (self.mediaPlayer.rate == 1) {        [self.mediaPlayer pause];         [startOrStopButton setImage:[UIImage imageNamed:@"audioPlayerStart.png"] forState:UIControlStateNormal];    } else {        [self.mediaPlayer play];                 [startOrStopButton setImage:[UIImage imageNamed:@"audioPlayerPause.png"] forState:UIControlStateNormal];         [self initProcessSliderTimer];    }} - (void)initTimelabel{    //更新显示的时间    NSString *currentTime = [self formatDateWithSecond:(int)currentDuration];    NSString *totalTime = [self formatDateWithSecond:(int)totalDuration];    NSString *timeString = [NSString stringWithFormat:@"%@ / %@",currentTime,totalTime];    timeLabel.text = timeString;}- (NSString *)formatDateWithSecond:(int)second{    if(!second || second<=0){        return @"00:00";    }    int hour = second/(60*60);    int minute = (second-(60*60)*hour)/60;    second -= (60*60)*hour+minute*60;        if(hour!=0){        return [NSString stringWithFormat:@"%02i:%02i:%02i", hour, minute, second];    }else{        return [NSString stringWithFormat:@"%02i:%02i", minute, second];    }    return nil; }- (void)initSlider{    if([[[UIDevice currentDevice] systemVersion] floatValue]>=7.0){        CGRect proceeFrame = processSlider.frame;        proceeFrame.origin.y = 49;        processSlider.frame = proceeFrame;        CGRect volumeFrame = volumeSlider.frame;        volumeFrame.origin.y = 49;        volumeSlider.frame = volumeFrame;    }    // 自定义 UISlider 的图片    UIImage *minImage = [UIImage imageNamed:@"audioPlayerSliderMinTrack.png"];   //进度条    UIImage *maxImage = [UIImage imageNamed:@"audioPlayerSliderMaxTrack.png"];   //滑块的底图    UIImage *tumbImage= [UIImage imageNamed:@"audioPlayerSliderThumb.png"];      //中间的圆形控制按钮        minImage=[minImage resizableImageWithCapInsets:UIEdgeInsetsMake(2, 2, 2, 2)];    maxImage=[maxImage resizableImageWithCapInsets:UIEdgeInsetsMake(2, 2, 2, 2)];        [processSlider setMinimumTrackImage:minImage forState:UIControlStateNormal];    [processSlider setMaximumTrackImage:maxImage forState:UIControlStateNormal];    [processSlider setThumbImage:tumbImage forState:UIControlStateNormal];     processSlider.minimumValue = 0.0;    processSlider.maximumValue = 1.0;    processSlider.continuous = YES;         // Attach an action to slider    [processSlider addTarget:self action:@selector(processSliderStartDragAction:)            forControlEvents:UIControlEventTouchDown];[processSlider addTarget:self action:@selector(sliderValueChangedAction:)            forControlEvents:UIControlEventValueChanged];[processSlider addTarget:self action:@selector(processSliderEndDragAction:)            forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];        [volumeSlider setMinimumTrackImage:minImage forState:UIControlStateNormal];    [volumeSlider setMaximumTrackImage:maxImage forState:UIControlStateNormal];    [volumeSlider setThumbImage:tumbImage forState:UIControlStateNormal];    volumeSlider.minimumValue = 0.0;    volumeSlider.maximumValue = 1.0;    volumeSlider.continuous = YES;    volumeSlider.value = [[MPMusicPlayerController applicationMusicPlayer] volume]; //获取系统声音的值      [volumeSlider addTarget:self action:@selector(sliderValueChangedAction:)            forControlEvents:UIControlEventValueChanged];}- (void)processSliderStartDragAction:(id)sender{       if (self.mediaPlayer.rate == 1) {        isPlay = true;        [self.mediaPlayer pause];    } else{        isPlay = false;    }}- (void)processSliderEndDragAction:(id)sender{    //调节播放进度      CMTime dragedCMTime = CMTimeMake(totalDuration*processSlider.value, 1);    [self.mediaPlayer seekToTime:dragedCMTime completionHandler:^(BOOL finish){        if(isPlay){            [self.mediaPlayer play];        }    }];}- (void)sliderValueChangedAction:(id)sender{    UISlider *targetSlider = (UISlider *)sender;    if (targetSlider == processSlider) {        currentDuration = totalDuration*targetSlider.value;        [self initTimelabel];     }else if (targetSlider == volumeSlider){        float volume=[[NSString stringWithFormat:@"%.1f",volumeSlider.value] floatValue];        [[MPMusicPlayerController applicationMusicPlayer] setVolume:volume];   //设置声音      } } - (void)dealloc{    NSLog(@"AudioPlayerView  dealloc!");    [self stopAVPlayer]; }- (void)stopAVPlayer{    if (self.mediaPlayer.rate == 1) {        [self.mediaPlayer pause];    }    self.mediaPlayer = nil;    mTimeObserver = nil;}@end


最后附上实现之后的效果: