ios零碎记录iOS技术资料iOS开发 技术集锦

iOS VLC-音乐播放(列表式播放封装)

2016-12-25  本文已影响1768人  Pocket

iOS 音乐播放

已经颓废了好几个月了,感觉在不写点什么就GG了。情绪这东西真的是毒药,控制不了容易一蹶不振,感觉做什么都没意思,以往都是我来开导别人,但是发生在自己身上时自己却看不开了。也许经历的还不够,相信时间会给我们答案。

说了这么多题外话,很久没有写东西,也没提前做准备,那就拿最近的项目需求来做题材写一篇关于iOS音乐播放。

需求

这个项目很蛋疼,需求什么都不明确,。导致后期改动颇大,做了很多无用工,当然也有我自己的原因,用的一些第三方框架之前没考虑太多。就拿音乐播放来说吧。我事先没考虑太多,只是觉得一个简单的播放音乐功能而已,用一些大家常见的第三方就OK了。一开始我用的是比较受推荐的“FreeStreamer”这个库,它里面有一个专门用来做列表控制播放的类“FSAudioController”比较适合用来做列表播放,那么问题来了,当项目大概好了后,打包给那边需求方测试,反馈下来就是让我一阵懵逼,这格式不支持,那格式不支持的(flac,wma,acc,wav,caf,ape),当时心里是有点不爽的,你需求方当初又没明确说过需要支持什么格式。再说看到这么一堆音频格式,说实话一般听音乐也就那么几种,什么APE无损格式的我都很少见过,一般常见就是mp3、m4a等一些,不过FreeStreamer这个库支持的格式说实话确实是少,连wav格式播放都有些怪,感觉播放这种格式音频有概率性的出现无声。不死心的我去找FreeStreamer论坛,发现作者自己说的原话,除了mp3和m4a常见格式之外,暂时没打算做支持其他格式的打算。那么就此扑街。

其实我第二个选择是用FFmpeg,因为在早先做MFI项目的时候,专门针对通过MFI传输过来的音频流用FFMpeg封装了一套用来解码播放音频的接口,这个可是支持市面上大多数格式了,如果有朋友对FFmpeg感兴趣,我会挑一个时间段专门写一些我对FFmpeg认知,然后想换上去的时候我发现这个wifi存储项目的视频播放功能我是用VLC写的,大家都知道VLC内部包含了FFmpeg这个库,然后在iOS中VLC库封的比较死,单独集成FFmpeg上去肯定是会报很多重复性的错误。那么索性就干脆用VLC写一个音乐播放得了。

前面已经有过一篇介绍VLC的简单使用,音乐播放也是差不多的,视频都能支持大部分格式播放,
那么音频肯定也是,因为视频内部可是包含音频的。

VLC 音乐播放

说到音乐,有必要说一下有些音乐文件有的是包含歌曲信息(歌手,专辑,专辑图),当然并不是所有音乐文件就一定会有。这得看制作音乐的时候有没有往里面写入歌曲相关的信息,下面我主要说一些用VLC做音乐播放的时候遇到的一些坑以及解决办法。

};
/**


- VLCMediaPlayer做列表切换播放问题

```objc
也不知道是我思考路子不对还是确实MobileVLCKit的问题。
我原先做列表播放的时候是想创建多个VLCMediaPlayer对象,通过对VLCMediaPlayer的控制达到切换播放的效果,
当然效果是做出来了,可是在后面测试的时候,在音频的切换的过程中会有几率造成音频无声的状况,
然后就只好播放完后销毁一个VLCMediaPlayer在重新创建达到切换的效果,
并且在销毁VLCMediaPlayer对象前也不能调用stop方法,不然有时候也会造成音频切换无声情况。

好了,废话我就不再说了,抛砖引玉的直接上个人接口封装的源码了。喜欢的朋友麻烦点一波关注和赞呐。

{
if ([keyPath isEqualToString:@"remainingTime"]) {
self.currentTime = [[[self.activeStream time] minuteStringValue] intValue] * 60;
self.allTime = [[[self.activeStream remainingTime] minuteStringValue] intValue] * 60 + self.currentTime;
self.currentProgress = [self.activeStream position];
[self update];
} else if ([keyPath isEqualToString:@"state"]) {
switch (self.activeStream.state) {
case VLCMediaPlayerStatePlaying:
{
if (self.onStateChange) {
self.onStateChange(VLCMusicStatePlaying);
}
}
break;

          case VLCMediaPlayerStateOpening:
          {
              if (self.onStateChange) {
                  self.onStateChange(VLCMusicStatePlaying);
              }
              [self updataMeta];
          }

              break;

          case VLCMediaPlayerStatePaused:
              if (self.onStateChange) {
                  self.onStateChange(VLCMusicStatePaused);
              }
              break;
          case VLCMediaPlayerStateStopped:
          {
            if (self.currentTime == self.allTime) { // 判断播放是否完结
                
                if (self.onStateChange) {
                    self.onStateChange(VLCMusicStateCompleted);
                }
                switch (self.type) {
                    case VLCMusicModelTypeListLoop:
                    {
                        if ([self hasNextItem]) {
                            [self playNextItem];
                        } else {
                            [self playItemAtIndex:0];
                        }
                    }
                        break;
                    case VLCMusicModelTypeSingleLoop:
                    {
                        self.currentTime = 0;
                        self.currentProgress = 0.0;
                        [self playItemAtIndex:self.index];

                    }
                        break;
                        
                    case VLCMusicModelTypeRandomPlay:
                    {
                        // 获取随机数
                        int index = arc4random() % self.musicPlaylist.count;
                        [self playItemAtIndex:index];
                    }
                        break;

                    default:
                    {
                        if ([self hasNextItem]) {
                            [self playNextItem];
                        } else {
                            [self playItemAtIndex:0];
                        }
                    }
                        break;
                }
            } else {
                if (self.onStateChange) {
                    self.onStateChange(VLCMusicStateStopped);
                }
            }
            
        }
              break;
          case VLCMediaPlayerStateBuffering:
              if (self.onStateChange) {
                  self.onStateChange(VLCMusicStateBuffering);
              }
              break;

          case VLCMediaPlayerStateError:
          {
              if (self.onStateChange) {
                  self.onStateChange(VLCMusicStateFailed);
              }

              if (self.onFailure) {
                  self.onFailure();
              }
          }

              break;
          default:
              break;
      }
          }

}

- (void)update
{
    if (self.onTimeChange) {
        VLCMusicTime *musicTime = [VLCMusicTime new];
        if (![self.totalTimeStr isEqualToString:@"--:--"]) {
            musicTime.allTime = self.totalTimeStr;
        } else {
            int time = (-[[self.activeStream remainingTime] intValue]) + [[self.activeStream time] intValue];
            VLCTime *v = [VLCTime timeWithInt:time];
            musicTime.allTime = [v stringValue];
        }
        musicTime.currentTime = [[self.activeStream time] stringValue];
        musicTime.progress = self.currentProgress;
        self.onTimeChange(musicTime);
    }
}

#pragma mark - -- VLCMediaDelegate
// vlc bug �本地的可以解析出,网络的不行了。。。。
- (void)mediaDidFinishParsing:(VLCMedia *)aMedia
{
    NSLog(@"mediaDidFinishParsing:%@",aMedia);
}

@end
```

接口用法

下面就简单说一下上面所封装的API的用法。设计UI的代码我就不贴出来了,相信你们只要把VLCMusicViewController看懂了或者不需要看懂(会用就行),就能设计出一个属于自己的漂亮的音乐播放控制器。如果很多人实在不会用我在考虑把接口用法demo上传到github。

ps:当初给类取名字的时候没取好,怪我!!!,你们可以自己改改(建议:VLCMusicManager)。
当初设计接口需求时可能多写了几个需求性属性控制参数,暂时没来得及实现(音量控制,自动播放下一首的关闭开关),勿怪啊。
相信看懂的你们可以自己在我这套不算很好的代码里整理出属于自己的精华。
1.创建VLCMusicViewController管理类
2.为VLCMusicViewController对象赋值几个block属性回调,
  onStateChange(状态回调,在这里可以改变播放按钮UI的改变),
  onMetaDataAvailable(歌曲信息改变回调,在这里可以改变歌曲信息UI),
  onTimeChange(时间和进度状态回调,在这里可以改变时间信息UI和进度条UI)
  onPlayType(播放顺序改变回调,在这里可以改变播放顺序UI)
  ...

放几张效果图

51C4A1DAEF2F4B92687E2EF08BA80370.gif IMG_2568.jpg IMG_2569.jpg IMG_2567.jpg

好了就简单介绍到这里了,没几个接口方法,多试几遍就会了。觉得我写的不错的兄弟可以点赞或者关注Pocket的一些不定期的日常更新。共勉,加油!

上一篇 下一篇

猜你喜欢

热点阅读