I am trying to create a UWP application that uses the laptop's webcam to process mediaframes on which I want to search faces using Microsoft Azure Face API.
I created a MediaCapture that works well, and a MediaFrameReader, which throws the exception mentioned in the question's title.
You can see my code here:
private async void StartDetection()
{
mediaStream = new InMemoryRandomAccessStream();
MediaEncodingProfile encodingProfile = MediaEncodingProfile.CreateMp4(encodingQuality);
await mediaCapture.StartRecordToStreamAsync(encodingProfile, mediaStream);
var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
MediaFrameSourceGroup selectedGroup = null;
MediaFrameSourceInfo colorSourceInfo = null;
foreach (var sourceGroup in frameSourceGroups)
{
foreach (var sourceInfo in sourceGroup.SourceInfos)
{
if (sourceInfo.MediaStreamType == MediaStreamType.VideoRecord
&& sourceInfo.SourceKind == MediaFrameSourceKind.Color)
{
colorSourceInfo = sourceInfo;
break;
}
}
if (colorSourceInfo != null)
{
selectedGroup = sourceGroup;
break;
}
}
var selectedGroupObjects = frameSourceGroups.Select(group =>
new
{
sourceGroup = group,
colorSourceInfo = group.SourceInfos.FirstOrDefault((sourceInfo) =>
{
// On Xbox/Kinect, omit the MediaStreamType and EnclosureLocation tests
return sourceInfo.MediaStreamType == MediaStreamType.VideoRecord
&& sourceInfo.SourceKind == MediaFrameSourceKind.Color
&& sourceInfo.DeviceInformation?.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front;
})
}).Where(t => t.colorSourceInfo != null).FirstOrDefault();
selectedGroup = selectedGroupObjects?.sourceGroup;
colorSourceInfo = selectedGroupObjects?.colorSourceInfo;
if (selectedGroup == null)
{
return;
}
var allGroups = await MediaFrameSourceGroup.FindAllAsync();
var eligibleGroups = allGroups.Select(g => new
{
Group = g,
SourceInfos = new MediaFrameSourceInfo[]
{
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Color),
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Depth),
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Infrared),
}
}).Where(g => g.SourceInfos.Any(info => info != null)).ToList();
if (eligibleGroups.Count == 0)
{
System.Diagnostics.Debug.WriteLine("No source group with color, depth or infrared found.");
return;
}
var selectedGroupIndex = 0;
selectedGroup = eligibleGroups[selectedGroupIndex].Group;
colorSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[0];
MediaFrameSourceInfo infraredSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[1];
MediaFrameSourceInfo depthSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[2];
var colorFrameSource = mediaCapture.FrameSources[colorSourceInfo.Id];
var preferredFormat = colorFrameSource.SupportedFormats.Where(format =>
{
return format.VideoFormat.Width >= 1080
&& format.Subtype == "RGB24";
}).FirstOrDefault();
if (preferredFormat == null)
{
return;
}
await colorFrameSource.SetFormatAsync(preferredFormat);
MediaFrameReader mediaFrameReader;
mediaFrameReader = await mediaCapture.CreateFrameReaderAsync(colorFrameSource, preferredFormat.Subtype);
mediaFrameReader.FrameArrived += CheckFrameForFaces;
await mediaFrameReader.StartAsync();
}
private async void CheckFrameForFaces(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
var mediaFrame = sender.TryAcquireLatestFrame(); // -> this is the line that throws the exception
var videoFrame = mediaFrame?.VideoMediaFrame;
var bitmap = videoFrame?.SoftwareBitmap;
WriteableBitmap wb = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight);
bitmap.CopyToBuffer(wb.PixelBuffer);
var img = Dlib.LoadImageData<RgbPixel>(wb.PixelBuffer.ToArray(), (uint)wb.PixelHeight, (uint)wb.PixelWidth, 3);
ImageWindow im = new ImageWindow(img);
im.WaitUntilClosed();
}
This code by the way is written based on the Microsoft documentation, which can be found here: https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/process-media-frames-with-mediaframereader
The only thing I changed is the MediaEncodingSubtype, because it didn't worked with Argb32, so I use Rgb24 (I checked all the supported formats in my computer). And I think the problem is derived from this property. When I initialize the MediaFrameReader object with the subtype Argb32 (as you can see in the documentation example) I get no exception, although the SoftwareBitmap will be null. On the other hand, if I use Rgb24 (because the preferredFormat has this subtype) I get the exception.
I can show some details of the exception:
System.ArgumentException
HResult=0x80070057
Message=Value does not fall within the expected range.
Source=Windows
StackTrace:
at Windows.Media.Capture.Frames.MediaFrameReader.TryAcquireLatestFrame()
at FaceAPI.MainPage.<CheckFrameForFaces>d__17.MoveNext() in P:\Dokumentumok\Suli\BME-VIK_6\Klitech\Házi feladat\KlitechHF\FaceAPI\FaceAPI\MainPage.xaml.cs:line 217