Android下播放用加密视频流服务器

2013-09-26
最近写了一个android下的http服务器,支持文件及加密视频文件按流输出并解密,可以视频直连然后播放</p>

我写了两个版本:
我开源的这个版本,这个版本有点问题……虽然支持视频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();
}
}