【问题标题】:C# Camera Image Controller, seems to prevent other requestsC# Camera Image Controller,似乎阻止了其他请求
【发布时间】:2021-09-08 14:26:13
【问题描述】:

我从这里获取了一些代码,它们似乎可以通过基本上将 mjpg 依赖于另一个控制器来完成这项工作。 Frame-by-frame MJPEG streaming with C#/ASP.NET MVC

当时这似乎可行,但现在返回代码时却不行。

图像出现并且该部分有效,但它似乎基本上阻止了对 API 的任何其他请求(例如左、右)约 1-3 分钟。这是在 Chrome 和 Edge 中。

在开发人员工具箱中,请求会随着时间/大小不断增加。所以这就像 Chrome 正在等待什么或者我没有发送什么。

想法?

public class CameraController : ApiController
    {
        private MJPEGStream mjpegStream = new MJPEGStream();
        private bool frameAvailable = false;
        private Bitmap frame = null;

        private string BOUNDARY = "frame";
    private WebClient Client { get; set; }

    private string URL { get; set; }

    private string CameraNumber { get; set; }


    /// <summary>
    /// Initializer for the MJPEGstream
    /// </summary>
    CameraController()
    {
        Client = new WebClient { Credentials = new NetworkCredential(ConfigurationManager.AppSettings["WebCamUser"], ConfigurationManager.AppSettings["WebCamPassword"]) };

        URL = ConfigurationManager.AppSettings["WebCamIP"].ToString();

        CameraNumber = ConfigurationManager.AppSettings["WebCameraNumber"].ToString();


        mjpegStream.Source = ConfigurationManager.AppSettings["WebCamIP"].ToString()+@"/mjpg/video.mjpg";
        mjpegStream.ForceBasicAuthentication = true;
        mjpegStream.Login = ConfigurationManager.AppSettings["WebCamUser"];
        mjpegStream.Password = ConfigurationManager.AppSettings["WebCamPassword"];

        mjpegStream.NewFrame += new NewFrameEventHandler(showFrameEvent);
    }

    


    [HttpGet]
    public string Image()
    {
        
        var imageName = DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".jpg";

        //ok
        //just have something here that deletes anything older than 2 mins
        string[] files = Directory.GetFiles(System.Web.Hosting.HostingEnvironment.MapPath("~/Content/Temp/"));

        foreach (string file in files)
        {
            FileInfo fi = new FileInfo(file);
            if (fi.CreationTime < DateTime.Now.AddMinutes(-2))
            {
                fi.Delete();
            }
        }

        var p = Path.Combine(System.Web.Hosting.HostingEnvironment.MapPath("~/Content/Temp/"), imageName);

        Client.DownloadFile(URL + "/axis-cgi/jpg/image.cgi", p);

        return imageName;
    }

    [HttpGet]
    public bool Left()
    {

        var response = Client.DownloadString(URL + "/axis-cgi/com/ptz.cgi?camera=" + CameraNumber + "&move=left");

        return true;
    }

    [HttpGet]
    public bool Right()
    {

        var response = Client.DownloadString(URL + "/axis-cgi/com/ptz.cgi?camera=" + CameraNumber + "&move=right");

        return true;
    }

    [HttpGet]
    public bool Up()
    {

        var response = Client.DownloadString(URL + "/axis-cgi/com/ptz.cgi?camera=" + CameraNumber + "&move=up");

        return true;
    }

    [HttpGet]
    public bool Down()
    {

        var response = Client.DownloadString(URL + "/axis-cgi/com/ptz.cgi?camera=" + CameraNumber + "&move=down");

        return true;
    }

    [HttpGet]
    public bool ZoomIn()
    {

        var response = Client.DownloadString(URL + "/axis-cgi/com/ptz.cgi?camera=" + CameraNumber + "&rzoom=2500");

        return true;
    }

    [HttpGet]
    public bool ZoomOut()
    {

        var response = Client.DownloadString(URL + "/axis-cgi/com/ptz.cgi?camera=" + CameraNumber + "&rzoom=-2500");

        return true;
    }

    [HttpGet]
    public string GetImageVideoFallback()
    {

        var image =  Client.DownloadData(URL + "/axis-cgi/jpg/image.cgi");

        var base64 = Convert.ToBase64String(image);
        var imgSrc = String.Format("data:image/jpg;base64,{0}", base64);

        return imgSrc;
    }


    [HttpGet]
    public HttpResponseMessage GetVideoContent()
    {
        mjpegStream.Start();
        var response = Request.CreateResponse();

        Func<Stream, HttpContent, TransportContext, Task> func = StartStream;

        response.Content = new PushStreamContent(func);
        response.Content.Headers.Remove("Content-Type");
        response.Content.Headers.TryAddWithoutValidation("Content-Type", "multipart/x-mixed-replace;boundary=" + BOUNDARY);
      
        return response;
    }

    /// <summary>
    /// Craete an appropriate header.
    /// </summary>
    /// <param name="length"></param>
    /// <returns></returns>
    private byte[] CreateHeader(int length)
    {
        string header =
            "--" + BOUNDARY + "\r\n" +
            "Content-Type:image/jpeg\r\n" +
            "Content-Length:" + length + "\r\n\r\n";

        return Encoding.UTF8.GetBytes(header);
    }

    public byte[] CreateFooter()
    {
        return Encoding.UTF8.GetBytes("\r\n");
    }

    /// <summary>
    /// Write the given frame to the stream
    /// </summary>
    /// <param name="stream">Stream</param>
    /// <param name="frame">Bitmap format frame</param>
    private async Task WriteFrameAsync(Stream stream, Bitmap frame)
    {
        // prepare image data
        byte[] imageData = null;

        // this is to make sure memory stream is disposed after using
        using (MemoryStream ms = new MemoryStream())
        {
            frame.Save(ms, ImageFormat.Jpeg);
            imageData = ms.ToArray();
        }

        // prepare header
        byte[] header = CreateHeader(imageData.Length);
        // prepare footer
        byte[] footer = CreateFooter();

        // Start writing data
        await stream.WriteAsync(header, 0, header.Length);
        await stream.WriteAsync(imageData, 0, imageData.Length);
        //await stream.WriteAsync(footer, 0, footer.Length);
        await Task.Delay(1000 / 30);
        await stream.FlushAsync();

    }

    /// <summary>
    /// While the MJPEGStream is running and clients are connected,
    /// continue sending frames.
    /// </summary>
    /// <param name="stream">Stream to write to.</param>
    /// <param name="httpContent">The content information</param>
    /// <param name="transportContext"></param>
    private async Task StartStream(Stream stream, HttpContent httpContent, TransportContext transportContext)
    {

        while (mjpegStream.IsRunning && HttpContext.Current.Response.IsClientConnected)
        {
            if (frameAvailable)
            {
                try
                {
                    frameAvailable = false;
                    await WriteFrameAsync(stream, frame);
                    await Task.Delay(1000 / 30);
                }
                catch (Exception) { }
                
            }
            else
            {
                Thread.Sleep(100);
            }
        }
        stopStream();
        stream.Flush();
        stream.Close();
        stream.Dispose();
    }

    /// <summary>
    /// This event is thrown when a new frame is detected by the MJPEGStream
    /// </summary>
    /// <param name="sender">Object that is sending the event</param>
    /// <param name="eventArgs">Data from the event, including the frame</param>
    private void showFrameEvent(object sender, NewFrameEventArgs eventArgs)
    {
        frame = new Bitmap(eventArgs.Frame);
        frameAvailable = true;
    }

    /// <summary>
    /// Stop the stream.
    /// </summary>
    private void stopStream()
    {
        //System.Diagnostics.Debug.WriteLine("Stop stream");
        mjpegStream.Stop();

        
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            stopStream();
            HttpContext.Current.ApplicationInstance.CompleteRequest();

        }

        base.Dispose(disposing);
    }
}

【问题讨论】:

    标签: c# api google-chrome streaming


    【解决方案1】:

    好的,所以链接回让我走上正确道路的问题/答案。 How to stream a mjpeg video on a website

    所以我遇到的问题是我的 API 中需要会话变量(出于安全原因),因此在我的 global.asax 中使用了它。

    protected void Application_PostAuthorizeRequest()
            {
                if (IsWebApiRequest())
                {
                    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
                }
            }
    
            private bool IsWebApiRequest()
            {
                return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
            }
    

    将会话/代码更新为

    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.ReadOnly);
    

    解决了问题,一切又开始工作了。

    【讨论】:

      猜你喜欢
      • 2014-02-03
      • 1970-01-01
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      • 2019-11-29
      • 1970-01-01
      • 1970-01-01
      • 2014-02-10
      相关资源
      最近更新 更多