在线视频所需修改
背景
Android平台的视频框架是在(Vitamio)框架的基础上实现的。基于此框架产品实现了视频播放功能。
目前产品的video库支持俩种位置的资源加载:
1. 本地视频资源
2. ewp服务器视频资源
需要增加在线视频的加载:
1. 外网的url地址
2. ewp的url地址
产品代码的分析
当报文存在video:load("video.mp4");
加载视频的脚本时,首先会初始化一个com.rytong.emp.gui.video.AndroidVideoPlayer
视频播放器,并对需要加载视频地址的进行处理:
if (mPath.startsWith("/")) {
String sourceUrl = EMPConfig.newInstance().getServerUri().concat(mPath);// 下载地址
mPath = mPath.substring(mPath.lastIndexOf("/") + 1, mPath.length());
mPath = mResources.downloadAndSaveFile(sourceUrl, mPath);
source = mPath;
} else if(mPath.startsWith("http://")){
// DoNothing for Now
} else {
source = mResources.getLocalFilePath(mPath);
}
由此代码可以看出,以http://开头的视频没做处理。只是对ewp服务器的视频地址以及本地视频地址进行加载。
private void setVideoSource(VideoView video, Object source) {
//对ewp服务器和本地视频地址分别处理之后,把得到的文件地址或者AssetFileDescriptor/FileDescriptor加载到VideoView上。
if (source instanceof String) {
video.setVideoPath((String) source);
} else {
FileDescriptor file = null;
long startoffset = 0;
long length = 0;
if (source instanceof AssetFileDescriptor) {
AssetFileDescriptor descriptor = (AssetFileDescriptor) source;
file = descriptor.getFileDescriptor();
startoffset = descriptor.getStartOffset();
length = descriptor.getLength();
} else if (source instanceof FileDescriptor) {
file = (FileDescriptor) source;
}
if (file == null) {
return;
}
video.setVideoFileDescriptor(file, startoffset, length);
}
}
所需要的修改
根据对产品代码的分析,实现对外网在线视频地址的加载,我们只需要在mPath.startsWith("http://")
的判断中做一些处理即可。
else if(mPath.startsWith("http://")){
// 得到视频地址为后续加载使用
source = mPath;
}
实现对在线播放ewp服务器视频避免下载视频时需要做如下修改:
if (mPath.startsWith("/")) {
String sourceUrl = EMPConfig.newInstance().getServerUri().concat(mPath);// 拼接后的视频地址,并且是以http://开头的
source = sourceUrl;//保留拼接后的url地址
}
加载视频的时候做如下处理:
if (source instanceof String) {
if(source.toString().startsWith("http://")){
video.setVideoURI(Uri.parse(source.toString()));
}else{
video.setVideoPath((String) source);
}
}
在线视频边下边播所需修改
实现此需求网络请求需要使用实时的流媒体传输协议,而最真实的流媒体协议传输格式并不是普通的http方式,而是rtsp,那样的话得搭建专门的流媒体服务器,成本比较高,采用普通的http方式,实现的是一种伪流媒体传输,但是对于常用的视频缓存播放也足够了。原理比较简单,就是把视频加载了一段后,就送到播放器播放,如果出现了错误,则优先缓存一部分文件,然后再继续播放,类似的处理过程循环往复。
if (source instanceof String) {
if(source.toString().startsWith("http://")){
//不现在直接播放,此处先注释掉
// video.setVideoURI(Uri.parse(source.toString()));
//伪流媒体传输处理方式
remoteUrl = source.toString();
mAndroidGUIFactory.mEMPRender.runTask(new EMPThreadPool.Task(100) {
@Override
public void doRun() throws Exception {
FileOutputStream out = null;
InputStream is = null;
try {
//应用系统方式处理网络链接
URL url = new URL(remoteUrl);
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();
//预缓存文件的地址
if (localUrl == null) {
localUrl = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ "/VideoCache/"
+ System.currentTimeMillis() + ".mp4";
}
System.out.println("localUrl: " + localUrl);
File cacheFile = new File(localUrl);
if (!cacheFile.exists()) {
cacheFile.getParentFile().mkdirs();
cacheFile.createNewFile();
}
readSize = cacheFile.length();
System.out.println("readSize1: " + readSize);
out = new FileOutputStream(cacheFile, true);
httpConnection.setRequestProperty("User-Agent", "NetFox");
httpConnection.setRequestProperty("RANGE", "bytes="
+ readSize + "-");
is = httpConnection.getInputStream();
mediaLength = httpConnection.getContentLength();
if (mediaLength == -1) {
return;
}
mediaLength += readSize;//得到可以播放的大小
System.out.println("mediaLength: " + mediaLength);
byte buf[] = new byte[4 * 1024];
int size = 0;
long lastReadSize = 0;
while ((size = is.read(buf)) != -1) {
try {
out.write(buf, 0, size);
readSize += size;
System.out.println("readSize2: " + readSize);
} catch (Exception e) {
e.printStackTrace();
}
//预缓存是否结束
if (!isready) {
if ((readSize - lastReadSize) > READY_BUFF) {
lastReadSize = readSize;
video.setVideoPath(localUrl);
isready = true;
}
} else {
//结束预缓存后,每次播放交换缓存的数据,遇到错误,缓存区动态扩展
if ((readSize - lastReadSize) > CACHE_BUFF
* (errorCnt + 1)) {
lastReadSize = readSize;
video.setVideoPath(localUrl);
}
}
}
video.setVideoPath(localUrl);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
//
}
}
}
}
});
}else{
video.setVideoPath((String) source);
}
}
存在的问题
上述针对在线视频播放所作的修改,在网络请求方面都是通过系统的方法处理的 。访问ewp服务器没有利用产品的网络请求方式,客户端与服务器没有建立加密信道,请求和返回的数据也没有做加解密处理。这是因为通过网络请求得到的视频数据是Byte类型的,而系统加载视频的方法只支持FileDescriptor,string(文件路径) ,uri 三种类型。而系统对这三种类型处理是native方法。如果要实现直接播放byte数据的话,需用C/C++语言,会涉及一些网络协议和视频编码格式的问题 。存在一定难度,需要进一步研究。