我写了两个版本:
我开源的这个版本,这个版本有点问题……虽然支持视频http 206range的Seek,但是个别播放器异常,videoview可以正常放但是ffplayerseek会死掉。并且没有太多并发能力
第二个版本修复了以上问题并且工作正常,因为商用可能所以不公布……见谅
public class StreamProxy implements Runnable {
privatestatic final String LOG_TAG = StreamProxy.class.getName();
private intport = 0;
privateboolean isRunning = true;
privateServerSocket socket;
privateThread thread;
public intgetPort() {
returnport;
}
public voidinit() {
try {
socket = newServerSocket(0, 0,
InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }));
socket.setSoTimeout(5000);
port =socket.getLocalPort();
Log.d(LOG_TAG, “port ” + port + ” obtained”);
} catch(UnknownHostException e) {
Log.e(LOG_TAG, “Error initializing server”, e);
} catch(IOException e) {
Log.e(LOG_TAG, “Error initializing server”, e);
}
}
public voidstart() {
if (socket== null) {
throw newIllegalStateException(
“Cannotstart proxy; it has not been initialized.”);
}
thread = newThread(this);
thread.start();
}
public voidstop() {
isRunning =false;
if (thread== null) {
throw newIllegalStateException(
“Cannot stopproxy; it has not been started.”);
}
thread.interrupt();
try {
thread.join(5000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
@Override
public voidrun() {
Log.d(LOG_TAG, “running”);
while(isRunning) {
try {
Socketclient = socket.accept();
if (client== null) {
continue;
}
Log.d(LOG_TAG, “client connected”);
HttpRequestrequest = readRequest(client);
processRequest(request, client);
} catch(SocketTimeoutException e) {
// Donothing
} catch(IOException e) {
Log.e(LOG_TAG, “Error connecting to client”, e);
}
}
Log.d(LOG_TAG, “Proxy interrupted. Shutting down.”);
}
privateHttpRequest readRequest(Socket client) {
HttpRequestrequest = null;
InputStreamis;
StringfirstLine;
BufferedReader reader;
Log.e(LOG_TAG, “ThreadName:” +Thread.currentThread().getName());
try {
is =client.getInputStream();
reader = newBufferedReader(new InputStreamReader(is), 8192);
firstLine =reader.readLine();
} catch(IOException e) {
Log.e(LOG_TAG, “Error parsing request”, e);
returnnull;
}
if(firstLine == null) {
Log.i(LOG_TAG, “Proxy client closed connection without arequest.”);
returnnull;
}
// decidemethod and uri
StringTokenizer st = new StringTokenizer(firstLine);
Stringmethod = st.nextToken();
String uri =st.nextToken().substring(1);
// createresult
request =new BasicHttpRequest(method, uri);
//rest
while (true){
try {
firstLine =reader.readLine();
if(firstLine == null || firstLine.trim().compareTo(“”) == 0)
break;
int p =firstLine.indexOf(‘:’);
if (p< 0)
continue;
final Stringatr = firstLine.substring(0, p).trim()
.toLowerCase();
final Stringval = firstLine.substring(p + 1).trim();
Log.d(LOG_TAG, “header:” + atr + “:” + val);
request.setHeader(atr, val);
} catch(IOException e) {
e.printStackTrace();
break;
}
}
returnrequest;
}
private voidprocessRequest(HttpRequest request, Socket client)
throwsIllegalStateException, IOException {
EncryptFileinputfile;
if (request== null) {
Log.d(LOG_TAG, “request load fail”);
return;
}
Log.d(LOG_TAG, “processing”);
// openfile
Stringfilepath = Environment.getExternalStorageDirectory() + “/”
+request.getRequestLine().getUri();
// s
try {
inputfile =new EncryptFile(filepath);
} catch(Exception e1) {
Log.d(LOG_TAG, “EncryptFile load fail”);
e1.printStackTrace();
return;
}
Stringmimetype = inputfile.getMimeType();
longfilesize = inputfile.getFileSize();
Log.d(LOG_TAG, “filepath:” + filepath);
Log.d(LOG_TAG, “mimetype:” + mimetype);
Log.d(LOG_TAG, “filesize:” + filesize);
Stringheaders;
//跳转播放哦
if(request.getHeaders(“range”).length != 0
&&request.getHeaders(“range”)[0].getValue().startsWith(
“bytes=”)){
String range= request.getHeaders(“range”)[0].getValue().substring(
6);
longstartFrom = 0, endAt = -1;
int minus =range.indexOf(‘-‘);
if (minus> 0) {
try {
StringstartR = range.substring(0, minus);
startFrom =Long.parseLong(startR);
String endR= range.substring(minus + 1);
endAt =Long.parseLong(endR);
} catch(NumberFormatException nfe) {
}
}
if (endAt<= 0)
endAt =filesize;
// seekfile
try {
inputfile.seekTo(startFrom);
} catch(Exception e) {
e.printStackTrace();
Log.d(LOG_TAG, “EncryptFile seek fail”);
return;
}
//header
headers =”HTTP/1.1 206 OK\r\n”;
headers +=”Content-Type: ” + mimetype + “\r\n”;
headers +=”Accept-Ranges: bytes\r\n”;
headers +=”Content-Length: ” + (filesize – startFrom) + “\r\n”;
headers +=”Content-Range: bytes ” + startFrom + “-” + endAt + “/”
+ filesize +”\r\n”;
headers +=”\r\n”;
Log.d(LOG_TAG, “accept:range 206 request”);
} else{
//从头播放哦
//header
headers =”HTTP/1.1 200 OK\r\n”;
headers +=”Content-Type: ” + mimetype + “\r\n”;
headers +=”Accept-Ranges: bytes\r\n”;
headers +=”Content-Length: ” + filesize + “\r\n”;
headers +=”\r\n”;
Log.d(LOG_TAG, “accept:start 200 request”);
}
Log.d(LOG_TAG, “respone_headers:” + headers);
//这里应该输出视频内容,略
} catch(Exception e) {
Log.e(LOG_TAG, e.getMessage(), e);
} finally{
if(inputfile != null) {
inputfile.close();
inputfile =null;
}
client.close();
}
}