一、前言:

前段时间弄了一款安卓电视盒子的远程遥控输入法APP:TVRemoteIME,此APP实现了远程跨屏的输入、遥控和应用管理功能。

最近发现盒子上要播放电影资源除了买APP会员之外,能直接免费播放电影的第三方APP越来越少了,要么更新不及时要么电影资源非常的少或者广告繁多。而在电脑上要找一部电影播放还是非常容易的,因为网络上个人搭建的电影资源网站繁多或者BT下载等等,于是想到在我的TVRemoteIME上增加播放器功能,这样在控制端(手机,电脑,PAD)直接输入一个播放资源地址或者上传一个电影资源文件(视频文件或者种子文件)即可在电视盒子上播放。

有了想法,就开始行动……

二、下载功能的实现

现网络上的电影资源文件基本上要下载回来才可以实现播放,下载地址格式很多都是迅雷、ed2k、种子文件(磁力链)等方式。要实现边下载边播放功能,首要的就是解决资源下载的问题。最初想法是实现种子文件的下载功能,也就是实现BT协议即可。因为之前有了解过MonoTorrent这个开源项目,所以认为在安卓里要实现BT下载问题也应该不大。由于初入安卓之门,于是想找找有没有可利用的现有“轮子”,在GitHub搜索时,却意外的发现了这个MiniThunder项目,它已完全实现了种子、ed2k、thunder等协议的文件下载功能,并且还支持视频的边下载边播放功能!完全就是我想要的东西!

具体使用方法的示例代码:

//初始化
XLTaskHelper.init(context);//添加网络文件的下载任务(http://, thunder://, ed2k://, ftp:// 等协议)
XLTaskHelper.instance().addThunderTask(url, localSavePath, null);//添加种子文件的下载任务
XLTaskHelper.instance().addTorrentTask(filename, localSavePath, indexs);//获取视频文件的本地播放地址(要求任务正在下载)
XLTaskHelper.instance().getLoclUrl(this.localSavePath + item.getName());

注:MiniThunder项目是利用迅雷库实现的功能,具体使用许可就暂时不明了,建议勿用于商业用途。测试过程中发现磁力链在项目库是有可添加下载任务,但却是无法下载,应该是迅雷已关闭了下载接口。

三、播放器的实现

安卓里的播放器现有的开源与不开源的项目太多了,比如安卓原生的VideoView或者Google的ExoPlayer项目,国内的有B站的ijkplayer,百度的播放器SDK,迅雷的Aplayer播放器引擎等等。原生的VideoView支持的视频格式太少了所以第一个放弃使用。最后选择了B站的ijkplayer,因为完全开源并且支持的视频协议非常的多。在Github能搜索到非常多的ijkplayer播放器示例项目代码,直接使用现有的“轮子”能省去自己设计UI界面的麻烦,于是找到了一个AFAP Player项目,里面已做好了百度和ijkplayer的示例播放器,界面非常的简洁,非常的适合我的要求。但为了能实现播放列表的功能,在AFAP Player的基础上我还做了一些功能增加,且由于播放器是要在电视盒子上播放,无法进行手触摸控制,所以需要做遥控器控制的兼容处理。

针对遥控器的操作我们主要实现以下功能:

1、按左右键实现播放的快退、快进功能

2、按上下键实现播放列表的选择(如视频源有多个的情况,比如种子资源文件里可能会包含非常多的视频文件)

3、按确定键实现播放及暂停播放功能

4、按返回键退出播放器

功能实现代码如下:(代码摘录于TVRemoteIME的XLVideoPlayActivity.java文件)

   private boolean changeProgressByKey = false;private int oldProgressValue = -1;private int newProgressValue = -1;@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) {switch (keyCode) {case KeyEvent.KEYCODE_DPAD_LEFT:case KeyEvent.KEYCODE_DPAD_RIGHT:if(changeProgressByKey){changeProgressByKey = false;oldProgressValue = -1;endGesture();}break;}return super.onKeyUp(keyCode, event);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {switch (keyCode){case KeyEvent.KEYCODE_ESCAPE:case KeyEvent.KEYCODE_BACK:if(playListView.isShown()) {show(defaultTimeout);return true;}break;case KeyEvent.KEYCODE_DPAD_LEFT:case KeyEvent.KEYCODE_DPAD_RIGHT:if(!changeProgressByKey)changeProgressByKey = true;if(oldProgressValue == -1){oldProgressValue = 0;newProgressValue = oldProgressValue;}newProgressValue += keyCode == KeyEvent.KEYCODE_DPAD_LEFT ? -1 : 1;Log.d(TAG, "newProgressValue = " + newProgressValue);if(newProgressValue < (0 - seekBar.getMax()))newProgressValue = (0 - seekBar.getMax());if(newProgressValue > seekBar.getMax())newProgressValue = seekBar.getMax();float deltaP = oldProgressValue - newProgressValue;onProgressSlide(-deltaP / seekBar.getMax());return true;case KeyEvent.KEYCODE_DPAD_DOWN:case KeyEvent.KEYCODE_DPAD_UP:if(playListView.isShown()){View view = playListView.getLayoutManager().getFocusedChild();if(view != null){View nextView = playListView.getLayoutManager().onInterceptFocusSearch(view, keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? View.FOCUS_DOWN : View.FOCUS_UP);if(nextView != null)nextView.requestFocus();}else {playListView.requestFocus(keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? View.FOCUS_DOWN : View.FOCUS_UP);}return true;}else if(xlDownloadManager.taskInstance().getPlayList().size() > 1){playListView.setVisibility(View.VISIBLE);return true;}break;case KeyEvent.KEYCODE_ENTER:case KeyEvent.KEYCODE_DPAD_CENTER:doPauseResume();show(defaultTimeout);return true;}return super.onKeyDown(keyCode, event);}

注:由于快进或快退可能会连接跳过一段播放时间,也就是在遥控操作时会一直按住左右键不放。所以代码里处理左右键按下事件时只记录进度值,在左右键弹上事件时才执行快退/快进功能。

四、边下边播的功能实现

下载功能及播放器两个“轮子”都有了,要实现边下边播的功能,只要将这两个“轮子”组装起来就好了。在这里我写了一个DownloadTask类来实现这功能的整合。此类的完全代码请参考项目代码。

1、在启动播放器前需要接收一个视频源地址参数:

mVideoPath = getIntent().getStringExtra("videoPath");

此视频源地址支持直播源地址(http://, rtmp://, mms://)、本地视频、种子文件(.torrent)、网络视频源(thunder://, ed2k://)。

2、将视频源地址传递给DownloadTask类处理

xlDownloadManager.taskInstance().setUrl(mVideoPath);

DownloadTask会分析此视频源地址的视频格式,分析出是直播源还是本地文件或者网络视频文件,如果是种子文件还会对种子文件进行分析,只取种子文件里的视频文件进行处理。

    public void setUrl(String url) {this.url = url;//删除旧任务及文件this.stopTask();this.playList.clear();this.mIsLiveMedia = FileUtils.isLiveMedia(this.url);this.isNetworkDownloadTask = !this.mIsLiveMedia && FileUtils.isNetworkDownloadTask(this.url);this.name = this.mIsLiveMedia ? FileUtils.getWebMediaFileName(this.url) :this.isNetworkDownloadTask ? XLTaskHelper.instance().getFileName(this.url) : FileUtils.getFileName(this.url);this.localSavePath = (new File(getBaseDir(), FileUtils.getFileNameWithoutExt(this.name)).toString()) + "/";this.isLocalMedia = !this.mIsLiveMedia && !this.isNetworkDownloadTask && FileUtils.isMediaFile(this.name);this.torrentInfo = null;this.torrentMediaIndexs = null;this.torrentUnmediaIndexs = null;this.currentPlayMediaIndex = 0;if(this.isLocalMedia){playList.add(new PlayListItem(this.name, 0, new File(this.getUrl()).length()));}else if(this.mIsLiveMedia || this.isNetworkDownloadTask){playList.add(new PlayListItem(this.name, 0, 0L));} else if (".torrent".equals(FileUtils.getFileExt(this.name))) {this.torrentInfo = XLTaskHelper.instance().getTorrentInfo(this.url);this.initTorrentIndexs();}}

3、启动下载任务

xlDownloadManager.taskInstance().startTask()

DownloadTask启动任务时会根据视频源的格式做相应的处理,如果是直播源与本地视频文件则不会做下载处理,而如果是种子文件或者网络视频文件则会调用XLTaskHelper添加下载任务

   public boolean startTask(){if(TextUtils.isEmpty(this.url) || this.taskId != 0L){return false;}if(this.isNetworkDownloadTask){if(this.url.toLowerCase().startsWith("magnet:?")){Log.e(TAG, "暂时不支持magnet链的下载播放");return false;}else {taskId = XLTaskHelper.instance().addThunderTask(this.url, localSavePath, null);}}else if(this.torrentInfo != null) {if(this.currentPlayMediaIndex != -1) {try {taskId = XLTaskHelper.instance().addTorrentTask(this.url, localSavePath, this.getTorrentDeselectedIndexs());} catch (Exception e) {}}}else {taskId = this.isLocalMedia || this.mIsLiveMedia ? -9999L : 0L;}Log.d(TAG, "startTask(" + this.url + "), taskId = " + taskId);return  taskId != 0L;}

4、开始边下载边播放

mVideoView.setVideoPath(xlDownloadManager.taskInstance().getPlayUrl());

DownloadTask获取播放地址时,如果是种子文件或者网络视频文件则获取mini_thunder的本地播放地址,否则直接返回播放源地址

    public String getPlayUrl(){if(this.isLocalMedia || this.mIsLiveMedia){return this.getUrl();}else if(this.taskId != 0L){if(this.isNetworkDownloadTask){return XLTaskHelper.instance().getLoclUrl(this.localSavePath + this.name);}else if(this.torrentInfo != null && this.currentPlayMediaIndex != -1){for(PlayListItem item : getPlayList()){if(item.getIndex() == this.currentPlayMediaIndex){return XLTaskHelper.instance().getLoclUrl(this.localSavePath + item.getName());}}}}return null;}

五、播放器的调用方法

播放器封装好后,外部要调用视频播放时一行代码即可实现播放功能:

XLVideoPlayActivity.intentTo(context, url, title);

url参数即是可支持的直播源、本地文件、种子文件或者网络视频文件地址。

要查看播放效果请参考 TVRemoteIME APP(TV盒子安装)。

六、结束

项目开源地址:TVRemoteIME

注:由于此播放器属于TVRemoteIME项目下的子模块项目,所以项目代码寄生于它,但目前TVRemoteIME的代码暂时不开源,后期视情况再决定是否开源。

转载于:https://www.cnblogs.com/kingthy/p/xlvideoplayer.html

实现安卓里边下边播的播放器(源码公开)相关推荐

  1. 安卓flash播放器源码项目实例Demo

    Android Flash swf播放器源码(2019) 为什么说标题加上2019? 其实不是什么新技术,因为android4.1之后的android 浏览器内核版本发生了变化导致 Adobe 的Fl ...

  2. Discuz论坛web网页mp3音频播放器源码下载

    最近在做一个DZ论坛的搭建,在前几天的时候遇到Flash+Js的幻灯片的问题,特写了一篇<JS+Flash焦点图轮播源代码(2屏,3屏,多屏)>来记录论坛搭建过程遇到的一些技术性问题,以便 ...

  3. android swf 播放器代码,Android Flash swf播放器源码(2016),技术稳定可以商用—— BY softboy...

    Android Flash swf播放器源码(2016) 为什么说标题加上2016? 其实不是什么新技术,因为android4.1之后的android 浏览器内核版本发生了变化导致 Adobe 的Fl ...

  4. android swf 播放器代码,Android Flash swf播放器源码(2019)

    Android Flash swf播放器源码(2019) 为什么说标题加上2019? 其实不是什么新技术,因为android4.1之后的android 浏览器内核版本发生了变化导致 Adobe 的Fl ...

  5. 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇...

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  6. 最全的Android开源音乐播放器源码汇总

    收集了很多音乐播放器类的Android项目源码,非常不错的开源项目,会让你事半功倍,希望大家补充...谢谢! Android基于经纬度切歌的冲绳音乐播放器源码 http://neast.cn/foru ...

  7. 超美响应式自适应引导页带音乐播放器源码

    介绍: 超美响应式自适应引导页带音乐播放器源码,纯html源码,右键记事本修改即可~自带音乐播放器,自带自动打字特效,自带网站存活时间,自带随机ACG背景,自适应响应式网页 网盘下载地址: http: ...

  8. html5 mp3播放器源码,HTML5自定义mp3播放器源码

    audio对象 src兼容.ogg .wav .mp3 width autoplay loop muted静音 播放play() var myAudio = new Audio(); myAudio. ...

  9. 最新哔哩哔哩视频弹幕播放器源码+带后台/亲测无错误

    正文: 最新哔哩哔哩视频弹幕播放器源码+带后台/亲测无错误,此款播放器源码添加及修复了很多功能,且所有源码均本地化,不存在外链的情况,测试环境:PHP7.0+MySQL5.6 安装教程: 1,访问/d ...

最新文章

  1. 剑指offer 06.逆向打印链表
  2. internetreadfile读取数据长度为0_Hadoop 读取数据
  3. discuz如何去掉论坛的网页后缀名称forum.php
  4. linux下svn重新定位的方法
  5. 我想吐槽“吐槽 Google 换新 Logo 的人”
  6. 前端工程师面经——概述及面试技巧加考点篇(一)
  7. 第十六章 复杂的抽像类结构
  8. data后缀文件解码_对任何格式的文件实现加密与解密软件
  9. java digester map_Tomcat7启动分析(三)Digester的使用(转载)
  10. 层级菜单构造--groupingby
  11. Java项目论文+PPT+源码等]S2SH+mysql的报刊订阅系统
  12. docker搭建rap2
  13. 【前端面试】Part 1:2020届初级前端校招笔试题及面经总结 —— 基础知识题
  14. 产品基础学习笔记---传智教育
  15. Python 海龟绘图 100 题——第 72 题
  16. 理解锁相环的工作原理
  17. CAD梦想画图中的“线型设置”
  18. cygwin git mysql,msysgit和Cygwin + git之间的区别?
  19. 超实用,12个免费雷达数据源
  20. Fiddler工具使用报告

热门文章

  1. Nodejs ejs模板引擎
  2. Java 运算符、表达式、语句
  3. LeetCode 1210. 穿过迷宫的最少移动次数(状态压缩BFS)
  4. LeetCode MySQL 1532. The Most Recent Three Orders(dense_rank + over窗口函数)
  5. 程序员面试金典 - 面试题 04.12. 求和路径(二叉树递归)
  6. postman 使用_Postman简单使用
  7. 利用nginx建立windows软连,实现IP访问文件
  8. oracle加密可以跟java一致吗,在GBase 8s上使用java udr实现Oracle兼容的加密解密功能...
  9. ps抠头发插件_彻底告别抠图的烦恼!PS自动抠图超级插件Topaz ReMask大放送
  10. 小米10pro第二个摄像头下面_小米10至尊纪念版、小米10 Pro对比评测:至尊版“至尊”在哪里?...