Vraag NanoHttpd-server kan geen grote video's streamen op Android


NanoHttpd-servercode kan worden gevonden hier.

Ik start een nieuwe thread in een service die de NanoHttpd-server gebruikt voor het streamen van grote video's (ongeveer 150 MB), maar het pauzeert gewoon naar rechts terwijl het laadvenster wordt weergegeven. Ik probeerde het verhogen en verlagen van de buffer-lezingen zonder succes. Het lijkt erop dat de server niet correct kan worden uitgevoerd op een Android-apparaat.

Dezelfde code werkt prima als ik de server start via een desktop-applicatie. Ik kan meer dan 150 MB streamen. Toen ik de server vanaf de telefoon uitvoerde, probeerde ik alleen maar 20 MB-bestanden en die waren ook goed. Ik moet echter veel meer streamen dan dat.


11
2018-02-29 05:07


oorsprong


antwoorden:


In het geval dat anderen dit tegenkomen en willen zien wat de daadwerkelijke code in deze oplossing is, plaats ik mijn code hier. Ik gebruik mijn Android-apparaat om een ​​videobestand van de SD-kaart te streamen voor een Chromecast-verzoek. Met behulp van deze code kan ik de stream in het midden starten en / of naar een specifieke locatie in de stream zoeken.

@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);
    }
}

14
2018-05-12 23:13



Dit probleem is het gevolg van het feit dat de HTTP-header niet is geïnitialiseerd, dus als de gebruiker eerst GET met bereikverzoek belt, dan een ander GET-verzoek zonder bereikveld belt, blijft het vorige bereikveld daar, maar in werkelijkheid verwacht het tweede GET-verzoek niet dat lees het uit het bereik.

Android MediaPlayer is zo'n geval voor een mp4-bestand met moov-box aan het einde, waardoor leesgegevens niet echt worden weergegeven.

Om dit probleem op te lossen, kunt u onderstaande patch proberen:

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

Met deze oplossing werkt het prima voor mij op Android 5.0-apparaat.


4
2017-12-15 04:36



Meer van een FYI dan wat dan ook, maar de nieuwste versie van NanoHttpd (beschikbaar op http://github.com/NanoHttpd/nanohttpd) is geoptimaliseerd om grotere uploads met een lagere geheugenvoetafdruk beter te ondersteunen. De code die u gebruikt, houdt de inkomende upload in het geheugen, de nieuwere versie schrijft naar schijf. Bekijk het en kijk of het geheugenproblemen kan oplossen.


3
2018-06-01 19:44



Mijn eigen probleem opgelost. Het probleem is dat de MediaPlayer (s) (wmp, vlc, android-speler) een GET-aanvraag afgeven met een opgegeven RANGE. Diende dat verzoek correct in, probleem opgelost.


2
2018-03-06 07:08