我正在开发一个允许用户上传和观看视频的应用程序。 但是我在流式传输视频时遇到了问题。我有两个申请 Angular4中的UI前端,后端中的Spring-boot Rest服务。 我尝试使用HTML 5 Video元素,因为我不希望任何第三方API支持播放视频。 我做了很多关于如何在网站上播放视频的研究,由于很多不同的建议,我每次都感到困惑。我希望有一种正确的方法来在前端流式传输视频。 这是我用来流式传输视频的休息服务的代码。
@Override
public ResponseEntity<InputStreamResource> retrieveResource(String fileId, String range) throws ServiceException {
VideoDetails dto = searchDao.getVideo(fileId);
File file = new File(dto.getFilePath());
long rangeStart = Long.parseLong(range.replace("bytes=", "").split("-")[0]);
long rangeEnd = Long.parseLong(range.replace("bytes=", "").split("-")[0]);
long contentLength = file.length();
return getStream(dto.getFilePath(), rangeStart, rangeEnd, contentLength);
}
private ResponseEntity<InputStreamResource> getStream(String filePath, long rangeStart, long rangeEnd,
long contentLength) throws ServiceException{
try {
InputStream inputStream = FileUtils.openInputStream(new File(filePath));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("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(contentLength - rangeEnd)); //I do not know what to put here
if (rangeStart == 0) {
return new ResponseEntity<>(new InputStreamResource(inputStream), headers, HttpStatus.OK);
} else {
headers.set("Content-Range", String.format("bytes %s-%s/%s", rangeStart, rangeEnd, contentLength));
return new ResponseEntity<>(new InputStreamResource(inputStream), headers, HttpStatus.PARTIAL_CONTENT);
}
} catch (Exception ex) {
throw new ServiceException(
"Unable to find the video resource for the give fileId: [FilePath = " + filePath + "]");
}
}
我在技术博客之一上获得了上述Java代码,而在UI端,我则获得了以下代码,
<div id="playerDiv" *ngIf="content">
<video id="my-video" controls preload="auto" width="640" height="400" controlsList="nodownload" src="http://localhost:8080/searchvideo/watch?fileId=AzxeyYab1">
</video>
</div>
我能够看到视频中流的第一个块,但是video元素不发送获取其余流块的请求。据我所知,视频元素不需要任何额外的代码来进行流传输。请纠正我,如果我错了
任何人都可以在这里帮助我。我想在这里提及一件事。实际上,我对流媒体相关的东西了解甚少。我什至不知道哪个是最好的API,在谷歌搜索后,我对此主题感到非常困惑,以至于我在想我的最后选择。
答案 0 :(得分:0)
好的,最后我得到了一些正确的答案。我将其发布为答案,但我不能接受,因为它仍然存在一些问题,我希望有人在这里为我提供帮助。请查看更改后的代码。
public void retrieveResource(String fileId, String range,HttpServletRequest request, HttpServletResponse response) throws ServiceException {
VideoDetails dto = searchDao.getVideo(fileId);
File file = new File(dto.getFilePath());
long contentLength = file.length();
int chunkSize = 10240 * 10240; //10MB at once
byte[] buffer = new byte[chunkSize];
response.setContentType("video/"+getFileExtension(file));
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "no-cache, no-store");
response.setHeader("Connection", "keep-alive");
response.setHeader("Content-Transfer-Encoding", "binary");
RandomAccessFile input = null;
OutputStream os = null;
if(range == null) {
//TO DO
}else {
try {
os = response.getOutputStream();
input = new RandomAccessFile(file, "r");
} catch (Exception e) {
e.printStackTrace();
};
long rangeStart = Long.parseLong(range.replace("bytes=", "").split("-")[0]);
long rangeEnd = chunkSize + rangeStart;
if (rangeEnd >= contentLength) {
rangeEnd = contentLength - 1;
}
if (range.length() == 2) {
rangeEnd = Long.parseLong(range.replace("bytes=", "").split("-")[1]);
}
try {
input.seek(rangeStart);
} catch (IOException e) {
e.printStackTrace();
}
try {
response.setHeader("Content-Range", String.format("bytes %d-%d/%d", rangeStart, rangeEnd, contentLength));
//response.setHeader("Content-Length",String.valueOf(rangeEnd-rangeStart+1) );
response.setStatus(206);
if(rangeEnd >= contentLength-1) {
input.readFully(buffer, 0, (int)(rangeEnd - rangeStart + 1));
}else {
input.readFully(buffer, 0, chunkSize);
}
os.write(buffer);
// os.flush();
// os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
上面的代码工作正常,我也可以在视频中来回导航,但不知何故,我在导航中遇到以下错误。
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Connection reset by peer
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:344)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:418)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:406)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:97)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:90)
at com.critic.video.service.search.SearchServiceImpl.retrieveResource(SearchServiceImpl.java:174)
at com.critic.video.controller.search.SearchVideoController.retrieveResource(SearchVideoController.java:76)
at com.critic.video.controller.search.SearchVideoController$$FastClassBySpringCGLIB$$58bf0cbb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.critic.video.controller.search.SearchVideoController$$EnhancerBySpringCGLIB$$8506950.retrieveResource(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
但是我的网页仍然可以正常工作。视频仍然继续。任何人都可以在这里帮助我,以摆脱该错误该怎么办。非常感谢您的帮助。