Records and encodes video to HEVC/MP4 using hardware acceleration, uploads to Azure Blob Storage, detects faces and sends notifications.
- Create Azure Storage account
- Set in configuration
- Run
SecurityCamera.Console.exe
.
Configuration is stored in appsettings.json
or can be added as CLI arguments.
Recording
Video
Format
:"HEVC"
or"MP4"
(default"HEVC"
)Quality
:"HD720p"
,"HD1080p"
,"Uhd2160p"
or any member of VideoEncodingQuality enum (default"HD1080p"
)Bitrate
: the average bit rate of the video stream, in bits per secondFrameRate
: the number of frames per second
Audio
Enabled
: whether to enable audio recording (defaultfalse
)Bitrate
: the average bit rate of the audio stream, in bits per secondBitsPerSample
: the number of bits per audio sample
Recording
ChunkSize
: size of video chunks (default"00:10:00"
)MaximumRecordTime
: maximum of total record time, shut down after that time passed (defaultnull
)
Blobs
ConnectionString
: the connection string for the Storage AccountContainerName
: the name of the container to upload blobs (default"recordings"
)BufferSize
: the size of the buffer to write the blob (defaultnull
, defaults to library default which is4 MiB
)BlobNameFormat
: format used for naming blobs, with argumentDateTimeOffset
at index0
(default"{0:yyyy/MM/dd/HH-mm-ss}.mp4"
)InitialSizeHint
: initial size of Page Blob in bytes (default: 64 MiB)ResizeFactor
: the factor to resize a Page Blob when its size limit is exceeded (default2.0
)
Wake
Enabled
: keep computer from sleep during recording (default:true
)
Alerts
FaceDetection
Enabled
: whether to enable face detection (defaulttrue
)DetectionMode
: any member of FaceDetectionMode enum (default"HighPerformance"
)DesiredDetectionInterval
: the time span for which face detection should be performed (default"00:00:00.500"
)
Sms
ConnectionString
: connection string for Azure Communication ServicesFrom
: from numberTo
: array of to numbers
WebHook
FaceDetectionUrl
: url to callFocusChangeUrl
: url to call
Telemetry
ApplicationInsights
: configure Application Insights
The URL set in WebHook
.FaceDetectionUrl
is invoked with POST
and content type application/json
:
{
"detectedFaces": [
{
"faceBox": {
"X": 123,
"Y": 456,
"Width": 240,
"Height": 240,
}
}
]
}
The URL set in WebHook
.FocusChangeUrl
is invoked with POST
and content type application/json
:
{
"state": "Focused"
}
First, we need to create a MediaEncodingProfile:
var profile = MediaEncodingProfile.CreateHevc(VideoEncodingQuality.HD1080p);
Then, we have to initialize a MediaCapture.
using var capture = new MediaCapture();
await capture.InitializeAsync();
This is where we could select the camera or microphone we would like to use. If we don't specify any, it is going to use the default settings.
The next step is to start and stop recording:
await capture.StartRecordToStreamAsync(profile, stream);
// capture video ...
await capture.StopRecordWithResultAsync();
For photos, there the Windows.Media.FaceAnalysis
namespace contains a FaceDetector class:
var faces = await FaceDetector.DetectFacesAsync(bitmap);
For videos, the FaceTracker is the right choice, as it was optimized to work with VideoFrames:
var faces = await FaceTracker.ProcessNextFrameAsync(videoFrame);
To process a video in real-time and pass VideoFrame
s to the FaceTracker
, we have multiple choices:
- Grab a preview using
GetPreviewFrameAsync
periodically, and pass theVideoFrame
for processing. - Implement a custom sink and process video using
StartRecordToCustomSinkAsync
. - Implement an IBasicVideoEffect and listen to
VideoFrame
s in itsProcessFrame
method.
Video processing and face detection is not easy at all, especially if we want to be efficient as well, even offload some of the work to the GPU. Fortunately, Microsoft has already implemented this functionaly as FaceDetectionEffect, which we can easily add to the MediaCapture
:
var definition = new FaceDetectionEffectDefinition
{
DetectionMode = FaceDetectionMode.HighPerformance,
};
var effect = await capture.AddVideoEffectAsync(definition, MediaStreamType.VideoRecord);
effect.FaceDetected += OnFaceDetected; // subscribe to event
effect.Enabled = true;
We can open a Page Blob or a Block Blob to write as a Stream
, so this way we can transfer the video seamlessly to Azure without buffering to disk or memory:
var container = BlobServiceClient.GetBlobContainerClient(blobsOptions.ContainerName);
var blob = container.GetBlockBlobClient($"{now:yyyy/MM/dd/HH-mm-ss}.mp4");
await using var stream = await blob.OpenWriteAsync(overwrite: false);
In order to use a Stream
in Windows Runtime, we have to it wrap into a IRandomAccessStream :
using var randomAccessStream = stream.AsRandomAccessStream();
Howewer, some media encodings are not streaming compatible, because they require seeking, which is not supported by the Azure Storage library, so the case of streaming is not that straight-forward unfortunately. An implementation which works with Page Blobs, can seek and replace pages of the blob on-demand, can be found in PageBlobRandomAccessStream.
Normally, a device running a Windows Runtime app will dim the display (and eventually turn it off) to save battery life when the user is away, but video apps need to keep the screen on so the user can see the video. The DisplayRequest class lets you tell Windows to keep the display turned on so the recording can continue.
var displayRequest = new DisplayRequest();
displayRequest.RequestActive();
And then release:
displayRequest.RequestRelease();
You can use Azure Communication Services to send SMS:
var client = new SmsClient();
await client.SendAsync(from, to, message);
- Wake:
DisplayRequest
requires STA - Recording: recording is paused while replacing blob chunk
This project is only for learning purposes. The author doesn't take any responsibility for this software. Do not use this solution for real-life use cases.