Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android使用MediaPlayer實現視頻預加載實例

Android使用MediaPlayer實現視頻預加載實例

編輯:Android開發實例

        本文是在 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. /** 
  2.  * 代理服務器類 
  3.  * @author hellogv 
  4.  * 
  5.  */ 
  6. public class HttpGetProxy{ 
  7.     final static public String TAG = "HttpGetProxy"; 
  8.     /** 鏈接帶的端口 */ 
  9.     private int remotePort=-1; 
  10.     /** 遠程服務器地址 */ 
  11.     private String remoteHost; 
  12.     /** 代理服務器使用的端口 */ 
  13.     private int 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.     public void asynStartProxy() { 
  98.  
  99.         new Thread() { 
  100.             public void run() { 
  101.                 startProxy(); 
  102.             } 
  103.         }.start(); 
  104.     } 
  105.  
  106.     private void startProxy() { 
  107.         HttpParser httpParser =null; 
  108.         int bytes_read; 
  109.         boolean enablePrebuffer=false;//必須放在這裡 
  110.          
  111.         byte[] local_request = new byte[1024]; 
  112.         byte[] remote_reply = new byte[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 = new byte[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.     private int sendPrebufferToMP(String fileName) throws IOException { 
  203.         int fileBufferSize=0; 
  204.         byte[] file_buffer = new byte[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 = new byte[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.     private void sendToMP(byte[] bytes) throws IOException{ 
  220.             sckPlayer.getOutputStream().write(bytes); 
  221.             sckPlayer.getOutputStream().flush(); 
  222.     } 
  223.  
  224.     private void 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.     } 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved