Quiero transmitir un video a mi IPad a través de la etiqueta de video HTML5 con tapiz5 (5.3.5) en el back-end. Por lo general, el marco del servidor ni siquiera debe desempeñar un papel en esto, pero de alguna manera lo hace.La transmisión de video a ipad no funciona con Tapestry5
De todos modos, con suerte alguien aquí puede ayudarme. Tenga en cuenta que mi proyecto es en gran medida un prototipo y que lo que describo se simplifica/reduce a las partes relevantes. Le agradecería mucho si las personas no respondieran con la obligación de "querer hacer lo incorrecto" o detalles de seguridad/rendimiento que no son relevantes para el problema.
Así que aquí va:
Configuración
Tengo un video tomado de la manzana HTML5 mostrar así que sé que el formato no es un problema. Tengo una página simple de tml "Reproducir" que solo contiene una etiqueta de "video".
Problema
empecé mediante la implementación de un RequestFilter que controla la solicitud de control de vídeo abriendo el archivo de vídeo y streaming de referencia para el cliente. Eso es básico "si la ruta comienza con 'archivo' y luego copia el archivo inputstream a response outputstream". Esto funciona muy bien con Chrome, pero no con el Ipad. Bien, pensé, deben faltar algunos encabezados, así que volví a mirar el Apple Showcase e incluí los mismos encabezados y el mismo tipo de contenido, pero no me gustó.
A continuación, pensé, bueno, veamos qué sucede si dejo que t5 entregue el archivo. Copié el video en el contexto de la aplicación web, deshabilité el filtro de mi solicitud y coloqué el nombre de archivo simple en el atributo src del video. Esto funciona en Chrome AND IPad. Eso me sorprendió y me impulsó a ver cómo T5 maneja los archivos estáticos/solicitud de contexto. Hasta ahora solo he llegado a sentir que hay dos caminos diferentes que he confirmado al cambiar el "cable src" cableado a un Asset con @Path ("contexto:"). Esto, de nuevo, funciona en Chrome pero no en IPad.
Así que realmente estoy perdido aquí. ¿Qué es este jugo secreto en las solicitudes de "contexto simple" que le permiten funcionar en el iPad? No pasa nada especial y, sin embargo, es la única forma en que esto funciona. El problema es que no puedo servir a esos vids de mi contexto webapp ...
Solución
Así, resulta que existe esta cabecera HTTP llamado "Rango" y que el IPad, a diferencia de Chrome utiliza con video La "salsa secreta" es que el manejador de servlets para la solicitud de recursos estáticos sabe cómo tratar las solicitudes de rango, mientras que las de T5 no. Aquí está mi implementación personalizada:
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();
}
Esta es información útil; no hay ninguna razón por la cual Tapestry no pueda manejar esto automáticamente dentro del código estándar de manejo de activos; simplemente no somos conscientes de que es necesario hacerlo. Agregar este nivel de información a nuestra JIRA es el primer paso. –
Excelente respuesta. Funciona como un encanto de inmediato. Muchas gracias. –