我需要创建一个流视频的端点。要流式传输的视频来自 Home Assistant 摄像头,采用 HLS 格式。
我尝试了不同的技术,但我无法在浏览器中本地观看视频流,甚至无法使用 html 播放器观看视频流。我看到数据正在传输,我只是不确定它是否是正确的数据。
这是我到目前为止所拥有的:
@Override
public StreamingResponseBody streamVideo(String cameraId) throws Exception {
String url = "http://localhost:8123/api/camera_proxy_stream/camera.back_patio_sub?token=c88e0f18d35004dd9051e477d3c4125894d2fc5db7b820450892d236cd65a603";
log.info("Streaming from: {}", url);
return outputStream -> {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet request = new HttpGet(url);
try (CloseableHttpResponse response = httpClient.execute(request)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
try (InputStream inputStream = entity.getContent()) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
}
}
};
}
@GetMapping(value = "/stream/{cameraId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<StreamingResponseBody> streamVideo(@PathVariable String cameraId) throws Exception {
try {
StreamingResponseBody stream = cameraLiveService.streamVideo(cameraId);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
.header(CONTENT_LENGTH, DEFAULT_CONTENT_LENGHT)
.header(PRAGMA, NO_CACHE)
.header(CACHE_CONTROL, NO_CACHE)
.body(stream);
} catch (AsyncRequestTimeoutException ex) {
//Configurable value for timeout in application.properties:spring.mvc.async.request-timeout
log.error("Timeout streaming video from camera: {}", cameraId, ex);
throw new StreamRequestTimeoutException("Timeout streaming video from camera: " + cameraId, ex);
}
}
如果我将 Home Assistant URL 粘贴到浏览器中,它就会开始播放,没有任何问题,但当我尝试代理它时,我无法实现它。
出于安全原因需要代理,以使用存储的 Home Assistant 长期令牌,但这是唯一的原因。
我也尝试过使用 RestTemplate,但似乎数据没有被传输,CloseableHttpClient 是我所看到的实际做的事情。
此外,“流式传输”数据时似乎不会抛出任何异常。
我在这里缺少什么?
我找到了解决方案。由于我能够看到字节到来,我知道问题出在响应本身,因此我决定保留 Home Assistant(原始提要)中的标头并删除我正在设置的标头。
Header[] headers = response.getAllHeaders();
//Keep the headers from the response.
for (Header header : headers) {
response.setHeader(header.getName(), header.getValue());
}