简体   繁体   English

在Chrome中,将Wrtie ByteArrayOutputStream转换为Html5视频失败(Java Servlet)

[英]Wrtie ByteArrayOutputStream to Html5 video failed in Chrome (Java Servlet)

I have a video tag in jsp, the src is the url to servlet. 我在jsp中有一个视频标签,src是servlet的URL。

<video src="/MyApp/video" controls="true"></video>

Here is the corresponding servlet 这是对应的servlet

public class VideoServlet extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        go(req, resp);
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    private void go(HttpServletRequest request, HttpServletResponse response) throws IOException {
        File file = new File("/Users/me/video.mp4");
        int fileSize = (int) file.length();
        FileInputStream inputStream = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(4096);
        try {
            inputStream = new FileInputStream(file);
            final byte[] buf = new byte[1024 * 8];
            for (int v; (v = inputStream.read(buf)) >= 0;) {
                if (v > 0)
                    outputStream.write(buf, 0, v);
            }

            response.setHeader("Accept-Ranges", "bytes");
            response.setContentType("video/mp4");
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            response.setContentLength(fileSize);
            response.setHeader("Content-Range", "bytes " + 0 + "-" + fileSize + "/" + fileSize);

            outputStream.writeTo(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            inputStream.close();
            outputStream.close();
        }
    }
}

When I use Firefox, it works, I can play the video after page loaded, but in Chrome, I got EofException (jetty) or ClientAbortException (tomcat). 当我使用Firefox时,它可以工作,可以在页面加载后播放视频,但是在Chrome中,我收到了EofException(jetty)或ClientAbortException(tomcat)。

Here is the exception stack trace when using jetty: 这是使用码头时的异常堆栈跟踪:

org.eclipse.jetty.io.EofException
    at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:292)
    at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:429)
    at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:322)
    at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:372)
    at org.eclipse.jetty.server.HttpConnection$SendCallback.process(HttpConnection.java:756)
    at org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:241)
    at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:224)
    at org.eclipse.jetty.server.HttpConnection.send(HttpConnection.java:522)
    at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:735)
    at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:786)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:234)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:218)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:530)
    at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:167)
    at VideoServlet.go(VideoServlet.java:56)
    at VideoServlet.doGet(VideoServlet.java:25)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:833)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
    at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:206)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:219)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.Server.handle(Server.java:561)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:334)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:104)
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:679)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:597)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: Broken pipe
    at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
    at sun.nio.ch.IOUtil.write(IOUtil.java:65)
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
    at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:270)
    ... 49 more

Is my usage wrong or maybe it is a browser issue? 我的用法是否错误,或者可能是浏览器问题?

If it's my usage wrong, how should I write ByteArrayOutputStream to browser to play the video? 如果我的用法有误,应该如何将ByteArrayOutputStream写入浏览器以播放视频?

I saw the document, https://tools.ietf.org/html/rfc7233#section-4.2 . 我看到了文档https://tools.ietf.org/html/rfc7233#section-4.2

A Content-Range field value is invalid if it contains a byte-range-resp that has a last-byte-pos value less than its first-byte-pos value, or a complete-length value less than or equal to its last-byte-pos value. 如果Content-Range字段值包含一个byte-range-resp,则其last-byte-pos值小于其first-byte-pos值,或者一个full-length值小于或等于last-byte-resp字节位置值。

So I changed 所以我改变了

response.setHeader("Content-Range", "bytes " + 0 + "-" + fileSize + "/" + fileSize);

to

response.setHeader("Content-Range", "bytes " + 0 + "-" + (fileSize - 1) + "/" + fileSize);

It works in Chrome now. 现在可以在Chrome中使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM