通过 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 文件之间的映射。而<video/>
元素只是自动处理事情。
我在这里是对的吗,或者即使我使用了<video/>
,我还需要在服务器上实现低级字节/套接字流的东西吗?
【问题讨论】:
【参考方案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 多媒体流的主要内容,如果未能解决你的问题,请参考以下文章