NanoHttpd 服务器代码可以在这里找到。
我正在使用 NanoHttpd 服务器流式传输大型视频(约 150mb)的服务中启动一个新线程,但它只是在显示加载对话框时暂停。我尝试增加和减少缓冲区读取无济于事。服务器似乎无法在 Android 设备上正常运行。
当我通过桌面应用程序启动服务器时,相同的代码工作正常。我可以流式传输超过 150mb。从手机运行服务器时,我只尝试了 20mb 的文件,它们也很好。但是,我需要流式传输的内容远不止这些。
如果其他人遇到此问题并想查看此解决方案中的实际代码,我将在此处发布我的代码。我正在使用我的 Android 设备从 SD 卡流式传输视频文件以获取 Chromecast 请求。使用此代码,我可以在中间开始流和/或寻找流中的特定位置。
@Override
@SuppressWarnings("deprecation")
public Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files) {
String mimeType = getMimeType();
String currentUri = getCurrentUri();
if (currentUri != null && currentUri.equals(uri)) {
String range = null;
Log.d(TAG, "Request headers:");
for (String key : headers.keySet()) {
Log.d(TAG, " " + key + ":" + headers.get(key));
if ("range".equals(key)) {
range = headers.get(key);
}
}
try {
if (range == null) {
return getFullResponse(mimeType);
} else {
return getPartialResponse(mimeType, range);
}
} catch (IOException e) {
Log.e(TAG, "Exception serving file: " + filePath, e);
}
} else {
Log.d(TAG, "Not serving request for: " + uri);
}
return new Response(Response.Status.NOT_FOUND, mimeType, "File not found");
}
private Response getFullResponse(String mimeType) throws FileNotFoundException {
cleanupStreams();
fileInputStream = new FileInputStream(filePath);
return new Response(Response.Status.OK, mimeType, fileInputStream);
}
private Response getPartialResponse(String mimeType, String rangeHeader) throws IOException {
File file = new File(filePath);
String rangeValue = rangeHeader.trim().substring("bytes=".length());
long fileLength = file.length();
long start, end;
if (rangeValue.startsWith("-")) {
end = fileLength - 1;
start = fileLength - 1
- Long.parseLong(rangeValue.substring("-".length()));
} else {
String[] range = rangeValue.split("-");
start = Long.parseLong(range[0]);
end = range.length > 1 ? Long.parseLong(range[1])
: fileLength - 1;
}
if (end > fileLength - 1) {
end = fileLength - 1;
}
if (start <= end) {
long contentLength = end - start + 1;
cleanupStreams();
fileInputStream = new FileInputStream(file);
//noinspection ResultOfMethodCallIgnored
fileInputStream.skip(start);
Response response = new Response(Response.Status.PARTIAL_CONTENT, mimeType, fileInputStream);
response.addHeader("Content-Length", contentLength + "");
response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
response.addHeader("Content-Type", mimeType);
return response;
} else {
return new Response(Response.Status.RANGE_NOT_SATISFIABLE, HTML_MIME_TYPE, rangeHeader);
}
}
仅供参考,但最新版本的 NanoHttpd(可在http://github.com/NanoHttpd/nanohttpd获得)已经过优化,可以更好地支持大型上传并减少内存占用。您使用的代码将传入的上传保存在内存中,较新的版本写入磁盘。检查一下,看看它是否可以解决内存问题。
这是由于 HTTP 标头未初始化造成的问题,因此如果用户首先调用 GET 请求范围请求,然后调用另一个没有范围字段的 GET 请求,前一个范围字段仍将保留在那里,但实际上第二个 GET 请求不期望从范围中读取它。
Android MediaPlayer 是这种情况,mp4 文件末尾带有 moov 框,这会导致读取数据实际上不是我们想要的。
要解决此问题,您可以尝试以下补丁:
diff --git a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
index ce292a4..aba21c4 100644
--- a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
+++ b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
@@ -1039,6 +1039,7 @@ public abstract class NanoHTTPD {
*/
private void decodeHeader(BufferedReader in, Map<String, String> pre, Map<String, String> parms, Map<String, St
throws ResponseException {
+ headers.put("range","bytes=0-");
try {
// Read the request line
String inLine = in.readLine();
有了这个修复,它在 android 5.0 设备上对我来说很好用。
解决了我自己的问题。问题是 MediaPlayer(s)(wmp、vlc、android 播放器)发出具有指定范围的 GET 请求。正确地满足了该请求,问题解决了。