[关闭]
@Vee 2017-08-23T12:48:20.000000Z 字数 3316 阅读 2490

列表播放 YouTube 视频

前言

港台APP改版中有一个列表播放 YouTube 视频的需求,但 YouTube 的视频链接是不能直接用 Android 系统的 VideoView 来播放的,因为这不是一个真正的视频流,而是一个网页,只能用 WebView 来播放。但是用 WebView 来播放体验总不太好,而且 UI 也无法进行定制。

三种播放 YouTube 视频的方法

1. 利用 YouTube App 播放

如果手机里面安装有 YouTube App 的话,可以利用如下方法打开 YouTube 进行播放:

  1. startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.youtube.com/watch?v=Hxy8BZGQ5Jo")));

这种方法局限性很大,如果手机没有安装 YouTube App 的话,是无法播放的,而且这种方法是打开别人家的 APP 而离开自家的 APP,这估计也是无法接受的。

2. 使用 YouTube Android Player API 进行播放

官方有提供在 Android 系统上播放 YouTube 视频的API(点击此处),这是官方支持的API,可以很好地播放视频,播放体验也不错。

虽然这是官方的 API,但是也有一点不好,就是无法自定义播放 UI,而且全屏时体验不好,经常黑屏。

如上图所示,使用该 API 播放的界面是 YouTube 官方的 UI,会带有 YouTube 自己的 logo。而且含有该播放器组件的 Activity 必须继承于 API 中的YouTubeBaseActivity,这样不便于集成。

总的来说,这不是一种比较好的方法,当然如果运营不介意界面如此,则不失为一种解决措施。详细接入方法请参考官方 API

3. 解析 YouTube 视频链接得到视频的真实地址得到视频流

用工具类(点此)将 YouTube 视频链接解析得到视频的真实地址,然后用 VideoView 播放。

该种方式是根据 YouTube 提供的接口(www.youtube.com/get_video_info?video_id=)来解析的,本质上来说也属于官方支持的。

这种方式可以说比较合适的了,然而这种方式有一个缺点,就是这个解析视频真实地址可能会失败,就是不是所有的视频都可以解析出来;而且这种方式是根据 YouTube 提供的接口(www.youtube.com/get_video_info?video_id=)来解析得到视频流的,不能保证以后 YouTube 是否会更改该接口规则。

如果实在无法接受第二种方案的 YouTube 视频界面,则可采用该种方案,然后把解析工作放在服务端去进行,这样就算以后规则更改,也可以在服务端动态调整,无需客户端修改。而且规则一旦定下来,如果没有特殊情况,一般也不会随便更改。
用法如下:

  1. String youtubeLink = "http://youtube.com/watch?v=xxxx";
  2. new YouTubeExtractor(this) {
  3. @Override
  4. public void onExtractionComplete(SparseArray<YtFile> ytFiles, VideoMeta vMeta) {
  5. if (ytFiles != null) {
  6. int itag = 22;
  7. String downloadUrl = ytFiles.get(itag).getUrl();
  8. }
  9. }
  10. }.extract(youtubeLink, true, true);

downloadUrl就是解析之后的视频流地址。
但是在extract方法中传入视频链接有时会解析失败,这时候最好自己解析出视频 id 之后再把 id 传入 extract中会提高成功率。解析视频 id 的工具方法如下:

  1. public static String extractYoutubeId(String url) throws MalformedURLException {
  2. String id = null;
  3. try {
  4. String query = new URL(url).getQuery();
  5. if (query != null) {
  6. String[] param = query.split("&");
  7. for (String row : param) {
  8. String[] param1 = row.split("=");
  9. if (param1[0].equals("v")) {
  10. id = param1[1];
  11. }
  12. }
  13. } else {
  14. if (url.contains("embed")) {
  15. id = url.substring(url.lastIndexOf("/") + 1);
  16. }
  17. }
  18. } catch (Exception ex) {
  19. Log.e("Exception", ex.toString());
  20. }
  21. return id;
  22. }

根据网上所说,该种方式解析视频真实地址不是所有视频都能解析成功的,不过目前自己公司的视频目前没有遇到过解析失败的例子。

在ListView/RecyclerView中播放 YouTube 视频

在列表中播放视频,这种时候在 ListView/RecyclerView 的 item 中嵌入 VideoView 就不合适了。因为 VideoView 继承于 SurfaceView ,而 SurfaceView 是独立于 View hierachy 而存在的,这就意味着 SurfaceView 在具有高效的渲染机制的同时,是不受 View 管理的,也就是 SurfaceView 的显示不受 View 属性控制的,不能进行平移、缩放等操作,也难以放在 ListView/RecyclerView、ScrollView 等一些控件中使用。

为了弥补 SurfaceView 的不足,Android 在 4.0 中加入了 TextureView, 它并没有创建一个单独的窗口用来绘制,这使得它可以像一般的 View 一样执行一些变换操作,设置透明度等,也很方便的放在其他 ViewGroup 中去。

所以要在 ListView/RecyclerView 中播放视频,我们就需要实现基于 TextureView 的 VideoView,实现代码参考 VideoView 就可以了。

这里引用了 GitHub 上面一个项目地址:https://github.com/waynell/VideoListPlayer,该项目实现了基于 TextureView + MediaPlayer 的视频播放器,也可以用于在 ListView/RecyclerView 中播放。但是该项目并没有提供控制视频播放的控制器,例如暂停、拖动进度条等操作。

没办法,只能自己去搞下来进行二次封装。地址为http://172.16.5.203/Android_Common/VideoListPlayer。主要为视频播放提供了一个操作面板用于控制视频的播放。

到此依然有一个问题:在列表中如何实现视频全屏小窗切换无痕播放

问题:列表视频全屏时如何做无痕切换播放?

列表中的视频 view 是嵌入在 ListView/RecyclerView 中去的,如何能改变其中的大小实现全屏而且还是无痕切换呢。目前想到的解决方案是:

在 ListView/RecyclerView 布局同等层级中加入视频 view, 将该 view 依附在 itemView 的显示区域, 然后监听 ListView/RecyclerView 的滚动, 通过滚动的位置来动态移动视频 view 的位置,这样在全屏时只需要将其他 View 隐藏,显示该视频 view 即可。注意,在列表播放的时候也是该视频 view 在播放,由于是同一个视频 view,故可以实现无痕切换。

上述方案确实可以解决全屏播放的问题,但是由于需要监听 ListView/RecyclerView 的滚动,动态移动视频 view,故接入的时候比较麻烦。

结论

经过一番折腾,终于实现了列表播放 YouTube 视频的需求。但是在自己完成全屏播放视频封装的时候,在 GitHub 上面发现了一个更加完美的也是基于 TextureView 封装的视频库,该库也支持列表播放、UI定制,关键是接入简单,完全不用监听 ListView/RecyclerView 的滚动。该库地址为https://github.com/lipangit/JieCaoVideoPlayer,上面有详细的接入文档。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注