Ich möchte ein Video zu meinem IPad über das HTML5-Video-Tag mit tapestry5 (5.3.5) auf dem Back-End streamen. Normalerweise sollte das serverseitige Framework nicht einmal eine Rolle spielen, aber irgendwie tut es das auch.Video-Streaming zu iPad funktioniert nicht mit Tapestry5
Wie auch immer, hoffentlich kann mir hier jemand helfen. Bitte bedenken Sie, dass mein Projekt ein Prototyp ist und dass das, was ich beschreibe, auf die relevanten Teile reduziert ist. Ich würde es sehr schätzen, wenn die Leute nicht mit dem obligatorischen "Sie wollen das Falsche tun" oder Sicherheits-/Performance-Nitpicks antworten, die für das Problem nicht relevant sind.
Also hier geht es:
Setup-
Ich habe ein Video aus dem Apple HTML5 genommen präsentieren, damit ich weiß, dass Format kein Problem ist. Ich habe eine einfache Tml-Seite "Play", die nur ein "Video" -Tag enthält.
Problem
Ich begann mit einem RequestFilter Implementierung, die die Anforderung von den Videosteuergriffen durch die referenzierte Videodatei zu öffnen und es zu Client-Streaming. Das ist grundlegend "wenn der Pfad mit 'Datei' beginnt, dann kopiere den Datei-Eingangsstrom in den Antwort-Ausgangsstrom". Dies funktioniert sehr gut mit Chrome, aber nicht mit dem Ipad. Gut, aber ich muss einige Header haben, die ich vermisse, also habe ich das Apple Showcase erneut angeschaut und die gleichen Header und Inhaltstypen, aber keine Freude.
Als nächstes, ich, naja, mal sehen, was passiert, wenn ich T5 die Datei liefern lassen. Ich habe das Video in den Webapp-Kontext kopiert, meinen Anforderungsfilter deaktiviert und den einfachen Dateinamen in das src-Attribut des Videos eingefügt. Dies funktioniert in Chrome UND IPad. Das überraschte mich und veranlasste mich zu sehen, wie T5 statische Dateien/Kontextanforderung behandelt. Bislang habe ich nur das Gefühl, dass es zwei verschiedene Wege gibt, die ich durch den Wechsel des festverdrahteten "video src" zu einem Asset mit einem @Path ("context:") bestätigt habe. Dies funktioniert wiederum in Chrome, nicht jedoch in IPad.
Also ich bin wirklich hier verloren. Was ist dieser geheime Saft in den "einfachen Kontext" -Anfragen, die es erlauben, auf dem IPad zu arbeiten? Es gibt nichts Besonderes und doch funktioniert es nur so. Das Problem ist, ich kann nicht wirklich diese vids von meinem Webapp Kontext dienen ...
Lösung
Also, es stellt sich heraus, dass es diese HTTP-Header „Range“ und dass das iPad, im Gegensatz zu Chrome verwendet es mit Video. Die "geheime Soße" besteht dann darin, dass der Servlet-Handler für die statische Ressourcenanforderung weiß, wie er mit Bereichsanforderungen umgehen soll, während T5 dies nicht tut. Hier ist meine benutzerdefinierte Implementierung:
OutputStream os = response.getOutputStream("video/mp4");
InputStream is = new BufferedInputStream(new FileInputStream(f));
try {
String range = request.getHeader("Range");
if(range != null && !range.equals("bytes=0-")) {
logger.info("Range response _______________________");
String[] ranges = range.split("=")[1].split("-");
int from = Integer.parseInt(ranges[0]);
int to = Integer.parseInt(ranges[1]);
int len = to - from + 1 ;
response.setStatus(206);
response.setHeader("Accept-Ranges", "bytes");
String responseRange = String.format("bytes %d-%d/%d", from, to, f.length());
logger.info("Content-Range:" + responseRange);
response.setHeader("Connection", "close");
response.setHeader("Content-Range", responseRange);
response.setDateHeader("Last-Modified", new Date().getTime());
response.setContentLength(len);
logger.info("length:" + len);
byte[] buf = new byte[4096];
is.skip(from);
while(len != 0) {
int read = is.read(buf, 0, len >= buf.length ? buf.length : len);
if(read != -1) {
os.write(buf, 0, read);
len -= read;
}
}
} else {
response.setStatus(200);
IOUtils.copy(is, os);
}
} finally {
os.close();
is.close();
}
Dies sind nützliche Informationen; Es gibt keinen Grund, warum Tapestry dies nicht automatisch im Standard-Asset-Handling-Code handhaben kann. Wir sind uns nur nicht bewusst, dass es getan werden muss. Das Hinzufügen dieses Informationslevels zu unserer JIRA ist der erste Schritt. –
Ausgezeichnete Antwort. Funktioniert sofort wie ein Zauber. Danke vielmals. –