WebAPI PushStreamContent 客户端读取视频流
WebAPI PushStreamContent client read video stream
我有一个通过 webapi 公开的相机。此相机 returns jpeg 帧。在服务器端,我使用以下方法:
[Route("api/v1/camera/live/stream")]
[HttpGet]
public HttpResponseMessage GetStream()
{
logger.Trace($"GET api/v1/camera/live/stream called");
var response = Request.CreateResponse(HttpStatusCode.PartialContent);
response.Content = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(async (stream, content, tansportContext) =>
{
EventHandler<AcquiredDataEventArgs<CameraFrame>> handler = (_, __) => { };
try
{
MjpegWriter writer = new MjpegWriter(stream);
handler = (s, e) => writer.Write(e.Data.Image.GetJpegStream());
camera.DataAcquired += handler;
while (HttpContext.Current.Response.IsClientConnected)
{
await Task.Delay(100);
}
camera.DataAcquired -= handler;
}
catch (Exception ex)
{
logger.Error($"Streaming error", ex);
throw;
}
logger.Trace("streaming ended");
}));
response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/x-mixed-replace; boundary=--boundary");
return response;
}
我想在 WPF 应用程序中实时显示此视频流。
如果我通过网络浏览器打开视频流,它会很好地流式传输视频...但是我如何流式传输到 c# 客户端应用程序?
您可以为此使用 HttpClient。只需确保不通过设置 HttpCompletionOption.ResponseHeadersRead
.
来缓冲响应
using (var httpClient = new HttpClient())
using (var response = await httpClient.GetAsync("http://...",
HttpCompletionOption.ResponseHeadersRead))
using (Stream stream = await response.Content.ReadAsStreamAsync())
{
// Do whatever with the resulting stream.
}
Lib(可通过 nuget 获得)Emgu.CV 是 OpenCV 上的 C# 包装器,可以接收流。
using Emgu.CV;
...
private void StartWatching()
{
Task.Run(() =>
{
try
{
capture = new VideoCapture(headConfiguration.CameraStreamingUri.ToString());
capture.ImageGrabbed += Capture_ImageGrabbed;
capture.Start(ExceptionHandler.AlwaysHandle);
}
catch (Exception ex)
{
capture = null;
Logger.Error(ex);
throw ex;
}
});
}
private void Capture_ImageGrabbed(object sender, EventArgs e)
{
if (capture == null || OnNewCameraFrame == null)
{
return;
}
try
{
var frame = new Mat();
if (capture.Retrieve(frame))
{
var output = new ByteImage(frame.Width, frame.Height, frame.Step);
Marshal.Copy(frame.DataPointer, output.Data, 0, output.Height * output.Stride);
OnNewCameraFrame?.Invoke(this, new ValueChangeArgs<ByteImage>(output));
}
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
我有一个通过 webapi 公开的相机。此相机 returns jpeg 帧。在服务器端,我使用以下方法:
[Route("api/v1/camera/live/stream")]
[HttpGet]
public HttpResponseMessage GetStream()
{
logger.Trace($"GET api/v1/camera/live/stream called");
var response = Request.CreateResponse(HttpStatusCode.PartialContent);
response.Content = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(async (stream, content, tansportContext) =>
{
EventHandler<AcquiredDataEventArgs<CameraFrame>> handler = (_, __) => { };
try
{
MjpegWriter writer = new MjpegWriter(stream);
handler = (s, e) => writer.Write(e.Data.Image.GetJpegStream());
camera.DataAcquired += handler;
while (HttpContext.Current.Response.IsClientConnected)
{
await Task.Delay(100);
}
camera.DataAcquired -= handler;
}
catch (Exception ex)
{
logger.Error($"Streaming error", ex);
throw;
}
logger.Trace("streaming ended");
}));
response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/x-mixed-replace; boundary=--boundary");
return response;
}
我想在 WPF 应用程序中实时显示此视频流。 如果我通过网络浏览器打开视频流,它会很好地流式传输视频...但是我如何流式传输到 c# 客户端应用程序?
您可以为此使用 HttpClient。只需确保不通过设置 HttpCompletionOption.ResponseHeadersRead
.
using (var httpClient = new HttpClient())
using (var response = await httpClient.GetAsync("http://...",
HttpCompletionOption.ResponseHeadersRead))
using (Stream stream = await response.Content.ReadAsStreamAsync())
{
// Do whatever with the resulting stream.
}
Lib(可通过 nuget 获得)Emgu.CV 是 OpenCV 上的 C# 包装器,可以接收流。
using Emgu.CV;
...
private void StartWatching()
{
Task.Run(() =>
{
try
{
capture = new VideoCapture(headConfiguration.CameraStreamingUri.ToString());
capture.ImageGrabbed += Capture_ImageGrabbed;
capture.Start(ExceptionHandler.AlwaysHandle);
}
catch (Exception ex)
{
capture = null;
Logger.Error(ex);
throw ex;
}
});
}
private void Capture_ImageGrabbed(object sender, EventArgs e)
{
if (capture == null || OnNewCameraFrame == null)
{
return;
}
try
{
var frame = new Mat();
if (capture.Retrieve(frame))
{
var output = new ByteImage(frame.Width, frame.Height, frame.Step);
Marshal.Copy(frame.DataPointer, output.Data, 0, output.Height * output.Stride);
OnNewCameraFrame?.Invoke(this, new ValueChangeArgs<ByteImage>(output));
}
}
catch (Exception ex)
{
Logger.Error(ex);
}
}