玩转 Android MediaPlayer之视频预加载

玩转 Android MediaPlayer之视频预加载

http://blog.csdn.net/hellogv/article/details/7845480 
 
       分类:            Android MediaPlayerAndroid番外15453人阅读评论(14)收藏举报

本文来自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是本文的核心,代理服务器的主要实现,源码如下:

  1. <span style="font-family: Comic Sans MS; font-size: 18px;">/**
  2. * 代理服务器类
  3. * @author hellogv
  4. *
  5. */ 
  6. publicclass HttpGetProxy{ 
  7.     finalstaticpublic String TAG = "HttpGetProxy"
  8.     /** 链接带的端口 */ 
  9.     privateint remotePort=-1
  10.     /** 远程服务器地址 */ 
  11.     private String remoteHost; 
  12.     /** 代理服务器使用的端口 */ 
  13.     privateint localPort; 
  14.     /** 本地服务器地址 */ 
  15.     private String localHost; 
  16.     private ServerSocket localServer = null
  17.     /** 收发Media Player请求的Socket */ 
  18.     private Socket sckPlayer = null
  19.     /** 收发Media Server请求的Socket */ 
  20.     private Socket sckServer = null
  21.      
  22.     private SocketAddress address; 
  23.      
  24.     /**下载线程*/ 
  25.     private DownloadThread download = null
  26.     /**
  27.      * 初始化代理服务器
  28.      *
  29.      * @param localport 代理服务器监听的端口
  30.      */ 
  31.     public HttpGetProxy(int localport) { 
  32.         try
  33.             localPort = localport; 
  34.             localHost = C.LOCAL_IP_ADDRESS; 
  35.             localServer = new ServerSocket(localport, 1,InetAddress.getByName(localHost)); 
  36.         } catch (Exception e) { 
  37.             System.exit(0); 
  38.         } 
  39.     } 
  40.  
  41.     /**
  42.      * 把URL提前下载在SD卡,实现预加载
  43.      * @param urlString
  44.      * @return 返回预加载文件名
  45.      * @throws Exception
  46.      */ 
  47.     public String prebuffer(String urlString,int size) throws Exception{ 
  48.         if(download!=null && download.isDownloading()) 
  49.             download.stopThread(true); 
  50.          
  51.         URI tmpURI=new URI(urlString); 
  52.         String fileName=ProxyUtils.urlToFileName(tmpURI.getPath()); 
  53.         String filePath=C.getBufferDir()+"/"+fileName; 
  54.          
  55.         download=new DownloadThread(urlString,filePath,size); 
  56.         download.startThread(); 
  57.          
  58.         return filePath; 
  59.     } 
  60.      
  61.     /**
  62.      * 把网络URL转为本地URL,127.0.0.1替换网络域名
  63.      *
  64.      * @param url网络URL
  65.      * @return [0]:重定向后MP4真正URL,[1]:本地URL
  66.      */ 
  67.     public String[] getLocalURL(String urlString) { 
  68.          
  69.         // ----排除HTTP特殊----// 
  70.         String targetUrl = ProxyUtils.getRedirectUrl(urlString); 
  71.         // ----获取对应本地代理服务器的链接----// 
  72.         String localUrl = null
  73.         URI originalURI = URI.create(targetUrl); 
  74.         remoteHost = originalURI.getHost(); 
  75.         if (originalURI.getPort() != -1) {// URL带Port 
  76.             address = new InetSocketAddress(remoteHost, originalURI.getPort());// 使用默认端口 
  77.             remotePort = originalURI.getPort();// 保存端口,中转时替换 
  78.             localUrl = targetUrl.replace( 
  79.                     remoteHost + ":" + originalURI.getPort(), localHost + ":" 
  80.                             + localPort); 
  81.         } else {// URL不带Port 
  82.             address = new InetSocketAddress(remoteHost, C.HTTP_PORT);// 使用80端口 
  83.             remotePort = -1
  84.             localUrl = targetUrl.replace(remoteHost, localHost + ":" 
  85.                     + localPort); 
  86.         } 
  87.          
  88.         String[] result= new String[]{targetUrl,localUrl}; 
  89.         return result; 
  90.     } 
  91.  
  92.     /**
  93.      * 异步启动代理服务器
  94.      *
  95.      * @throws IOException
  96.      */ 
  97.     publicvoid asynStartProxy() { 
  98.  
  99.         new Thread() { 
  100.             publicvoid run() { 
  101.                 startProxy(); 
  102.             } 
  103.         }.start(); 
  104.     } 
  105.  
  106.     privatevoid startProxy() { 
  107.         HttpParser httpParser =null
  108.         int bytes_read; 
  109.         boolean enablePrebuffer=false;//必须放在这里 
  110.          
  111.         byte[] local_request = newbyte[1024]; 
  112.         byte[] remote_reply = newbyte[1024]; 
  113.  
  114.         while (true) { 
  115.             boolean hasResponseHeader = false
  116.             try {// 开始新的request之前关闭过去的Socket 
  117.                 if (sckPlayer != null
  118.                     sckPlayer.close(); 
  119.                 if (sckServer != null
  120.                     sckServer.close(); 
  121.             } catch (IOException e1) {} 
  122.             try
  123.                 // -------------------------------------- 
  124.                 // 监听MediaPlayer的请求,MediaPlayer->代理服务器 
  125.                 // -------------------------------------- 
  126.                 sckPlayer = localServer.accept(); 
  127.                 Log.e("TAG","------------------------------------------------------------------"); 
  128.                 if(download!=null && download.isDownloading()) 
  129.                     download.stopThread(false); 
  130.                  
  131.                 httpParser=new HttpParser(remoteHost,remotePort,localHost,localPort); 
  132.                  
  133.                 ProxyRequest request = null
  134.                 while ((bytes_read = sckPlayer.getInputStream().read(local_request)) != -1) { 
  135.                     byte[] buffer=httpParser.getRequestBody(local_request,bytes_read); 
  136.                     if(buffer!=null){ 
  137.                         request=httpParser.getProxyRequest(buffer); 
  138.                         break
  139.                     } 
  140.                 } 
  141.                  
  142.                 boolean isExists=new File(request._prebufferFilePath).exists(); 
  143.                 enablePrebuffer = isExists && request._isReqRange0;//两者具备才能使用预加载 
  144.                 Log.e(TAG,"enablePrebuffer:"+enablePrebuffer); 
  145.                 sentToServer(request._body); 
  146.                 // ------------------------------------------------------ 
  147.                 // 把网络服务器的反馈发到MediaPlayer,网络服务器->代理服务器->MediaPlayer 
  148.                 // ------------------------------------------------------ 
  149.                 boolean enableSendHeader=true
  150.                 while ((bytes_read = sckServer.getInputStream().read(remote_reply)) != -1) { 
  151.                     byte[] tmpBuffer = newbyte[bytes_read]; 
  152.                     System.arraycopy(remote_reply, 0, tmpBuffer, 0, tmpBuffer.length); 
  153.                      
  154.                     if(hasResponseHeader){ 
  155.                     sendToMP(tmpBuffer); 
  156.                     } 
  157.                     else
  158.                         List<byte[]> httpResponse=httpParser.getResponseBody(remote_reply, bytes_read); 
  159.                         if(httpResponse.size()>0){ 
  160.                             hasResponseHeader = true
  161.                             if (enableSendHeader) { 
  162.                                 // send http header to mediaplayer 
  163.                                 sendToMP(httpResponse.get(0)); 
  164.                                 String responseStr = new String(httpResponse.get(0)); 
  165.                                 Log.e(TAG+"<---", responseStr); 
  166.                             } 
  167.                             if (enablePrebuffer) {//send prebuffer to mediaplayer 
  168.                                 int fileBufferSize = sendPrebufferToMP(request._prebufferFilePath); 
  169.                                 if (fileBufferSize > 0) {//重新发送请求到服务器 
  170.                                     String newRequestStr = httpParser.modifyRequestRange(request._body, 
  171.                                                     fileBufferSize); 
  172.                                     Log.e(TAG + "-pre->", newRequestStr); 
  173.                                     enablePrebuffer = false
  174.  
  175.                                     // 下次不处理response的http header 
  176.                                     sentToServer(newRequestStr); 
  177.                                     enableSendHeader = false
  178.                                     hasResponseHeader = false
  179.                                     continue
  180.                                 } 
  181.                             } 
  182.  
  183.                             //发送剩余数据 
  184.                             if (httpResponse.size() == 2) { 
  185.                                 sendToMP(httpResponse.get(1)); 
  186.                             } 
  187.                         } 
  188.                     } 
  189.                 } 
  190.                 Log.e(TAG, ".........over.........."); 
  191.  
  192.                 // 关闭 2个SOCKET 
  193.                 sckPlayer.close(); 
  194.                 sckServer.close(); 
  195.             } catch (Exception e) { 
  196.                 Log.e(TAG,e.toString()); 
  197.                 Log.e(TAG,ProxyUtils.getExceptionMessage(e)); 
  198.             } 
  199.         } 
  200.     } 
  201.      
  202.     privateint sendPrebufferToMP(String fileName) throws IOException { 
  203.         int fileBufferSize=0
  204.         byte[] file_buffer = newbyte[1024]; 
  205.         int bytes_read = 0
  206.         FileInputStream fInputStream = new FileInputStream(fileName); 
  207.         while ((bytes_read = fInputStream.read(file_buffer)) != -1) { 
  208.             fileBufferSize += bytes_read; 
  209.             byte[] tmpBuffer = newbyte[bytes_read]; 
  210.             System.arraycopy(file_buffer, 0, tmpBuffer, 0, bytes_read); 
  211.             sendToMP(tmpBuffer); 
  212.         } 
  213.         fInputStream.close(); 
  214.          
  215.         Log.e(TAG,"读取完毕...下载:"+download.getDownloadedSize()+",读取:"+fileBufferSize); 
  216.         return fileBufferSize; 
  217.     } 
  218.      
  219.     privatevoid sendToMP(byte[] bytes) throws IOException{ 
  220.             sckPlayer.getOutputStream().write(bytes); 
  221.             sckPlayer.getOutputStream().flush(); 
  222.     } 
  223.  
  224.     privatevoid sentToServer(String requestStr) throws IOException{ 
  225.         try
  226.             if(sckServer!=null
  227.                 sckServer.close(); 
  228.         } catch (Exception ex) {} 
  229.         sckServer = new Socket(); 
  230.         sckServer.connect(address); 
  231.         sckServer.getOutputStream().write(requestStr.getBytes());// 发送MediaPlayer的请求 
  232.         sckServer.getOutputStream().flush(); 
  233.     } 
  234. }</span> 
posted @ 2014-03-28 10:35  萧萧  阅读(1143)  评论(0)    收藏  举报