Видео Использование HTML 5 и сервлет
Ниже приведен код для потокового видео. Это нормально с IE9 и Firefox, но не с Chrome и Mac Safari.
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;
}
}
4 ответа
Честно говоря, такой подход абсолютно не верен.
Вы нюхаете пользовательский агент на стороне сервера и зависите от него на работе. Во всех случаях это плохая идея. Если все, что вам нужно, это указать другой файл в зависимости от пользовательского агента, а не делать это на стороне HTML, с помощью JavaScript или CSS. Оба клиентских языка способны идентифицировать настоящий браузер без необходимости перехватывать строку пользовательского агента (которая может быть подделана).
Вы не отвечаете правильно на
Range
Запросы. Вы отправляете полный файл обратно вместо запрошенногоRange
, Firefox и IE не используют запросы диапазона, и поэтому он "работает". Chrome и Safari используют запросы диапазона.
Это должно быть возможно без использования пользовательского агента и правильного реагирования на Range
запросы от RandomAccessFile
вместо File
а также byte[]
, Достаточно много кода, чтобы принять во внимание все требования спецификации HTTP, поэтому вот лишь ссылка, где вы можете найти конкретный пример такого сервлета: FileServlet, поддерживающий возобновление и кэширование.
Однако гораздо лучше делегировать задание сервлету по умолчанию для сервлетконтейнера. Если это, например, Tomcat, то все, что вам нужно сделать, это добавить следующую строку в /conf/server.xml
:
<Context docBase="D:\media" path="/media" />
Таким образом, нужные медиа-файлы просто доступны по http://localhost:8080/media/final.ogg и http://localhost:8080/media/final.mp4 без необходимости доморощенного сервлета.
Похоже, это скорее проблема поддержки формата.
Вы можете попробовать формат OGG. HTML5 код
<audio controls="controls">
<source src="song.ogg" type="audio/ogg" />
Your browser does not support the audio tag.
</audio>
String diskfilename = "final.mp4";
response.setHeader("Content-Disposition", "attachment; filename=\"" + diskfilename + "\"" );
Просто прокомментируйте эти две строки, а затем запустите Chrome, ваше видео будет воспроизводиться.
Google Chrome не поддерживает H.264 (включая mp4), поэтому вам также необходимо использовать final.ogg с Google Chrome. в то время как для сафари вам нужно изменить эту строку
browser.indexOf("CoreMedia") != -1
добавить "Safari" вместо "CoreMedia"
надеюсь это работает.