07、多媒体

一、音频

iOS里面共有四种专门实现播放音频的方式
1.System Sound Services (系统声音服务) 它是最底层也是最简单的声音服务 一般用来播放一些很小的提示音或者警告音,还有很大的局限性:声音长度要小于30s;格式为IMA4;不能控制播放进度;调用方法后立即播放声音;没有循环播放和立体声音播放;
具体代码如下:

//system sounds services  系统声音服务
-(void)systemSoundsServices{
  //得到要播放的资源
    NSString* wavPath=[[NSBundle mainBundle] pathForResource:@"1" ofType:@"wav"];
    //声明声音的ID  要给我们的歌曲添加系统的ID,让系统可以根据该ID找到该音频资源
    SystemSoundID soundsID;
    //创建ID
    //第一个参数:音频资源的路径
    //第二个参数:对soundsID取地址
    //把文件路径转换成URL
    NSURL* url=[NSURL fileURLWithPath:wavPath];
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &soundsID);
    //播放带震动
    AudioServicesPlayAlertSound(soundsID);
    //只播放声音,不带震动效果
    AudioServicesPlaySystemSound(soundsID);
    
}

另一种写法也可以实现

-(void)cfsystemSoundsServices{
    CFBundleRef mainBun;
    SystemSoundID soundsID;
    mainBun=CFBundleGetMainBundle();
    CFURLRef soundRef=CFBundleCopyResourceURL(mainBun, CFSTR("1"), CFSTR("wav"), NULL);
     AudioServicesCreateSystemSoundID(soundRef, &soundsID);
     AudioServicesPlaySystemSound(soundsID);
    
}

2.OpenAL (跨平台的开源的音频处理接口) 一般用来做开发游戏的音频;详细资料请参考以下两个网址
http://www.devdiv.com/thread-19636-1-1.html
http://www.cocoachina.com/bbs/read.php?tid-112679-page-1.html
3.Audio Queue Services (播放和录制音频服务) 主要用来实现录制音频,为了简化音频文件的处理,通常还需要使用到AudioFileServices,可以参考http://blog.csdn.net/midfar/article/details/7233454
4.AVAudioPlayer (高级音频播放器) 可以支持多种格式的音频播放;可以播放任一长度的音频文件;支持循环播放;可以同步播放多个音频文件;控制播放进度以及从音频的任意一点开始播放。
在这里我们做一个简单的音乐播放器,从上往下,第一个进度条是控制进度的,第二个slider是控制音量的

音乐播放器.png

先在storyBoard中搭建界面,并将要用的控件拖成属性或方法

屏幕快照 2016-12-28 下午8.25.39.png

先导入<AVFoundation/AVFoundation.h> <AudioToolbox/AudioToolbox.h>

#import "ViewController.h"
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import "customSlider.h"
@interface ViewController ()<customSliderDelegate,AVAudioPlayerDelegate>{
    AVAudioPlayer* player;
}

@property (weak, nonatomic) IBOutlet customSlider *progressSlider;//自定义的进度条
@property (weak, nonatomic) IBOutlet UILabel *timeLabel;//音频的时长
@property(nonatomic,retain)NSTimer* timer;//定时器

@property (weak, nonatomic) IBOutlet UIImageView *albumImg;//专辑图片
@property (weak, nonatomic) IBOutlet UIImageView *bigImg;//高斯模糊的背景图
@property (weak, nonatomic) IBOutlet UILabel *musicNamaLabel;//音乐的名字
@property (weak, nonatomic) IBOutlet UIButton *pauseOrplayBtn;//暂停或者播放的按钮
@property(nonatomic,retain)NSMutableArray* allMusicArray;//存放所有的歌曲
@property(nonatomic,assign)NSInteger currentIndex;//当前播放的歌曲是第几首

- (IBAction)lastBtn:(UIButton *)sender;//上一曲的点击按钮
- (IBAction)nextBtn:(UIButton *)sender;//下一曲的点击按钮

- (IBAction)playOrPause:(UIButton *)sender;//暂停或者播放的按钮
- (IBAction)volumAction:(UISlider *)sender;//控制声音的slider
@end

@implementation ViewController

//判断当前音乐是否播放完毕
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    [self nextBtn:nil];
    
}

//存放所有的歌曲
-(NSMutableArray*)allMusicArray{
    if (!_allMusicArray) {
        _allMusicArray=[[NSMutableArray alloc] init];
    }
    return _allMusicArray;
}

//创建本地歌曲资源
-(void)creatSourceOfMusic{
    
    NSDictionary* music_Dic1=@{@"name":@"杨承熹-IF YOU.mp3",@"img":@"111.png"};
     NSDictionary* music_Dic2=@{@"name":@"薛之谦 - 你还要我怎样.mp3",@"img":@"xzq11.png"};
     NSDictionary* music_Dic3=@{@"name":@"Maroon 5-Sugar.mp3",@"img":@"sugar.png"};
     NSDictionary* music_Dic4=@{@"name":@"Justin Bieber-Eenie Meenie.mp3",@"img":@"justin.png"};
     NSDictionary* music_Dic5=@{@"name":@"香香-恋歌.mp3",@"img":@"lg.png"};
    NSDictionary* music_Dic6=@{@"name":@"薛之谦-绅士.mp3",@"img":@"xzq22.png"};
    // 添加
    [self.allMusicArray addObjectsFromArray:@[music_Dic1,music_Dic2,music_Dic3,music_Dic4,music_Dic5,music_Dic6]];
}

//上一首
- (IBAction)lastBtn:(UIButton *)sender {
   //判断当前播放的歌曲是否为第一首歌,如果是,就播放最后一首,如果不是,就-1
    if (self.currentIndex==0) {
        //是第一首歌,播放最后一首
        NSDictionary* dic=self.allMusicArray.lastObject;
        [self avAudioPlayerWithName:dic[@"name"]];
        self.albumImg.image=[UIImage imageNamed:dic[@"img"]];
        self.bigImg.image=[UIImage imageNamed:dic[@"img"]];
         self.musicNamaLabel.text=dic[@"name"];
        [self playPlayer];
        self.currentIndex=self.allMusicArray.count-1;
       
    }else{
        self.currentIndex--;
        NSDictionary* dic=self.allMusicArray[self.currentIndex];
         [self avAudioPlayerWithName:dic[@"name"]];
        self.albumImg.image=[UIImage imageNamed:dic[@"img"]];
        self.bigImg.image=[UIImage imageNamed:dic[@"img"]];
         self.musicNamaLabel.text=dic[@"name"];
        [self playPlayer];
    }
    
    [self.pauseOrplayBtn setTitle:@"暂停" forState:(UIControlStateNormal)];
    
}

//下一首
- (IBAction)nextBtn:(UIButton *)sender {
    //判断当前播放的歌曲是否为最后一首歌,如果是,就播放第一首
    if (self.currentIndex==self.allMusicArray.count-1) {
        NSDictionary* dic=self.allMusicArray.firstObject;
        [self avAudioPlayerWithName:dic[@"name"]];
        self.albumImg.image=[UIImage imageNamed:dic[@"img"]];
        self.bigImg.image=[UIImage imageNamed:dic[@"img"]];
        self.musicNamaLabel.text=dic[@"name"];
        [self playPlayer];
        self.currentIndex=0;
    }else{
        self.currentIndex++;
        NSDictionary* dic=self.allMusicArray[self.currentIndex];
        [self avAudioPlayerWithName:dic[@"name"]];
        self.albumImg.image=[UIImage imageNamed:dic[@"img"]];
        self.bigImg.image=[UIImage imageNamed:dic[@"img"]];
         self.musicNamaLabel.text=dic[@"name"];
        [self playPlayer];
    }

    [self.pauseOrplayBtn setTitle:@"暂停" forState:(UIControlStateNormal)];
    
    
}

//毛玻璃效果
-(void)effectMethod{
    UIBlurEffect* blureffect=[UIBlurEffect effectWithStyle:(UIBlurEffectStyleLight)];
     UIVisualEffectView* effectView=[[UIVisualEffectView alloc] initWithEffect:blureffect];
    effectView.frame=self.view.bounds;
    [self.bigImg addSubview:effectView];
}
-(NSTimer*)timer{
    if (!_timer) {
        //初始化的定时器会自动开启,不需要手动开启
        //第一个参数:每隔几秒执行一次定时器回调方法
        //第二个参数:定时器的回调方法在哪个类中实现就写哪个类的对象,一般写self
        //第三个参数:定时器的回调方法 如果带参数,参数就是定时器对象本身,类似于按钮
        //第四个参数:向定时器回调方法中传值,通过_timer.userInfo得到此处所写的值,如果不需要传值,此处直接填nil
        //第五个参数:是否重复执行回调方法  YES:重复执行  NO:只执行一次
        _timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
        
        //暂停timer  在将来的某一时刻开启定时器
        [_timer setFireDate:[NSDate distantFuture]];
    }
    return _timer;
}

//timer的回调方法
-(void)timerAction{
    //更新进度条的进度
    self.progressSlider.value=player.currentTime;
    //时间调整
    //剩余的秒数
    NSTimeInterval restDuration=player.duration-player.currentTime;
    self.timeLabel.text=[self transformWithSeconds:(int)restDuration];
    self.albumImg.layer.transform=CATransform3DRotate(self.albumImg.layer.transform, M_PI/60, 0, 0, 1);
    
}

//暂停
-(void)pausePlayer{
    [player pause];
    //暂停定时器
    [self.timer setFireDate:[NSDate distantFuture]];
    
}

//播放
-(void)playPlayer{
    [player play];
    //开启定时器
    [self.timer setFireDate:[NSDate distantPast]];
    
}

//AVAudioPlayer 只能播放本地音乐
-(void)avAudioPlayerWithName:(NSString*)musicName{
    //获取资源路径
  NSString* musicPath=[[NSBundle mainBundle] pathForResource:musicName ofType:nil];
     NSURL* url=[NSURL fileURLWithPath:musicPath];
     player=[[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    //指定代理
    player.delegate=self;
    //设置音量
    player.volume=0.5;
    //准备播放
    [player prepareToPlay];
    //获取歌曲的总时长
    NSLog(@"111--%f",player.duration);
    //将slider的最大值设置为歌曲的总时长
    self.progressSlider.maximumValue=(int)player.duration;
    //显示总时长
    self.timeLabel.text=[self transformWithSeconds:(int)player.duration];
    
    
    //播放
//    [player play];
    
}

//播放或者暂停
- (IBAction)playOrPause:(UIButton *)sender {
    //判断当前是否正在播放歌曲
    if (player.isPlaying) {
        //说明音乐正在播放,暂停
//        [player pause];
        [self pausePlayer];
        [sender setTitle:@"播放" forState:(UIControlStateNormal)];
    }else{
        //说明音乐在暂停状态,开始播放
//        [player play];
        [self playPlayer];
        [sender setTitle:@"暂停" forState:(UIControlStateNormal)];
    }
    
        
}

//调整音量
- (IBAction)volumAction:(UISlider *)sender {
    
    //通过滑竿调整音量
    player.volume=sender.value;
    
}

//调整播放进度
- (IBAction)progressAction:(customSlider *)sender {
    if (player.isPlaying) {
        //先暂停掉
//        [player pause];
        [self pausePlayer];
        
    }

    //让播放器的当前播放时间设置为和进度条一致
//    player.currentTime = sender.value;
    
}

//手指离开slider的时候会执行的代理方法
-(void)endDraggingWithSlider:(customSlider *)slider{
    player.currentTime = slider.value;
//    [player play];
    [self playPlayer];
    [self.pauseOrplayBtn setTitle:@"暂停" forState:(UIControlStateNormal)];
    
    
}

//将秒转换为00:00:00的格式
-(NSString*)transformWithSeconds:(int)seconds{
    
    //获取小时
    int hours=seconds/3600;
    //获取分钟
    //除去小时,看剩下多少秒,总秒数对3600取余就是剩余的秒数
    int minutes=seconds%3600/60;
    //获取秒数
    int second=seconds%60;
    NSString* hourStr=@"";
    NSString* minuteStr=@"";
    NSString* secondStr=@"";
    if (hours<10) {
        hourStr=[NSString stringWithFormat:@"0%d",hours];
        
    }else{
        hourStr=[NSString stringWithFormat:@"%d",hours];
    }
    
    if (minutes<10) {
        minuteStr=[NSString stringWithFormat:@"0%d",minutes];
    }else{
        minuteStr=[NSString stringWithFormat:@"%d",minutes];
    }
    
    if (second<10) {
        secondStr=[NSString stringWithFormat:@"0%d",second];
    }else{
        secondStr=[NSString stringWithFormat:@"%d",second];
    }
    NSArray* array=@[hourStr,minuteStr,secondStr];
    return [array componentsJoinedByString:@":"];
    
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //创建资源的方法
    [self creatSourceOfMusic];
    NSDictionary* dic=self.allMusicArray[0];
    [self avAudioPlayerWithName:dic[@"name"]];
    self.musicNamaLabel.text=dic[@"name"];
    self.albumImg.layer.masksToBounds=YES;
    self.albumImg.layer.cornerRadius=75;
    self.progressSlider.delegate=self;
    [self effectMethod];
    
}

在这里还需要我们自定义一个slider用来控制音频的播放进度customSlider继承于UISlider
customSlider.h中

#import <UIKit/UIKit.h>
@class customSlider;

@protocol  customSliderDelegate<NSObject>

-(void)endDraggingWithSlider:(customSlider*)slider;

@end

@interface customSlider : UISlider

@property(nonatomic,assign)id<customSliderDelegate>delegate;

@end

customSlider.m中

#import "customSlider.h"
@implementation customSlider

//当手指离开滑动条的时候
-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
    if (self.delegate && [self.delegate respondsToSelector:@selector(endDraggingWithSlider:)]) {
        
        [self.delegate endDraggingWithSlider:self];
        
    }else{
        NSLog(@"customSlider的代理未指定或者代理方法未实现");
    }
    
}

这样一个简单的音乐播放器就完成了,但这里只能播放本地的音乐哦😊😊😊😊😊😊😊

二、视频

iOS里面的视频用到的是AVPlayer(包含在AVFoundation)内,与AVAudioPlayer有点类似,但是AVPlayer的功能更加强大,它既可以播放音频也可以播放视频,而且可以直接播放网络音频。
在这里做一个简单的视频播放器,从上往下,第一个进度条是控制进度的,第二个slider是控制音量的


视频播放器.png

先在storyBoard中搭建界面,并将要用的控件拖成属性或方法


storyBoard.png

先导入<AVFoundation/AVFoundation.h>

#import "AVPlayerViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface AVPlayerViewController ()
@property(nonatomic,retain)AVPlayer* player;//播放器对象
@property(nonatomic,retain)AVPlayerItem* playerItem;//播放单元
@property(nonatomic,retain)AVPlayerLayer* layer;
@property (weak, nonatomic) IBOutlet UIButton *playOrpause;//播放或暂停
@property (weak, nonatomic) IBOutlet UISlider *progressSlider;//进度条
@property (weak, nonatomic) IBOutlet UIButton *nextAction;//下一个
@property(nonatomic,assign)BOOL isPlaying;//标志当前是否为播放状态
@property(nonatomic,retain)NSMutableArray* allSourcesMArray;//存放所有的视频连接
@property(nonatomic,assign)NSInteger currentIndex;//当前视频播放的是第几个
- (IBAction)volumAction:(UISlider *)sender;//控制音量的slider
- (IBAction)preAction:(UIButton *)sender;//上一个
- (IBAction)playAction:(UIButton *)sender;//播放按钮
@end

@implementation AVPlayerViewController
-(NSMutableArray*)allSourcesMArray{
    if (!_allSourcesMArray) {
        _allSourcesMArray=[[NSMutableArray alloc] init];
        [_allSourcesMArray addObject:@"http://huya-w2.dwstatic.com/56/12/1642/3412476-100-1477091884.mp4"];
        [_allSourcesMArray addObject:@"http://www.xiaobuqi.com//d/file/joke/2016-01/1452962161.mp4"];
        [_allSourcesMArray addObject:@"http://www.xiaobuqi.com//d/file/joke/2016-01/1452184059.mp4"];
           }
    return _allSourcesMArray;
}

-(AVPlayerLayer*)layer{
    if (!_layer) {
        _layer=[[AVPlayerLayer alloc] init];
        //射中playerLayer的大小
        _layer.frame=self.view.bounds;
        //设置视频缩放模式
        _layer.videoGravity=AVLayerVideoGravityResizeAspect;
        //添加
        [self.view.layer addSublayer:_layer];
    }
    return _layer;
}

-(void)playerMethodWithSourcePath:(NSString*)sourcePath{
    //资源URL
   
    if (!sourcePath ||sourcePath.length==0) {
        NSLog(@"资源路径不能为空");
        return;
       
    }
     NSURL* url=nil;
    if ([sourcePath hasPrefix:@"http"]) {
        //网络资源
        url=[NSURL URLWithString:sourcePath];
    }else{
        //本地资源
        url=[NSURL fileURLWithPath:sourcePath];
    }
    //创建播放单元
    self.playerItem=[AVPlayerItem playerItemWithURL:url];
    //创建播放器
    if (self.player && self.player.currentItem) {
        //说明播放器对象已经存在
    [self.player.currentItem removeObserver:self forKeyPath:@"status"];
        [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    }else{
       //说明播放器对象不存在
        self.player=[AVPlayer playerWithPlayerItem:self.playerItem];
    }
    //创建显示的layer对象
    if (!self.layer.player) {
        //如果layer没有绑定播放器,就给他绑定一个播放器
        self.layer.player=self.player;
    }
    //通过KVO监听item的status的属性的变化
    //表示多媒体资源是否准备可以播放
    ////   self.playerItem.status;
    //    //KVO key-value-observer  检测对象属性是否发生变化
    //    //1.只有通过KVC或者属性的setter方法进行赋值,KVO才能监测到
    //    //2.如果观察同一个对象的同一个属性,在没有移除旧的观察者又添加新的同一个观察者,直接崩溃
    //    //3.如果没有添加观察者,但又移除观察者,崩溃
    //    //4.如果观察者被销毁,但是没有移除该观察者,崩溃
    //5.如果被观察者被销毁,但是没有移除观察者,崩溃
    //    //为被观察者的对象添加观察者
    //    // 第一个参数:观察者对象,KVO的回调方法在哪个类中实现,观察者就是哪个类对象
    //    //第二个参数:要监测被观察对象的哪个属性,此处就写对应的属性名
    //    //第三个参数:要观察属性的哪种状态
    //    //第四个参数:上下文,一般用来为KVO的回调方法传值,如果不需要,直接写nil
     [self.playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
    // 调整音量
    self.player.volume=0.5;
    //监测播放进度
    //第一个参数:从什么地方开始监测
    //    //第二个参数:将监测过程在哪个队列中进行
    //    //第三个参数:block   视频播放过程中该block会多次执行,block中的CMTime是当前视频播放的位置
    //    //防止block中造成循环引用造成内存泄漏
    __weak AVPlayerViewController *vc=self;
    [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, self.playerItem.currentTime.timescale) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
     //更改进度条的进度
     vc.progressSlider.value= time.value/time.timescale;
        }];
     //通过广播中心监测视频播放完成的状态
    //第一个参数:观察者,用来监听广播中心的消息
    //    //第二个参数:回调方法,当我们监听的消息过来就会执行该回调方法,如果带参数,参数类型是广播
    //    //第三个参数:具体广播的名称
    //    //第四个参数:广播内容的标记,如果赋值为nil,就是监听该广播下所有的消息,如果是具体的值,那就只监听对应标记的消息
    NSNotificationCenter* notification=[NSNotificationCenter defaultCenter];
    [notification addObserver:self selector:@selector(palyerFinish:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}

//实现广播通知中心的回调方法
-(void)palyerFinish:(NSNotification*)notification{
    //广播中可能带的值  userInfo和object都是发广播时赋的值
    NSLog(@"%@",notification.userInfo);
    NSLog(@"%@",notification.object);
    NSLog(@"视频播放完成");
    
}

//KVO的回调方法
//第一个参数:被观察的属性名
//第二个参数:被观察的对象
//第三个参数:被观察的属性值的新值、旧值都存在该字典中
//第四个参数:上下文,用来接收添加观察者的时候context传递过来的值
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
    
    //从字典中获取最新状态下的值
    AVPlayerItemStatus newStatus=[change[NSKeyValueChangeNewKey] intValue];
    switch (newStatus) {
        case AVPlayerItemStatusFailed:
            NSLog(@"资源有误,无法播放");
            break;
        case AVPlayerItemStatusUnknown:
            NSLog(@"资源未知错误");
            break;
        case AVPlayerItemStatusReadyToPlay:
            [self.player play];
             self.isPlaying=YES;
            //播放单元获取的duration是一个CMTime类型的结构体  CMTime是一个表示视频的时间单位
            //value:视频的总帧数
            //timescale:帧/秒  该视频的播放速率  每秒多少帧
            if (self.playerItem.duration.timescale) {
               self.progressSlider.maximumValue= self.playerItem.duration.value *1.0/self.playerItem.duration.timescale;
            }
           
            NSLog(@"资源已准备完成,可以播放");
            break;
        default:
            break;
    }
    
    
}
//调整音量
- (IBAction)volumAction:(UISlider *)sender {
    self.player.volume=sender.value;
}

//调整进度
- (IBAction)progressAction:(UISlider *)sender {
    [self.player pause];
    //将视频从指定位置开始播放
    //第一个参数:从哪个位置开始播放
    //第二个参数:调整完成之后要进行的操作
    [self.player seekToTime:CMTimeMakeWithSeconds(sender.value, self.playerItem.currentTime.timescale) completionHandler:^(BOOL finished) {
        if (finished) {
             NSLog(@"视频已播放完成,请结束观看");
            [self.player play];
        }
       
    }];
    
}

//上一个
- (IBAction)preAction:(UIButton *)sender {
    NSInteger index=self.currentIndex-1;
    [self changeSourceWithIndex:index];
    [self.playOrpause setTitle:@"暂停" forState:UIControlStateNormal];
}

//播放暂停
- (IBAction)playAction:(UIButton *)sender {
    if (self.isPlaying) {
        [self.player pause];
        self.isPlaying=NO;
        [sender setTitle:@"播放" forState:(UIControlStateNormal)];
    }else{
        [self.player play];
        self.isPlaying=YES;
        [sender setTitle:@"暂停" forState:(UIControlStateNormal)];
    }
    
}

//下一个
- (IBAction)nextAction:(UIButton *)sender {
    NSInteger index=self.currentIndex+1;
    [self changeSourceWithIndex:index];
    [self.playOrpause setTitle:@"暂停" forState:UIControlStateNormal];
}

//切换资源的方法
-(void)changeSourceWithIndex:(NSInteger)index{
    [self.player pause];
    if (index<0) {
        //在播放最后一首的时候点击了上一曲
        [self playerMethodWithSourcePath:self.allSourcesMArray.lastObject];
        self.currentIndex=self.allSourcesMArray.count-1;
    }else if (index==self.allSourcesMArray.count){
        //在播放最后一首的时候,点击了下一曲
        [self playerMethodWithSourcePath:self.allSourcesMArray[0]];
        self.currentIndex=0;
    }else{
        //在中间,既不是第一,也不是最后
        [self playerMethodWithSourcePath:self.allSourcesMArray[index]];
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.isPlaying=NO;
    self.currentIndex=0;
//    [self avPlayer];
    [self playerMethodWithSourcePath:self.allSourcesMArray[0]];
    //通知中心发送广播
    [[NSNotificationCenter defaultCenter] postNotificationName:@"test" object:@"这里是FM99.9,我是余菲,我在陕西等您" userInfo:@{@"name":@"余菲"}];
    
  }

这样一个简单的视频播放器就完成了,😊😊😊😊
其实思路和音乐播放器差不多

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容