本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!
本文是在《玩转 Android MediaPlayer之Media Proxy》基础上做更进一步的开发,实现一个视频客户端很常用的功能~~~预加载。要学会本文介绍的内容,强烈建议把《玩转 Android MediaPlayer之Media Proxy》看懂,由浅入深,你懂的。
预加载,分为两类,本文介绍的是“代理服务器”这种方式:
1.边存边播:下载多少播放多少。
优点:快速加载播放,实现简单;缺点:不能拖动未存区域;适合音频媒体
2.代理服务器:预先下载媒体的头部(头部Size为 s1 byte)->监听播放器的请求,当Request的是预加载的URL->代理把媒体头部作为Response返回给播放器,并改Ranage 为 s1 byte 发送Request->代理服务器纯粹作为透传。
优点:快速加载播放,支持拖动;缺点:实现非常复杂;适合视频媒体
预加载不仅可以缩短视频媒体的加载过程,还为“分段拼接”提供支持......通俗地说,IOS的播放器是高帅富,支持2个播放器交替播放从而无缝播放分片视频;Android的播放器是男屌丝,只能有一个实例一个个播放,切换分片视频时有明显的蛋疼感......使用预加载可以缩短停顿的时间。
先来看看预加载的效果,预加载4000ms打开视频消耗1420ms,不用预加载打开视频消耗2633ms:

==================================================================================================

本文的源码可以到http://download.csdn.net/detail/hellogv/4486051下载,本文所用的MP4搜索自百度....
HttpGetProxy.java是本文的核心,代理服务器的主要实现,源码如下:
[java] view plain copy print ?
- <span style="font-family:Comic Sans MS;font-size:18px;">
-
-
-
-
- public class HttpGetProxy{
- final static public String TAG = "HttpGetProxy";
-
- private int remotePort=-1;
-
- private String remoteHost;
-
- private int localPort;
-
- private String localHost;
- private ServerSocket localServer = null;
-
- private Socket sckPlayer = null;
-
- private Socket sckServer = null;
-
- private SocketAddress address;
-
-
- private DownloadThread download = null;
-
-
-
-
-
- public HttpGetProxy(int localport) {
- try {
- localPort = localport;
- localHost = C.LOCAL_IP_ADDRESS;
- localServer = new ServerSocket(localport, 1,InetAddress.getByName(localHost));
- } catch (Exception e) {
- System.exit(0);
- }
- }
-
-
-
-
-
-
-
- public String prebuffer(String urlString,int size) throws Exception{
- if(download!=null && download.isDownloading())
- download.stopThread(true);
-
- URI tmpURI=new URI(urlString);
- String fileName=ProxyUtils.urlToFileName(tmpURI.getPath());
- String filePath=C.getBufferDir()+"/"+fileName;
-
- download=new DownloadThread(urlString,filePath,size);
- download.startThread();
-
- return filePath;
- }
-
-
-
-
-
-
-
- public String[] getLocalURL(String urlString) {
-
-
- String targetUrl = ProxyUtils.getRedirectUrl(urlString);
-
- String localUrl = null;
- URI originalURI = URI.create(targetUrl);
- remoteHost = originalURI.getHost();
- if (originalURI.getPort() != -1) {
- address = new InetSocketAddress(remoteHost, originalURI.getPort());
- remotePort = originalURI.getPort();
- localUrl = targetUrl.replace(
- remoteHost + ":" + originalURI.getPort(), localHost + ":"
- + localPort);
- } else {
- address = new InetSocketAddress(remoteHost, C.HTTP_PORT);
- remotePort = -1;
- localUrl = targetUrl.replace(remoteHost, localHost + ":"
- + localPort);
- }
-
- String[] result= new String[]{targetUrl,localUrl};
- return result;
- }
-
-
-
-
-
-
- public void asynStartProxy() {
-
- new Thread() {
- public void run() {
- startProxy();
- }
- }.start();
- }
-
- private void startProxy() {
- HttpParser httpParser =null;
- int bytes_read;
- boolean enablePrebuffer=false;
-
- byte[] local_request = new byte[1024];
- byte[] remote_reply = new byte[1024];
-
- while (true) {
- boolean hasResponseHeader = false;
- try {
- if (sckPlayer != null)
- sckPlayer.close();
- if (sckServer != null)
- sckServer.close();
- } catch (IOException e1) {}
- try {
-
-
-
- sckPlayer = localServer.accept();
- Log.e("TAG","------------------------------------------------------------------");
- if(download!=null && download.isDownloading())
- download.stopThread(false);
-
- httpParser=new HttpParser(remoteHost,remotePort,localHost,localPort);
-
- ProxyRequest request = null;
- while ((bytes_read = sckPlayer.getInputStream().read(local_request)) != -1) {
- byte[] buffer=httpParser.getRequestBody(local_request,bytes_read);
- if(buffer!=null){
- request=httpParser.getProxyRequest(buffer);
- break;
- }
- }
-
- boolean isExists=new File(request._prebufferFilePath).exists();
- enablePrebuffer = isExists && request._isReqRange0;
- Log.e(TAG,"enablePrebuffer:"+enablePrebuffer);
- sentToServer(request._body);
-
-
-
- boolean enableSendHeader=true;
- while ((bytes_read = sckServer.getInputStream().read(remote_reply)) != -1) {
- byte[] tmpBuffer = new byte[bytes_read];
- System.arraycopy(remote_reply, 0, tmpBuffer, 0, tmpBuffer.length);
-
- if(hasResponseHeader){
- sendToMP(tmpBuffer);
- }
- else{
- List<byte[]> httpResponse=httpParser.getResponseBody(remote_reply, bytes_read);
- if(httpResponse.size()>0){
- hasResponseHeader = true;
- if (enableSendHeader) {
-
- sendToMP(httpResponse.get(0));
- String responseStr = new String(httpResponse.get(0));
- Log.e(TAG+"<---", responseStr);
- }
- if (enablePrebuffer) {
- int fileBufferSize = sendPrebufferToMP(request._prebufferFilePath);
- if (fileBufferSize > 0) {
- String newRequestStr = httpParser.modifyRequestRange(request._body,
- fileBufferSize);
- Log.e(TAG + "-pre->", newRequestStr);
- enablePrebuffer = false;
-
-
- sentToServer(newRequestStr);
- enableSendHeader = false;
- hasResponseHeader = false;
- continue;
- }
- }
-
-
- if (httpResponse.size() == 2) {
- sendToMP(httpResponse.get(1));
- }
- }
- }
- }
- Log.e(TAG, ".........over..........");
-
-
- sckPlayer.close();
- sckServer.close();
- } catch (Exception e) {
- Log.e(TAG,e.toString());
- Log.e(TAG,ProxyUtils.getExceptionMessage(e));
- }
- }
- }
-
- private int sendPrebufferToMP(String fileName) throws IOException {
- int fileBufferSize=0;
- byte[] file_buffer = new byte[1024];
- int bytes_read = 0;
- FileInputStream fInputStream = new FileInputStream(fileName);
- while ((bytes_read = fInputStream.read(file_buffer)) != -1) {
- fileBufferSize += bytes_read;
- byte[] tmpBuffer = new byte[bytes_read];
- System.arraycopy(file_buffer, 0, tmpBuffer, 0, bytes_read);
- sendToMP(tmpBuffer);
- }
- fInputStream.close();
-
- Log.e(TAG,"读取完毕...下载:"+download.getDownloadedSize()+",读取:"+fileBufferSize);
- return fileBufferSize;
- }
-
- private void sendToMP(byte[] bytes) throws IOException{
- sckPlayer.getOutputStream().write(bytes);
- sckPlayer.getOutputStream().flush();
- }
-
- private void sentToServer(String requestStr) throws IOException{
- try {
- if(sckServer!=null)
- sckServer.close();
- } catch (Exception ex) {}
- sckServer = new Socket();
- sckServer.connect(address);
- sckServer.getOutputStream().write(requestStr.getBytes());
- sckServer.getOutputStream().flush();
- }
- }</span>