我在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上实现