使用 Java servlet 的视频下载/流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18577307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 09:09:51  来源:igfitidea点击:

Video download/stream using Java servlet

javajspservletsvideodownload

提问by harshadura

I am trying to download a video file in my server when the client access URL similar to this:

当客户端访问 URL 类似于以下内容时,我试图在我的服务器中下载视频文件:

http://localhost:8088/openmrs/moduleServlet/patientnarratives/videoDownloadServlet?videoObsId=61

I have tried this code. But its not working. When i visit the servlet it only download a Blank (0 size) file.

我试过这个代码。但它不起作用。当我访问 servlet 时,它只下载一个空白(0 大小)文件。

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
{
    try {
        Integer videoObsId = Integer.parseInt(request.getParameter("videoObsId"));

        Obs complexObs = Context.getObsService().getComplexObs(videoObsId, OpenmrsConstants.RAW_VIEW); 
        ComplexData complexData = complexObs.getComplexData();
        Object object2 = complexData.getData(); // <-- an API used in my service. this simply returns an object.

        byte[] videoObjectData = SerializationUtils.serialize(object2);

        // Get content type by filename.
        String contentType = null;
        if (contentType == null) {
            contentType = "application/octet-stream";
        }

        // Init servlet response.
        response.reset();
        response.setBufferSize(DEFAULT_BUFFER_SIZE);
        response.setContentType(contentType);
        response.setHeader("Content-Length", String.valueOf(videoObjectData.length));
        response.setHeader("Content-Disposition", "attachment; filename=\"" + "test.flv" + "\"");

        // Prepare streams.
        BufferedInputStream input = null;
        BufferedOutputStream output = null;

        try {
            // Open streams.
            input = new BufferedInputStream(new ByteArrayInputStream(videoObjectData), DEFAULT_BUFFER_SIZE);              
            output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

            // Write file contents to response.
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int length;
            while ((length = input.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
        } finally {
            // Gently close streams.
            close(output);
            close(input);
        }
    }

    // Add error handling above and remove this try/catch
    catch (Exception e) {
        log.error("unable to get file", e);
    }
}
private static void close(Closeable resource) {
    if (resource != null) {
        try {
            resource.close();
        } catch (IOException e) {
            // Do your thing with the exception. Print it, log it or mail it.
            e.printStackTrace();
        }
    }
}

I have used BalusC's fileservlet tutorialbut in my case i dont have file object as the inputstream just the byte array object.

我使用过 BalusC 的fileservlet 教程,但在我的情况下,我没有文件对象作为输入流,只是字节数组对象。

help..

帮助..

采纳答案by BalusC

The servlet which you found is indeed insuitable for the purpose of streaming a video file. It's more intented as a simple file download servlet for static files like PDF, XLS, etc.

您发现的 servlet 确实不适合用于流式传输视频文件。它更像是一个简单的文件下载 servlet,用于静态文件,如 PDF、XLS 等。

A lot of video players require that the server supports so-called HTTP range requests. I.e. it must be able to return a specific byte range of the video file by a request with a Rangeheader. For example, only the bytes from index 1000 until 2000 on a file of 10000 bytes long. This is mandatory in order to be able to skip a certain range of the video stream quickly enough without the need to download the whole file and/or to improve buffering speed by creating multiple HTTP connections which each requests a different part of the video file.

许多视频播放器要求服务器支持所谓的 HTTP 范围请求。即它必须能够通过带有Range标头的请求返回视频文件的特定字节范围。例如,在 10000 字节长的文件中,只有从索引 1000 到 2000 的字节。这是强制性的,以便能够在不需要下载整个文件的情况下足够快地跳过特定范围的视频流和/或通过创建多个 HTTP 连接来提高缓冲速度,每个连接请求视频文件的不同部分。

This is however a lot of additional code in the servlet which requires a well understanding of the HTTP Rangespecification. A ready to use example is provided in flavor of this extended file servletby the very same author of the file servlet which you found. In your specific case it's perhaps recommendable to save the file to local disk file system based cache first (e.g. by File#createTempFile()and some key in HTTP session), so that you don't need to obtain it from the external service again and again.

然而,这是 servlet 中的许多附加代码,需要对 HTTPRange规范有很好的理解。您找到的文件 servlet 的作者是这个扩展文件 servlet的风格,提供了一个随时可用的示例。在您的特定情况下,可能建议首先将文件保存到基于缓存的本地磁盘文件系统(例如,通过File#createTempFile()HTTP 会话中的某些密钥),这样您就不需要一次又一次地从外部服务获取它。