NanoHttpd服务器无法在android上传输大型视频

时间:2012-02-29 05:07:17

标签: java android memory streaming nanohttpd

可以找到NanoHttpd服务器代码here

我正在使用NanoHttpd服务器流式传输大型视频(约150mb)的服务中启动一个新线程,但它只是在显示加载对话框时暂停。我尝试增加和减少缓冲区读取无济于事。似乎服务器无法在Android设备上正常运行。

当我通过桌面应用程序启动服务器时,相同的代码工作正常。我的流量超过150mb。从手机运行服务器时,我只尝试了20mb文件,它们也很好。但是,我需要更多的信息流。

4 个答案:

答案 0 :(得分:14)

如果其他人遇到此问题并希望了解此解决方案中的实际代码,我将在此处发布我的代码。我正在使用我的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);
    }
}

答案 1 :(得分:4)

由于HTTP标头未初始化,这是一个问题,因此如果用户首先使用范围请求调用GET,然后调用另一个没有范围字段的GET请求,则前一个范围字段仍将保留,但实际上第二个GET请求不是&# 39; t期望从范围内读取它。

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设备上正常工作。

答案 2 :(得分:3)

更多的FYI比任何东西,但是,最新版本的NanoHttpd(可在http://github.com/NanoHttpd/nanohttpd获得)已经过优化,可以更好地支持大型上传,减少内存占用。您正在使用的代码将传入的上载保存在内存中,较新的版本会写入磁盘。检查一下,看看它是否可以解决内存问题。

答案 3 :(得分:2)

解决了我自己的问题。问题是MediaPlayer(wmp,vlc,android player)发出了一个带有指定RANGE的GET请求。正确地提供了请求,问题解决了。