techyian / MMALSharp

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

CapturePictureTimeout generates some partial corrupt image files #128

Closed thnk2wn closed 4 years ago

thnk2wn commented 4 years ago

Using pre-release version 0.6.0-299 and I'm using TakePictureTimeout to capture multiple photos over a 5 second window (current config). Each time I notice there are multiple 0 byte image files generated and/or image files > 0 bytes but < 2 MB. In all the cases when the image files are below around 2 MB they are unusable.

These are files I copied over from the Pi. There are many that are valid but some each time that are empty / black / corrupt:

image

Is this a problem with my code (below) or something with the library? Are these pictures taken around the time the cancellation is invoked? Can the library take care of cleaning these up or is it something I need to delete on my own after based on file size?

        private async Task CaptureFootageAsync()
        {
            if (this.camera == null) this.camera = MMALCamera.Instance;

            if (!Directory.Exists(this.sirenSettings.MediaPath))
                Directory.CreateDirectory(this.sirenSettings.MediaPath);

            TimeSpan duration = this.CaptureDuration;

            this.logger.LogInformation(
                "Capturing footage to {path} for {duration}",
                this.sirenSettings.MediaPath,
                duration);

            using (var imgCaptureHandler = CreateImageStreamHandler())
            using (var cts = new CancellationTokenSource(duration))
            {
                await this.camera.TakePictureTimeout(
                    imgCaptureHandler,
                    MMALEncoding.JPEG,
                    MMALEncoding.I420,
                    cts.Token);
            }
        }

        private TimeSpan CaptureDuration => TimeSpan.FromSeconds(this.sirenSettings.CaptureDuration);

        private ImageStreamCaptureHandler CreateImageStreamHandler()
        {
            return new ImageStreamCaptureHandler(this.sirenSettings.MediaPath, "jpg");
        }
techyian commented 4 years ago

An extra check is needed here to make sure the Cancellation Token hasn't expired before making a new file. That seems to have resolved it locally for me. I'll commit a change now for you and you'll just need to grab the latest pre-release from MyGet. Thanks for noticing this :)

techyian commented 4 years ago

Regarding the image files which are less than the 2MB you mentioned, I don't seem to be able to reproduce that locally. Which camera module are you using and how much memory do you have allocated to the GPU? Are you seeing any warnings logged by the library?

thnk2wn commented 4 years ago

Great, thanks @techyian!

I have the Pi 4 with 4 GB RAM. I believe it allocates memory to the GPU as needed. I didn't do any custom configuration there so it's whatever the defaults are for the latest rapsbian lite image.

I do have a public repo with the app if it helps troubleshoot. Glad to pull latest whenever it's out and try again.

I think I'm using the standard camera module, believe it's this: https://uk.pi-supply.com/products/raspberry-pi-camera-board-v1-3-5mp-1080p. Here's a photo:

IMG_9967

techyian commented 4 years ago

I'm struggling to reproduce this unfortunately. I've tried with my Pi 4 2 GB with the OV5647 camera module which is the one you're using and images are being saved correctly. Both Mono and .NET Core 3.1 have been tested.

The camera will benefit from a larger memory split even on the Pi 4, so it may be worthwhile increasing that to 128/256 MB (I think 64 MB is the default). Are you using the official power supply?

I can't see anything immediately obvious in your repo that would affect the saving of images. The TakePictureTimeout helper method will return once your cancellation token has expired, but will ensure the last image is fully processed before doing so.

I know it sounds unlikely, but has there been an issue when copying the files over from the Pi or do the file sizes match what's stored on the Pi?

thnk2wn commented 4 years ago

I had already deleted the previously generated files on the Pi so I wasn't able to check those sizes.

Yeah using the official power supply.

In doing a new test, I do the 0 byte files on the PI:

image

It's possible that the files >0 bytes and < 2 MB were some kind of scp copy issue. So far I'm not seeing that issue on the Pi but I'll keep a look out. Your fix looks like it'd stop the 0 byte issue. I can test it out once pushed to Myget

techyian commented 4 years ago

Appveyor will automatically push to MyGet on each successful CI build - you'll find version 0.6.0-303 in MyGet which should hopefully resolve the 0 bytes issue.

thnk2wn commented 4 years ago

This appears fixed now. Thanks!