techyian / MMALSharp

C# wrapper to Broadcom's MMAL with an API to the Raspberry Pi camera.
MIT License
195 stars 33 forks source link

Capturing still image to memory stream no longer working #200

Open mkj-stonehill opened 3 years ago

mkj-stonehill commented 3 years ago

I wanted to add dual camera support to MMALSharp, so I cloned the repo, and build it into my application (it was using version 0.6 from nuget before, to successfully capture images from camera 0).

There were a few changes required in my app with the latest version of MMALSharp (mostly the merged properties in MMALCameraConfig), but they seemed straight-forward. However, now when I run it, the very first await this.Cam.ProcessAsync(this.Cam.Camera.StillPort); I do never completes.

I've looked at Issue #198 (which is very similar); but I'm never even getting the StillPort.NativeOutputPortCallback call.

I've even looked through all of the diffs from the 0.6 release on, but nothing obvious (to me) jumps out. It's probably something stupid I'm doing (or not doing), that just happened to work on 0.6, but no longer does. Can you point me in the right direction?

I've added logging (using NLog), and here's the log I get:

2021-04-01 14:00:30.5362|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_CAMERA_NUM
2021-04-01 14:00:31.9463|DEBUG|MMALSharp|Camera config set
2021-04-01 14:00:31.9606|DEBUG|MMALSharp|vc.ril.camera:ctr:0 : Enabling control port.
2021-04-01 14:00:31.9639|DEBUG|MMALSharp|vc.ril.camera:ctr:0 : Enabling port.
2021-04-01 14:00:31.9639|DEBUG|MMALSharp|Configuring camera parameters.
2021-04-01 14:00:31.9785|DEBUG|MMALSharp|Getting parameter MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG
2021-04-01 14:00:32.0022|DEBUG|MMALSharp|Setting saturation: 0
2021-04-01 14:00:32.0043|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_SATURATION
2021-04-01 14:00:32.0505|DEBUG|MMALSharp|Setting sharpness: 0
2021-04-01 14:00:32.0528|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_SHARPNESS
2021-04-01 14:00:32.0528|DEBUG|MMALSharp|Setting contrast: 0
2021-04-01 14:00:32.0528|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_CONTRAST
2021-04-01 14:00:32.0624|DEBUG|MMALSharp|Setting brightness: 50
2021-04-01 14:00:32.0624|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_BRIGHTNESS
2021-04-01 14:00:32.0624|DEBUG|MMALSharp|Setting ISO: 200
2021-04-01 14:00:32.0624|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_ISO
2021-04-01 14:00:32.0857|DEBUG|MMALSharp|Setting video stabilisation: False
2021-04-01 14:00:32.0857|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_VIDEO_STABILISATION
2021-04-01 14:00:32.1047|DEBUG|MMALSharp|Setting exposure compensation: 0
2021-04-01 14:00:32.1047|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_EXPOSURE_COMP
2021-04-01 14:00:32.1047|DEBUG|MMALSharp|Setting exposure mode: MMAL_PARAM_EXPOSUREMODE_AUTO
2021-04-01 14:00:32.1179|DEBUG|MMALSharp|Setting exposure metering mode: MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
2021-04-01 14:00:32.1238|DEBUG|MMALSharp|Setting AWB mode: MMAL_PARAM_AWBMODE_AUTO
2021-04-01 14:00:32.1386|DEBUG|MMALSharp|Setting AWB gains: 0, 0
2021-04-01 14:00:32.1447|DEBUG|MMALSharp|Setting Image FX: MMAL_PARAM_IMAGEFX_NONE
2021-04-01 14:00:32.1447|DEBUG|MMALSharp|Setting colour effects
2021-04-01 14:00:32.1597|DEBUG|MMALSharp|Setting rotation: 0
2021-04-01 14:00:32.1597|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_ROTATION
2021-04-01 14:00:32.1650|DEBUG|MMALSharp|Setting shutter speed: 4000
2021-04-01 14:00:32.1650|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_SHUTTER_SPEED
2021-04-01 14:00:32.1650|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_CAPTURE_STATS_PASS
2021-04-01 14:00:32.1858|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_CAMERA_BURST_CAPTURE
2021-04-01 14:00:32.1858|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_ANALOG_GAIN
2021-04-01 14:00:32.1938|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_DIGITAL_GAIN
2021-04-01 14:00:32.1938|DEBUG|MMALSharp|Commit preview
2021-04-01 14:00:32.2127|DEBUG|MMALSharp|vc.ril.camera:out:0 : Committing port format changes.
2021-04-01 14:00:32.2287|DEBUG|MMALSharp|vc.ril.camera:out:0(OPQV) : Committing port format changes.
2021-04-01 14:00:32.2371|DEBUG|MMALSharp|Commit video
2021-04-01 14:00:32.2371|DEBUG|MMALSharp|vc.ril.camera:out:1 : Committing port format changes.
2021-04-01 14:00:32.2479|DEBUG|MMALSharp|vc.ril.camera:out:1(OPQV) : Committing port format changes.
2021-04-01 14:00:32.2595|DEBUG|MMALSharp|Commit still
2021-04-01 14:00:32.2632|DEBUG|MMALSharp|vc.ril.camera:out:2 : Committing port format changes.
2021-04-01 14:00:32.2632|DEBUG|MMALSharp|vc.ril.camera:out:2(OPQV) : Committing port format changes.
2021-04-01 14:00:32.3167|DEBUG|MMALSharp|Camera component configured.
2021-04-01 14:00:35.9231|DEBUG|MMALSharp|vc.ril.image_encode:in:0 : Shallow copy port format.
2021-04-01 14:00:35.9231|DEBUG|MMALSharp|vc.ril.image_encode:out:0 : Committing port format changes.
2021-04-01 14:00:35.9347|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Committing port format changes.
2021-04-01 14:00:35.9347|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_JPEG_Q_FACTOR
2021-04-01 14:00:35.9584|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_EXIF_DISABLE
2021-04-01 14:00:35.9841|DEBUG|MMALSharp|vc.ril.camera:out:2(OPQV) : Shallow copy port format.
2021-04-01 14:00:35.9841|DEBUG|MMALSharp|vc.ril.image_encode:in:0 : Committing port format changes.
2021-04-01 14:00:36.0036|DEBUG|MMALSharp|Enabling connection between vc.ril.camera:out:2(OPQV)  and vc.ril.image_encode:in:0(OPQV)
2021-04-01 14:00:36.0175|DEBUG|MMALSharp|Enabling connection between vc.ril.camera:out:0(OPQV)  and vc.null_sink:in:0(OPQV)
2021-04-01 14:00:37.1708|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Starting output port.
2021-04-01 14:00:37.1852|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Enabling port.
2021-04-01 14:00:37.1955|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Initialising buffer pool.
2021-04-01 14:00:37.2035|DEBUG|MMALSharp|Creating buffer pool with 1 buffers of size 81920
2021-04-01 14:00:37.2295|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Sending buffer to output port: Length 0.
2021-04-01 14:00:37.2343|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Sending buffer start.
2021-04-01 14:00:37.2343|DEBUG|MMALSharp|vc.ril.image_encode:out:0(JPEG) : Sending buffer complete.
2021-04-01 14:00:37.2453|DEBUG|MMALSharp|Setting shutter speed: 4000
2021-04-01 14:00:37.2453|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_SHUTTER_SPEED
2021-04-01 14:00:37.2453|DEBUG|MMALSharp|Setting parameter MMAL_PARAMETER_CAPTURE
mkj-stonehill commented 3 years ago

In order to debug this more easily, I created the following console application. When run, MMAL throws an exception on the ConfigureCameraSettings() call:

Unhandled Exception:

MMALSharp.MMALNoSpaceException: Out of resources. Unable to enable component occurred

If I comment out the line which sets the resolution, it runs successfully to completion, and I get 5 BMP files, all at the default resolution of 1280 x 720. How do I acquire still images of the max camera resolution? This is a Pi Camera V2.1, so it should be capable of 3280 x 2464, which is what I get when I take a picture using raspistill. Setting the resolution to anything larger than the default 1280 x 20 (e.g. I tried Resolution.As1080p) causes this exception

using MMALSharp;
using MMALSharp.Common;
using MMALSharp.Common.Utility;
using MMALSharp.Components;
using MMALSharp.Handlers;
using MMALSharp.Native;
using MMALSharp.Ports;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace cap
{
    class Program
    {
        async static Task Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            Console.WriteLine("Configuring camera pipeline...");
            sw.Start();

            // Configure various settings
            MMALCameraConfig.Resolution = new Resolution(3280, 2464);

            // Get reference to the (one and only) camera object
            MMALCamera cam = MMALCamera.Instance;

            using (var imgCaptureHandler = new MemoryStreamCaptureHandler())
            using (var imgEncoder = new MMALImageEncoder())
            using (var nullSink = new MMALNullSinkComponent())
            {
                cam.ConfigureCameraSettings();

                var portConfig = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90);
                imgEncoder.ConfigureOutputPort(portConfig, imgCaptureHandler);
                cam.Camera.StillPort.ConnectTo(imgEncoder);
                cam.Camera.PreviewPort.ConnectTo(nullSink);

                // Camera warm up time
                sw.Stop();
                Console.WriteLine($"{sw.ElapsedMilliseconds}ms; Warming up camera...");
                sw.Restart();
                await Task.Delay(2000);
                sw.Stop();
                Console.WriteLine($"{sw.ElapsedMilliseconds}ms;");

                for (int n=1; n<=5; n++)
                {
#if false
                    Console.WriteLine("\nHit any key to take a picture (ESC to exit)...");
                    k = Console.ReadKey();
                    if (k.Key == ConsoleKey.Escape)
                        break;
#endif
                    // Wait for the next picture
                    Console.WriteLine($"\nAcquiring picture {n}...");
                    sw.Restart();
                    await cam.ProcessAsync(cam.Camera.StillPort);
                    sw.Stop();
                    Console.WriteLine($"{sw.ElapsedMilliseconds}ms; saving to cap{n}.bmp...");
                    sw.Restart();
                    using (var bitmap = Bitmap.FromStream(imgCaptureHandler.CurrentStream))
                    {
                        bitmap.Save($"cap{n}.bmp");
                    }
                    sw.Stop();
                    Console.WriteLine($"{sw.ElapsedMilliseconds}ms;");
                }
                Console.WriteLine("\nExiting.");
            }
        }
    }
}
Kas-code commented 3 years ago

I've received an MMALNoSpaceException before when I've had two processes trying to aceess the camera at the same time. You could try rebooting the Pi, and check that you don't accidentally have two instances of your program running, and that raspistill isn't running at the same time.

If that doesn't solve the issue, the first thing I'd try is to change:

    cam.ConfigureCameraSettings();

to:

    cam.ConfigureCameraSettings(imgCaptureHandler);

Failing that, you could try removing the MMALImageEncoder, and use this method to convert the raw bytes to a bitmap instead:

        public static Bitmap BitmapFromRawData(byte[] data, int width, int height)
        {
            var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            var bmpData = bmp.LockBits(new Rectangle(0, 0,
                bmp.Width,
                bmp.Height),
            ImageLockMode.WriteOnly,
            bmp.PixelFormat);
            var pNative = bmpData.Scan0;
            Marshal.Copy(data, 0, pNative, width * height * 3);
            bmp.UnlockBits(bmpData);
            return bmp;
        }

If you use the method above, ensure you have your encoding set to:

   MMALCameraConfig.StillEncoding = MMALEncoding.BGR24;
   MMALCameraConfig.StillSubFormat = MMALEncoding.BGR24;