How to return a video using Spring MVC so that it can be moved using the html5 <video> tag?

If I have a file on a web server (Tomcat) and create a tag, I can watch the video, pause it, move around it and restart it after it is complete.

But if I create a REST interface that sends a video file on demand and adds its URL to the tag, I can play and pause. No fast forward, no fast forward, no navigation , nothing.

So, is there a way to fix this? Am I missing something?

The video files are located on the same server as the REST interface , and the REST interface only checks the session and sends the video after finding out which one it should send.

These are the methods that I have tried so far. They all work, but not one of them allows navigation.

Method 1, ResponseEntity:

/* * This will actually load the whole video file in a byte array in memory, * so it 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:

 /* * 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:

 @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); } 
+15
java spring rest html5 video
Dec 17 '13 at 12:48
source share
4 answers

The HTTP resume download feature may be your friend. I used to have the same problem. After introducing the HTTP range, you can now navigate through the video:

http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html

+3
Mar 08 '14 at 8:17
source share
— -

A simple solution for handling non - static resources :

 @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 LogFileMvcEndpoint and more or less equal to Paul-Warrens (@ paul-warren) StoreByteRangeHttpRequestHandler , which I found later).

Hopefully this is what Spring will support in the near future, see https://jira.spring.io/browse/SPR-13834 (vote for it).

+5
Aug 20 '17 at 19:14
source share

I know this is an old post, but in case it is useful to someone else by asking the same / similar questions.

There are currently projects like Spring Content that supports streaming video. All the code that you will need for the simplest implementation will be: -

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

And that would be enough to create a Java API and a set of REST endpoints that will allow you to stream PUT / POST, GET and DELETE videos. GET supports byte ranges and will play correctly in an HTML5 video player, etc.

+2
Jul 18 '17 at 15:24
source share

In fact, the front end shows the video controls for the <video> tag.

Each browser for a special video format has a default control panel.

You can use html and css to create your own control with the media API. Media api

From Div to HTML5 [By default, the <video> element will not expose any player controls. You can create your own controls using plain old HTML, CSS, and JavaScript. The <video> element has methods such as play () and pause (), and a read / write property called currentTime. There are also read / write volume and disabled properties. That way, you really have everything you need to create your own interface.]

0
Dec 17 '13 at 13:07 on
source share



All Articles