xamarinxamarin.formsuwpxamarin.uwpmediacapture

App MediaFrameReader always returns null Bitmap


I am using MediaCapture to preview camera on the screen, which is working fine.

However, I need to access the current frames in my App. Therefore I added FrameReader to the MediaCapture to get the event Reader_FrameArrived.

So the event is working, however the bitmap itself is always null.

I implemented the ecent callback just like shown in the examples:

var mediaFrameReference = sender.TryAcquireLatestFrame();
var videoMediaFrame = mediaFrameReference?.VideoMediaFrame;
var softwareBitmap = videoMediaFrame?.SoftwareBitmap;

if (softwareBitmap != null)
{
    Debug.WriteLine("here");
}
else
{
    return;
}

and this is how I initialize the reader:

var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();

var allGroups = await MediaFrameSourceGroup.FindAllAsync();
var eligibleGroups = allGroups.Select(g => new
{
    Group = g,

    // For each source kind, find the source which offers that kind of media frame,
    // or null if there is no such source.
    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; // Select the first eligible group
MediaFrameSourceGroup selectedGroup = eligibleGroups[selectedGroupIndex].Group;
MediaFrameSourceInfo colorSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[0];
MediaFrameSourceInfo infraredSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[1];
MediaFrameSourceInfo depthSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[2];

//_mediaCapture.FrameSources.TryGetValue(cameraDevice.Id, out _source);
var colorFrameSource = _mediaCapture.FrameSources[colorSourceInfo.Id];

if (colorFrameSource != null)
{
    _reader = await _mediaCapture.CreateFrameReaderAsync(colorFrameSource, MediaEncodingSubtypes.Argb32);
    _reader.FrameArrived += Reader_FrameArrived;
    
    MediaFrameReaderStartStatus result = await _reader.StartAsync();

    Debug.WriteLine(result.ToString());
}

Any ideas why the bitmap could be null?


Solution

  • I am using MediaCapture to preview camera on the screen, which is working fine.

    For the scenario, we suggest you use MediaCapture class capture bitmap, it contains GetPreviewFrameAsync method gets a preview frame from the capture device than convert it to SoftwareBitmap.

    private async Task GetPreviewFrameAsSoftwareBitmapAsync()
    {
        // Get information about the preview
        var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
    
        // Create the video frame to request a SoftwareBitmap preview frame
        var videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)previewProperties.Width, (int)previewProperties.Height);
    
        // Capture the preview frame
        using (var currentFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame))
        {
            // Collect the resulting frame
            SoftwareBitmap previewFrame = currentFrame.SoftwareBitmap;
    
            // Show the frame information
            FrameInfoTextBlock.Text = String.Format("{0}x{1} {2}", previewFrame.PixelWidth, previewFrame.PixelHeight, previewFrame.BitmapPixelFormat);
    
            // Add a simple green filter effect to the SoftwareBitmap
            if (GreenEffectCheckBox.IsChecked == true)
            {
                ApplyGreenFilter(previewFrame);
            }
    
            // Show the frame (as is, no rotation is being applied)
            if (ShowFrameCheckBox.IsChecked == true)
            {
                // Create a SoftwareBitmapSource to display the SoftwareBitmap to the user
                var sbSource = new SoftwareBitmapSource();
                await sbSource.SetBitmapAsync(previewFrame);
    
                // Display it in the Image control
                PreviewFrameImage.Source = sbSource;
            }
    
            // Save the frame (as is, no rotation is being applied)
            if (SaveFrameCheckBox.IsChecked == true)
            {
                var file = await _captureFolder.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName);
    
                Debug.WriteLine("Saving preview frame to " + file.Path);
    
                await SaveSoftwareBitmapAsync(previewFrame, file);
            }
        }
    }
    

    And here is official code sample that you could refer directly.