【问题标题】:Stream a video file over http with Spark Java使用 Spark Java 通过 http 流式传输视频文件
【发布时间】:2016-01-28 15:51:13
【问题描述】:

我正在尝试流式传输视频文件,我正在尝试实现类似于 Jersey 的东西,如下所示:

      ResponseBuilder builder = Response.ok(out.toByteArray());
      builder.header("Content-Disposition", "attachment; filename=" + fields.get("filename"));
      response = builder.build();
    } else {
      response = Response.status(404).
          entity(" Unable to get file with ID: " + id).
          type("text/plain").
          build();
    }

    return response;
  }

这是我用于文件上传和下载/流式传输的内容(下载半成品,文件大小因损坏而正确):

我真的需要大家帮忙,谢谢

更新

改变了:

ByteArrayOutputStream out =  new ByteArrayOutputStream();

到:

ServletOutputStream out = res.raw().getOutputStream();

更新 2 好的,我终于让它工作了,视频在浏览器中播放,但现在得到了一个 Jetty io.EofException,我关闭了流,但仍然必须是简单的。

下面是前后对比:

从浏览器下载文件是可行的,但我怎样才能直接在浏览器中流式传输呢?

之前(没用)

    //download a video/ trying to stream it right in the browser if possible
    get("/post/:id", (req, res ) -> {

            res.raw().setContentType("application/octet-stream");

            String id = req.params(":id");

            ObjectId objectId = new ObjectId(id);
            BasicDBObject query = new BasicDBObject();

            query.put("_id", objectId);
            //DBObject video = collection.findOne(query);

            GridFS gridfile = new GridFS(db, "videos");
            GridFSDBFile gridFSDBFile = gridfile.findOne(query);
            res.raw().setHeader("Content-Disposition", "attachment; filename=" + gridFSDBFile.getFilename());

            InputStream inputStream = gridFSDBFile.getInputStream();

             ServletOutputStream out = res.raw().getOutputStream();
            // ByteArrayOutputStream out =  new ByteArrayOutputStream();
            int data = inputStream.read();
            while (data >= 0) {
                out.write((char) data);
                data = inputStream.read();
            }
            out.flush();
            out.close();
            return out;
        });

AFTER(这很好用,但会出现文件结束异常):

   get("/post/:id", (req, res ) -> {
            //what's the difference between these 2?
            res.raw().setContentType("video/mp4");
            res.type("video/mp4");

            String id = req.params(":id");

            ObjectId objectId = new ObjectId(id);
            BasicDBObject query = new BasicDBObject();

            query.put("_id", objectId);
            GridFS gridfile = new GridFS(db, "videos");
            GridFSDBFile gridFSDBFile = gridfile.findOne(query);

            res.raw().setContentLengthLong(gridFSDBFile.getLength());
            InputStream inputStream = gridFSDBFile.getInputStream();

            ServletOutputStream out = res.raw().getOutputStream();

            int data = inputStream.read();
            while (data >= 0) {
                gridFSDBFile.writeTo(out);
                data = inputStream.read();
            }

           // out.flush();
           out.close();

           return 200;

        });

上传:

 post("/postvideo/:username", (req, res) -> {
            MultipartConfigElement multipartConfigElement =
                    new MultipartConfigElement("/tmp");
            req.raw().
                    setAttribute("org.eclipse.jetty.multipartConfig",
                            multipartConfigElement);
            String username = req.params(":username");
            double[] location =
                    new double[2];
            double lattitude =
                    Double.parseDouble(req.queryParams("lat"));
            double longitude =
                    Double.parseDouble(req.queryParams("lon"));
            location[0] = lattitude;
            location[1] = longitude;

            InputStream inputStream = req.raw().getPart("file").getInputStream();;

            Part uploadedFile = req.raw().getPart("file");
            // File file = new File(uploadedFile.getName());
            GridFS gridFS = new GridFS(db, "videos");

            GridFSInputFile gfsFile = gridFS.createFile(inputStream);

            gfsFile.put("location", location);
            gfsFile.put("username", username);
            gfsFile.put("contentType", req.raw().getContentType());
            gfsFile.put("filename", uploadedFile.getSubmittedFileName());
            collection.insert(gfsFile);

            gfsFile.save();
            return 201;
        });

【问题讨论】:

  • 很抱歉成为吹毛求疵的人,但当我看到你提出问题的方式时,我感到畏缩。您不能通过建筑风格流式传输视频。
  • @toniedzwiedz ???好吧,真的不明白你的意思。无论如何,我改进了我的解决方案并且完美运行。也许我用错了,但你的评论实际上是无用的。

标签: java rest jersey mime-types spark-java


【解决方案1】:

这是有效的方法。我将上传一个解决方案,让您也可以跳到视频的各个部分,小菜一碟;)

  get("/post/:id", (req, res ) -> {
        //what's the difference between these 2?
        res.raw().setContentType("video/mp4");
        res.type("video/mp4");

        String id = req.params(":id");

        ObjectId objectId = new ObjectId(id);
        BasicDBObject query = new BasicDBObject();

        query.put("_id", objectId);
        GridFS gridfile = new GridFS(db, "videos");
        GridFSDBFile gridFSDBFile = gridfile.findOne(query);

        res.raw().setContentLengthLong(gridFSDBFile.getLength());
        InputStream inputStream = gridFSDBFile.getInputStream();

        ServletOutputStream out = res.raw().getOutputStream();

        int data = inputStream.read();
        while (data >= 0) {
            gridFSDBFile.writeTo(out);
            data = inputStream.read();
        }

       // out.flush();
       out.close();

       return 200;

    });

【讨论】:

  • 嗨@franklinexpress - 我查看了 Sparkjava 的 github 问题,似乎具有无限(未知长度)流的方法不起作用?这是正确的吗?我的具体用例是代理实时音频流(例如 http://82.77.137.30:8557/;
  • 是的,它应该可以工作。我现在已经实现了使用具有搜索功能(Accept-Ranges)的 Servlet,搜索部分不适用于未知长度,但流式传输应该。
  • 天哪。所以,我不会设置长度。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 1970-01-01
  • 2019-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
相关资源
最近更新 更多