IPCamAppBar/IPCamLib/Base/BaseHTTPStreamCamera.cs

74 lines
2.5 KiB
C#

using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace IPCamLib.Base
{
/// <summary>
/// Abstract base class for IP cameras reading an HTTP stream.
/// </summary>
public abstract class BaseHTTPStreamCamera : ICamera
{
private readonly Uri streamUri;
/// <param name="streamUri">The URI to the camera stream.
/// Can include basic credentials in the standard 'username:password@' format.</param>
protected BaseHTTPStreamCamera(Uri streamUri)
{
this.streamUri = streamUri;
}
/// <inheritdoc />
public async Task Fetch(ICameraObserver observer, CancellationToken cancellationToken)
{
var request = WebRequest.CreateHttp(streamUri);
if (!string.IsNullOrEmpty(streamUri.UserInfo))
{
var parts = streamUri.UserInfo.Split(':');
request.Credentials = new NetworkCredential(parts[0], parts.Length > 1 ? parts[1] : "");
}
request.ReadWriteTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;
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(observer, responseStream, cancellationToken);
}
catch (TaskCanceledException)
{
}
finally
{
request.Abort();
}
}
/// <summary>
/// Implement in concrete descendants to continuously read frames from the HTTP stream.
/// </summary>
/// <param name="observer">The observer implementation passed to Fetch which should receive the decoded frames.</param>
/// <param name="stream">The HTTP response stream.</param>
/// <param name="cancellationToken">Stop reading frames when this token is cancelled.</param>
protected abstract Task ReadFrames(ICameraObserver observer, Stream stream, CancellationToken cancellationToken);
}
}