WPF中来自MemoryStream的图像

时间:2019-07-01 10:41:16

标签: c# wpf mjpeg

我在WinForm中使用MjpegStreamDecoder类

using System;
using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JpegGet {
    class MjpegStreamDecoder {

        const byte picMarker = 0xFF;
        const byte picStart = 0xD8;
        const byte picEnd = 0xD9;

        private CancellationTokenSource cts;

        public string sourceUrl;
        public string login = null;
        public string password = null;

        public int chunkMaxSize = 1024;
        public int frameBufferSize = 1024 * 1024;

        public Action<Image> imageAction;


        public MjpegStreamDecoder() {
            cts = new CancellationTokenSource(); //  Cts.Cancel();
        }






        public async Task Start() {
            using (var cli = new HttpClient()) {

                if (!string.IsNullOrEmpty(login) && !string.IsNullOrEmpty(password)) {
                    cli.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{login}:{password}")));
                }

                using (var stream = await cli.GetStreamAsync(sourceUrl).ConfigureAwait(false)) {
                    var streamBuffer = new byte[chunkMaxSize]; 
                    var frameBuffer = new byte[frameBufferSize]; 
                    var frameIdx = 0; 
                    var inPicture = false; 
                    byte current = 0x00; 
                    byte previous = 0x00; 

                    while (true) {
                        var streamLength = await stream.ReadAsync(streamBuffer, 0, chunkMaxSize, cts.Token).ConfigureAwait(false);
                        parseStreamBuffer(frameBuffer, ref frameIdx, streamLength, streamBuffer, ref inPicture, ref previous, ref current);
                    };
                }
            }
        }





        void parseStreamBuffer(byte[] frameBuffer, ref int frameIdx, int streamLength, byte[] streamBuffer, ref bool inPicture, ref byte previous, ref byte current) {
            var idx = 0;
            while (idx < streamLength) {
                if (inPicture) {
                    parsePicture(frameBuffer, ref frameIdx, ref streamLength, streamBuffer, ref idx, ref inPicture, ref previous, ref current);
                } else {
                    searchPicture(frameBuffer, ref frameIdx, ref streamLength, streamBuffer, ref idx, ref inPicture, ref previous, ref current);
                }
            }
        }





        void searchPicture(byte[] frameBuffer, ref int frameIdx, ref int streamLength, byte[] streamBuffer, ref int idx, ref bool inPicture, ref byte previous, ref byte current) {
            do {
                previous = current;
                current = streamBuffer[idx++];

                if (previous == picMarker && current == picStart) {
                    frameIdx = 2;
                    frameBuffer[0] = picMarker;
                    frameBuffer[1] = picStart;
                    inPicture = true;
                    return;
                }
            } while (idx < streamLength);
        }





        void parsePicture(byte[] frameBuffer, ref int frameIdx, ref int streamLength, byte[] streamBuffer, ref int idx, ref bool inPicture, ref byte previous, ref byte current) {
            do {
                previous = current;
                current = streamBuffer[idx++];
                frameBuffer[frameIdx++] = current;

                if (previous == picMarker && current == picEnd) {
                    Image img = null;

                    using (var stream = new MemoryStream(frameBuffer, 0, frameIdx)) {
                        try {
                            img = Image.FromStream(stream);
                        } catch {

                        }
                    }
                    Task.Run(() => imageAction(img));
                    inPicture = false;
                    return;
                }
            } while (idx < streamLength);
        }
    }
}

在MainForm.cs中:

using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace JpegGet {
    public partial class MainForm : Form {

        readonly SynchronizationContext sync;
        MjpegStreamDecoder streamer;


        public MainForm() {
            InitializeComponent();

            sync = SynchronizationContext.Current;

            streamer = new MjpegStreamDecoder();
            streamer.sourceUrl = "https://webcam1.lpl.org/axis-cgi/mjpg/video.cgi";
            streamer.imageAction = image => {
                sync.Post(new SendOrPostCallback(_ => {
                    pictureBox1.Image = image;
                }), null);
            };

            Task.Run(() => startVideoAsync());
        }



        async Task startVideoAsync() {
            await streamer.Start();
        }
    }
}

此代码可以正常工作,我不知道如何处理WPF。

WPF没有Image.FromStream(),如何绑定图像?

也许有一种更简单的方法来获取MJPEG流,如果可以的话,我将不胜感激,因为我的最终目标是使用xamarin在Android上实现

0 个答案:

没有答案