Ответ 1
Решил мою собственную проблему. Проблема в том, что MediaPlayer (s) (wmp, vlc, android player) выдают запрос GET с указанным диапазоном. Правильно выполнил этот запрос, проблема решена.
Код сервера NanoHttpd можно найти здесь.
Я запускаю новую тему в службе, которая использует сервер NanoHttpd для потоковой передачи больших видеороликов (около 150 Мб), но она просто приостанавливается, пока отображается диалоговое окно загрузки. Я пытался увеличивать и уменьшать чтение буфера безрезультатно. Кажется, что сервер не может нормально работать на устройстве Android.
Тот же код отлично работает, когда я запускаю сервер через настольное приложение. Я могу транслировать более 150 мб. При запуске сервера с телефона я только пробовал файлы 20 МБ, и они тоже были хороши. Однако мне нужно передать гораздо больше.
Решил мою собственную проблему. Проблема в том, что MediaPlayer (s) (wmp, vlc, android player) выдают запрос GET с указанным диапазоном. Правильно выполнил этот запрос, проблема решена.
В случае, если другие сталкиваются с этим и хотят видеть, что представляет собой настоящий код в этом решении, я отправляю свой код здесь. Я использую свое устройство 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);
}
}
Это проблема из-за того, что HTTP-заголовок не инициализирован, поэтому, если пользователь сначала вызовет GET с запросом диапазона, затем вызовет другой запрос GET без поля диапазона, поле предыдущего диапазона все равно останется там, но на самом деле второй запрос GET не будет ' 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.
Больше FYI, чем что-либо, но самая новая версия NanoHttpd (доступная по адресу http://github.com/NanoHttpd/nanohttpd) была оптимизирована для лучшей поддержки больших загружает с уменьшенной площадью памяти. Используемый код содержит входящую загрузку в память, более новую версию записывает на диск. Проверьте это и проверьте, не может ли это решить проблемы с памятью.