通过 HTML5 视频元素的 Java 多媒体流

Posted

技术标签:

【中文标题】通过 HTML5 视频元素的 Java 多媒体流【英文标题】:Java multimedia streaming via HTML5 video element 【发布时间】:2014-06-30 04:09:32 【问题描述】:

我试图让我的 Java 后端将视频文件(MP4 等)“流式传输”到浏览器。我担心我必须编写非常复杂的低级 NIO 类型代码,例如:

public class VideoController extends HttpServlet 
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) 
        File f = new File("/opt/videos/video19394.mp4");
        PrintStream ps = resp.getWriter();

        while(still reading f) 
            writeTheVideoBytesToStream(f, ps);
        
    

似乎 这一切都由 html5 <video/> 元素处理(yes??)。这样,从客户端,我可以指定:

<video   url="http://myapp.example.com/videos/19394" />

然后,在服务器端,即使是像web.xml 这样简单的东西,我也可以指定像http://myapp.example.com/videos/19394 这样的URL 请求和位于服务器上/opt/videos/video19394.mp4 的MP4 文件之间的映射。而&lt;video/&gt; 元素只是自动处理事情。

我在这里是对的吗,或者即使我使用了&lt;video/&gt;,我还需要在服务器上实现低级字节/套接字流的东西吗?

【问题讨论】:

【参考方案1】:

您可以使用 Spring Boot 框架,只需从 REST 端点提供 InputStream。 这也将允许在 HTML5 中使用视频标签进行滚动。

代码看起来像这样:

@RequestMapping(value = "videos/file-name", method = GET)
@ResponseBody
public final ResponseEntity<InputStreamResource> 
retrieveResource(@PathVariable(value = "file-name")
final String fileName,
@RequestHeader(value = "Range", required = false)
String range) throws Exception 

long rangeStart = Longs.tryParse(range.replace("bytes=","").split("-")[0]);//parse range header, which is bytes=0-10000 or something like that
long rangeEnd = Longs.tryParse(range.replace("bytes=","").split("-")[0]);//parse range header, which is bytes=0-10000 or something like that
long contentLenght = ;//you must have it somewhere stored or read the full file size

InputStream inputStream = Resources.getResource(fileName).openStream();//or read from wherever your data is into stream
HttpHeaders headers = new HttpHeaders();
headers.setContentType("video/mp4");
headers.set("Accept-Ranges", "bytes");
headers.set("Expires", "0");
headers.set("Cache-Control", "no-cache, no-store");
headers.set("Connection", "keep-alive");
headers.set("Content-Transfer-Encoding", "binary");
headers.set("Content-Length", String.valueOf(rangeEnd - rangeStart));

//if start range assume that all content
if (rangeStart == 0) 
  return new ResponseEntity<>(new InputStreamResource(inputStream), headers, OK);
 else 
  headers.set("Content-Range", format("bytes %s-%s/%s", rangeStart, rangeEnd, contentLenght));
  return new ResponseEntity<>(new InputStreamResource(inputStream), headers, PARTIAL_CONTENT);


【讨论】:

在“else”子句中,您应该发送整个输入流的一部分。【参考方案2】:

正如@saganas 所建议的,您需要实现一个支持字节范围请求的控制器。但是,Spring Content 支持开箱即用的视频流(即字节范围支持)并提供非常简单的编程接口。例如,将 Spring Content 用于文件系统,您可以通过在代码中定义单个接口来创建视频流服务。就是这样。

方法如下。通过 start.spring.io 或您的 IDE spring 项目向导(在撰写本文时为 Spring Boot 1.5.10)创建一个新的 Spring Boot 项目。添加以下 Spring Boot/Content 依赖项,以便最终获得这些:-

<dependencies>
    <!-- Standard Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.3</version>
    </dependency>

    <!-- Spring Content -->
    <dependency>
        <groupId>com.github.paulcwarren</groupId>
        <artifactId>spring-content-fs-boot-starter</artifactId>
        <version>0.0.9</version>
    </dependency>
    <dependency>
        <groupId>com.github.paulcwarren</groupId>
        <artifactId>spring-content-rest-boot-starter</artifactId>
        <version>0.0.9</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

在您的 Spring Boot Application 类中,创建您的 VideoStore 接口。这会导致 Spring Content 注入一个 java 实现(该接口的)以及 REST 端点,这意味着您不必担心自己编写这些:-

    @SpringBootApplication 
    public class DemoApplication 

        public static void main(String[] args)         
           SpringApplication.run(DemoApplication.class, args);  
        

        @StoreRestResource(path="videos")   
        public interface VideoStore extends Store<String>  
    

注意:- 默认情况下,Spring Content 将在 java.io.tmpdir 下创建一个存储,因此您还需要将 SPRING_CONTENT_FS_FILESYSTEM_ROOT 环境变量设置为指向“存储”的根目录。

将您的视频放到这个“根”位置。启动应用程序,您的视频将从以下位置流式传输:-

/videos/ExampleVideo.mp4

Spring Content 也支持其他“存储”。以 S3 为例。所以你不必使用文件系统。但它非常适合快速启动和运行。如果您确实想使用不同的商店,只需切换正确的 Spring Content 依赖项即可。

【讨论】:

以上是关于通过 HTML5 视频元素的 Java 多媒体流的主要内容,如果未能解决你的问题,请参考以下文章

HTML5基础知识点笔记

HTML5学习多媒体元素

HTML5的媒体元素及iframe框架的使用

如何自动化测试 html5 媒体元素

HTML5新增多媒体属性(加入视频音频)CSS3高级应用(过渡变形动画)精灵图

三天学会HTML5 ——多媒体元素的使用