12

NanoHttpdサーバーコードはここにあります。

NanoHttpdサーバーを使用して大きなビデオ(約150 MB)をストリーミングするサービスで新しいスレッドを開始していますが、読み込みダイアログが表示されている間、スレッドは一時停止します。バッファ読み取りを増減してみましたが、役に立ちませんでした。サーバーはAndroidデバイスで正しく実行できないようです。

デスクトップアプリケーションを介してサーバーを起動すると、同じコードが正常に機能します。150MB以上ストリーミングできます。電話からサーバーを実行しているとき、私は20MBのファイルだけを試しましたが、それらも良かったです。ただし、それ以上のストリーミングが必要です。

4

4 に答える 4

15

他の人がこれに遭遇し、このソリューションの実際のコードが何であるかを知りたい場合は、ここにコードを投稿します。Androidデバイスを使用して、Chromecastリクエスト用にSDカードからビデオファイルをストリーミングしています。このコードを使用して、ストリームを途中で開始したり、ストリーム内の特定の場所を探したりすることができます。

@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);
    }
}
于 2014-05-12T23:13:19.827 に答える
5

参考までに、NanoHttpdの最新バージョン(http://github.com/NanoHttpd/nanohttpdで入手可能)は、メモリフットプリントを削減して大規模なアップロードをより適切にサポートするように最適化されています。使用しているコードは、受信したアップロードをメモリに保持し、新しいバージョンはディスクに書き込みます。それをチェックして、メモリの問題を解決できるかどうかを確認してください。

于 2013-06-01T19:44:27.863 に答える
4

これはHTTPヘッダーが初期化されていないために発生する問題です。したがって、ユーザーが最初に範囲リクエストを使用してGETを呼び出し、次に範囲フィールドを使用せずに別のGETリクエストを呼び出すと、前の範囲フィールドはそのまま残りますが、実際には2番目のGETリクエストは範囲からそれを読んでください。

Android MediaPlayerは、最後にmoovボックスが付いたmp4ファイルの場合です。これにより、実際にはデータの読み取りが不要になります。

この問題を解決するには、以下のパッチを試すことができます。

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();

この修正により、Android5.0デバイスで正常に動作します。

于 2014-12-15T04:36:08.883 に答える
2

私自身の問題を解決しました。問題は、MediaPlayer(wmp、vlc、android player)が、指定されたRANGEでGETリクエストを発行することです。そのリクエストを正しく処理し、問題を解決しました。

于 2012-03-06T07:08:12.803 に答える