玩转 Android MediaPlayer之视频预加载

本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

       本文是在《Android MediaPlayer与Http Proxy结合之提高篇》基础上,进一步优化代理服务器,支持了Http的302、301重定向,获取Http Request和Http Response的文本内容。本文以视频播放结合Http Proxy,讲述MediaPlayer播放过程中的握手过程。

吐槽一下:用google搜索“代理服务器”无效,所以本文用Media Proxy,大家懂的......

先来看看本文程序运行的截屏动画:

再来看看程序运行时输出的Log信息.....这里是关键:

07-29 15:51:30.692: E/HttpGetProxy(449): ..........sckPlayer connected.......... MediaPlayer发出请求
07-29 15:51:30.692: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:30.692: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:30.692: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:30.692: E/to Media Server---->(449):

07-29 15:51:31.119: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:31.122: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:31.775: E/from Media Server---->(449): HTTP/1.1 200 OK

07-29 15:51:31.775: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:33 GMT

07-29 15:51:31.775: E/from Media Server---->(449): Server: Apache

07-29 15:51:31.775: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:31.775: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:31.775: E/from Media Server---->(449): Content-Length: 754777

07-29 15:51:31.775: E/from Media Server---->(449): Content-Type: video/3gpp


07-29 15:51:34.512: E/HttpGetProxy(449): ..........sckPlayer connected..........MediaPlayer发出请求
07-29 15:51:34.532: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:34.532: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:34.532: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:34.532: E/to Media Server---->(449): Range: bytes=720896-

07-29 15:51:34.532: E/to Media Server---->(449):

07-29 15:51:34.873: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:34.873: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:35.505: E/from Media Server---->(449): HTTP/1.1 206 Partial Content

07-29 15:51:35.505: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:36 GMT

07-29 15:51:35.505: E/from Media Server---->(449): Server: Apache

07-29 15:51:35.505: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:35.505: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:35.505: E/from Media Server---->(449): Content-Length: 33881

07-29 15:51:35.505: E/from Media Server---->(449): Content-Range: bytes 720896-754776/754777

07-29 15:51:35.505: E/from Media Server---->(449): Content-Type: video/3gpp
07-29 15:51:38.754: E/HttpGetProxy(449): ..........over..........


07-29 15:51:51.461: E/HttpGetProxy(449): ..........sckPlayer connected..........MediaPlayer发出请求
07-29 15:51:51.471: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:51.471: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:51.471: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:51.471: E/to Media Server---->(449): Range: bytes=196608-

07-29 15:51:51.471: E/to Media Server---->(449):

07-29 15:51:51.722: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:51.722: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:52.285: E/from Media Server---->(449): HTTP/1.1 206 Partial Content

07-29 15:51:52.285: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:53 GMT

07-29 15:51:52.285: E/from Media Server---->(449): Server: Apache

07-29 15:51:52.285: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:52.285: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:52.285: E/from Media Server---->(449): Content-Length: 558169

07-29 15:51:52.285: E/from Media Server---->(449): Content-Range: bytes 196608-754776/754777

07-29 15:51:52.285: E/from Media Server---->(449): Content-Type: video/3gpp


07-29 15:51:54.812: E/HttpGetProxy(449): ..........sckPlayer connected..........MediaPlayer发出请求
07-29 15:51:54.822: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:54.822: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:54.822: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:54.822: E/to Media Server---->(449): Range: bytes=589824-

07-29 15:51:54.822: E/to Media Server---->(449):

07-29 15:51:55.117: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:55.117: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:55.693: E/from Media Server---->(449): HTTP/1.1 206 Partial Content

07-29 15:51:55.693: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:57 GMT

07-29 15:51:55.693: E/from Media Server---->(449): Server: Apache

07-29 15:51:55.693: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:55.693: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:55.693: E/from Media Server---->(449): Content-Length: 164953

07-29 15:51:55.693: E/from Media Server---->(449): Content-Range: bytes 589824-754776/754777

07-29 15:51:55.693: E/from Media Server---->(449): Content-Type: video/3gpp
07-29 15:51:59.620: E/HttpGetProxy(449): ..........over..........

 

从截屏动画和Log信息看出,手动seek一次,但MediaPlayer进行了多次Range请求,这说明了“MediaPlayer会自动seek”,或许与MediaPlayer本地缓存有关。另外,不同硬解厂家实现的MediaPlayer估计会有不同的操作。

 

本文的代码可以到这里下载:

http://download.csdn.net/detail/hellogv/4463651

HttpGetProxy.JAVA还是本文的关键部分:

  1. public class HttpGetProxy {    
  2.     final static private String TAG = "HttpGetProxy";    
  3.     final static private String LOCAL_IP_ADDRESS_1 = "127.0.0.1";  
  4.     final static private String LOCAL_IP_ADDRESS_2 = "10.0.2.2";  
  5.     final static private int HTTP_PORT = 80;  
  6.     final static private String HTTP_END="\r\n\r\n";  
  7.       
  8.     /**代理服务器使用的端口*/  
  9.     private int proxy_ip_port;  
  10.     /**链接带的端口*/  
  11.     private String original_ip_port;  
  12.     /**远程服务器地址*/  
  13.     private String remoteHost;  
  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.      * 初始化代理服务器  
  26.      * @param localport 代理服务器监听的端口  
  27.      */    
  28.     public HttpGetProxy(int localport) {    
  29.         try {  
  30.             _HttpGetProxy(LOCAL_IP_ADDRESS_1,localport);  
  31.         } catch (Exception e) {  
  32.             Log.e(TAG,LOCAL_IP_ADDRESS_1+"???"+e.toString());  
  33.             try {  
  34.                 _HttpGetProxy(LOCAL_IP_ADDRESS_2,localport);  
  35.             }catch (Exception e1) {  
  36.                 Log.e(TAG,LOCAL_IP_ADDRESS_2+"???"+e.toString());  
  37.                 System.exit(0);  
  38.             }  
  39.         }  
  40.     }  
  41.       
  42.     private void _HttpGetProxy(String ipAddress,int localport) throws UnknownHostException, IOException {    
  43.         proxy_ip_port=localport;    
  44.         localServer = new ServerSocket(localport,1,InetAddress.getByName(ipAddress));  
  45.         localHost=ipAddress;  
  46.     }  
  47.      
  48.     /**  
  49.      * 把网络URL转为本地URL,127.0.0.1替换网络域名  
  50.      * @param url 网络URL   
  51.      * @return 本地URL  
  52.      */    
  53.     public String getLocalURL(String urlString){  
  54.         //----排除HTTP特殊----//  
  55.         String targetUrl=ProxyUtils.getRedirectUrl(urlString);  
  56.         //----获取对应本地代理服务器的链接----//  
  57.         String result = null;  
  58.         URI originalURI=URI.create(targetUrl);    
  59.         remoteHost=originalURI.getHost();    
  60.         if(originalURI.getPort()!=-1){//URL带Port  
  61.             address = new InetSocketAddress(remoteHost,originalURI.getPort());//使用默认端口    
  62.             original_ip_port = originalURI.getPort()+"";//保存端口,中转时替换  
  63.             result=targetUrl.replace(remoteHost+":"+originalURI.getPort(),    
  64.                     localHost+":"+proxy_ip_port);    
  65.         }    
  66.         else{//URL不带Port    
  67.             address = new InetSocketAddress(remoteHost,HTTP_PORT);//使用80端口   
  68.             original_ip_port = "";  
  69.             result=targetUrl.replace(remoteHost,localHost+":"+proxy_ip_port);    
  70.         }  
  71.         return result;       
  72.     }    
  73.       
  74.     /**  
  75.      * 启动代理服务器  
  76.      * @throws IOException  
  77.      */    
  78.     public void asynStartProxy(){    
  79.         new Thread() {    
  80.             public void run() {  
  81.                 int bytes_read;    
  82.                 byte[] local_request = new byte[1024];    
  83.                 byte[] remote_reply = new byte[1024];    
  84.                 while (true) {    
  85.                     try {    
  86.                         //--------------------------------------    
  87.                         //监听MediaPlayer的请求,MediaPlayer->代理服务器    
  88.                         //--------------------------------------    
  89.                         sckPlayer = localServer.accept();    
  90.                         Log.e(TAG, "..........sckPlayer connected..........");     
  91.                           
  92.                         String requestStr = "";  
  93.                         while ((bytes_read = sckPlayer.getInputStream().read(local_request)) != -1) {  
  94.                             byte[] tmpBuffer=new byte[bytes_read];   
  95.                             System.arraycopy(local_request,0,tmpBuffer,0,bytes_read);  
  96.                             String str = new String(tmpBuffer);  
  97.                             //Log.e("from MediaPlayer---->", str);    
  98.                             requestStr = requestStr + str;    
  99.                             if (requestStr.contains("GET")    
  100.                                     && requestStr.contains(HTTP_END)) {    
  101.                                 break;  
  102.                             }     
  103.                         }  
  104.                           
  105.                         //把request中的本地ip改为远程ip  
  106.                         requestStr = requestStr.replace(localHost,remoteHost);  
  107.                         //把代理服务器端口改为原URL端口  
  108.                         if(TextUtils.isEmpty(original_ip_port))  
  109.                             requestStr = requestStr.replace(":"+proxy_ip_port, "");  
  110.                         else  
  111.                             requestStr = requestStr.replace(":"+proxy_ip_port, ":"+original_ip_port);  
  112.   
  113.                         Log.e("to Media Server---->", requestStr);  
  114.                         //--------------------------------------    
  115.                         //把MediaPlayer的请求发到网络服务器,代理服务器->网络服务器    
  116.                         //--------------------------------------  
  117.                         sckServer = new Socket();    
  118.                         sckServer.connect(address);    
  119.                         Log.e(TAG,"..........remote Server connected..........");    
  120.                         sckServer.getOutputStream().write(requestStr.getBytes());//发送MediaPlayer的请求    
  121.                         //------------------------------------------------------    
  122.                         //把网络服务器的反馈发到MediaPlayer,网络服务器->代理服务器->MediaPlayer    
  123.                         //------------------------------------------------------  
  124.                         Log.e(TAG,"..........remote start to receive..........");  
  125.                         String responseStr = "";  
  126.                         boolean isCaptured=false;  
  127.                         while ((bytes_read = sckServer.getInputStream().read(remote_reply)) != -1) {  
  128.                             byte[] tmpBuffer=new   byte[bytes_read];   
  129.                             System.arraycopy(remote_reply,0,tmpBuffer,0,bytes_read);  
  130.                             //----捕获收到的Response文本内容----//  
  131.                             if (!isCaptured) {  
  132.                                 String str = new String(tmpBuffer);  
  133.                                 responseStr += str;  
  134.                                 if (responseStr.contains("HTTP/")    
  135.                                         && responseStr.contains(HTTP_END)) {  
  136.                                       
  137.                                     int endIndex=responseStr.indexOf(HTTP_END, 0);  
  138.                                     responseStr=responseStr.substring(0, endIndex);  
  139.                                     Log.e("from Media Server---->", responseStr);  
  140.                                     isCaptured=true;  
  141.                                 }  
  142.                             }  
  143.                             sckPlayer.getOutputStream().write(tmpBuffer);    
  144.                             sckPlayer.getOutputStream().flush();  
  145.                         }  
  146.                         Log.e(TAG, "..........over..........");   
  147.                          
  148.                         //关闭对内,对内 2个SOCKET  
  149.                         sckPlayer.close();    
  150.                         sckServer.close();    
  151.                     } catch (IOException e) {    
  152.                         // TODO Auto-generated catch block    
  153.                         e.printStackTrace();    
  154.                     }    
  155.                 }    
  156.             }    
  157.         }.start();    
  158.     }    
  159. }   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值