将视频帧转换为流式视频

Posted

技术标签:

【中文标题】将视频帧转换为流式视频【英文标题】:turn video frames to streaming video 【发布时间】:2018-08-20 16:41:38 【问题描述】:

服务器正在发送视频帧。我想使用它们来进行流式传输。我想知道如何组装帧来创建流媒体视频。到目前为止,我可以将帧显示为图片。下面是我的角度代码

组件角度

 getVideo() 
    interval(250).switchMap(() => this.appService.getPictures())
      .subscribe(data => 
        const file = new Blob([data], type:'image/png');
        this.url = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(file));
      )
  

模板 html

<img div="test" [src]="url"  />

我正在尝试使用相机的帧速率更改图片。但是我的图片没有更新,由于 http 请求的数量很大,它冻结了我的浏览器。

我想要实现的是缓冲帧以便使用 video 标签而不是 img 标签,就像我使用 video 标签连接到服务器发送的实时流一样src 设置为服务器的url

Github 链接:https://github.com/kedevked/frameProcessing

【问题讨论】:

为什么不只渲染视频呢?而不是返回帧图像? 因为服务器发送的是图片,而不是视频。 &lt;video src ="url" &gt;&lt;/video&gt; 不会显示任何内容 我不认为它会那样工作。它会很慢并且会消耗大量带宽。也许尝试降低帧率。让另一台服务器读取这些帧并将它们转换回视频是一种选择吗? 我不能考虑使用另一台服务器进行处理 @edkeveked,很有趣。能否提供api返回图片或者更好的示例项目给github? 【参考方案1】:

与其以一定的时间间隔触发http请求,不如使用websocket。

通过逐帧显示图像,它给人一种现场视频的印象。唯一的问题是网络中可能存在延迟,这使得帧速率不是恒定的。但是,它适用于无法考虑缓冲视频服务器端的用例,例如当我们需要沿每一帧发送数据时。

使用 websocket 服务

createStream(url) 
  this.ws = webSocket<any>(url);
  return return this.ws.asObservable()

组件

constructor (private streamingService: StreamingService) 
ngOnInit(): void  
  this.getStream()


getStream() 
  this.streamingService.createStream().subscribe(data => 
    const file = new Blob([data], type:'image/png');
        this.url = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(file));
 )

当我们不仅要发送图像,还要沿图像发送数据时,此解决方案非常适合。在这种情况下,图像需要以 base64 格式发送。

getStream() 
      this.streamingService.createStream().subscribe(data => 
            this.url = data.base64ImageData
     )
    

由于 base64 编码的有效负载是初始图像的 133%,因此在所有设置中使用它可能成本很高。如果图像需要与其他数据一起提供,则可以将整个数据作为二进制发送。这将需要在服务器端对数据进行编码并在客户端对其进行解码。 由于这可能需要一些计算,因此可以考虑使用 web-worker 不仅可以解码数据,还可以显示图像。

如果图片以二进制形式发送,使用canvas进行渲染会更快

canvas.getContex('2d').putImageData(imageBinaryData, 0, 0)

【讨论】:

base64 不会增加 133%,而不是 1.33%? 感谢您发现错误,我编辑了答案【参考方案2】:

我在这里看到两个问题,这可能会改进此解决方案。

首先,你怎么知道请求会花费不到 250 毫秒?如果没有,你知道 switchMap 会取消它吗?如果您不想丢失当前的请求,也许 exhaustMapconcatMap 更适合。

第二点是间隔(X)和HTTP请求在角度区域内,所以它们会触发变化检测......这可能会给您带来几个性能问题。因此,您应该在区域外运行间隔和请求并手动检测更改

说我会设计一个这样的解决方案:

private subscription: Subscription;
cosntructor(public ngZone: NgZone, public cd: ChangeDetectorRef)
   getVideo();


getVideo() 
    this.subscription = this.ngZone.runOutsideAngular(() => 
         interval(250).pipe(exhaustMap(() => this.appService.getPictures()))
           .subscribe(data => 
              const file = new Blob([data], type:'image/png');
              this.url = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(file));
              // Do change detection in orther to actualize [url] binding
              this.cd.detectChanges();
           )
    );

ngOnDestroy() 
    // remember to unsubscribe from interval subscription
    this.subscription.unsubscribe()

我认为使用此代码不会有很多性能问题...尽管这种类型的长轮询从来都不是很好,但我认为它不会冻结您的应用程序。试试看,然后告诉我。

希望这会有所帮助。

【讨论】:

我真正想做的是缓冲帧,以便拥有可以在video 标签中使用的视频。 嗨@edkeveked,鉴于您的情况,首选的解决方案是使用图像标签,您不能缓冲 getPictures() 等并将其转换为视频格式,尽管它没有意义。如果您想这样做,只需更改您的服务并设置一些 WebRTC 连接或提供视频内容的 sov。是我的推荐。虽然,试试我的解决方案,它可能会很好。 代码抛出此错误:interval().concatMap() is not a function。您能否提供一个使用 WebRTC 时的工作示例,我们可以从服务器而不是设备摄像头获取帧,然后将其转换为视频? @edkeveked 抱歉,我忘记了管道操作员。我不能给你举个例子,太多了。这意味着服务器端、客户端等方面的变化...查看 kurento kurento.org,他们有很好的文档和已经完成的代码,以便在服务器和客户端上使用 webRTC。

以上是关于将视频帧转换为流式视频的主要内容,如果未能解决你的问题,请参考以下文章

ffmpeg

从rtsp流式传输视频,帧速率为1 fps

快进和快退

matlab将视频帧转换成灰度图程序解释

将实时视频帧转换为灰度 (OpenCV)

如何将 WPF 表单的内容(作为帧)流式传输到 AVI 文件?