IPCamAppBar/CameraStream.cs

130 lines
3.6 KiB
C#

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace IPCamAppBar
{
public class FrameEventArgs : EventArgs
{
public Image Image { get; set; }
}
public delegate void FrameEvent(object sender, FrameEventArgs args);
internal abstract class CameraStream : IDisposable
{
public event FrameEvent Frame;
private readonly CancellationTokenSource cancelTaskTokenSource = new CancellationTokenSource();
private Task streamTask;
protected CameraStream()
{
}
public void Start(string url)
{
if (streamTask != null)
throw new InvalidOperationException("CameraStream already started");
streamTask = Task.Run(() => Fetch(url, cancelTaskTokenSource.Token));
}
public void Dispose()
{
cancelTaskTokenSource.Cancel();
streamTask?.Wait();
}
private async Task Fetch(string url, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var uri = new Uri(url);
var request = WebRequest.CreateHttp(uri);
if (!string.IsNullOrEmpty(uri.UserInfo))
{
var parts = uri.UserInfo.Split(':');
request.Credentials = new NetworkCredential(parts[0], parts.Length > 1 ? parts[1] : "");
}
try
{
HttpWebResponse response;
using (cancellationToken.Register(() => request.Abort(), false))
{
response = (HttpWebResponse)await request.GetResponseAsync();
cancellationToken.ThrowIfCancellationRequested();
}
if (response.StatusCode != HttpStatusCode.OK)
throw new WebException(response.StatusDescription);
using (var responseStream = response.GetResponseStream())
{
await ReadFrames(responseStream, cancellationToken);
}
}
catch (TaskCanceledException)
{
}
catch (Exception e)
{
if (cancellationToken.IsCancellationRequested)
break;
// TODO onException
await Task.Delay(5000, cancellationToken);
}
}
}
protected abstract Task ReadFrames(Stream stream, CancellationToken cancellationToken);
protected virtual void OnFrame(FrameEventArgs args)
{
Frame?.Invoke(this, args);
}
}
internal static class BufferExtensions
{
public static int Find(this byte[] buffer, byte[] pattern, int limit = int.MaxValue, int startAt = 0)
{
var patternIndex = 0;
var bufferIndex = 0;
for (bufferIndex = startAt; bufferIndex < buffer.Length && patternIndex < pattern.Length && bufferIndex < limit; bufferIndex++)
{
if (buffer[bufferIndex] == pattern[patternIndex])
{
patternIndex++;
}
else
{
patternIndex = 0;
}
}
if (patternIndex == pattern.Length)
return bufferIndex - pattern.Length;
return -1;
}
}
}