HardBirch

玩转 Android MediaPlayer之Media Proxy

时间:12-07-30 栏目:安卓入门与提高 作者:张飞不张,文采横飞 评论:8 点击: 3,972 次

       本文是在《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还是本文的关键部分:

 

public class HttpGetProxy {
    final static private String TAG = "HttpGetProxy";
    final static private String LOCAL_IP_ADDRESS_1 = "127.0.0.1";
    final static private String LOCAL_IP_ADDRESS_2 = "10.0.2.2";
    final static private int HTTP_PORT = 80;
    final static private String HTTP_END="rnrn";

    /**代理服务器使用的端口*/
    private int proxy_ip_port;
    /**链接带的端口*/
    private String original_ip_port;
    /**远程服务器地址*/
    private String remoteHost;
    /**本地服务器地址*/
    private String localHost;
    private ServerSocket localServer = null;
    /**收发Media Player请求的Socket*/
    private Socket sckPlayer = null;
    /**收发Media Server请求的Socket*/
    private Socket sckServer = null;

    private SocketAddress address;  

    /**
     * 初始化代理服务器
     * @param localport 代理服务器监听的端口
     */
    public HttpGetProxy(int localport) {
    	try {
			_HttpGetProxy(LOCAL_IP_ADDRESS_1,localport);
		} catch (Exception e) {
			Log.e(TAG,LOCAL_IP_ADDRESS_1+"???"+e.toString());
			try {
				_HttpGetProxy(LOCAL_IP_ADDRESS_2,localport);
			}catch (Exception e1) {
				Log.e(TAG,LOCAL_IP_ADDRESS_2+"???"+e.toString());
				System.exit(0);
			}
		}
    }

    private void _HttpGetProxy(String ipAddress,int localport) throws UnknownHostException, IOException {
    	proxy_ip_port=localport;
        localServer = new ServerSocket(localport,1,InetAddress.getByName(ipAddress));
        localHost=ipAddress;
    }

    /**
     * 把网络URL转为本地URL,127.0.0.1替换网络域名
     * @param url 网络URL
     * @return 本地URL
     */
    public String getLocalURL(String urlString){
    	//----排除HTTP特殊----//
    	String targetUrl=ProxyUtils.getRedirectUrl(urlString);
    	//----获取对应本地代理服务器的链接----//
        String result = null;
        URI originalURI=URI.create(targetUrl);
        remoteHost=originalURI.getHost();
        if(originalURI.getPort()!=-1){//URL带Port
            address = new InetSocketAddress(remoteHost,originalURI.getPort());//使用默认端口
            original_ip_port = originalURI.getPort()+"";//保存端口,中转时替换
            result=targetUrl.replace(remoteHost+":"+originalURI.getPort(),
            		localHost+":"+proxy_ip_port);
        }
        else{//URL不带Port
            address = new InetSocketAddress(remoteHost,HTTP_PORT);//使用80端口
            original_ip_port = "";
            result=targetUrl.replace(remoteHost,localHost+":"+proxy_ip_port);
        }
        return result;
    }  

    /**
     * 启动代理服务器
     * @throws IOException
     */
    public void asynStartProxy(){
        new Thread() {
            public void run() {
                int bytes_read;
                byte[] local_request = new byte[1024];
                byte[] remote_reply = new byte[1024];
                while (true) {
                    try {
                        //--------------------------------------
                        //监听MediaPlayer的请求,MediaPlayer->代理服务器
                        //--------------------------------------
                        sckPlayer = localServer.accept();
                        Log.e(TAG, "..........sckPlayer connected..........");   

                        String requestStr = "";
                        while ((bytes_read = sckPlayer.getInputStream().read(local_request)) != -1) {
                            byte[] tmpBuffer=new byte[bytes_read];
                            System.arraycopy(local_request,0,tmpBuffer,0,bytes_read);
                            String str = new String(tmpBuffer);
                            //Log.e("from MediaPlayer---->", str);
                            requestStr = requestStr + str;
                            if (requestStr.contains("GET")
                                    && requestStr.contains(HTTP_END)) {
                                break;
                            }
                        }

                        //把request中的本地ip改为远程ip
                        requestStr = requestStr.replace(localHost,remoteHost);
                        //把代理服务器端口改为原URL端口
                        if(TextUtils.isEmpty(original_ip_port))
                        	requestStr = requestStr.replace(":"+proxy_ip_port, "");
                        else
                        	requestStr = requestStr.replace(":"+proxy_ip_port, ":"+original_ip_port);

                        Log.e("to Media Server---->", requestStr);
                        //--------------------------------------
                        //把MediaPlayer的请求发到网络服务器,代理服务器->网络服务器
                        //--------------------------------------
                        sckServer = new Socket();
                        sckServer.connect(address);
                        Log.e(TAG,"..........remote Server connected..........");
                        sckServer.getOutputStream().write(requestStr.getBytes());//发送MediaPlayer的请求
                        //------------------------------------------------------
                        //把网络服务器的反馈发到MediaPlayer,网络服务器->代理服务器->MediaPlayer
                        //------------------------------------------------------
                        Log.e(TAG,"..........remote start to receive..........");
                        String responseStr = "";
                        boolean isCaptured=false;
                        while ((bytes_read = sckServer.getInputStream().read(remote_reply)) != -1) {
                        	byte[] tmpBuffer=new   byte[bytes_read];
                            System.arraycopy(remote_reply,0,tmpBuffer,0,bytes_read);
                            //----捕获收到的Response文本内容----//
							if (!isCaptured) {
								String str = new String(tmpBuffer);
								responseStr += str;
								if (responseStr.contains("HTTP/")
	                                    && responseStr.contains(HTTP_END)) {

									int endIndex=responseStr.indexOf(HTTP_END, 0);
									responseStr=responseStr.substring(0, endIndex);
									Log.e("from Media Server---->", responseStr);
									isCaptured=true;
	                            }
							}
                            sckPlayer.getOutputStream().write(tmpBuffer);
                            sckPlayer.getOutputStream().flush();
                        }
                        Log.e(TAG, "..........over.........."); 

                        //关闭对内,对内 2个SOCKET
                        sckPlayer.close();
                        sckServer.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

 

声明: 本文由( 张飞不张,文采横飞 )原创编译,转载请保留链接: 玩转 Android MediaPlayer之Media Proxy

玩转 Android MediaPlayer之Media Proxy:目前有8 条留言

  1. 8楼
    kf156:

    顶虫哥!

    2012-07-30 10:37 [回复]
  2. 看看。学点东西

    2012-07-30 10:45 [回复]
  3. 6楼
    xuyan87101:

    顶,我去,牛牛这么快!

    2012-07-30 10:46 [回复]
  4. 5楼
    hmc1985:

    不错!

    2012-07-30 12:29 [回复]
  5. 4楼
    hubenshan:

    每次都听牛!

    2012-07-30 14:50 [回复]
  6. 地板
    Iptton:

    mark一下

    2012-07-30 17:38 [回复]
  7. 强人

    2012-08-01 16:06 [回复]
  8. 沙发
    ivychen0324:

    It is very helpful to my work! Thank you for sharing.

    2012-09-09 19:23 [回复]

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐