今天讲一下对VLC播放器音频播放功能进行二次开发,讲解如何改造音乐播放相关功能。最近一直在忙着优化视频解码部分代码,因为我的视频播放器需要在一台主频比较低的机器上跑(800M主频),所以视频解码能力受到极大考验,VLC的解码库挺复杂,花了两三周时间,也只看了点皮毛。

  这里说几句题外话,中间也尝试过使用其他的解码器,其中选了目前比较有名的Vitamio来试验,不过它让我大失所望,对于720*420的视频解码能力竟然还不如Beta版的VLC的解码,我测试一个立方体旋转视频,播放的时候,整个视频画面变形了o(╯□╰)o。这里喷一下Vitamio4.0,在中低端机器上表现实在让人失望。不过对于1280*720视频,它解码能力比目前的VLC表现好很多。但是对于低码率的视频都解析不好,没办法只能放弃(不知为何Vitamio对高分辨率解析不错,但是中低分辨率解析一团糟,我特意使用Vitamio官方的VPlayer测试也是这样)。最后还是选择自己去优化一下视频视频解码。这方面以前在PC上也做过,所以还是有点经验,后面一段时间估计要在这方面花不少精力。

  言归正传,几天讲一下对音乐播放方面二次开发,主要是因为我的多媒体程序是放到平板上面运行,所以屏幕空间比较大。原生的VLC的音乐播放界面有点简洁,因此增加了一些功能。下面针对一些开发流程和VLC音频控制(java层)播放讲解。下面是我修改后的效果:

  看上去变化挺大,其实界面功能改动不是很多,主要增加了一个歌曲列表和LRC歌词显示。然后对布局进行了调整,主要是针对平板电脑屏幕空间比较大进行排布。下面针对歌曲列表和歌词显示以及开发过程中遇到的问题,讲解一下。

(PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)

1、增加歌曲列表

  这个不算什么新功能,原生VLC里面已经做得很好。你要做的其实很简单,只要把相应的适配器数据导入到新的列表控件即可:

  1. //Edited by mythou
    //http://www.cnblogs.com/mythou/
  1. mSongsAdapter= new AudioListAdapter(getActivity());
  2. setListAdapter(mSongsAdapter);

这里说一下AudioAdapter适配器,它是生成所有歌曲列表信息的数据适配器,我们看看AudioListAdapter生成元素的getView方法:

  1. //Edited by mythou
    //http://www.cnblogs.com/mythou/
  1.   public View getView(int position, View convertView, ViewGroup parent)
  2. {
  3. ViewHolder holder;
  4. View v = convertView;
         //使用缓冲机制,没有View 缓存的时候才重新加载生成新的View
  5. if (v == null)
  6. {
  7. LayoutInflater inflater = (LayoutInflater) getContext()
  8. .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  9. v = inflater.inflate(R.layout.audio_browser_item, parent, false);
  10. holder = new ViewHolder();
  11. holder.layout = (View) v.findViewById(R.id.layout_item);
  12. holder.cover = (ImageView) v.findViewById(R.id.cover);
  13. holder.title = (TextView) v.findViewById(R.id.title);
  14. holder.artist = (TextView) v.findViewById(R.id.artist);
  15. v.setTag(holder);
  16. } else
  17. holder = (ViewHolder) v.getTag();
  18.  
  19. Media media = getItem(position);
  20.      //获取歌曲ID3信息的封面,ID3信息都是VLC Lib库下面用JNI实现的
  21. Bitmap cover = AudioUtil.getCover(v.getContext(), media, );
  22. if (cover == null)
  23. cover = BitmapCache.GetFromResource(v, R.drawable.icon);
  24.  
  25. holder.cover.setImageBitmap(cover);
  26.  
  27. Util.setItemBackground(holder.layout, position);
  28. holder.title.setText(media.getTitle());
  29. ColorStateList titleColor = v.getResources().getColorStateList(
  30. mCurrentIndex == position ? R.color.list_title_last
  31. : R.color.list_title);
  32. holder.title.setTextColor(titleColor);
  33. holder.artist.setText(media.getSubtitle());
  34. return v;
  35. }

  上面就是适配器的主要getView方法,其他的方法跟我们使用基本List的时候需要的Adapter一样,这里不多说。需要注意的是,这里的ListView都是用了缓存机制,这样可以加快执行速度,也可以减少内存使用。是优化ListView的第一个需要改善的地方。

  这里补充一点有关ID3信息获取问题,VLC里面默认的ID3信息获取都是UTF-8编码,对于很多国外的歌曲没有任何问题。不过对于国内部分歌曲,ID3信息是使用GB2312编码,最终会导致显示乱码问题。这个对于Android默认播放器也存在这个问题,因此为了更好兼容国内GBK或者G2312编码的歌曲,还需要对VLC Lib里面有关获取ID3信息的代码进行判断,加入转码机制。

2、VLC多媒体数据库

  下面简单讲一下VLC里面多媒体数据管理,如果是插拔卡后。程序第一次启动会重新扫描多媒体文件,并生成多媒体数据库。这一点跟Android自带的MediaScanner服务差不多。有关扫描的部分这里先不说,今天主要是讲讲如何获取音乐部分的数据。

  1. //Edited by mythou
    //http://www.cnblogs.com/mythou/
  1.      List<Media> audioList;
  2. List<String> itemList;
  3. String currentItem = null;
  4. int currentIndex = -;
  5.  
  6. if (name == null || mode == AudioBrowserFragment.MODE_SONG)
  7. {
  8. mTitle.setText(R.string.songs);
  9. itemList = AudioServiceController.getInstance().getItems();
  10. currentItem = AudioServiceController.getInstance().getItem();
  11. audioList = MediaLibrary.getInstance(getActivity()).getMediaItems(
  12. itemList);
  13. }
         else
  14. {
  15. mTitle.setText(name2 != null ? name2 : name);
  16. audioList = MediaLibrary.getInstance(getActivity()).getAudioItems(
  17. name, name2, mode);
  18. }
  19.  
  20. mSongsAdapter.clear();
  21.  
  22. for (int i = ; i < audioList.size(); i++)
  23. {
  24. Media media = audioList.get(i);
  25. if (currentItem != null && currentItem.equals(media.getLocation()))
  26. currentIndex = i;
  27. mSongsAdapter.add(media);
  28. }

  上面是获取Audio音频数据的方法,主要是通过MediaLibrary类实现,通过MediaLibrary接口可以获取到一个Audio音频文件的List表,我们的列表数据都是基于这里获取的,只要设置到适配器里面就可以。、

  除了MediaLibrary以外,Media类也是我们需要关注的,它是一个抽象了所有多媒体文件属性的类。用于保存多媒体文件相关数据以及识别哪些文件类型是我们支持的。具体源码请自行查看,代码难度不大,不过可以学到如何编写一个大程序时分模块的思路。

  下面就是程序默认支持的音频文件过滤:

  1. //Edited by mythou
    //http://www.cnblogs.com/mythou/
  1.   String[] audio_extensions = {
  2. ".3ga", ".a52", ".aac", ".ac3", ".adt", ".adts", ".aif", ".aifc", ".aiff", ".amr",
  3. ".aob", ".ape", ".awb", ".caf", ".dts", ".flac", ".it", ".m4a", ".m4p",
  4. ".mid", ".mka", ".mlp", ".mod", ".mpa", ".mp1", ".mp2", ".mp3", ".mpc", ".mpga",
  5. ".oga", ".ogg", ".oma", ".opus", ".ra", ".ram", ".rmi", ".s3m", ".spx", ".tta",
  6. ".voc", ".vqf", ".w64", ".wav", ".wma", ".wv", ".xa", ".xm" };

3、歌词同步滚动

  歌词显示这部分是我另外加上去的,因为现在的Android市场上的音乐播放器,基本都是支持歌词现在的,歌词现在分两部分,一部分是本地歌词支持,另外一部分是下载在线歌词。对于目前的应用环境来说,这两个功能都很重要。java解析LRC类型歌词的方法网上已经有很多,这个从以前java时代就有很多好的解析类,我们自己也没必要重新写一个,因此我也是在网络上找了一个解析LRC歌词比较好的方法,直接引用。然后根据Android的环境,重载了一个TextView用来滚动显示歌词。

  这里简单说说歌词同步滚动问题,我们把LRC歌词分析出来后,保存到一个数据列表里面,然后根据歌曲播放的时间,动态高亮显示对应歌词即可。对LRC熟悉的朋友应该都明白如何工作。这方面资料网上很多,基本上只要找个解析LRC的类,然后重载一下TextView即可实现。

  对于网络下载歌词,因为我自己目前没有歌词服务器,只能依靠第三方的开放平台。我这里选用了baidu的开发平台服务。相关方法可以查看百度开发者平台网站的相关开发包。里面提供了Demo和详细接口文档。

  我这里只是做个引导,具体加入到自己工程方法,需要自己实践。这个难度不大,baidu的开发平台还是做得很好,接口容易使用。代码我这里就不给出来了。这个整合难度不高,只要自己动动手都能实现。

4、JNI调试Log输出问题

  如果你打开Logcat看过VLC播放音乐后,会发现它会一直打印Log。这个虽然说不会很占用资源,不过一直打印Log,自己看着就不爽。而且也影响我们看自己的输入打印信息。所以我们可以把它关了,一来可以清爽很多,二来也可以节省资源。

  1.  
  1. //Edited by mythou
    //http://www.cnblogs.com/mythou/
  1. Linux-VLC-Project\android-vlc-project\android\vlc\modules\audio_output\opensles_android.c

  上面是那个一直打印Buffer的路径,Linux-VLC-Project是我VLC在Linux下面的根目录。你可以按照我上面源码路径找到对应的C文件。下面就是一个时间输出的时候,会打印音频Buffer的接口,只要把msg_Dbg屏蔽即可。从这里我们也可以学到如何在JNI的C/C++代码里面输入Log到Logcat。如何实现,自己看看源码吧,不过需要你有点C/C++的基础。

  1.  
  1. //Edited by mythou
    //http://www.cnblogs.com/mythou/
  1. static int TimeGet(audio_output_t* aout, mtime_t* restrict drift)
  2. {
  3. aout_sys_t *sys = aout->sys;
  4.  
  5. SLAndroidSimpleBufferQueueState st;
  6. SLresult res = GetState(sys->playerBufferQueue, &st);
  7. if (unlikely(res != SL_RESULT_SUCCESS)) {
  8. msg_Err(aout, "Could not query buffer queue state in TimeGet (%lu)", res);
  9. return -;
  10. }
  11.  
  12. vlc_mutex_lock(&sys->lock);
  13. bool started = sys->started;
  14. vlc_mutex_unlock(&sys->lock);
  15.  
  16. if (!started)
  17. return -;
  18.  
  19. *drift = (CLOCK_FREQ * OPENSLES_BUFLEN * st.count / )
  20. + sys->samples * CLOCK_FREQ / sys->rate;
  21.  
  22. msg_Dbg(aout, "latency %"PRId64" ms, %d/%d buffers", *drift / ,
  23. (int)st.count, OPENSLES_BUFFERS);
  24.  
  25. return ;
  26. }

  整个VLC项目的核心还是在VLC的解码库里面,虽然Java层我们可以学到很多Android的应用开发知识,不过对于一个音视频播放器来说,解码才是核心。如果对这方面有兴趣的朋友可以好好研究一下,因为这个研究熟悉了,基本上跟你做什么平台区别不大,目前所有平台播放器基本都是基于FFMpeg解码库移植。

5、结语

  今天就讲到这里吧,其实java层改动并不难,我这里只是给个简单思路,有这方面需求的可以自己看源码,结合自己需要实践一下。编程还是需要自己多写写代码才能有长进。

  接下来一段时间应该会好好分析VLC的解码库,看它的解码库,真是考验C的基本功。Java层的分析暂时就到这里,剩余的很多模块,大家可以自己结合需要,自行分析和修改。

2013-8-16

Edited by 泡泡糖

系列文章

Linux 下编译Android-VLC开源播放器详解(附源码下载)

Android VLC播放器二次开发1——程序结构分析

Android VLC播放器二次开发2——CPU类型检查+界面初始化

Edited by mythou

原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3293582.html 

Android VLC播放器二次开发3——音乐播放(歌曲列表+歌词同步滚动)的更多相关文章

  1. Android VLC播放器二次开发2——CPU类型检查+界面初始化

    上一篇讲了VLC整个程序的模块划分和界面主要使用的技术,今天分析一下VLC程序初始化过程,主要是初始化界面.加载解码库的操作.今天主要分析一下org.videolan.vlc.gui.MainActi ...

  2. 搭建rtmp直播流服务之4:videojs和ckPlayer开源播放器二次开发(播放rtmp、hls直播流及普通视频)

    前面几章讲解了使用 nginx-rtmp搭建直播流媒体服务器; ffmpeg推流到nginx-rtmp服务器; java通过命令行调用ffmpeg实现推流服务; 从数据源获取,到使用ffmpeg推流, ...

  3. Android VLC播放器二次开发1——程序结构分析

    最近因为一个新项目需要一个多媒体播放器,所以需要做个视频.音频.图片方面的播放器.也查阅了不少这方面的资料,如果要从头做一个播放器工作量太大了,而且难度也很大.所以最后选择了VLC作为基础,进行二次开 ...

  4. Android应用开发--MP3音乐播放器代码实现(一)

    需求1:将内存卡中的MP3音乐读取出来并显示到列表当中 1.   从数据库中查询所有音乐数据,保存到List集合当中,List当中存放的是Mp3Info对象 2.   迭代List集合,把每一个Mp3 ...

  5. 记录一个Unity播放器插件的开发

    背景 公司最近在做VR直播平台,VR开发我们用到了Unity,而在Unity中播放视频就需要一款视频插件,我们调研了几个视频插件,记录两个,如下: Unity视频插件调研 网上搜了搜,最流行的有以下两 ...

  6. vlc播放器设置开机自动全屏播放网络视频流

    因工作需要,要用vlc视频播放器实现开机自动全屏播放某个网络视频流.百度了下,说的都很模糊,经过整理,设置方法如下: 一,添加视频流地址:rtsp://wowzaec2demo.streamlock. ...

  7. Android开发之音乐播放器的实现

    Android音乐播放器 使用到Android的Actiivity和Service组件 播放音频的代码应该运行在服务中,定义一个播放服务MusicService,服务里定义play.stop.paus ...

  8. Android开发之音乐播放器

    做了一天的音乐播放器小项目,已经上传到github,将链接发到这里供大家参阅提议 https://github.com/wangpeng0531/MusicPlayer.git

  9. Android学习笔记_24_多媒体MediaPlayer对象之音乐播放器与SoundPool声音池

    一.MediaPlayer对象常用方法介绍: MediaPlayer mediaPlayer = new MediaPlayer(); if (mediaPlayer.isPlaying()) { m ...

随机推荐

  1. docker 部署springboot应用

    第一步:搭建springboot的web应用,可在CMD命令行中通过mvn install命令将应用打成jar包:如demo-0.0.1-SNAPSHOT.jar 第二步:将jar包copy到cent ...

  2. [软件研究]对AMH面板的研究

    0x00 前言 继续研究,这次来看一下AMH面板,图截自官网 就让我们来看看这个多个"首个"的面板做的怎么样吧. 0x01 安装 官方提供了两种安装方式,一是极速安装,二是编译安装 ...

  3. luogu P4178 Tree

    题目链接 luogu P4178 Tree 题解 点分治 代码 // luogu-judger-enable-o2 #include<cstdio> #include<algorit ...

  4. APIO2018 铜滚记

    「一旦闭上双眼,就昏昏欲睡」「仿佛与这个世界的联系,被瞬间切断」「可是,负罪感与背德感又会在黑暗中将我吞噬」「即使这样,却也无法与身体的疲惫抗衡」 「如果,这些东西也无法让意识的存在稳定下来的话」「那 ...

  5. CentOS 7安装Ansible

    在CentOS下安装Ansible非常的简单,但需要注意一下几点: 1.为了简单建议使用yum的epel源安装,毕竟没什么模块需要自己定制的,如果非要指定版本,可以指定不同的版本,下面会讲. 2.母机 ...

  6. Activex控件的IObjectSafety接口问题

    我的05年做流氓插件的时候,就注意到了这个问题,只要注册表加入 类似的就可以  HKEY_CLASSES_ROOT\Component    Categories\{7DD95801-9882-11C ...

  7. Javascript:自己写模板引擎

    背景 因为JS没有提供“字符串插入”和“多行字符串”特性,传统的拼凑字符串容易出错.性能不高和不容易理解代码,为了应对这些问题,很多个人和团队开发了模板引擎,现在主流的JS框架几乎都提供此类功能了. ...

  8. verilog语法实例学习(11)

    同步时序电路的一般形式 时序电路由组合逻辑以及一个或多个触发器实现.一般的架构如下图所示:W为输入,Z为输出,触发器中存储的状态为Q.在时钟信号的控制下,触发器通过加在其输入端的组合逻辑输入,使得电路 ...

  9. 检测三种不同操作系统的Bash脚本

    检测三种不同操作系统(GNU/Linux, Mac OS X, Windows NT)的Bash脚本. 设计: 1.使用“uname”命令获取系统信息,带上“-s”参数个打印内核名称. 2.使用“ex ...

  10. art.template 循环里面分组。

    后台提供给我们一个数组,我们要用模版实现上面的格式输出怎么版呢? 下面就是解决方案: <h2>循环4个一组</h2> <script type="text/ht ...