当前位置: 首页 > 知识库问答 >
问题:

如何通过Spring Webserver将HTTP视频流代理到任何数量的客户端

汪阿苏
2023-03-14

假设我有一个视频HTTP流在与Spring Web服务器位于同一网络的服务器上广播,例如在一些url中,例如:

http://localhost:9090/httpstream

如何使用Spring将此视频流代理给任意数量的客户端?以下示例演示了想要的流程:

  1. Spring Web服务器可在以下位置找到:http://localhost:9091/spring

这是必需的,因为HTTPStream是一个不安全且未经身份验证的主机,我想把它包装成一个Spring Web服务器,这样我就可以使用某种形式的安全性,比如基本身份验证

我试图请求某种形式的映射,但我找不到要返回的对象类型,也找不到如何建立连接,但预期的行为应该是这样的:

@Controller
public class HttpStreamProxyController {

    @RequestMapping("/spring") {
    public /*Stream Object?*/ getSecuredHttpStream() {
       if (clientIsSecured) {
       //... Security information

       return   //What should be returned?
       }
   }
}

共有3个答案

储修谨
2023-03-14

在Spring Boot应用程序中进行视频流传输的一种好方法(不过,我使用了另一个来源——USB摄像头):

@GetMapping(value = "/stream")
public ResponseEntity<StreamingResponseBody> stream() {
    StreamingResponseBody stream = outputStream -> {
        while (streaming.get()) {
            final var raw = streamImage.get();
            final var jpeg = convert(byte2Buffered(raw.getImageData(), raw.getImageWidth(), raw.getImageHeight()));
            outputStream.write(jpeg);
        }
        outputStream.flush();
    };
    final var headers = new HttpHeaders();
    headers.add("Access-Control-Allow-Origin", "*");
    headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
    headers.add("Content-Type", "multipart/x-mixed-replace;boundary=frame");
    headers.add("Expires", "0");
    headers.add("Pragma", "no-cache");
    headers.add("Max-Age", "0");
    return ResponseEntity.ok()
            .headers(headers)
            .body(stream);
}

这样,您将在URLendpoint上获得一个流,您可以使用img超文本标记语言标记将其嵌入到网页中。

池宸
2023-03-14

我为同样的问题挣扎了几天,试图将我的节点应用程序迁移到Spring/React。我正在使用一个运行Motion的覆盆子pi,它充当一个远程流服务器,我以前可以使用节点模块mjpeg-代理来轻松地按照OP的意愿进行代理。这个线程是我Java搜索中最有用的一组例子,但是没有一个例子对我很有用。我希望我的控制器类和组件能帮助其他尝试同样方法的人。

请注意response.setContentType("Multipart/x-混合-替换;边界=BoundaryString");因为边界=BoundaryString部分是最后一个关键部分。我打开了chrome调试器,同时直接连接到流,这是在响应头中-当我复制它时,突然一切都正常了!


import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.net.URI;

@RestController
@RequestMapping(value = "/video")
public class VideoController {

    Logger log = LoggerFactory.getLogger(VideoController.class);

    @RequestMapping("/oculus")
    public void oculus(HttpServletResponse response) {
        log.info("Calling /video/oculus...");
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.execute(
                URI.create("http://oculus:8081"),
                HttpMethod.GET,
                (ClientHttpRequest request) -> {},
                responseExtractor -> {
                    response.setContentType("multipart/x-mixed-replace; boundary=BoundaryString");
                    IOUtils.copy(responseExtractor.getBody(), response.getOutputStream());
                    return null;
                }
        );
    }

    @RequestMapping("/door")
    public void door(HttpServletResponse response) {
        log.info("Calling /video/door...");

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.execute(
                URI.create("http://vox:9002"),
                HttpMethod.GET,
                clientHttpRequest -> {
                    clientHttpRequest.getHeaders().add(HttpHeaders.AUTHORIZATION, "Basic blahblahBase64encodedUserAndPass=");
                },
                responseExtractor -> {
                    response.setContentType("multipart/x-mixed-replace; boundary=BoundaryString");
                    IOUtils.copy(responseExtractor.getBody(), response.getOutputStream());
                    return null;
                }
        );
    }

}

我已经包括了使用Motion的basic auth以及不受保护的流的示例。

这两个流都可以在我的应用程序上使用以下代码


class Video extends React.Component{
    render() {
        return (
            <div className="Content">
                <p>
                    <img className="stream" src="/video/oculus"/>
                </p>
                <p>
                    <img className="stream" src="/video/door"/>
                </p>
            </div>
        );
    }
}

export default Video;```
曹泉
2023-03-14

我不确定您正在使用哪种来源生成视频流(实时摄像头、视频文件或youtube视频或..)

您可能可以使用StreamingResponseBody(需要Spring 4.2)。请参考以下链接

http://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/streaming-response-body/

http://shazsterblog.blogspot.in/2016/02/asynchronous-streaming-request.html

试试这个-

    @GetMapping("/stream1")
        @ResponseBody
        public StreamingResponseBody getVidoeStream1(@RequestParam String any) throws IOException {
            /* do security check before connecting to stream hosting server */ 
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<Resource> responseEntity = restTemplate.exchange( "http://localhost:8080/stream", HttpMethod.GET, null, Resource.class );
            InputStream st = responseEntity.getBody().getInputStream();
            return (os) -> {
                readAndWrite(st, os);
            };


    }

private void readAndWrite(final InputStream is, OutputStream os)
            throws IOException {
        byte[] data = new byte[2048];
        int read = 0;
        while ((read = is.read(data)) > 0) {
            os.write(data, 0, read);
        }
        os.flush();
    }

应该行得通。您可以根据需要编写自己的readAndWrite()实现。

所以,你的Spring代理控制器可能是这样的...

@Controller
public class HttpStreamProxyController {

    @RequestMapping("/spring") 
    @ResponseBody
    public StreamingResponseBody  getSecuredHttpStream() {
       if (clientIsSecured) {
       //... Security information

    RestTemplate restTemplate = new RestTemplate();
    // get video stream by connecting to stream hosting server  like this
            ResponseEntity<Resource> responseEntity = restTemplate.exchange( "https://ur-to-stream", HttpMethod.GET, null, Resource.class );
            InputStream st = responseEntity.getBody().getInputStream();
    // Or if there is any other preferred way of getting the video stream use that. The idea is to get the video input stream    

    // now return a StreamingResponseBody  object created by following lambda 
            return (os) -> {
                readAndWrite(st, os);
            };

       } else {
          return null;
       }

   }
}

restendpoint返回的StreamingResponseBody在HTML5中可以正常工作,它可能类似于。。

<video width="320" height="240" controls>
  <source src="/spring" type="video/mp4">
  Your browser does not support the video tag
</video>
 类似资料:
  • 我正在尝试基于Apache示例和FTPSClient类,使用Apache Commons网络库开发Java FTPS客户端。要运行de代码,我使用Java8,更新45。 当我调用“retrieveFile”方法时,会发生异常。我不确定,但我相信用于传输文件的连接没有使用上面指定的HTTP代理。 使用FileZilla客户端,我可以使用相同的配置传输文件。 我如何解决这个问题? 我的代码: 输出:

  • 我编写了一个SOCKS代理,如果关闭链接,它可以同时处理HTTP和HTTPS流量。 如果链接已打开并且转发主机和端口属于过滤HTTP代理,则只有HTTP流量可以流动。HTTPS流量不流动并报告SSL错误。 请注意,当请求直接来自浏览器而不是SOCKS服务器时,HTTP代理会处理HTTPS流量。 例如,如果我向https://www.google.com出现以下情况: 1)客户端发送SOCKS 5问

  • 我想实现如下内容: 使用RTSP从IP-Camera读取视频流(已完成) 使用OpenCV处理图像(已完成) 将图像发送到浏览器以显示(这是问题所在) 第三部分利用RTSP协议将图像作为视频流发送。 注意:服务器端使用的语言是Java(OpenCV也在Java中),服务器是Tomcat。 如果有人认为用RTSP来实现不是更好,那么最好的方法是什么来实现这个功能,因为RTSP对于视频流来说是特殊的,

  • 现在,我正在Amazon Kinesis视频流的客户端工作,使用Video.js和HTTP Streaming来显示视频。 然而,在stream server上,每个片段都有一些元数据(仅限文本)(如以下链接:https://aws.amazon.com/about-aws/whats-new/2018/10/kinesis-video-streams-fragment-level-metadat

  • 问题内容: 我真的很想了解使用node.js将ffmpeg实时输出流到HTML5客户端的最佳方法,因为有很多变量在起作用,而且我在这个领域没有很多经验,花了很多小时尝试不同的组合。 我的用例是: 1)IP摄像机RTSP H.264流由FFMPEG采集,并使用节点中的以下FFMPEG设置重新混合到mp4容器中,并输出到STDOUT。这仅在初始客户端连接上运行,因此部分内容请求不会尝试再次产生FFMP

  • 我真的很难理解使用Node.js将ffmpeg的实时输出流到HTML5客户端的最佳方法,因为有很多变量在起作用,而我在这方面没有太多经验,我花了很多时间尝试不同的组合。 我的用例是: 1)IP视频摄像机RTSP H.264流由FFMPEG拾取,并使用节点中的以下FFMPEG设置重新多路复用到mp4容器中,输出到stdout。这只在初始客户端连接上运行,以便部分内容请求不会再次尝试生成FFMPEG。