本文是在《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/hcb1230/6593509
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="\r\n\r\n";
/**代理服务器使用的端口*/
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();
}
}