如果我只是将每个渲染图像发送给大量数据。我只想发送更改的像素。因此,我想利用内置此功能的视频流。
客户端应该能够使用html video标签,并且我需要经常向该视频流添加最新的位图。
我尝试使用.net webapi和PushStreamContent来实现它,但是video标签只是不断加载,并且没有发生错误。
我以一个工作示例作为起点: Frame-by-frame MJPEG streaming with C#/ASP.NET MVC
这样做是正确的方法吗?
[HttpGet]
public HttpResponseMessage GetVideoContent()
{
//myImageFacade.StartImageReading();
var response = Request.CreateResponse();
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)StartStream);
response.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/x-mixed-replace; boundary=" + BOUNDARY);
return response;
}
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.ASCII.GetBytes(header);
}
public byte[] CreateFooter()
{
return Encoding.ASCII.GetBytes("\r\n");
}
private void WriteFrame(Stream stream)
{
// prepare image data
byte[] imageData = null;
var aNewFrame = GetDummyBitmap();
System.Drawing.Bitmap bmp;
using (MemoryStream outStream = new MemoryStream())
{
JpegBitmapEncoder enc = new JpegBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create((BitmapSource)aNewFrame));
enc.Save(outStream);
bmp = new System.Drawing.Bitmap(outStream);
imageData = outStream.ToArray();
}
// prepare header
byte[] header = CreateHeader(imageData.Length);
// prepare footer
byte[] footer = CreateFooter();
// Start writing data
stream.Write(header, 0, header.Length);
stream.Write(imageData, 0, imageData.Length);
stream.Write(footer, 0, footer.Length);
}
private WriteableBitmap GetDummyBitmap()
{
string aDummyJpegMini = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAXABUDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9JKKKKD+mAooooAKKKKACiiigD//Z";
byte[] theByteData = Convert.FromBase64String(aDummyJpegMini);
try
{
var aBitmap = new Bitmap(21, 24, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
var aBitmapData = aBitmap.LockBits(new Rectangle(0, 0, aBitmap.Width, aBitmap.Height), ImageLockMode.WriteOnly, aBitmap.PixelFormat);
Marshal.Copy(theByteData, 0, aBitmapData.Scan0, theByteData.Length);
aBitmap.UnlockBits(aBitmapData);
var aData = aBitmapData;
WriteableBitmap aBmp = new WriteableBitmap(
aData.Width,
aData.Height,
96,
96,
PixelFormats.Bgr24,
null);
int aLen = aData.Height * aData.Stride;
aBmp.WritePixels(new Int32Rect(0, 0, aData.Width, aData.Height), aData.Scan0, aLen, aData.Stride, 0, 0);
return aBmp;
}
catch (Win32Exception ex)
{
}
catch (Exception ex)
{
}
return null;
}