angular - 流式 RTSP(AspNet 5 API、FFMPEG、Angular 10、videoJs)

标签 angular asp.net-core ffmpeg rtsp video.js

说明 :
我有一个通过 RTSP 连接到 IP 摄像机的 API (ASP.Net 5)。相机发送一个用 ffmpeg 转换为 m3u8 流的 h264 流,该流返回给 angular 客户端,如下所示:

public async Task<ActionResult> GetCameraH264Stream()
{
        string deviceIp = "rtsp://[CAMERA_IP]/";
        string recordingUri = "rtsp://[USER:PASSWORD]@[CAMERA_IP]/axis-media/media.amp";
        
        string output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".m3u8");
        var mediaInfo = await FFmpeg.GetMediaInfo(recordingUri);

        var conversionResult = FFmpeg.Conversions.New()
            .AddStream(mediaInfo.Streams)
            .SetOutput(output)
            .Start();
        
        // Allow any Cors
        Response.Headers.Add("Access-Control-Allow-Origin", "*");
        Response.Headers.Add("Cache-Control", "no-cache");
        
        // Open the file, and read the stream to return to the client
        FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream");
        result.EnableRangeProcessing = true;
        return result;
}
如果我直接调用此方法,浏览器会下载一个文件,我可以使用 VLC 读取该文件。
在我的 Angular 应用程序中,我有这个组件:
应用程序-vjs-播放器 :
@Component({
       selector: 'app-vjs-player',
       template: '<video #target class="video-js" controls muted playsinline preload="none"> 
                  </video>',
       encapsulation: ViewEncapsulation.None,
    })
export class VjsPlayerComponent implements OnInit, OnDestroy {
  @ViewChild('target', {static: true}) target: ElementRef;
  
  @Input() options: {
      fluid: boolean,
      aspectRatio: string,
      autoplay: boolean,
      sources: {
          src: string,
          type: string,
      }[],
      vhs: {
        overrideNative: true
      },
  };
  player: videojs.Player;

  constructor(
    private elementRef: ElementRef,
  ) { }

  ngOnInit() {
    // instantiate Video.js
    this.player = videojs(this.target.nativeElement, this.options, function onPlayerReady() {
      console.log('onPlayerReady', this);
    });
    
  }

  ngOnDestroy() {
    // destroy player
    if (this.player) {
      this.player.dispose();
    }
  }
}

该组件的使用方式如下:
客服 :
playerOptions = {
    fluid: false,
    aspectRatio: "16:9",
      autoplay: false,
      sources: [{
          src: 'https://localhost:44311/api/GetCameraH264Stream',
          type: 'application/x-mpegURL',
      }],
}
HTML :
<app-vjs-player #videoJs [options]="playerOptions"></app-vjs-player>
问题
这一切似乎工作得很好,直到当 api 返回流时 vjs 抛出这个错误:

ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) The media could not be loaded, either because the server or network failed or because the format is not supported


当我打开网络开发工具时,请求状态为“已取消”,但我不知道videojs是否因为无法读取filestreal而取消它,或者是因为API返回流的方式。
任何想法 ?
来源
Forwarding RTSP stream from IP Camera to Browser in ASP.NET Core
VideoJs Angular integration
Xabe.FFMPEG
编辑
  • 我试图限制分辨率和比特率,但我不能这样配置相机,还有其他应用程序在使用它。相机没有任何允许此配置的流 url
  • 更改 api 响应的内容类型后,我已经能够从我的代码中获取图像。我改了:

  • FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream");
    

    FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/x-mpegURL");
    
    这样会显示第一个数据包,但仍会取消下一个请求。

    最佳答案

    响应 ContentType 的更改正在起作用(请参阅问题的最后编辑)。
    取消的请求似乎是由于网络速度慢。上面的所有代码都按原样工作,除了最后一个 modif ( application/octet-stream => application/x-mpegURL )。这是更新的api方法:

    
    public async Task<ActionResult> GetCameraH264Stream()
    {
            string deviceIp = "rtsp://[CAMERA_IP]/";
            string recordingUri = "rtsp://[USER:PASSWORD]@[CAMERA_IP]/axis-media/media.amp";
            
            string output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".m3u8");
            var mediaInfo = await FFmpeg.GetMediaInfo(recordingUri);
    
            var conversionResult = FFmpeg.Conversions.New()
                .AddStream(mediaInfo.Streams)
                .SetOutput(output)
                .Start();
            
            // Allow any Cors
            Response.Headers.Add("Access-Control-Allow-Origin", "*");
            Response.Headers.Add("Cache-Control", "no-cache");
            
            // Open the file, and read the stream to return to the client
            FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/x-mpegURL");
            result.EnableRangeProcessing = true;
            return result;
    }
    
    
    编辑
    似乎上面的代码会在每次发出请求时创建一个 ffmpeg.exe 进程。这个过程永远不会结束,因为这是来自永远不会结束的摄像机的流。我还不知道如何杀死 ffmpeg 进程,但我已经修改了流转换检索,因此它使用现有的 ffmpeg 进程来处理流(如果它已经存在):
    public async Task<ActionResult> GetCameraH264Stream()
    {
            string deviceIp = "rtsp://[CAMERA_IP]/";
            string recordingUri = "rtsp://[USER:PASSWORD]@[CAMERA_IP]/axis-media/media.amp";
    
            
            if (!this.cache.GetCache("camstream").TryGetValue(streamingUri, out object output)) 
            {
                    output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".m3u8");
                    var mediaInfo = await FFmpeg.GetMediaInfo(streamingUri);
                    var conversionResult = FFmpeg.Conversions.New()
                    .AddStream(mediaInfo.Streams)
                    .SetOutput((string) output)
                    .Start();
                    this.cache.GetCache("camstream").Set(streamingUri, output);
    
                    // Delay until the file is created
                    while (!System.IO.File.Exists((string)output))
                    {
                        await Task.Delay(100);
                    }
            }
    
            // Allow any Cors
            Response.Headers.Add("Access-Control-Allow-Origin", "*");
            Response.Headers.Add("Cache-Control", "no-cache");
    
            // Open the file, and read the stream to return to the client
            FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/x-mpegURL");
            result.EnableRangeProcessing = true;
            return result;
    }
    
    
    对于 .ts 文件:
    
    private async Task<ActionResult> GetCameraH264StreamTSFile(string tsFileName)
    {
                string output = Path.Combine(Path.GetTempPath(), tsFileName);
                Response.Headers.Add("Access-Control-Allow-Origin", "*");
                return File(System.IO.File.OpenRead(output), "application/octet-stream", enableRangeProcessing: true);
    }
    
    

    关于angular - 流式 RTSP(AspNet 5 API、FFMPEG、Angular 10、videoJs),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70438730/

    相关文章:

    javascript - Angular react 形式 : Producing an array of checkbox values?

    javascript - 通过 html datalist 和 *ngFor 显示一个值并提交另一个值

    c# - 如何从 SignalR 获取连接客户端的域

    c# - 在 asp.net 核心服务器中处理关闭的 websocket 连接

    c#-4.0 - ffmpeg 水印错误 : video pixel format unknown, Parser not found for codec

    video - 使用 FFMPEG 从视频中更新单个图像

    python - key 错误 : 'video_fps' with moviepy ffmpeg

    路由前的 Angular 动画

    angular - Observable.of 不是具有正确导入的函数

    c# - 无法从 docker 运行 asp.net 5