Voglio riprodurre un video in streaming sul mio IPad tramite il tag video HTML5 con tapestry5 (5.3.5) sul backend. Di solito il framework serveride non dovrebbe nemmeno giocare un ruolo in questo, ma in qualche modo lo fa.Lo streaming video su ipad non funziona con Tapestry5
In ogni caso, speriamo che qualcuno qui possa aiutarmi. Tieni presente che il mio progetto è un prototipo e che ciò che descrivo è semplificato/ridotto alle parti pertinenti. Lo apprezzerei molto se le persone non rispondessero con l'obbligo "si vuole fare la cosa sbagliata" o la sicurezza/prestazioni nitpicks che non sono rilevanti per il problema.
così qui va:
Setup
Ho un video preso da Apple HTML5 vetrina quindi so che il formato non è un problema. Ho una semplice pagina tml "Play" che contiene solo un tag "video".
Problema
ho iniziato mediante l'attuazione di un RequestFilter che gestisce la richiesta del controllo video aprendo il file video di riferimento e in streaming al cliente. È fondamentale "se il percorso inizia con" file ", quindi copia il file inputstream nella risposta outputstream". Funziona molto bene con Chrome ma non con l'Ipad. Bene, pensavo che dovessero esserci alcune intestazioni che mi mancano quindi ho di nuovo guardato l'Apple Showcase e ho incluso le stesse intestazioni e il tipo di contenuto ma nessuna gioia.
Successivamente, anche se, beh, vediamo cosa succede se lascio che t5 serva il file. Ho copiato il video nel contesto webapp, ho disattivato il filtro delle richieste e inserito il semplice nome file nell'attributo src del video. Funziona su Chrome AND IPad. Questo mi ha sorpreso e mi ha spinto a vedere come T5 gestisce i file statici/la richiesta di contesto. Finora sono arrivato così lontano da sentire che ci sono due percorsi diversi che ho confermato spostando il "video src" cablato in un asset con un @Path ("context:"). Questo, ancora, funziona su Chrome ma non su IPad.
Quindi sono davvero perso qui. Qual è questo succo segreto nelle richieste di "contesto semplice" che gli consentono di lavorare su IPad? Non c'è niente di speciale in corso e tuttavia è l'unico modo in cui funziona. Il problema è, non posso servire realmente quei vids dal mio contesto webapp ...
Soluzione
Così, si scopre che c'è questa intestazione http chiamato "Gamma" e che l'iPad, a differenza di Chrome utilizza con il video. La "salsa segreta" è quindi che il gestore di servlet per la richiesta di risorse statiche sa come gestire le richieste di intervallo mentre quelle di T5 no. Ecco la mia implementazione personalizzata:
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();
}
Questa è un'informazione utile; non c'è motivo per cui Tapestry non possa gestirlo automaticamente all'interno del codice standard di gestione degli asset; non ci rendiamo conto che è necessario. L'aggiunta di questo livello di informazioni al nostro JIRA è il primo passo. –
Ottima risposta. Funziona come un fascino subito. Molte grazie. –