java - HTML5 视频跳过 32,768 之后的范围
问题描述
我正在使用 Java 探索 Http Range 请求和视频流。我想创建一个将视频流式传输到标签的控制器。
出于某种原因,在结束范围 32768 之后,浏览器发送了开始 100237312 的请求。这是我控制台中的一段日志:
...
Start: 27648, End: 28672, chunk size: 1024
Start: 28672, End: 29696, chunk size: 1024
Start: 29696, End: 30720, chunk size: 1024
Start: 30720, End: 31744, chunk size: 1024
Start: 31744, End: 32768, chunk size: 1024
Start: 100237312, End: 100238336, chunk size: 1024
Start: 100238336, End: 100239360, chunk size: 1024
...
我的代码:
package com.example.demo.controllers;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.nio.file.Files;
import java.util.Arrays;
@RestController
@RequestMapping("/video")
public class VideoCtrl {
@CrossOrigin
@ResponseBody
@GetMapping
public ResponseEntity<InputStreamResource> getVideo(@RequestHeader("Range") String range) {
String[] rangeHeaderParams = HttpRange.parseHttpRangeHeader(range);
File file = new File(getClass().getClassLoader().getResource("video_for_test.mp4").getFile());
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
long fileSize = file.length();
assert is != null;
final int CHUNK_SIZE = 1024;
String type = rangeHeaderParams[0];
int start = Integer.parseInt(rangeHeaderParams[1]);
int end = start + CHUNK_SIZE;
System.out.println(String.format(
"Start: %d, End: %d, chunk size: %d\n", start, end, end - start
));
byte[] chunk = new byte[CHUNK_SIZE];
try {
is.skip(start);
is.read(chunk, 0, end - start);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("Content-Range", String.format("%s %d-%d/%d", type, start, end, fileSize));
responseHeaders.set("Accept-Ranges", type);
responseHeaders.set("Content-Length", String.format("%d", CHUNK_SIZE));
responseHeaders.set("Content-Type", "video/mp4");
responseHeaders.set("Connection", "keep-alive");
responseHeaders.set("Content-Transfer-Encoding", "binary");
responseHeaders.set("Cache-Control", "no-cache, no-store");
responseHeaders.set("Expires", "0");
responseHeaders.set("Keep-Alive", "timeout=100000 max=50");
return new ResponseEntity<>(new InputStreamResource(new ByteArrayInputStream(chunk)), responseHeaders, HttpStatus.PARTIAL_CONTENT);
} catch (IOException e) {
return new ResponseEntity<>(new InputStreamResource(new ByteArrayInputStream("error".getBytes())), null, HttpStatus.BAD_REQUEST);
}
}
}
客户端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<video controls width="480">
<source src="http://localhost:8080/video" type="video/mp4">
</video>
</body>
</html>
如果有人解释整个概念,我将不胜感激,因为我认为它在实践中不起作用。理论上,我应该只返回文件的一部分并发送结束范围,以便浏览器知道下一个“开始”是什么。
解决方案
MP4 文件的工作方式与您想象的不同。你不只是从一开始就开始玩。有一个名为“moov box”的“索引”,描述了“mdat box”中数据的布局。moov 框可以位于文件的开头或结尾。在这种情况下,moov 可能位于偏移量 100237312。但是浏览器必须下载文件的开头才能了解 moov 的位置。一旦 moov 完全下载,浏览器就可以计算文件任何开始时间的字节范围偏移量。这就是寻找的工作方式。
推荐阅读
- python - 正则表达式在 python 中没有给出预期的结果
- node.js - 使选择产品和产品价格不是强制性的
- r - 如何在 R 中加速 for 循环/追加到向量
- angular - 如何使用角度 7 将新行添加到 ag 网格的特定索引
- javascript - 如何使用 javascript 从 iframe 小部件获取外汇数据
- sql-server - SSRS FORMAT 函数默认将小数四舍五入为 2
- reactjs - 在 React 中的组件之间发送自定义逻辑事件
- php - zend update 正在删除旧值
- mysql - 如何:插入到值位于另一个表中的列中
- css - 样式 div 使用 flexbox 在两行中对称