2011-12-21 19 views
5

El siguiente código es para transmisión de video. Esto está bien con IE9 y Firefox, pero no está bien con Chrome y Mac Safari.Video usando HTML 5 y servlet

import java.io.*; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

/** 
* Servlet implementation class VideoStreamServlet 
*/ 

public class VideoStreamServlet extends HttpServlet { 
    private static final long serialVersionUID = 1L; 

    /** 
    * Default constructor. 
    */ 
    public VideoStreamServlet() { 
     // TODO Auto-generated constructor stub 
    } 

    /** 
    * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 
    */ 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     // TODO Auto-generated method stub 
     String range = request.getHeader("range"); 
     String browser = request.getHeader("User-Agent"); 
     System.out.println(browser); 
     if(browser.indexOf("Firefox") != -1){ 
      System.out.println("==========ITS FIREFOX============="); 
      byte[] data = getBytesFromFile(new File("D:/media/final.ogg")); 
      response.setContentType("video/ogg"); 
      response.setContentLength(data.length); 
      response.setHeader("Content-Range", range + Integer.valueOf(data.length-1)); 
      response.setHeader("Accept-Ranges", "bytes"); 
      response.setHeader("Etag", "W/\"9767057-1323779115364\""); 
      byte[] content = new byte[1024]; 
      BufferedInputStream is = new BufferedInputStream(new ByteArrayInputStream(data)); 
      OutputStream os = response.getOutputStream(); 
      while (is.read(content) != -1) { 
       //System.out.println("... write bytes"); 
       os.write(content); 
      } 
      is.close(); 
      os.close(); 
     } 

     else if(browser.indexOf("Chrome") != -1){ 
      System.out.println("==========ITS Chrome============="); 
      byte[] data = getBytesFromFile(new File("D:/media/final.mp4")); 
      String diskfilename = "final.mp4"; 
      response.setContentType("video/mp4"); 
      //response.setContentType("application/octet-stream"); 
      response.setHeader("Content-Disposition", "attachment; filename=\"" + diskfilename + "\""); 
      System.out.println("data.length " + data.length); 
      response.setContentLength(data.length); 
      response.setHeader("Content-Range", range + Integer.valueOf(data.length-1)); 
      response.setHeader("Accept-Ranges", "bytes"); 
      response.setHeader("Etag", "W/\"9767057-1323779115364\""); 
      byte[] content = new byte[1024]; 
      BufferedInputStream is = new BufferedInputStream(new ByteArrayInputStream(data)); 
      OutputStream os = response.getOutputStream(); 
      while (is.read(content) != -1) { 
       //System.out.println("... write bytes"); 
       os.write(content); 
      } 
      is.close(); 
      os.close(); 
     } 

     else if(browser.indexOf("MSIE") != -1) { 
      System.out.println("==========ITS IE9============="); 
      byte[] data = getBytesFromFile(new File("D:/media/final.mp4")); 
      String diskfilename = "final.mp4"; 
      response.setContentType("video/mpeg"); 
      //response.setContentType("application/octet-stream"); 
      response.setHeader("Content-Disposition", "attachment; filename=\"" + diskfilename + "\""); 
      System.out.println("data.length " + data.length); 
      response.setContentLength(data.length); 
      response.setHeader("Content-Range", range + Integer.valueOf(data.length-1)); 
      response.setHeader("Accept-Ranges", "text/x-dvi"); 
      response.setHeader("Etag", "W/\"9767057-1323779115364\""); 
      byte[] content = new byte[1024]; 
      BufferedInputStream is = new BufferedInputStream(new ByteArrayInputStream(data)); 
      OutputStream os = response.getOutputStream(); 
      while (is.read(content) != -1) { 
       //System.out.println("... write bytes"); 
       os.write(content); 
      } 
      is.close(); 
      os.close(); 
     } 
     else if(browser.indexOf("CoreMedia") != -1) { 
      System.out.println("============ Safari============="); 
      byte[] data = getBytesFromFile(new File("D:/media/final.mp4")); 
      String diskfilename = "final.mp4"; 
      response.setContentType("video/mpeg"); 
      //response.setContentType("application/octet-stream"); 
      response.setHeader("Content-Disposition", "attachment; filename=\"" + diskfilename + "\""); 
      System.out.println("data.length " + data.length); 
      //response.setContentLength(data.length); 
      //response.setHeader("Content-Range", range + Integer.valueOf(data.length-1)); 
      // response.setHeader("Accept-Ranges", " text/*, text/html, text/html;level=1, */* "); 
      // response.setHeader("Etag", "W/\"9767057-1323779115364\""); 
      byte[] content = new byte[1024]; 
      BufferedInputStream is = new BufferedInputStream(new ByteArrayInputStream(data)); 
      OutputStream os = response.getOutputStream(); 
      while (is.read(content) != -1) { 
       //System.out.println("... write bytes"); 
       os.write(content); 
      } 
      is.close(); 
      os.close(); 
     } 
    } 

    /** 
    * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 
    */ 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     // TODO Auto-generated method stub 
    } 
    private static byte[] getBytesFromFile(File file) throws IOException { 
     InputStream is = new FileInputStream(file); 
     //System.out.println("\nDEBUG: FileInputStream is " + file); 
     // Get the size of the file 
     long length = file.length(); 
     //System.out.println("DEBUG: Length of " + file + " is " + length + "\n"); 
     /* 
     * You cannot create an array using a long type. It needs to be an int 
     * type. Before converting to an int type, check to ensure that file is 
     * not loarger than Integer.MAX_VALUE; 
     */ 
     if (length > Integer.MAX_VALUE) { 
      System.out.println("File is too large to process"); 
      return null; 
     } 
     // Create the byte array to hold the data 
     byte[] bytes = new byte[(int)length]; 
     // Read in the bytes 
     int offset = 0; 
     int numRead = 0; 
     while ((offset < bytes.length) 
       && 
       ((numRead=is.read(bytes, offset, bytes.length-offset)) >= 0)) { 
      offset += numRead; 
     } 
     // Ensure all the bytes have been read in 
     if (offset < bytes.length) { 
      throw new IOException("Could not completely read file " + file.getName()); 
     } 
     is.close(); 
     return bytes; 
    } 

} 
+0

Algunas notas: lo que está haciendo no es "transmisión", solo está publicando los archivos a través de HTTP como cualquier otro; manejar diferentes navegadores a nivel de servidor es una muy mala idea (y en general debe hacerse lo menos posible); solo debe separar las 2-3 líneas que difieren para cada caso en lugar de replicar todo el código. – Viruzzo

Respuesta

8

Honestamente, este enfoque no es del todo correcto.

  • Está oliendo el agente de usuario en el lado del servidor y dependiendo del trabajo de negocios en él. Esto es en todos los casos una mala idea. Si todo lo que desea es especificar un archivo diferente según el agente de usuario, entonces hágalo en el lado HTML, con ayuda de JavaScript o CSS. Ambos idiomas del lado del cliente pueden identificar el real navegador sin la necesidad de oler la cadena del agente de usuario (que es, en concreto, spoofable).

  • Usted no está respondiendo correctamente en Range solicitudes. Está enviando el archivo completo en lugar del Range solicitado. Firefox e IE no usan solicitudes de rango y es por eso que "funciona". Chrome y Safari usan solicitudes de rango.

Esto debería ser posible sin oler el agente de usuario y adecuada respuesta a las peticiones de los RangeRandomAccessFile en lugar de File y byte[]. Es solo un montón de código tener en cuenta todos los requisitos de HTTP specification, así que aquí hay solo un enlace donde puede encontrar un ejemplo concreto de dicho servlet: FileServlet supporting resume and caching.

Sin embargo, es mucho mejor delegar el trabajo al servlet predeterminado del servletcontainer. Si se trata de, por ejemplo, Tomcat, entonces todo lo que necesita hacer es añadir la siguiente línea al /conf/server.xml:

<Context docBase="D:\media" path="/media" /> 

De esta manera los archivos multimedia deseados son sólo disponibles por http://localhost:8080/media/final.ogg y http://localhost:8080/media/final.mp4 sin la necesidad de homegrow un servlet.

+1

Gracias, esto es muy útil para mí "FileServlet support resume and caching". –

+0

Para el enfoque de contexto tomcat: ¿Hay alguna manera de implementar un filtro de solicitud en los archivos multimedia? – jwi

0

Google Chrome no es compatible con H.264 (incluye mp4) por lo que debe utilizar final.ogg con google chrome también. mientras que para Safari es necesario cambiar esta línea

browser.indexOf("CoreMedia") != -1 

añadir "Safari" en lugar de "CoreMedia"

espero que funcione.

1

Esto parece ser más un problema de soporte de formato.

Puede probar el formato ogg. El código HTML5 es

<audio controls="controls"> 
  <source src="song.ogg" type="audio/ogg" /> 
  Your browser does not support the audio tag. 
</audio> 
0
String diskfilename = "final.mp4"; 
response.setHeader("Content-Disposition", "attachment; filename=\"" + diskfilename + "\""); 

Sólo comentar estas dos líneas y luego se ejecutan en cromo jugará el vídeo.

Cuestiones relacionadas