首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >流式RTSP (AspNet 5 API,FFMPEG,角10,视频10)

流式RTSP (AspNet 5 API,FFMPEG,角10,视频10)
EN

Stack Overflow用户
提问于 2021-12-21 16:36:42
回答 1查看 1.1K关注 0票数 1

描述

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

代码语言:javascript
运行
复制
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读取该文件。

在我的角度应用程序中,我有这样的组件:

app-vjs-player

代码语言:javascript
运行
复制
@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();
    }
  }
}

此组件的使用方式如下:

TS

代码语言:javascript
运行
复制
playerOptions = {
    fluid: false,
    aspectRatio: "16:9",
      autoplay: false,
      sources: [{
          src: 'https://localhost:44311/api/GetCameraH264Stream',
          type: 'application/x-mpegURL',
      }],
}

代码语言:javascript
运行
复制
<app-vjs-player #videoJs [options]="playerOptions"></app-vjs-player>

问题

所有这些似乎都很好,直到api返回流时vjs抛出此错误为止:

错误:(代码:4 MEDIA_ERR_SRC_NOT_SUPPORTED)无法加载媒体,原因是服务器或网络失败或格式不受支持。

当我打开network工具时,请求状态被“取消”,但是我不知道视频is是否因为文件无法读取而取消它,或者是因为API返回流的方式。

知道吗?

在ASP.NET核中将RTSP流从IP摄像机转发到浏览器

视频角积分

Xabe.FFMPEG

编辑

  • 我试图限制分辨率和比特率,但我不能像这样配置相机,还有其他应用程序在使用它。相机没有允许这种配置的任何流url。
  • 在更改api响应的内容类型后,我能够从代码中获得图像。我改变了:
代码语言:javascript
运行
复制
FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream");

代码语言:javascript
运行
复制
FileStreamResult result = new FileStreamResult(System.IO.File.Open(output, FileMode.Open, FileAccess.Read, FileShare.Read), "application/x-mpegURL");

这样就会显示第一个数据包,但是下一个请求仍然会被取消。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-22 13:19:21

对响应ContentType的更改正在起作用(请参阅最后一次问题编辑)。

似乎取消的请求是由缓慢的网络触发的。除最后一个修饰符(application/octet => application/x )外,上述所有代码都正常工作。下面是更新的api方法:

代码语言:javascript
运行
复制
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进程:

代码语言:javascript
运行
复制
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文件:

代码语言:javascript
运行
复制
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);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70438730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档