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.
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.
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.
These are the methods I've tried so far. They all work, but none of them allow navigating.
/*
* 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;
}
/*
* 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());
}
}
@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);
}
If you encountered “HTML5 video not found” error while playing a video on any website then it implies your browser doesn't support the HTML5 format codecs or your browser doesn't have the proper video codec installed.
Instead, your @Controllers directly return Java objects, which Spring MVC will conveniently serialize to JSON/XML or any other format that the user requested with the help of HttpMessageConverters.
@RestController is not meant to be used to return views to be resolved. It is supposed to return data which will be written to the body of the response, hence the inclusion of @ResponseBody .
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 on).
Hopefully this is something which Spring will support in the near future, see https://jira.spring.io/browse/SPR-13834 (please vote for it).
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://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With