Java 如何使用 Spring MVC 返回视频,以便可以使用 html5 <video> 标签进行导航?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20634603/
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
How do I return a video with Spring MVC so that it can be navigated using the html5 <video> tag?
提问by Calabacin
If I have a file in the web server (Tomcat) and create a tag, I can watch the video, pause it, navigate through it, and restart it after it finishes.
如果我在 Web 服务器 (Tomcat) 中有一个文件并创建了一个标签,我就可以观看视频、暂停它、浏览它,并在它完成后重新启动它。
But if I create a REST interface that sends the video file when requested, and add its URL to a tag, I can only play and pause. No rewinding, no fast forward, no navigating, nothing.
但是,如果我创建一个 REST 接口在请求时发送视频文件,并将其 URL 添加到标签,我只能播放和暂停。没有倒带,没有快进,没有导航,什么都没有。
So, is there a way for this to be fixed? Am I missing something somewhere?
那么,有没有办法解决这个问题?我在某处遗漏了什么吗?
Video files are in the same server as the REST interface, and the REST interface only checks session and sends the video after finding out which one it should send.
视频文件和REST接口在同一台服务器上,REST接口只检查会话并在找到应该发送的视频后发送视频。
These are the methods I've tried so far. They all work, but none of them allow navigating.
这些是我迄今为止尝试过的方法。它们都可以工作,但都不允许导航。
Method 1, ResponseEntity:
方法一,ResponseEntity:
/*
* This will actually load the whole video file in a byte array in memory,
* so it's not recommended.
*/
@RequestMapping(value = "/{id}/preview", method = RequestMethod.GET)
@ResponseBody public ResponseEntity<byte[]> getPreview1(@PathVariable("id") String id, HttpServletResponse response) {
ResponseEntity<byte[]> result = null;
try {
String path = repositoryService.findVideoLocationById(id);
Path path = Paths.get(pathString);
byte[] image = Files.readAllBytes(path);
response.setStatus(HttpStatus.OK.value());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentLength(image.length);
result = new ResponseEntity<byte[]>(image, headers, HttpStatus.OK);
} catch (java.nio.file.NoSuchFileException e) {
response.setStatus(HttpStatus.NOT_FOUND.value());
} catch (Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
return result;
}
Method 2, Stream copy:
方法二、Stream复制:
/*
* IOUtils is available in Apache commons io
*/
@RequestMapping(value = "/{id}/preview2", method = RequestMethod.GET)
@ResponseBody public void getPreview2(@PathVariable("id") String id, HttpServletResponse response) {
try {
String path = repositoryService.findVideoLocationById(id);
File file = new File(path)
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename="+file.getName().replace(" ", "_"));
InputStream iStream = new FileInputStream(file);
IOUtils.copy(iStream, response.getOutputStream());
response.flushBuffer();
} catch (java.nio.file.NoSuchFileException e) {
response.setStatus(HttpStatus.NOT_FOUND.value());
} catch (Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
Method 3, FileSystemResource:
方法三、FileSystemResource:
@RequestMapping(value = "/{id}/preview3", method = RequestMethod.GET)
@ResponseBody public FileSystemResource getPreview3(@PathVariable("id") String id, HttpServletResponse response) {
String path = repositoryService.findVideoLocationById(id);
return new FileSystemResource(path);
}
采纳答案by user3395533
The HTTP resume download function might be your friend. I had the same problem before. After implementing http range the navigation in the video was possible:
HTTP 恢复下载功能可能是您的朋友。我以前也遇到过同样的问题。实现 http 范围后,视频中的导航是可能的:
http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html
http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html
回答by Sho
In fact, it is the front end who shows the video controls for the <video> tag.
实际上,显示 <video> 标签的视频控件的是前端。
Each browser for a special video format, has a default control panel.
每个浏览器对于一种特殊的视频格式,都有一个默认的控制面板。
You can use html and css to create your own control with media API. Media api
您可以使用 html 和 css 通过媒体 API 创建您自己的控件。 媒体接口
From Div into HTML5[By default, the <video> element will not expose any sort of player controls. You can create your own controls with plain old HTML, CSS, and JavaScript. The <video> element has methods like play() and pause() and a read/write property called currentTime. There are also read/write volume and muted properties. So you really have everything you need to build your own interface.]
从Div 到 HTML5[默认情况下,<video> 元素不会公开任何类型的播放器控件。您可以使用普通的旧 HTML、CSS 和 JavaScript 创建自己的控件。<video> 元素具有诸如 play() 和 pause() 之类的方法以及名为 currentTime 的读/写属性。还有读/写音量和静音属性。因此,您确实拥有构建自己的界面所需的一切。]
回答by Paul Warren
I know this is an old post but in case it is useful to anyone else out there asking the same/similar questions.
我知道这是一篇旧帖子,但以防万一它对其他提出相同/类似问题的人有用。
Now-a-days there are projects like Spring Contentthat natively support video streaming. All the code you would need for the simplest implementation would be:-
现在有像Spring Content这样的项目本身就支持视频流。最简单的实现所需的所有代码是:-
@StoreRestResource(path="videos")
public interface VideoStore extends Store<String> {}
And this would be enough to create a Java API and a set of REST endpoints that would allow you to PUT/POST, GET and DELETE streams of video. GET support byte ranges and will play properly in HTML5 video players and such like.
这足以创建一个 Java API 和一组 REST 端点,允许您 PUT/POST、GET 和 DELETE 视频流。GET 支持字节范围,可以在 HTML5 视频播放器等中正常播放。
回答by bgraves
A simple solution for handling non-staticresources:
处理非静态资源的简单解决方案:
@SpringBootApplication
public class DemoApplication {
private final static File MP4_FILE = new File("/home/ego/bbb_sunflower_1080p_60fps_normal.mp4");
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Controller
final static class MyController {
@Autowired
private MyResourceHttpRequestHandler handler;
// supports byte-range requests
@GetMapping("/")
public void home(
HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException {
request.setAttribute(MyResourceHttpRequestHandler.ATTR_FILE, MP4_FILE);
handler.handleRequest(request, response);
}
// does not support byte-range requests
@GetMapping(path = "/plain", produces = "video/mp4")
public FileSystemResource plain() {
return new FileSystemResource(MP4_FILE);
}
}
@Component
final static class MyResourceHttpRequestHandler extends ResourceHttpRequestHandler {
private final static String ATTR_FILE = MyResourceHttpRequestHandler.class.getName() + ".file";
@Override
protected Resource getResource(HttpServletRequest request) throws IOException {
final File file = (File) request.getAttribute(ATTR_FILE);
return new FileSystemResource(file);
}
}
}
(inspired by Spring Boots LogFileMvcEndpointand more or less equal to Paul-Warrens (@paul-warren) StoreByteRangeHttpRequestHandlerwhich I found later on).
(受 Spring Boots LogFileMvcEndpoint 的启发,或多或少等于我后来发现的Paul-Warrens (@paul-warren) StoreByteRangeHttpRequestHandler)。
Hopefully this is something which Spring will support in the near future, see https://jira.spring.io/browse/SPR-13834(please vote for it).
希望这是 Spring 在不久的将来会支持的东西,请参阅https://jira.spring.io/browse/SPR-13834(请投赞成票)。
回答by dmalechek
To support Safari, you must handle the range requests and provide the proper 206 return code. https://tools.ietf.org/html/rfc7233
要支持 Safari,您必须处理范围请求并提供正确的 206 返回码。 https://tools.ietf.org/html/rfc7233
https://melgenek.github.io/spring-video-serviceis a Spring example.
https://melgenek.github.io/spring-video-service是一个 Spring 示例。